about summary refs log tree commit diff
path: root/src
diff options
context:
space:
mode:
authorMichael Biebl <biebl@debian.org>2016-08-03 22:59:23 +0200
committerMichael Biebl <biebl@debian.org>2016-08-03 22:59:23 +0200
commitd6201f5d8daada3d64a0a3e0038e14eebec683ce (patch)
tree035500728cc23e7ee5368c3fd605270265a077f7 /src
parent73e152af6e3fb4f5848bfb8394484026ff119003 (diff)
Imported Upstream version 1.2.4 upstream/1.2.4
Diffstat (limited to 'src')
-rw-r--r--src/Makefile.am10
-rw-r--r--src/Makefile.in67
-rw-r--r--src/NetworkManagerUtils.c1
-rw-r--r--src/devices/Makefile.in1
-rw-r--r--src/devices/adsl/Makefile.in1
-rw-r--r--src/devices/bluetooth/Makefile.in1
-rw-r--r--src/devices/bluetooth/nm-bluez-device.c88
-rw-r--r--src/devices/nm-device-bond.c2
-rw-r--r--src/devices/nm-device-tun.c7
-rw-r--r--src/devices/nm-device-vxlan.c7
-rw-r--r--src/devices/nm-device.c216
-rw-r--r--src/devices/nm-device.h4
-rw-r--r--src/devices/nm-lldp-listener.c4
-rw-r--r--src/devices/team/Makefile.in1
-rw-r--r--src/devices/team/nm-device-team.c14
-rw-r--r--src/devices/tests/Makefile.in1
-rw-r--r--src/devices/wifi/Makefile.in1
-rw-r--r--src/devices/wifi/nm-device-wifi.c2
-rw-r--r--src/devices/wifi/tests/Makefile.in1
-rw-r--r--src/devices/wwan/Makefile.in1
-rw-r--r--src/dhcp-manager/Makefile.in1
-rw-r--r--src/dhcp-manager/nm-dhcp-client.c2
-rw-r--r--src/dhcp-manager/nm-dhcp-dhclient-utils.c26
-rw-r--r--src/dhcp-manager/nm-dhcp-dhclient.c13
-rw-r--r--src/dhcp-manager/nm-dhcp-dhcpcd.c15
-rw-r--r--src/dhcp-manager/tests/Makefile.in1
-rw-r--r--src/dhcp-manager/tests/test-dhcp-dhclient.c41
-rw-r--r--src/dns-manager/nm-dns-dnsmasq.c286
-rw-r--r--src/dns-manager/nm-dns-manager.c953
-rw-r--r--src/dns-manager/nm-dns-manager.h66
-rw-r--r--src/dns-manager/nm-dns-plugin.c29
-rw-r--r--src/dns-manager/nm-dns-plugin.h26
-rw-r--r--src/dns-manager/nm-dns-unbound.c4
-rw-r--r--src/dns-manager/nm-dns-utils.c105
-rw-r--r--src/dns-manager/nm-dns-utils.h28
-rw-r--r--src/dnsmasq-manager/nm-dnsmasq-manager.c36
-rw-r--r--src/dnsmasq-manager/tests/Makefile.in1
-rw-r--r--src/main.c19
-rw-r--r--src/nm-active-connection.c385
-rw-r--r--src/nm-audit-manager.h1
-rw-r--r--src/nm-auth-utils.c3
-rw-r--r--src/nm-auth-utils.h17
-rw-r--r--src/nm-config-data.c2
-rw-r--r--src/nm-config-data.h92
-rw-r--r--src/nm-config.c81
-rw-r--r--src/nm-config.h8
-rw-r--r--src/nm-connection-provider.c9
-rw-r--r--src/nm-connection-provider.h8
-rw-r--r--src/nm-core-utils.c178
-rw-r--r--src/nm-core-utils.h7
-rw-r--r--src/nm-default-route-manager.c16
-rw-r--r--src/nm-enum-types.c67
-rw-r--r--src/nm-enum-types.h2
-rw-r--r--src/nm-ip4-config.c59
-rw-r--r--src/nm-ip4-config.h5
-rw-r--r--src/nm-ip6-config.c58
-rw-r--r--src/nm-ip6-config.h5
-rw-r--r--src/nm-manager.c393
-rw-r--r--src/nm-policy.c70
-rw-r--r--src/nm-sleep-monitor-systemd.c258
-rw-r--r--src/nm-sleep-monitor-upower.c134
-rw-r--r--src/nm-sleep-monitor.c396
-rw-r--r--src/nm-sleep-monitor.h14
-rw-r--r--src/platform/Makefile.in1
-rw-r--r--src/platform/nm-linux-platform.c80
-rw-r--r--src/platform/nm-platform.h2
-rw-r--r--src/platform/tests/Makefile.in1
-rw-r--r--src/platform/wifi/wifi-utils.c16
-rw-r--r--src/platform/wifi/wifi-utils.h4
-rw-r--r--src/ppp-manager/Makefile.in1
-rw-r--r--src/rdisc/Makefile.in1
-rw-r--r--src/rdisc/tests/Makefile.in1
-rw-r--r--src/settings/nm-agent-manager.c4
-rw-r--r--src/settings/nm-agent-manager.h2
-rw-r--r--src/settings/nm-secret-agent.c4
-rw-r--r--src/settings/nm-settings-connection.c177
-rw-r--r--src/settings/nm-settings-connection.h4
-rw-r--r--src/settings/nm-settings.c232
-rw-r--r--src/settings/nm-settings.h16
-rw-r--r--src/settings/plugins/Makefile.in1
-rw-r--r--src/settings/plugins/ibft/Makefile.in1
-rw-r--r--src/settings/plugins/ibft/tests/Makefile.in1
-rw-r--r--src/settings/plugins/ifcfg-rh/Makefile.in1
-rw-r--r--src/settings/plugins/ifcfg-rh/plugin.c4
-rw-r--r--src/settings/plugins/ifcfg-rh/reader.c5
-rw-r--r--src/settings/plugins/ifcfg-rh/tests/Makefile.in1
-rw-r--r--src/settings/plugins/ifcfg-rh/tests/network-scripts/Makefile.in1
-rw-r--r--src/settings/plugins/ifnet/Makefile.in1
-rw-r--r--src/settings/plugins/ifnet/tests/Makefile.in1
-rw-r--r--src/settings/plugins/ifupdown/Makefile.in1
-rw-r--r--src/settings/plugins/ifupdown/tests/Makefile.in1
-rw-r--r--src/settings/plugins/keyfile/Makefile.in1
-rw-r--r--src/settings/plugins/keyfile/tests/Makefile.in1
-rw-r--r--src/settings/plugins/keyfile/tests/keyfiles/Makefile.in1
-rw-r--r--src/supplicant-manager/tests/Makefile.in1
-rw-r--r--src/supplicant-manager/tests/certs/Makefile.in1
-rw-r--r--src/tests/Makefile.in1
-rw-r--r--src/tests/config/Makefile.in1
-rw-r--r--src/tests/config/test-config.c40
-rw-r--r--src/tests/test-general.c121
-rw-r--r--src/vpn-manager/nm-vpn-connection.c120
-rw-r--r--src/vpn-manager/nm-vpn-connection.h4
102 files changed, 3189 insertions, 2018 deletions
diff --git a/src/Makefile.am b/src/Makefile.am
index aa35eefb..48af5a06 100644
--- a/src/Makefile.am
+++ b/src/Makefile.am
@@ -305,8 +305,6 @@ libNetworkManager_la_SOURCES = \
 	dns-manager/nm-dns-manager.h \
 	dns-manager/nm-dns-plugin.c \
 	dns-manager/nm-dns-plugin.h \
-	dns-manager/nm-dns-utils.c \
-	dns-manager/nm-dns-utils.h \
 	\
 	dnsmasq-manager/nm-dnsmasq-manager.c \
 	dnsmasq-manager/nm-dnsmasq-manager.h \
@@ -438,6 +436,7 @@ libNetworkManager_la_SOURCES = \
 	nm-rfkill-manager.h \
 	nm-session-monitor.h \
 	nm-session-monitor.c \
+	nm-sleep-monitor.c \
 	nm-sleep-monitor.h \
 	nm-types.h \
 	nm-core-utils.c \
@@ -446,13 +445,6 @@ libNetworkManager_la_SOURCES = \
 	NetworkManagerUtils.h
 
 
-if SUSPEND_RESUME_UPOWER
-libNetworkManager_la_SOURCES += nm-sleep-monitor-upower.c
-else
-# systemd/consolekit suspend/resume used whenever upower is not enabled
-libNetworkManager_la_SOURCES += nm-sleep-monitor-systemd.c
-endif
-
 if WITH_WEXT
 libNetworkManager_la_SOURCES += \
 	platform/wifi/wifi-utils-wext.c \
diff --git a/src/Makefile.in b/src/Makefile.in
index 51ded6bc..1047880d 100644
--- a/src/Makefile.in
+++ b/src/Makefile.in
@@ -110,15 +110,12 @@ host_triplet = @host@
 @ENABLE_TESTS_TRUE@	libNetworkManager-base.la
 
 sbin_PROGRAMS = NetworkManager$(EXEEXT)
-@SUSPEND_RESUME_UPOWER_TRUE@am__append_6 = nm-sleep-monitor-upower.c
-# systemd/consolekit suspend/resume used whenever upower is not enabled
-@SUSPEND_RESUME_UPOWER_FALSE@am__append_7 = nm-sleep-monitor-systemd.c
-@WITH_WEXT_TRUE@am__append_8 = \
+@WITH_WEXT_TRUE@am__append_6 = \
 @WITH_WEXT_TRUE@	platform/wifi/wifi-utils-wext.c \
 @WITH_WEXT_TRUE@	platform/wifi/wifi-utils-wext.h
 
-@WITH_LIBSOUP_TRUE@am__append_9 = $(LIBSOUP_LIBS)
-@WITH_WEXT_TRUE@am__append_10 = \
+@WITH_LIBSOUP_TRUE@am__append_7 = $(LIBSOUP_LIBS)
+@WITH_WEXT_TRUE@am__append_8 = \
 @WITH_WEXT_TRUE@	platform/wifi/wifi-utils-wext.c \
 @WITH_WEXT_TRUE@	platform/wifi/wifi-utils-wext.h
 
@@ -197,8 +194,7 @@ am__libNetworkManager_la_SOURCES_DIST = devices/nm-device-bond.h \
 	dns-manager/nm-dns-dnsmasq.h dns-manager/nm-dns-unbound.c \
 	dns-manager/nm-dns-unbound.h dns-manager/nm-dns-manager.c \
 	dns-manager/nm-dns-manager.h dns-manager/nm-dns-plugin.c \
-	dns-manager/nm-dns-plugin.h dns-manager/nm-dns-utils.c \
-	dns-manager/nm-dns-utils.h \
+	dns-manager/nm-dns-plugin.h \
 	dnsmasq-manager/nm-dnsmasq-manager.c \
 	dnsmasq-manager/nm-dnsmasq-manager.h \
 	dnsmasq-manager/nm-dnsmasq-utils.c \
@@ -262,26 +258,21 @@ am__libNetworkManager_la_SOURCES_DIST = devices/nm-device-bond.h \
 	nm-auth-subject.h nm-auth-utils.c nm-auth-utils.h nm-manager.c \
 	nm-manager.h nm-multi-index.c nm-multi-index.h nm-policy.c \
 	nm-policy.h nm-rfkill-manager.c nm-rfkill-manager.h \
-	nm-session-monitor.h nm-session-monitor.c nm-sleep-monitor.h \
-	nm-types.h nm-core-utils.c nm-core-utils.h \
+	nm-session-monitor.h nm-session-monitor.c nm-sleep-monitor.c \
+	nm-sleep-monitor.h nm-types.h nm-core-utils.c nm-core-utils.h \
 	NetworkManagerUtils.c NetworkManagerUtils.h \
-	nm-sleep-monitor-upower.c nm-sleep-monitor-systemd.c \
 	platform/wifi/wifi-utils-wext.c \
 	platform/wifi/wifi-utils-wext.h
 am__objects_1 =
-@SUSPEND_RESUME_UPOWER_TRUE@am__objects_2 =  \
-@SUSPEND_RESUME_UPOWER_TRUE@	nm-sleep-monitor-upower.lo
-@SUSPEND_RESUME_UPOWER_FALSE@am__objects_3 =  \
-@SUSPEND_RESUME_UPOWER_FALSE@	nm-sleep-monitor-systemd.lo
-@WITH_WEXT_TRUE@am__objects_4 = wifi-utils-wext.lo
+@WITH_WEXT_TRUE@am__objects_2 = wifi-utils-wext.lo
 am_libNetworkManager_la_OBJECTS = $(am__objects_1) $(am__objects_1) \
 	nm-device.lo nm-lldp-listener.lo nm-arping-manager.lo \
 	nm-device-ethernet-utils.lo nm-device-factory.lo \
 	nm-device-generic.lo nm-dhcp-client.lo nm-dhcp-utils.lo \
 	nm-dhcp-listener.lo nm-dhcp-manager.lo nm-dns-dnsmasq.lo \
 	nm-dns-unbound.lo nm-dns-manager.lo nm-dns-plugin.lo \
-	nm-dns-utils.lo nm-dnsmasq-manager.lo nm-dnsmasq-utils.lo \
-	nmp-netns.lo nmp-object.lo nm-platform-utils.lo nm-platform.lo \
+	nm-dnsmasq-manager.lo nm-dnsmasq-utils.lo nmp-netns.lo \
+	nmp-object.lo nm-platform-utils.lo nm-platform.lo \
 	nm-linux-platform.lo nm-fake-platform.lo wifi-utils-nl80211.lo \
 	wifi-utils.lo nm-fake-rdisc.lo nm-lndp-rdisc.lo nm-rdisc.lo \
 	nm-ppp-manager.lo nm-agent-manager.lo nm-inotify-helper.lo \
@@ -300,8 +291,8 @@ am_libNetworkManager_la_OBJECTS = $(am__objects_1) $(am__objects_1) \
 	nm-ip6-config.lo nm-logging.lo nm-auth-manager.lo \
 	nm-auth-subject.lo nm-auth-utils.lo nm-manager.lo \
 	nm-multi-index.lo nm-policy.lo nm-rfkill-manager.lo \
-	nm-session-monitor.lo nm-core-utils.lo NetworkManagerUtils.lo \
-	$(am__objects_2) $(am__objects_3) $(am__objects_4)
+	nm-session-monitor.lo nm-sleep-monitor.lo nm-core-utils.lo \
+	NetworkManagerUtils.lo $(am__objects_2)
 libNetworkManager_la_OBJECTS = $(am_libNetworkManager_la_OBJECTS)
 libnm_iface_helper_la_DEPENDENCIES =  \
 	$(top_builddir)/libnm-core/libnm-core.la \
@@ -340,7 +331,7 @@ am_libnm_iface_helper_la_OBJECTS = nm-dhcp-client.lo nm-dhcp-utils.lo \
 	nm-lndp-rdisc.lo nm-rdisc.lo nm-route-manager.lo \
 	nm-exported-object.lo nm-ip4-config.lo nm-ip6-config.lo \
 	nm-enum-types.lo nm-logging.lo nm-multi-index.lo \
-	nm-core-utils.lo NetworkManagerUtils.lo $(am__objects_4)
+	nm-core-utils.lo NetworkManagerUtils.lo $(am__objects_2)
 libnm_iface_helper_la_OBJECTS = $(am_libnm_iface_helper_la_OBJECTS)
 libsystemd_nm_la_DEPENDENCIES = $(am__DEPENDENCIES_1)
 am_libsystemd_nm_la_OBJECTS = libsystemd_nm_la-nm-sd.lo \
@@ -379,16 +370,16 @@ libsystemd_nm_la_OBJECTS = $(am_libsystemd_nm_la_OBJECTS)
 am__installdirs = "$(DESTDIR)$(libexecdir)" "$(DESTDIR)$(sbindir)" \
 	"$(DESTDIR)$(dbusservicedir)"
 PROGRAMS = $(libexec_PROGRAMS) $(sbin_PROGRAMS)
-am__objects_5 = nm-device-bond.$(OBJEXT) nm-device-bridge.$(OBJEXT) \
+am__objects_3 = nm-device-bond.$(OBJEXT) nm-device-bridge.$(OBJEXT) \
 	nm-device-ethernet.$(OBJEXT) nm-device-infiniband.$(OBJEXT) \
 	nm-device-ip-tunnel.$(OBJEXT) nm-device-macvlan.$(OBJEXT) \
 	nm-device-tun.$(OBJEXT) nm-device-veth.$(OBJEXT) \
 	nm-device-vlan.$(OBJEXT) nm-device-vxlan.$(OBJEXT)
-am__objects_6 = nm-dhcp-dhclient.$(OBJEXT) \
+am__objects_4 = nm-dhcp-dhclient.$(OBJEXT) \
 	nm-dhcp-dhclient-utils.$(OBJEXT) nm-dhcp-dhcpcd.$(OBJEXT) \
 	nm-dhcp-systemd.$(OBJEXT)
-am_NetworkManager_OBJECTS = $(am__objects_5) $(am__objects_1) \
-	$(am__objects_6) $(am__objects_1) main-utils.$(OBJEXT) \
+am_NetworkManager_OBJECTS = $(am__objects_3) $(am__objects_1) \
+	$(am__objects_4) $(am__objects_1) main-utils.$(OBJEXT) \
 	main.$(OBJEXT)
 NetworkManager_OBJECTS = $(am_NetworkManager_OBJECTS)
 NetworkManager_DEPENDENCIES = libNetworkManager.la
@@ -685,6 +676,7 @@ NEWT_LIBS = @NEWT_LIBS@
 NM = @NM@
 NMEDIT = @NMEDIT@
 NM_CONFIG_DEFAULT_AUTH_POLKIT_TEXT = @NM_CONFIG_DEFAULT_AUTH_POLKIT_TEXT@
+NM_CONFIG_DEFAULT_DNS_RC_MANAGER = @NM_CONFIG_DEFAULT_DNS_RC_MANAGER@
 NM_CONFIG_DEFAULT_LOGGING_AUDIT_TEXT = @NM_CONFIG_DEFAULT_LOGGING_AUDIT_TEXT@
 NM_CONFIG_LOGGING_BACKEND_DEFAULT_TEXT = @NM_CONFIG_LOGGING_BACKEND_DEFAULT_TEXT@
 NM_MAJOR_VERSION = @NM_MAJOR_VERSION@
@@ -1065,8 +1057,7 @@ libNetworkManager_la_SOURCES = $(nm_device_headers) \
 	dns-manager/nm-dns-dnsmasq.h dns-manager/nm-dns-unbound.c \
 	dns-manager/nm-dns-unbound.h dns-manager/nm-dns-manager.c \
 	dns-manager/nm-dns-manager.h dns-manager/nm-dns-plugin.c \
-	dns-manager/nm-dns-plugin.h dns-manager/nm-dns-utils.c \
-	dns-manager/nm-dns-utils.h \
+	dns-manager/nm-dns-plugin.h \
 	dnsmasq-manager/nm-dnsmasq-manager.c \
 	dnsmasq-manager/nm-dnsmasq-manager.h \
 	dnsmasq-manager/nm-dnsmasq-utils.c \
@@ -1130,10 +1121,9 @@ libNetworkManager_la_SOURCES = $(nm_device_headers) \
 	nm-auth-subject.h nm-auth-utils.c nm-auth-utils.h nm-manager.c \
 	nm-manager.h nm-multi-index.c nm-multi-index.h nm-policy.c \
 	nm-policy.h nm-rfkill-manager.c nm-rfkill-manager.h \
-	nm-session-monitor.h nm-session-monitor.c nm-sleep-monitor.h \
-	nm-types.h nm-core-utils.c nm-core-utils.h \
-	NetworkManagerUtils.c NetworkManagerUtils.h $(am__append_6) \
-	$(am__append_7) $(am__append_8)
+	nm-session-monitor.h nm-session-monitor.c nm-sleep-monitor.c \
+	nm-sleep-monitor.h nm-types.h nm-core-utils.c nm-core-utils.h \
+	NetworkManagerUtils.c NetworkManagerUtils.h $(am__append_6)
 GLIB_GENERATED = nm-enum-types.h nm-enum-types.c
 GLIB_MKENUMS_H_FLAGS = --identifier-prefix NM --fhead '\#include <nm-core-enum-types.h>\n'
 GLIB_MKENUMS_C_FLAGS = --identifier-prefix NM
@@ -1151,7 +1141,7 @@ libNetworkManager_la_LIBADD =  \
 	$(top_builddir)/introspection/libnmdbus.la libsystemd-nm.la \
 	$(GLIB_LIBS) $(GUDEV_LIBS) $(LIBNL_LIBS) $(SYSTEMD_LOGIN_LIBS) \
 	$(SYSTEMD_JOURNAL_LIBS) $(LIBNDP_LIBS) $(LIBDL) $(LIBM) \
-	$(SELINUX_LIBS) $(LIBAUDIT_LIBS) $(am__append_9)
+	$(SELINUX_LIBS) $(LIBAUDIT_LIBS) $(am__append_7)
 NetworkManager_LDFLAGS = \
 	-rdynamic \
 	-Wl,--version-script="$(srcdir)/NetworkManager.ver"
@@ -1179,7 +1169,7 @@ libnm_iface_helper_la_SOURCES = dhcp-manager/nm-dhcp-client.c \
 	nm-ip6-config.c nm-ip6-config.h nm-enum-types.c \
 	nm-enum-types.h nm-logging.c nm-logging.h nm-multi-index.c \
 	nm-multi-index.h nm-core-utils.c nm-core-utils.h \
-	NetworkManagerUtils.c NetworkManagerUtils.h $(am__append_10)
+	NetworkManagerUtils.c NetworkManagerUtils.h $(am__append_8)
 libnm_iface_helper_la_LIBADD = \
 	$(top_builddir)/libnm-core/libnm-core.la \
 	$(top_builddir)/introspection/libnmdbus.la \
@@ -1491,7 +1481,6 @@ distclean-compile:
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/nm-dns-manager.Plo@am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/nm-dns-plugin.Plo@am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/nm-dns-unbound.Plo@am__quote@
-@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/nm-dns-utils.Plo@am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/nm-dnsmasq-manager.Plo@am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/nm-dnsmasq-utils.Plo@am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/nm-enum-types.Plo@am__quote@
@@ -1522,8 +1511,7 @@ distclean-compile:
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/nm-settings-connection.Plo@am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/nm-settings-plugin.Plo@am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/nm-settings.Plo@am__quote@
-@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/nm-sleep-monitor-systemd.Plo@am__quote@
-@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/nm-sleep-monitor-upower.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/nm-sleep-monitor.Plo@am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/nm-supplicant-config.Plo@am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/nm-supplicant-interface.Plo@am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/nm-supplicant-manager.Plo@am__quote@
@@ -1673,13 +1661,6 @@ nm-dns-plugin.lo: dns-manager/nm-dns-plugin.c
 @AMDEP_TRUE@@am__fastdepCC_FALSE@	DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
 @am__fastdepCC_FALSE@	$(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o nm-dns-plugin.lo `test -f 'dns-manager/nm-dns-plugin.c' || echo '$(srcdir)/'`dns-manager/nm-dns-plugin.c
 
-nm-dns-utils.lo: dns-manager/nm-dns-utils.c
-@am__fastdepCC_TRUE@	$(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT nm-dns-utils.lo -MD -MP -MF $(DEPDIR)/nm-dns-utils.Tpo -c -o nm-dns-utils.lo `test -f 'dns-manager/nm-dns-utils.c' || echo '$(srcdir)/'`dns-manager/nm-dns-utils.c
-@am__fastdepCC_TRUE@	$(AM_V_at)$(am__mv) $(DEPDIR)/nm-dns-utils.Tpo $(DEPDIR)/nm-dns-utils.Plo
-@AMDEP_TRUE@@am__fastdepCC_FALSE@	$(AM_V_CC)source='dns-manager/nm-dns-utils.c' object='nm-dns-utils.lo' libtool=yes @AMDEPBACKSLASH@
-@AMDEP_TRUE@@am__fastdepCC_FALSE@	DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
-@am__fastdepCC_FALSE@	$(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o nm-dns-utils.lo `test -f 'dns-manager/nm-dns-utils.c' || echo '$(srcdir)/'`dns-manager/nm-dns-utils.c
-
 nm-dnsmasq-manager.lo: dnsmasq-manager/nm-dnsmasq-manager.c
 @am__fastdepCC_TRUE@	$(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT nm-dnsmasq-manager.lo -MD -MP -MF $(DEPDIR)/nm-dnsmasq-manager.Tpo -c -o nm-dnsmasq-manager.lo `test -f 'dnsmasq-manager/nm-dnsmasq-manager.c' || echo '$(srcdir)/'`dnsmasq-manager/nm-dnsmasq-manager.c
 @am__fastdepCC_TRUE@	$(AM_V_at)$(am__mv) $(DEPDIR)/nm-dnsmasq-manager.Tpo $(DEPDIR)/nm-dnsmasq-manager.Plo
diff --git a/src/NetworkManagerUtils.c b/src/NetworkManagerUtils.c
index 09ed25c5..9894872b 100644
--- a/src/NetworkManagerUtils.c
+++ b/src/NetworkManagerUtils.c
@@ -23,6 +23,7 @@
 
 #include "NetworkManagerUtils.h"
 
+#include "nm-common-macros.h"
 #include "nm-utils.h"
 #include "nm-setting-connection.h"
 #include "nm-setting-ip4-config.h"
diff --git a/src/devices/Makefile.in b/src/devices/Makefile.in
index 4415d31b..d6848e53 100644
--- a/src/devices/Makefile.in
+++ b/src/devices/Makefile.in
@@ -324,6 +324,7 @@ NEWT_LIBS = @NEWT_LIBS@
 NM = @NM@
 NMEDIT = @NMEDIT@
 NM_CONFIG_DEFAULT_AUTH_POLKIT_TEXT = @NM_CONFIG_DEFAULT_AUTH_POLKIT_TEXT@
+NM_CONFIG_DEFAULT_DNS_RC_MANAGER = @NM_CONFIG_DEFAULT_DNS_RC_MANAGER@
 NM_CONFIG_DEFAULT_LOGGING_AUDIT_TEXT = @NM_CONFIG_DEFAULT_LOGGING_AUDIT_TEXT@
 NM_CONFIG_LOGGING_BACKEND_DEFAULT_TEXT = @NM_CONFIG_LOGGING_BACKEND_DEFAULT_TEXT@
 NM_MAJOR_VERSION = @NM_MAJOR_VERSION@
diff --git a/src/devices/adsl/Makefile.in b/src/devices/adsl/Makefile.in
index c8549200..b6805537 100644
--- a/src/devices/adsl/Makefile.in
+++ b/src/devices/adsl/Makefile.in
@@ -351,6 +351,7 @@ NEWT_LIBS = @NEWT_LIBS@
 NM = @NM@
 NMEDIT = @NMEDIT@
 NM_CONFIG_DEFAULT_AUTH_POLKIT_TEXT = @NM_CONFIG_DEFAULT_AUTH_POLKIT_TEXT@
+NM_CONFIG_DEFAULT_DNS_RC_MANAGER = @NM_CONFIG_DEFAULT_DNS_RC_MANAGER@
 NM_CONFIG_DEFAULT_LOGGING_AUDIT_TEXT = @NM_CONFIG_DEFAULT_LOGGING_AUDIT_TEXT@
 NM_CONFIG_LOGGING_BACKEND_DEFAULT_TEXT = @NM_CONFIG_LOGGING_BACKEND_DEFAULT_TEXT@
 NM_MAJOR_VERSION = @NM_MAJOR_VERSION@
diff --git a/src/devices/bluetooth/Makefile.in b/src/devices/bluetooth/Makefile.in
index 233ad9e8..d2b0b865 100644
--- a/src/devices/bluetooth/Makefile.in
+++ b/src/devices/bluetooth/Makefile.in
@@ -372,6 +372,7 @@ NEWT_LIBS = @NEWT_LIBS@
 NM = @NM@
 NMEDIT = @NMEDIT@
 NM_CONFIG_DEFAULT_AUTH_POLKIT_TEXT = @NM_CONFIG_DEFAULT_AUTH_POLKIT_TEXT@
+NM_CONFIG_DEFAULT_DNS_RC_MANAGER = @NM_CONFIG_DEFAULT_DNS_RC_MANAGER@
 NM_CONFIG_DEFAULT_LOGGING_AUDIT_TEXT = @NM_CONFIG_DEFAULT_LOGGING_AUDIT_TEXT@
 NM_CONFIG_LOGGING_BACKEND_DEFAULT_TEXT = @NM_CONFIG_LOGGING_BACKEND_DEFAULT_TEXT@
 NM_MAJOR_VERSION = @NM_MAJOR_VERSION@
diff --git a/src/devices/bluetooth/nm-bluez-device.c b/src/devices/bluetooth/nm-bluez-device.c
index 5ee22f93..dcfa5eec 100644
--- a/src/devices/bluetooth/nm-bluez-device.c
+++ b/src/devices/bluetooth/nm-bluez-device.c
@@ -54,6 +54,8 @@ typedef struct {
 	gboolean usable;
 	NMBluetoothCapabilities connection_bt_type;
 
+	guint check_emit_usable_id;
+
 	char *adapter_address;
 	char *address;
 	char *name;
@@ -257,14 +259,14 @@ pan_connection_check_create (NMBluezDevice *self)
 	g_free (uuid);
 }
 
-static void
+static gboolean
 check_emit_usable (NMBluezDevice *self)
 {
 	NMBluezDevicePrivate *priv = NM_BLUEZ_DEVICE_GET_PRIVATE (self);
 	gboolean new_usable;
 
 	/* only expect the supported capabilities set. */
-	g_assert ((priv->capabilities & ~(NM_BT_CAPABILITY_NAP | NM_BT_CAPABILITY_DUN)) == NM_BT_CAPABILITY_NONE );
+	nm_assert ((priv->capabilities & ~(NM_BT_CAPABILITY_NAP | NM_BT_CAPABILITY_DUN)) == NM_BT_CAPABILITY_NONE );
 
 	new_usable = (priv->initialized && priv->capabilities && priv->name &&
 	              ((priv->bluez_version == 4) ||
@@ -291,6 +293,17 @@ END:
 		priv->usable = new_usable;
 		g_object_notify (G_OBJECT (self), NM_BLUEZ_DEVICE_USABLE);
 	}
+
+	return G_SOURCE_REMOVE;
+}
+
+static void
+check_emit_usable_schedule (NMBluezDevice *self)
+{
+	NMBluezDevicePrivate *priv = NM_BLUEZ_DEVICE_GET_PRIVATE (self);
+
+	if (priv->check_emit_usable_id == 0)
+		priv->check_emit_usable_id = g_idle_add ((GSourceFunc) check_emit_usable, self);
 }
 
 /********************************************************************/
@@ -331,15 +344,26 @@ connection_compatible (NMBluezDevice *self, NMConnection *connection)
 	return TRUE;
 }
 
-static void
-_internal_add_connection (NMBluezDevice *self, NMConnection *connection)
+static gboolean
+_internal_track_connection (NMBluezDevice *self, NMConnection *connection, gboolean tracked)
 {
 	NMBluezDevicePrivate *priv = NM_BLUEZ_DEVICE_GET_PRIVATE (self);
+	gboolean was_tracked;
+
+	was_tracked = !!g_slist_find (priv->connections, connection);
+	if (was_tracked == !!tracked)
+		return FALSE;
 
-	if (!g_slist_find (priv->connections, connection)) {
+	if (tracked)
 		priv->connections = g_slist_prepend (priv->connections, g_object_ref (connection));
-		check_emit_usable (self);
+	else {
+		priv->connections = g_slist_remove (priv->connections, connection);
+		if (priv->pan_connection == connection)
+			priv->pan_connection = NULL;
+		g_object_unref (connection);
 	}
+
+	return TRUE;
 }
 
 static void
@@ -347,8 +371,10 @@ cp_connection_added (NMConnectionProvider *provider,
                      NMConnection *connection,
                      NMBluezDevice *self)
 {
-	if (connection_compatible (self, connection))
-		_internal_add_connection (self, connection);
+	if (connection_compatible (self, connection)) {
+		if (_internal_track_connection (self, connection, TRUE))
+			check_emit_usable (self);
+	}
 }
 
 static void
@@ -356,15 +382,8 @@ cp_connection_removed (NMConnectionProvider *provider,
                        NMConnection *connection,
                        NMBluezDevice *self)
 {
-	NMBluezDevicePrivate *priv = NM_BLUEZ_DEVICE_GET_PRIVATE (self);
-
-	if (g_slist_find (priv->connections, connection)) {
-		priv->connections = g_slist_remove (priv->connections, connection);
-		if (priv->pan_connection == connection)
-			priv->pan_connection = NULL;
-		g_object_unref (connection);
+	if (_internal_track_connection (self, connection, FALSE))
 		check_emit_usable (self);
-	}
 }
 
 static void
@@ -372,10 +391,9 @@ cp_connection_updated (NMConnectionProvider *provider,
                        NMConnection *connection,
                        NMBluezDevice *self)
 {
-	if (connection_compatible (self, connection))
-		_internal_add_connection (self, connection);
-	else
-		cp_connection_removed (provider, connection, self);
+	if (_internal_track_connection (self, connection,
+	                                connection_compatible (self, connection)))
+		check_emit_usable_schedule (self);
 }
 
 static void
@@ -383,10 +401,17 @@ load_connections (NMBluezDevice *self)
 {
 	NMBluezDevicePrivate *priv = NM_BLUEZ_DEVICE_GET_PRIVATE (self);
 	const GSList *connections, *iter;
+	gboolean changed = FALSE;
 
 	connections = nm_connection_provider_get_connections (priv->provider);
-	for (iter = connections; iter; iter = g_slist_next (iter))
-		cp_connection_added (priv->provider, NM_CONNECTION (iter->data), self);
+	for (iter = connections; iter; iter = g_slist_next (iter)) {
+		NMConnection *connection = iter->data;
+
+		if (connection_compatible (self, connection))
+			changed |= _internal_track_connection (self, connection, TRUE);
+	}
+	if (changed)
+		check_emit_usable (self);
 }
 
 /***********************************************************/
@@ -1031,20 +1056,9 @@ nm_bluez_device_new (const char *path,
 	if (adapter_address)
 		set_adapter_address (self, adapter_address);
 
-	g_signal_connect (priv->provider,
-	                  NM_CP_SIGNAL_CONNECTION_ADDED,
-	                  G_CALLBACK (cp_connection_added),
-	                  self);
-
-	g_signal_connect (priv->provider,
-	                  NM_CP_SIGNAL_CONNECTION_REMOVED,
-	                  G_CALLBACK (cp_connection_removed),
-	                  self);
-
-	g_signal_connect (priv->provider,
-	                  NM_CP_SIGNAL_CONNECTION_UPDATED,
-	                  G_CALLBACK (cp_connection_updated),
-	                  self);
+	g_signal_connect (priv->provider, NM_CP_SIGNAL_CONNECTION_ADDED,   G_CALLBACK (cp_connection_added),   self);
+	g_signal_connect (priv->provider, NM_CP_SIGNAL_CONNECTION_REMOVED, G_CALLBACK (cp_connection_removed), self);
+	g_signal_connect (priv->provider, NM_CP_SIGNAL_CONNECTION_UPDATED, G_CALLBACK (cp_connection_updated), self);
 
 	g_bus_get (G_BUS_TYPE_SYSTEM,
 	           NULL,
@@ -1084,6 +1098,8 @@ dispose (GObject *object)
 	NMBluezDevicePrivate *priv = NM_BLUEZ_DEVICE_GET_PRIVATE (self);
 	NMConnection *to_delete = NULL;
 
+	nm_clear_g_source (&priv->check_emit_usable_id);
+
 	if (priv->pan_connection) {
 		/* Check whether we want to remove the created connection. If so, we take a reference
 		 * and delete it at the end of dispose(). */
diff --git a/src/devices/nm-device-bond.c b/src/devices/nm-device-bond.c
index 6ae29b9c..9c98c8ea 100644
--- a/src/devices/nm-device-bond.c
+++ b/src/devices/nm-device-bond.c
@@ -316,7 +316,7 @@ apply_bonding_config (NMDevice *device)
 	if (NM_IN_STRSET (mode, "active-backup", "balance-alb", "balance-tlb")) {
 		value = nm_setting_bond_get_option_by_name (s_bond, NM_SETTING_BOND_OPTION_PRIMARY);
 		set_bond_attr (device, "primary", value ? value : "");
-		set_simple_option (device, "lp_internal", s_bond, NM_SETTING_BOND_OPTION_LP_INTERVAL);
+		set_simple_option (device, "lp_interval", s_bond, NM_SETTING_BOND_OPTION_LP_INTERVAL);
 	}
 
 	/* Clear ARP targets */
diff --git a/src/devices/nm-device-tun.c b/src/devices/nm-device-tun.c
index eac2fb82..01cd8ea6 100644
--- a/src/devices/nm-device-tun.c
+++ b/src/devices/nm-device-tun.c
@@ -104,6 +104,12 @@ reload_tun_properties (NMDeviceTun *self)
 	g_object_thaw_notify (object);
 }
 
+static NMDeviceCapabilities
+get_generic_capabilities (NMDevice *dev)
+{
+	return NM_DEVICE_CAP_IS_SOFTWARE;
+}
+
 static void
 link_changed (NMDevice *device, NMPlatformLink *info)
 {
@@ -430,6 +436,7 @@ nm_device_tun_class_init (NMDeviceTunClass *klass)
 	device_class->complete_connection = complete_connection;
 	device_class->check_connection_compatible = check_connection_compatible;
 	device_class->create_and_realize = create_and_realize;
+	device_class->get_generic_capabilities = get_generic_capabilities;
 	device_class->realize_start_notify = realize_start_notify;
 	device_class->unrealize_notify = unrealize_notify;
 	device_class->update_connection = update_connection;
diff --git a/src/devices/nm-device-vxlan.c b/src/devices/nm-device-vxlan.c
index d308d47a..45f33bdd 100644
--- a/src/devices/nm-device-vxlan.c
+++ b/src/devices/nm-device-vxlan.c
@@ -136,6 +136,12 @@ update_properties (NMDevice *device)
 	g_object_thaw_notify (object);
 }
 
+static NMDeviceCapabilities
+get_generic_capabilities (NMDevice *dev)
+{
+	return NM_DEVICE_CAP_IS_SOFTWARE;
+}
+
 static void
 link_changed (NMDevice *device, NMPlatformLink *info)
 {
@@ -647,6 +653,7 @@ nm_device_vxlan_class_init (NMDeviceVxlanClass *klass)
 	device_class->create_and_realize = create_and_realize;
 	device_class->check_connection_compatible = check_connection_compatible;
 	device_class->complete_connection = complete_connection;
+	device_class->get_generic_capabilities = get_generic_capabilities;
 	device_class->update_connection = update_connection;
 	device_class->act_stage1_prepare = act_stage1_prepare;
 	device_class->ip4_config_pre_commit = ip4_config_pre_commit;
diff --git a/src/devices/nm-device.c b/src/devices/nm-device.c
index 8472ff80..62259bc4 100644
--- a/src/devices/nm-device.c
+++ b/src/devices/nm-device.c
@@ -34,7 +34,7 @@
 #include <netlink/route/addr.h>
 #include <linux/if_addr.h>
 
-#include "nm-device.h"
+#include "nm-common-macros.h"
 #include "nm-device-private.h"
 #include "NetworkManagerUtils.h"
 #include "nm-manager.h"
@@ -387,6 +387,9 @@ static gboolean nm_device_set_ip6_config (NMDevice *self,
                                           gboolean commit,
                                           gboolean routes_full_sync,
                                           NMDeviceStateReason *reason);
+static gboolean ip6_config_merge_and_apply (NMDevice *self,
+                                            gboolean commit,
+                                            NMDeviceStateReason *out_reason);
 
 static void nm_device_master_add_slave (NMDevice *self, NMDevice *slave, gboolean configure);
 static void nm_device_slave_notify_enslave (NMDevice *self, gboolean success);
@@ -413,6 +416,7 @@ static NMActStageReturn dhcp4_start (NMDevice *self, NMConnection *connection, N
 static gboolean dhcp6_start (NMDevice *self, gboolean wait_for_ll, NMDeviceStateReason *reason);
 static void nm_device_start_ip_check (NMDevice *self);
 static void realize_start_setup (NMDevice *self, const NMPlatformLink *plink);
+static void nm_device_set_mtu (NMDevice *self, guint32 mtu);
 
 /***********************************************************/
 
@@ -520,6 +524,34 @@ NM_UTILS_LOOKUP_STR_DEFINE_STATIC (_reason_to_string, NMDeviceStateReason,
 
 /***********************************************************/
 
+static void
+init_ip4_config_dns_priority (NMDevice *self, NMIP4Config *config)
+{
+	gs_free char *value = NULL;
+	gint priority;
+
+	value = nm_config_data_get_connection_default (NM_CONFIG_GET_DATA,
+	                                               "ipv4.dns-priority",
+	                                               self);
+	priority = _nm_utils_ascii_str_to_int64 (value, 10, G_MININT, G_MAXINT, 0);
+	nm_ip4_config_set_dns_priority (config, priority ?: NM_DNS_PRIORITY_DEFAULT_NORMAL);
+}
+
+static void
+init_ip6_config_dns_priority (NMDevice *self, NMIP6Config *config)
+{
+	gs_free char *value = NULL;
+	gint priority;
+
+	value = nm_config_data_get_connection_default (NM_CONFIG_GET_DATA,
+	                                               "ipv6.dns-priority",
+	                                               self);
+	priority = _nm_utils_ascii_str_to_int64 (value, 10, G_MININT, G_MAXINT, 0);
+	nm_ip6_config_set_dns_priority (config, priority ?: NM_DNS_PRIORITY_DEFAULT_NORMAL);
+}
+
+/***********************************************************/
+
 gboolean
 nm_device_ipv6_sysctl_set (NMDevice *self, const char *property, const char *value)
 {
@@ -1091,6 +1123,38 @@ find_slave_info (NMDevice *self, NMDevice *slave)
 	return NULL;
 }
 
+static void
+apply_mtu_from_config (NMDevice *self)
+{
+	const char *method = NM_SETTING_IP4_CONFIG_METHOD_DISABLED;
+	NMSettingIPConfig *s_ip4;
+	NMSettingWired *s_wired;
+	guint32 mtu;
+
+	/* Devices having an IPv4 configuration will set MTU during the commit
+	 * stage, so it is an error to call this function if the IPv4 method is not
+	 * 'disabled'.
+	 */
+	s_ip4 = (NMSettingIPConfig *)
+		nm_device_get_applied_setting (self, NM_TYPE_SETTING_IP4_CONFIG);
+	if (s_ip4)
+		method = nm_setting_ip_config_get_method (s_ip4);
+	g_return_if_fail (nm_streq (method, NM_SETTING_IP4_CONFIG_METHOD_DISABLED));
+
+	s_wired  = (NMSettingWired *)
+		nm_device_get_applied_setting (self, NM_TYPE_SETTING_WIRED);
+
+	if (s_wired) {
+		mtu = nm_setting_wired_get_mtu (s_wired);
+		if (mtu) {
+			_LOGD (LOGD_DEVICE | LOGD_IP,
+			       "setting MTU of device without IP4 config to %u",
+			       mtu);
+			nm_device_set_mtu (self, mtu);
+		}
+	}
+}
+
 /**
  * nm_device_master_enslave_slave:
  * @self: the master device
@@ -1148,6 +1212,11 @@ nm_device_master_enslave_slave (NMDevice *self, NMDevice *slave, NMConnection *c
 			nm_device_activate_stage3_ip6_start (self);
 	}
 
+	/* Since slave devices don't have their own IP configuration,
+	 * set the MTU here.
+	 */
+	apply_mtu_from_config (slave);
+
 	return success;
 }
 
@@ -1500,6 +1569,7 @@ device_link_changed (NMDevice *self)
 	NMPlatformLink info;
 	const NMPlatformLink *pllink;
 	int ifindex;
+	gboolean was_up;
 
 	priv->device_link_changed_id = 0;
 
@@ -1572,6 +1642,7 @@ device_link_changed (NMDevice *self)
 	if (ip_ifname_changed)
 		nm_device_update_dynamic_ip_setup (self);
 
+	was_up = priv->up;
 	priv->up = NM_FLAGS_HAS (info.n_ifi_flags, IFF_UP);
 
 	if (   info.initialized
@@ -1599,6 +1670,20 @@ device_link_changed (NMDevice *self)
 	set_unmanaged_external_down (self, FALSE);
 
 	device_recheck_slave_status (self, &info);
+
+	if (priv->up && !was_up) {
+		/* the link was down and just came up. That happens for example, while changing MTU.
+		 * We must restore IP configuration. */
+		if (priv->ip4_state == IP_DONE) {
+			if (!ip4_config_merge_and_apply (self, NULL, TRUE, NULL))
+				_LOGW (LOGD_IP4, "failed applying IP4 config after link comes up again");
+		}
+		if (priv->ip6_state == IP_DONE) {
+			if (!ip6_config_merge_and_apply (self, TRUE, NULL))
+				_LOGW (LOGD_IP6, "failed applying IP6 config after link comes up again");
+		}
+	}
+
 	return G_SOURCE_REMOVE;
 }
 
@@ -4287,6 +4372,7 @@ ip4_config_merge_and_apply (NMDevice *self,
 	gboolean routes_full_sync;
 	gboolean ignore_auto_routes = FALSE;
 	gboolean ignore_auto_dns = FALSE;
+	gboolean auto_method = FALSE;
 
 	/* Merge all the configs into the composite config */
 	if (config) {
@@ -4302,10 +4388,15 @@ ip4_config_merge_and_apply (NMDevice *self,
 		if (s_ip4) {
 			ignore_auto_routes = nm_setting_ip_config_get_ignore_auto_routes (s_ip4);
 			ignore_auto_dns = nm_setting_ip_config_get_ignore_auto_dns (s_ip4);
+
+			if (nm_streq0 (nm_setting_ip_config_get_method (s_ip4),
+			               NM_SETTING_IP4_CONFIG_METHOD_AUTO))
+				auto_method = TRUE;
 		}
 	}
 
 	composite = nm_ip4_config_new (nm_device_get_ip_ifindex (self));
+	init_ip4_config_dns_priority (self, composite);
 
 	if (commit)
 		ensure_con_ip4_config (self);
@@ -4357,10 +4448,12 @@ ip4_config_merge_and_apply (NMDevice *self,
 		goto END_ADD_DEFAULT_ROUTE;
 	}
 
-	if (nm_device_uses_generated_assumed_connection (self)) {
-		/* a generate-assumed-connection always detects the default route from platform */
+	/* a generated-assumed connection detects the default route from the platform,
+	 * but if the IP method is automatic we need to update the default route to
+	 * maintain connectivity.
+	 */
+	if (nm_device_uses_generated_assumed_connection (self) && !auto_method)
 		goto END_ADD_DEFAULT_ROUTE;
-	}
 
 	/* At this point, we treat assumed and non-assumed connections alike.
 	 * For assumed connections we do that because we still manage RA and DHCP
@@ -4946,7 +5039,8 @@ act_stage3_ip4_config_start (NMDevice *self,
 		} else
 			ret = NM_ACT_STAGE_RETURN_FAILURE;
 	} else if (strcmp (method, NM_SETTING_IP4_CONFIG_METHOD_DISABLED) == 0) {
-		/* Nothing to do... */
+		apply_mtu_from_config (self);
+		/* Nothing else to do... */
 		ret = NM_ACT_STAGE_RETURN_STOP;
 	} else
 		_LOGW (LOGD_IP4, "unhandled IPv4 config method '%s'; will fail", method);
@@ -5009,6 +5103,7 @@ ip6_config_merge_and_apply (NMDevice *self,
 	gboolean routes_full_sync;
 	gboolean ignore_auto_routes = FALSE;
 	gboolean ignore_auto_dns = FALSE;
+	gboolean auto_method = FALSE;
 
 	/* Apply ignore-auto-routes and ignore-auto-dns settings */
 	connection = nm_device_get_applied_connection (self);
@@ -5018,14 +5113,21 @@ ip6_config_merge_and_apply (NMDevice *self,
 		if (s_ip6) {
 			ignore_auto_routes = nm_setting_ip_config_get_ignore_auto_routes (s_ip6);
 			ignore_auto_dns = nm_setting_ip_config_get_ignore_auto_dns (s_ip6);
+
+			if (NM_IN_STRSET (nm_setting_ip_config_get_method (s_ip6),
+			                  NM_SETTING_IP6_CONFIG_METHOD_AUTO,
+			                  NM_SETTING_IP6_CONFIG_METHOD_DHCP))
+				auto_method = TRUE;
 		}
 	}
 
 	/* If no config was passed in, create a new one */
 	composite = nm_ip6_config_new (nm_device_get_ip_ifindex (self));
+	init_ip6_config_dns_priority (self, composite);
 
 	if (commit)
 		ensure_con_ip6_config (self);
+
 	g_assert (composite);
 
 	/* Merge all the IP configs into the composite config */
@@ -5081,10 +5183,12 @@ ip6_config_merge_and_apply (NMDevice *self,
 		goto END_ADD_DEFAULT_ROUTE;
 	}
 
-	if (nm_device_uses_generated_assumed_connection (self)) {
-		/* a generate-assumed-connection always detects the default route from platform */
+	/* a generated-assumed connection detects the default route from the platform,
+	 * but if the IP method is automatic we need to update the default route to
+	 * maintain connectivity.
+	 */
+	if (nm_device_uses_generated_assumed_connection (self) && !auto_method)
 		goto END_ADD_DEFAULT_ROUTE;
-	}
 
 	/* At this point, we treat assumed and non-assumed connections alike.
 	 * For assumed connections we do that because we still manage RA and DHCP
@@ -7895,6 +7999,9 @@ nm_device_set_ip4_config (NMDevice *self,
 
 	g_return_val_if_fail (NM_IS_DEVICE (self), FALSE);
 
+	_LOGD (LOGD_IP4, "ip4-config: update (commit=%d, routes-full-sync=%d, new-config=%p)",
+	       commit, routes_full_sync, new_config);
+
 	priv = NM_DEVICE_GET_PRIVATE (self);
 	ip_ifindex = nm_device_get_ip_ifindex (self);
 
@@ -7928,7 +8035,7 @@ nm_device_set_ip4_config (NMDevice *self,
 			 * this causes a re-read and reset. This should only happen for relevant changes */
 			nm_ip4_config_replace (old_config, new_config, &has_changes);
 			if (has_changes) {
-				_LOGD (LOGD_IP4, "update IP4Config instance (%s)",
+				_LOGD (LOGD_IP4, "ip4-config: update IP4Config instance (%s)",
 				       nm_exported_object_get_path (NM_EXPORTED_OBJECT (old_config)));
 			}
 		} else {
@@ -7938,13 +8045,13 @@ nm_device_set_ip4_config (NMDevice *self,
 			if (success && !nm_exported_object_is_exported (NM_EXPORTED_OBJECT (new_config)))
 				nm_exported_object_export (NM_EXPORTED_OBJECT (new_config));
 
-			_LOGD (LOGD_IP4, "set IP4Config instance (%s)",
+			_LOGD (LOGD_IP4, "ip4-config: set IP4Config instance (%s)",
 			       nm_exported_object_get_path (NM_EXPORTED_OBJECT (new_config)));
 		}
 	} else if (old_config) {
 		has_changes = TRUE;
 		priv->ip4_config = NULL;
-		_LOGD (LOGD_IP4, "clear IP4Config instance (%s)",
+		_LOGD (LOGD_IP4, "ip4-config: clear IP4Config instance (%s)",
 		       nm_exported_object_get_path (NM_EXPORTED_OBJECT (old_config)));
 		/* Device config is invalid if combined config is invalid */
 		g_clear_object (&priv->dev_ip4_config);
@@ -7963,23 +8070,16 @@ nm_device_set_ip4_config (NMDevice *self,
 			nm_exported_object_clear_and_unexport (&old_config);
 
 		if (nm_device_uses_generated_assumed_connection (self)) {
-			NMConnection *connection = nm_device_get_applied_connection (self);
 			NMConnection *settings_connection = NM_CONNECTION (nm_device_get_settings_connection (self));
 			NMSetting *s_ip4;
 
-			g_object_freeze_notify (G_OBJECT (connection));
 			g_object_freeze_notify (G_OBJECT (settings_connection));
 
 			nm_connection_remove_setting (settings_connection, NM_TYPE_SETTING_IP4_CONFIG);
 			s_ip4 = nm_ip4_config_create_setting (priv->ip4_config);
 			nm_connection_add_setting (settings_connection, s_ip4);
 
-			nm_connection_remove_setting (connection, NM_TYPE_SETTING_IP4_CONFIG);
-			s_ip4 = nm_ip4_config_create_setting (priv->ip4_config);
-			nm_connection_add_setting (connection, s_ip4);
-
 			g_object_thaw_notify (G_OBJECT (settings_connection));
-			g_object_thaw_notify (G_OBJECT (connection));
 		}
 
 		nm_device_queue_recheck_assume (self);
@@ -8070,6 +8170,9 @@ nm_device_set_ip6_config (NMDevice *self,
 
 	g_return_val_if_fail (NM_IS_DEVICE (self), FALSE);
 
+	_LOGD (LOGD_IP6, "ip6-config: update (commit=%d, routes-full-sync=%d, new-config=%p)",
+	       commit, routes_full_sync, new_config);
+
 	priv = NM_DEVICE_GET_PRIVATE (self);
 	ip_ifindex = nm_device_get_ip_ifindex (self);
 
@@ -8097,7 +8200,7 @@ nm_device_set_ip6_config (NMDevice *self,
 			 * this causes a re-read and reset. This should only happen for relevant changes */
 			nm_ip6_config_replace (old_config, new_config, &has_changes);
 			if (has_changes) {
-				_LOGD (LOGD_IP6, "update IP6Config instance (%s)",
+				_LOGD (LOGD_IP6, "ip6-config: update IP6Config instance (%s)",
 				       nm_exported_object_get_path (NM_EXPORTED_OBJECT (old_config)));
 			}
 		} else {
@@ -8107,13 +8210,13 @@ nm_device_set_ip6_config (NMDevice *self,
 			if (success && !nm_exported_object_is_exported (NM_EXPORTED_OBJECT (new_config)))
 				nm_exported_object_export (NM_EXPORTED_OBJECT (new_config));
 
-			_LOGD (LOGD_IP6, "set IP6Config instance (%s)",
+			_LOGD (LOGD_IP6, "ip6-config: set IP6Config instance (%s)",
 			       nm_exported_object_get_path (NM_EXPORTED_OBJECT (new_config)));
 		}
 	} else if (old_config) {
 		has_changes = TRUE;
 		priv->ip6_config = NULL;
-		_LOGD (LOGD_IP6, "clear IP6Config instance (%s)",
+		_LOGD (LOGD_IP6, "ip6-config: clear IP6Config instance (%s)",
 		       nm_exported_object_get_path (NM_EXPORTED_OBJECT (old_config)));
 	}
 
@@ -8128,23 +8231,16 @@ nm_device_set_ip6_config (NMDevice *self,
 			nm_exported_object_clear_and_unexport (&old_config);
 
 		if (nm_device_uses_generated_assumed_connection (self)) {
-			NMConnection *connection = nm_device_get_applied_connection (self);
 			NMConnection *settings_connection = NM_CONNECTION (nm_device_get_settings_connection (self));
 			NMSetting *s_ip6;
 
-			g_object_freeze_notify (G_OBJECT (connection));
 			g_object_freeze_notify (G_OBJECT (settings_connection));
 
 			nm_connection_remove_setting (settings_connection, NM_TYPE_SETTING_IP6_CONFIG);
 			s_ip6 = nm_ip6_config_create_setting (priv->ip6_config);
 			nm_connection_add_setting (settings_connection, s_ip6);
 
-			nm_connection_remove_setting (connection, NM_TYPE_SETTING_IP6_CONFIG);
-			s_ip6 = nm_ip6_config_create_setting (priv->ip6_config);
-			nm_connection_add_setting (connection, s_ip6);
-
 			g_object_thaw_notify (G_OBJECT (settings_connection));
-			g_object_thaw_notify (G_OBJECT (connection));
 		}
 
 		nm_device_queue_recheck_assume (self);
@@ -8545,6 +8641,17 @@ nm_device_bring_up (NMDevice *self, gboolean block, gboolean *no_firmware)
 	nm_device_update_hw_address (self);
 
 	_update_ip4_address (self);
+
+	/* when the link comes up, we must restore IP configuration if necessary. */
+	if (priv->ip4_state == IP_DONE) {
+		if (!ip4_config_merge_and_apply (self, NULL, TRUE, NULL))
+			_LOGW (LOGD_IP4, "failed applying IP4 config after bringing link up");
+	}
+	if (priv->ip6_state == IP_DONE) {
+		if (!ip6_config_merge_and_apply (self, TRUE, NULL))
+			_LOGW (LOGD_IP6, "failed applying IP6 config after bringing link up");
+	}
+
 	return TRUE;
 }
 
@@ -8782,7 +8889,6 @@ update_ip4_config (NMDevice *self, gboolean initial)
 	NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE (self);
 	int ifindex;
 	gboolean capture_resolv_conf;
-	NMDnsManagerResolvConfMode resolv_conf_mode;
 
 	/* If a commit is scheduled, this function would potentially interfere with
 	 * it changing IP configurations before they are applied. Postpone the
@@ -8801,8 +8907,8 @@ update_ip4_config (NMDevice *self, gboolean initial)
 	if (!ifindex)
 		return;
 
-	resolv_conf_mode = nm_dns_manager_get_resolv_conf_mode (nm_dns_manager_get ());
-	capture_resolv_conf = initial && (resolv_conf_mode == NM_DNS_MANAGER_RESOLV_CONF_EXPLICIT);
+	capture_resolv_conf =    initial
+	                      && nm_dns_manager_get_resolv_conf_explicit (nm_dns_manager_get ());
 
 	/* IPv4 */
 	g_clear_object (&priv->ext_ip4_config);
@@ -8873,7 +8979,6 @@ update_ip6_config (NMDevice *self, gboolean initial)
 	NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE (self);
 	int ifindex;
 	gboolean capture_resolv_conf;
-	NMDnsManagerResolvConfMode resolv_conf_mode;
 
 	/* If a commit is scheduled, this function would potentially interfere with
 	 * it changing IP configurations before they are applied. Postpone the
@@ -8892,8 +8997,8 @@ update_ip6_config (NMDevice *self, gboolean initial)
 	if (!ifindex)
 		return;
 
-	resolv_conf_mode = nm_dns_manager_get_resolv_conf_mode (nm_dns_manager_get ());
-	capture_resolv_conf = initial && (resolv_conf_mode == NM_DNS_MANAGER_RESOLV_CONF_EXPLICIT);
+	capture_resolv_conf =    initial
+	                      && nm_dns_manager_get_resolv_conf_explicit (nm_dns_manager_get ());
 
 	/* IPv6 */
 	g_clear_object (&priv->ext_ip6_config);
@@ -8994,9 +9099,9 @@ queued_ip6_config_change (gpointer user_data)
 	g_object_ref (self);
 	update_ip6_config (self, FALSE);
 
-	if (   nm_platform_link_get (NM_PLATFORM_GET, priv->ifindex)
-	    && priv->state < NM_DEVICE_STATE_DEACTIVATING) {
-		/* Handle DAD falures */
+	if (   priv->state < NM_DEVICE_STATE_DEACTIVATING
+	    && nm_platform_link_get (NM_PLATFORM_GET, priv->ifindex)) {
+		/* Handle DAD failures */
 		for (iter = priv->dad6_failed_addrs; iter; iter = g_slist_next (iter)) {
 			NMPlatformIP6Address *addr = iter->data;
 
@@ -9277,6 +9382,7 @@ nm_device_get_unmanaged_flags (NMDevice *self, NMUnmanagedFlags flag)
  * @allow_state_transition: if %FALSE, setting flags never triggers a device
  *   state change. If %TRUE, the device can change state, if it is real and
  *   switches from managed to unmanaged (or vice versa).
+ * @now: whether the state change should be immediate or delayed
  * @reason: the device state reason passed to nm_device_state_changed() if
  *   the device becomes managed/unmanaged. This is only relevant if the
  *   device switches state and if @allow_state_transition is %TRUE.
@@ -9288,11 +9394,13 @@ _set_unmanaged_flags (NMDevice *self,
                       NMUnmanagedFlags flags,
                       NMUnmanFlagOp set_op,
                       gboolean allow_state_transition,
+                      gboolean now,
                       NMDeviceStateReason reason)
 {
 	NMDevicePrivate *priv;
 	gboolean was_managed, transition_state;
 	NMUnmanagedFlags old_flags, old_mask;
+	NMDeviceState new_state;
 	const char *operation = NULL;
 	char str1[512];
 	char str2[512];
@@ -9364,10 +9472,11 @@ _set_unmanaged_flags (NMDevice *self,
 #undef _FMT
 
 	if (transition_state) {
-		if (was_managed)
-			nm_device_state_changed (self, NM_DEVICE_STATE_UNMANAGED, reason);
+		new_state = was_managed ? NM_DEVICE_STATE_UNMANAGED : NM_DEVICE_STATE_UNAVAILABLE;
+		if (now)
+			nm_device_state_changed (self, new_state, reason);
 		else
-			nm_device_state_changed (self, NM_DEVICE_STATE_UNAVAILABLE, reason);
+			nm_device_queue_state (self, new_state, reason);
 	}
 }
 
@@ -9385,7 +9494,7 @@ nm_device_set_unmanaged_flags (NMDevice *self,
                                NMUnmanagedFlags flags,
                                NMUnmanFlagOp set_op)
 {
-	_set_unmanaged_flags (self, flags, set_op, FALSE, NM_DEVICE_STATE_REASON_NONE);
+	_set_unmanaged_flags (self, flags, set_op, FALSE, FALSE, NM_DEVICE_STATE_REASON_NONE);
 }
 
 /**
@@ -9406,7 +9515,16 @@ nm_device_set_unmanaged_by_flags (NMDevice *self,
                                   NMUnmanFlagOp set_op,
                                   NMDeviceStateReason reason)
 {
-	_set_unmanaged_flags (self, flags, set_op, TRUE, reason);
+	_set_unmanaged_flags (self, flags, set_op, TRUE, TRUE, reason);
+}
+
+void
+nm_device_set_unmanaged_by_flags_queue (NMDevice *self,
+                                        NMUnmanagedFlags flags,
+                                        NMUnmanFlagOp set_op,
+                                        NMDeviceStateReason reason)
+{
+	_set_unmanaged_flags (self, flags, set_op, TRUE, FALSE, reason);
 }
 
 void
@@ -9710,12 +9828,6 @@ nm_device_check_connection_available (NMDevice *self,
 	return available;
 }
 
-static void
-available_connections_notify (NMDevice *self)
-{
-	_notify (self, PROP_AVAILABLE_CONNECTIONS);
-}
-
 static gboolean
 available_connections_del_all (NMDevice *self)
 {
@@ -9815,7 +9927,7 @@ nm_device_recheck_available_connections (NMDevice *self)
 	}
 
 	if (changed)
-		available_connections_notify (self);
+		_notify (self, PROP_AVAILABLE_CONNECTIONS);
 	available_connections_check_delete_unrealized (self);
 }
 
@@ -9889,7 +10001,7 @@ cp_connection_added_or_updated (NMConnectionProvider *cp, NMConnection *connecti
 		changed = available_connections_del (self, connection);
 
 	if (changed) {
-		available_connections_notify (self);
+		_notify (self, PROP_AVAILABLE_CONNECTIONS);
 		available_connections_check_delete_unrealized (self);
 	}
 }
@@ -9902,7 +10014,7 @@ cp_connection_removed (NMConnectionProvider *cp, NMConnection *connection, gpoin
 	g_return_if_fail (NM_IS_DEVICE (self));
 
 	if (available_connections_del (self, connection)) {
-		available_connections_notify (self);
+		_notify (self, PROP_AVAILABLE_CONNECTIONS);
 		available_connections_check_delete_unrealized (self);
 	}
 }
@@ -10524,7 +10636,7 @@ _set_state_full (NMDevice *self,
 
 	if (state <= NM_DEVICE_STATE_UNAVAILABLE) {
 		if (available_connections_del_all (self))
-			available_connections_notify (self);
+			_notify (self, PROP_AVAILABLE_CONNECTIONS);
 		if (old_state > NM_DEVICE_STATE_UNAVAILABLE)
 			_clear_queued_act_request (priv);
 	}
diff --git a/src/devices/nm-device.h b/src/devices/nm-device.h
index 9f689850..21804396 100644
--- a/src/devices/nm-device.h
+++ b/src/devices/nm-device.h
@@ -489,6 +489,10 @@ void nm_device_set_unmanaged_by_flags (NMDevice *device,
                                        NMUnmanagedFlags flags,
                                        NMUnmanFlagOp set_op,
                                        NMDeviceStateReason reason);
+void nm_device_set_unmanaged_by_flags_queue (NMDevice *self,
+                                             NMUnmanagedFlags flags,
+                                             NMUnmanFlagOp set_op,
+                                             NMDeviceStateReason reason);
 void nm_device_set_unmanaged_by_user_config (NMDevice *self, const GSList *unmanaged_specs);
 void nm_device_set_unmanaged_by_user_udev (NMDevice *self);
 void nm_device_set_unmanaged_by_quitting (NMDevice *device);
diff --git a/src/devices/nm-lldp-listener.c b/src/devices/nm-lldp-listener.c
index 592059f5..9cc1d086 100644
--- a/src/devices/nm-lldp-listener.c
+++ b/src/devices/nm-lldp-listener.c
@@ -531,7 +531,7 @@ lldp_neighbor_new (sd_lldp_neighbor *neighbor_sd, GError **error)
 	neigh->valid = TRUE;
 
 out:
-	return nm_unauto (&neigh);
+	return g_steal_pointer (&neigh);
 }
 
 static GVariant *
@@ -694,7 +694,7 @@ process_lldp_neighbor (NMLldpListener *self, sd_lldp_neighbor *neighbor_sd, gboo
 	        LOG_NEIGH_ARG (neigh));
 
 	changed = TRUE;
-	g_hash_table_add (priv->lldp_neighbors, nm_unauto (&neigh));
+	g_hash_table_add (priv->lldp_neighbors, g_steal_pointer (&neigh));
 
 done:
 	if (changed)
diff --git a/src/devices/team/Makefile.in b/src/devices/team/Makefile.in
index 115a7589..4ca3014f 100644
--- a/src/devices/team/Makefile.in
+++ b/src/devices/team/Makefile.in
@@ -355,6 +355,7 @@ NEWT_LIBS = @NEWT_LIBS@
 NM = @NM@
 NMEDIT = @NMEDIT@
 NM_CONFIG_DEFAULT_AUTH_POLKIT_TEXT = @NM_CONFIG_DEFAULT_AUTH_POLKIT_TEXT@
+NM_CONFIG_DEFAULT_DNS_RC_MANAGER = @NM_CONFIG_DEFAULT_DNS_RC_MANAGER@
 NM_CONFIG_DEFAULT_LOGGING_AUDIT_TEXT = @NM_CONFIG_DEFAULT_LOGGING_AUDIT_TEXT@
 NM_CONFIG_LOGGING_BACKEND_DEFAULT_TEXT = @NM_CONFIG_LOGGING_BACKEND_DEFAULT_TEXT@
 NM_MAJOR_VERSION = @NM_MAJOR_VERSION@
diff --git a/src/devices/team/nm-device-team.c b/src/devices/team/nm-device-team.c
index 60842c18..b4b522d8 100644
--- a/src/devices/team/nm-device-team.c
+++ b/src/devices/team/nm-device-team.c
@@ -318,10 +318,18 @@ teamd_dbus_appeared (GDBusConnection *connection,
 		                                   2000,
 		                                   NULL,
 		                                   NULL);
-		g_variant_get (ret, "(u)", &pid);
 
-		if (pid != priv->teamd_pid)
-			teamd_cleanup (device, FALSE);
+		if (ret) {
+			g_variant_get (ret, "(u)", &pid);
+			if (pid != priv->teamd_pid)
+				teamd_cleanup (device, FALSE);
+		} else {
+			_LOGW (LOGD_TEAM, "failed to determine D-Bus name owner");
+			/* If we can't determine the bus name owner, don't kill our
+			 * teamd instance. Hopefully another existing teamd just died and
+			 * our instance will be able to grab the bus name.
+			 */
+		}
 	}
 
 	/* Grab a teamd control handle even if we aren't going to use it
diff --git a/src/devices/tests/Makefile.in b/src/devices/tests/Makefile.in
index 31cf0d38..b07e6dfd 100644
--- a/src/devices/tests/Makefile.in
+++ b/src/devices/tests/Makefile.in
@@ -527,6 +527,7 @@ NEWT_LIBS = @NEWT_LIBS@
 NM = @NM@
 NMEDIT = @NMEDIT@
 NM_CONFIG_DEFAULT_AUTH_POLKIT_TEXT = @NM_CONFIG_DEFAULT_AUTH_POLKIT_TEXT@
+NM_CONFIG_DEFAULT_DNS_RC_MANAGER = @NM_CONFIG_DEFAULT_DNS_RC_MANAGER@
 NM_CONFIG_DEFAULT_LOGGING_AUDIT_TEXT = @NM_CONFIG_DEFAULT_LOGGING_AUDIT_TEXT@
 NM_CONFIG_LOGGING_BACKEND_DEFAULT_TEXT = @NM_CONFIG_LOGGING_BACKEND_DEFAULT_TEXT@
 NM_MAJOR_VERSION = @NM_MAJOR_VERSION@
diff --git a/src/devices/wifi/Makefile.in b/src/devices/wifi/Makefile.in
index a180a434..34aa4b97 100644
--- a/src/devices/wifi/Makefile.in
+++ b/src/devices/wifi/Makefile.in
@@ -394,6 +394,7 @@ NEWT_LIBS = @NEWT_LIBS@
 NM = @NM@
 NMEDIT = @NMEDIT@
 NM_CONFIG_DEFAULT_AUTH_POLKIT_TEXT = @NM_CONFIG_DEFAULT_AUTH_POLKIT_TEXT@
+NM_CONFIG_DEFAULT_DNS_RC_MANAGER = @NM_CONFIG_DEFAULT_DNS_RC_MANAGER@
 NM_CONFIG_DEFAULT_LOGGING_AUDIT_TEXT = @NM_CONFIG_DEFAULT_LOGGING_AUDIT_TEXT@
 NM_CONFIG_LOGGING_BACKEND_DEFAULT_TEXT = @NM_CONFIG_LOGGING_BACKEND_DEFAULT_TEXT@
 NM_MAJOR_VERSION = @NM_MAJOR_VERSION@
diff --git a/src/devices/wifi/nm-device-wifi.c b/src/devices/wifi/nm-device-wifi.c
index 95a89eab..82b12a11 100644
--- a/src/devices/wifi/nm-device-wifi.c
+++ b/src/devices/wifi/nm-device-wifi.c
@@ -26,6 +26,7 @@
 #include <unistd.h>
 #include <errno.h>
 
+#include "nm-common-macros.h"
 #include "nm-device.h"
 #include "nm-device-wifi.h"
 #include "nm-device-private.h"
@@ -696,6 +697,7 @@ manf_defaults[] = {
 	"WLAN",
 	"ALICE-WLAN",
 	"Speedport W 501V",
+	"TURBONETT",
 };
 
 #define ARRAY_SIZE(a)  (sizeof (a) / sizeof (a[0]))
diff --git a/src/devices/wifi/tests/Makefile.in b/src/devices/wifi/tests/Makefile.in
index be874cc3..956730f8 100644
--- a/src/devices/wifi/tests/Makefile.in
+++ b/src/devices/wifi/tests/Makefile.in
@@ -522,6 +522,7 @@ NEWT_LIBS = @NEWT_LIBS@
 NM = @NM@
 NMEDIT = @NMEDIT@
 NM_CONFIG_DEFAULT_AUTH_POLKIT_TEXT = @NM_CONFIG_DEFAULT_AUTH_POLKIT_TEXT@
+NM_CONFIG_DEFAULT_DNS_RC_MANAGER = @NM_CONFIG_DEFAULT_DNS_RC_MANAGER@
 NM_CONFIG_DEFAULT_LOGGING_AUDIT_TEXT = @NM_CONFIG_DEFAULT_LOGGING_AUDIT_TEXT@
 NM_CONFIG_LOGGING_BACKEND_DEFAULT_TEXT = @NM_CONFIG_LOGGING_BACKEND_DEFAULT_TEXT@
 NM_MAJOR_VERSION = @NM_MAJOR_VERSION@
diff --git a/src/devices/wwan/Makefile.in b/src/devices/wwan/Makefile.in
index e7722414..89328665 100644
--- a/src/devices/wwan/Makefile.in
+++ b/src/devices/wwan/Makefile.in
@@ -363,6 +363,7 @@ NEWT_LIBS = @NEWT_LIBS@
 NM = @NM@
 NMEDIT = @NMEDIT@
 NM_CONFIG_DEFAULT_AUTH_POLKIT_TEXT = @NM_CONFIG_DEFAULT_AUTH_POLKIT_TEXT@
+NM_CONFIG_DEFAULT_DNS_RC_MANAGER = @NM_CONFIG_DEFAULT_DNS_RC_MANAGER@
 NM_CONFIG_DEFAULT_LOGGING_AUDIT_TEXT = @NM_CONFIG_DEFAULT_LOGGING_AUDIT_TEXT@
 NM_CONFIG_LOGGING_BACKEND_DEFAULT_TEXT = @NM_CONFIG_LOGGING_BACKEND_DEFAULT_TEXT@
 NM_MAJOR_VERSION = @NM_MAJOR_VERSION@
diff --git a/src/dhcp-manager/Makefile.in b/src/dhcp-manager/Makefile.in
index 0f98c8c5..063489cb 100644
--- a/src/dhcp-manager/Makefile.in
+++ b/src/dhcp-manager/Makefile.in
@@ -317,6 +317,7 @@ NEWT_LIBS = @NEWT_LIBS@
 NM = @NM@
 NMEDIT = @NMEDIT@
 NM_CONFIG_DEFAULT_AUTH_POLKIT_TEXT = @NM_CONFIG_DEFAULT_AUTH_POLKIT_TEXT@
+NM_CONFIG_DEFAULT_DNS_RC_MANAGER = @NM_CONFIG_DEFAULT_DNS_RC_MANAGER@
 NM_CONFIG_DEFAULT_LOGGING_AUDIT_TEXT = @NM_CONFIG_DEFAULT_LOGGING_AUDIT_TEXT@
 NM_CONFIG_LOGGING_BACKEND_DEFAULT_TEXT = @NM_CONFIG_LOGGING_BACKEND_DEFAULT_TEXT@
 NM_MAJOR_VERSION = @NM_MAJOR_VERSION@
diff --git a/src/dhcp-manager/nm-dhcp-client.c b/src/dhcp-manager/nm-dhcp-client.c
index 9f4cdf3e..c1025817 100644
--- a/src/dhcp-manager/nm-dhcp-client.c
+++ b/src/dhcp-manager/nm-dhcp-client.c
@@ -884,7 +884,9 @@ dispose (GObject *object)
 
 	g_clear_pointer (&priv->iface, g_free);
 	g_clear_pointer (&priv->hostname, g_free);
+	g_clear_pointer (&priv->fqdn, g_free);
 	g_clear_pointer (&priv->uuid, g_free);
+	g_clear_pointer (&priv->client_id, g_bytes_unref);
 
 	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 bf2df1e0..008f8af2 100644
--- a/src/dhcp-manager/nm-dhcp-dhclient-utils.c
+++ b/src/dhcp-manager/nm-dhcp-dhclient-utils.c
@@ -36,8 +36,9 @@
 #define HOSTNAME4_TAG    "send host-name"
 #define HOSTNAME4_FORMAT HOSTNAME4_TAG " \"%s\"; # added by NetworkManager"
 
-#define FQDN_TAG    "send fqdn.fqdn"
-#define FQDN_FORMAT FQDN_TAG " \"%s\"; # added by NetworkManager"
+#define FQDN_TAG_PREFIX  "send fqdn."
+#define FQDN_TAG         FQDN_TAG_PREFIX "fqdn"
+#define FQDN_FORMAT      FQDN_TAG " \"%s\"; # added by NetworkManager"
 
 #define ALSOREQ_TAG "also request "
 
@@ -205,13 +206,14 @@ nm_dhcp_dhclient_create_config (const char *interface,
                                 GBytes **out_new_client_id)
 {
 	GString *new_contents;
-	GPtrArray *alsoreq;
+	GPtrArray *alsoreq, *fqdn_opts;
 	int i;
 
 	g_return_val_if_fail (!anycast_addr || nm_utils_hwaddr_valid (anycast_addr, ETH_ALEN), NULL);
 
 	new_contents = g_string_new (_("# Created by NetworkManager\n"));
 	alsoreq = g_ptr_array_sized_new (5);
+	fqdn_opts = g_ptr_array_sized_new (5);
 
 	if (orig_contents) {
 		char **lines, **line;
@@ -244,6 +246,14 @@ nm_dhcp_dhclient_create_config (const char *interface,
 					continue;
 			}
 
+			/* To let user's FQDN options (except "fqdn.fqdn") override the
+			 * default ones set by NM, add them later
+			 */
+			if (!strncmp (p, FQDN_TAG_PREFIX, NM_STRLEN (FQDN_TAG_PREFIX))) {
+				g_ptr_array_add (fqdn_opts, g_strdup (p + NM_STRLEN (FQDN_TAG_PREFIX)));
+				continue;
+			}
+
 			/* Ignore 'script' since we pass our own */
 			if (g_str_has_prefix (p, "script "))
 				continue;
@@ -320,6 +330,16 @@ nm_dhcp_dhclient_create_config (const char *interface,
 	}
 	g_ptr_array_free (alsoreq, TRUE);
 
+	for (i = 0; i < fqdn_opts->len; i++) {
+		char *t = g_ptr_array_index (fqdn_opts, i);
+
+		if (i == 0)
+			g_string_append_printf (new_contents, "\n# FQDN options from %s\n", orig_path);
+		g_string_append_printf (new_contents, FQDN_TAG_PREFIX "%s\n", t);
+		g_free (t);
+	}
+	g_ptr_array_free (fqdn_opts, TRUE);
+
 	g_string_append_c (new_contents, '\n');
 
 	if (anycast_addr) {
diff --git a/src/dhcp-manager/nm-dhcp-dhclient.c b/src/dhcp-manager/nm-dhcp-dhclient.c
index 4b6d301b..b35921ec 100644
--- a/src/dhcp-manager/nm-dhcp-dhclient.c
+++ b/src/dhcp-manager/nm-dhcp-dhclient.c
@@ -52,6 +52,7 @@ typedef struct {
 	const char *def_leasefile;
 	char *lease_file;
 	char *pid_file;
+	NMDhcpListener *dhcp_listener;
 } NMDhcpDhclientPrivate;
 
 static const char *
@@ -622,7 +623,8 @@ nm_dhcp_dhclient_init (NMDhcpDhclient *self)
 	if (!priv->def_leasefile)
 		priv->def_leasefile = SYSCONFDIR "/dhclient6.leases";
 
-	g_signal_connect (nm_dhcp_listener_get (),
+	priv->dhcp_listener = g_object_ref (nm_dhcp_listener_get ());
+	g_signal_connect (priv->dhcp_listener,
 	                  NM_DHCP_LISTENER_EVENT,
 	                  G_CALLBACK (nm_dhcp_client_handle_event),
 	                  self);
@@ -633,9 +635,12 @@ dispose (GObject *object)
 {
 	NMDhcpDhclientPrivate *priv = NM_DHCP_DHCLIENT_GET_PRIVATE (object);
 
-	g_signal_handlers_disconnect_by_func (nm_dhcp_listener_get (),
-	                                      G_CALLBACK (nm_dhcp_client_handle_event),
-	                                      NM_DHCP_DHCLIENT (object));
+	if (priv->dhcp_listener) {
+		g_signal_handlers_disconnect_by_func (priv->dhcp_listener,
+		                                      G_CALLBACK (nm_dhcp_client_handle_event),
+		                                      NM_DHCP_DHCLIENT (object));
+		g_clear_object (&priv->dhcp_listener);
+	}
 
 	g_free (priv->pid_file);
 	g_free (priv->conf_file);
diff --git a/src/dhcp-manager/nm-dhcp-dhcpcd.c b/src/dhcp-manager/nm-dhcp-dhcpcd.c
index 8bbb6e4c..17ec993a 100644
--- a/src/dhcp-manager/nm-dhcp-dhcpcd.c
+++ b/src/dhcp-manager/nm-dhcp-dhcpcd.c
@@ -44,6 +44,7 @@ G_DEFINE_TYPE (NMDhcpDhcpcd, nm_dhcp_dhcpcd, NM_TYPE_DHCP_CLIENT)
 
 typedef struct {
 	char *pid_file;
+	NMDhcpListener *dhcp_listener;
 } NMDhcpDhcpcdPrivate;
 
 static const char *
@@ -191,7 +192,10 @@ stop (NMDhcpClient *client, gboolean release, const GByteArray *duid)
 static void
 nm_dhcp_dhcpcd_init (NMDhcpDhcpcd *self)
 {
-	g_signal_connect (nm_dhcp_listener_get (),
+	NMDhcpDhcpcdPrivate *priv = NM_DHCP_DHCPCD_GET_PRIVATE (self);
+
+	priv->dhcp_listener = g_object_ref (nm_dhcp_listener_get ());
+	g_signal_connect (priv->dhcp_listener,
 	                  NM_DHCP_LISTENER_EVENT,
 	                  G_CALLBACK (nm_dhcp_client_handle_event),
 	                  self);
@@ -202,9 +206,12 @@ dispose (GObject *object)
 {
 	NMDhcpDhcpcdPrivate *priv = NM_DHCP_DHCPCD_GET_PRIVATE (object);
 
-	g_signal_handlers_disconnect_by_func (nm_dhcp_listener_get (),
-	                                      G_CALLBACK (nm_dhcp_client_handle_event),
-	                                      NM_DHCP_DHCPCD (object));
+	if (priv->dhcp_listener) {
+		g_signal_handlers_disconnect_by_func (priv->dhcp_listener,
+		                                      G_CALLBACK (nm_dhcp_client_handle_event),
+		                                      NM_DHCP_DHCPCD (object));
+		g_clear_object (&priv->dhcp_listener);
+	}
 
 	g_free (priv->pid_file);
 
diff --git a/src/dhcp-manager/tests/Makefile.in b/src/dhcp-manager/tests/Makefile.in
index 1a072c73..2528b3c5 100644
--- a/src/dhcp-manager/tests/Makefile.in
+++ b/src/dhcp-manager/tests/Makefile.in
@@ -527,6 +527,7 @@ NEWT_LIBS = @NEWT_LIBS@
 NM = @NM@
 NMEDIT = @NMEDIT@
 NM_CONFIG_DEFAULT_AUTH_POLKIT_TEXT = @NM_CONFIG_DEFAULT_AUTH_POLKIT_TEXT@
+NM_CONFIG_DEFAULT_DNS_RC_MANAGER = @NM_CONFIG_DEFAULT_DNS_RC_MANAGER@
 NM_CONFIG_DEFAULT_LOGGING_AUDIT_TEXT = @NM_CONFIG_DEFAULT_LOGGING_AUDIT_TEXT@
 NM_CONFIG_LOGGING_BACKEND_DEFAULT_TEXT = @NM_CONFIG_LOGGING_BACKEND_DEFAULT_TEXT@
 NM_MAJOR_VERSION = @NM_MAJOR_VERSION@
diff --git a/src/dhcp-manager/tests/test-dhcp-dhclient.c b/src/dhcp-manager/tests/test-dhcp-dhclient.c
index 0561d43c..046dd7e2 100644
--- a/src/dhcp-manager/tests/test-dhcp-dhclient.c
+++ b/src/dhcp-manager/tests/test-dhcp-dhclient.c
@@ -334,6 +334,46 @@ test_fqdn (void)
 	             NULL);
 }
 
+static const char *fqdn_options_override_orig = \
+	"\n"
+	"send fqdn.fqdn \"foobar.com\"\n"    /* NM must ignore this ... */
+	"send fqdn.encoded off;\n"           /* ... and honor these */
+	"send fqdn.server-update off;\n";
+
+static const char *fqdn_options_override_expected = \
+	"# Created by NetworkManager\n"
+	"# Merged from /path/to/dhclient.conf\n"
+	"\n"
+	"send fqdn.fqdn \"example2.com\"; # added by NetworkManager\n"
+	"send fqdn.encoded on;\n"
+	"send fqdn.server-update on;\n"
+	"\n"
+	"option rfc3442-classless-static-routes code 121 = array of unsigned integer 8;\n"
+	"option ms-classless-static-routes code 249 = array of unsigned integer 8;\n"
+	"option wpad code 252 = string;\n"
+	"\n"
+	"also request rfc3442-classless-static-routes;\n"
+	"also request ms-classless-static-routes;\n"
+	"also request static-routes;\n"
+	"also request wpad;\n"
+	"also request ntp-servers;\n"
+	"\n"
+	"# FQDN options from /path/to/dhclient.conf\n"
+	"send fqdn.encoded off;\n"
+	"send fqdn.server-update off;\n\n";
+
+static void
+test_fqdn_options_override (void)
+{
+	test_config (fqdn_options_override_orig,
+	             fqdn_options_override_expected,
+	             FALSE, NULL,
+	             "example2.com", NULL,
+	             NULL,
+	             "eth0",
+	             NULL);
+}
+
 /*******************************************/
 
 static const char *override_hostname_orig = \
@@ -804,6 +844,7 @@ 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/fqdn", test_fqdn);
+	g_test_add_func ("/dhcp/dhclient/fqdn_options_override", test_fqdn_options_override);
 	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);
diff --git a/src/dns-manager/nm-dns-dnsmasq.c b/src/dns-manager/nm-dns-dnsmasq.c
index 4cee1608..69b26068 100644
--- a/src/dns-manager/nm-dns-dnsmasq.c
+++ b/src/dns-manager/nm-dns-dnsmasq.c
@@ -26,12 +26,14 @@
 #include <sys/wait.h>
 #include <arpa/inet.h>
 #include <sys/stat.h>
+#include <linux/if.h>
 
 #include "nm-dns-dnsmasq.h"
+#include "nm-core-internal.h"
+#include "nm-platform.h"
 #include "nm-utils.h"
 #include "nm-ip4-config.h"
 #include "nm-ip6-config.h"
-#include "nm-dns-utils.h"
 #include "nm-bus-manager.h"
 #include "NetworkManagerUtils.h"
 
@@ -48,6 +50,7 @@ G_DEFINE_TYPE (NMDnsDnsmasq, nm_dns_dnsmasq, NM_TYPE_DNS_PLUGIN)
 typedef struct {
 	GDBusProxy *dnsmasq;
 	GCancellable *dnsmasq_cancellable;
+	GCancellable *update_cancellable;
 	gboolean running;
 
 	GVariant *set_server_ex_args;
@@ -68,6 +71,70 @@ typedef struct {
 
 /*****************************************************************************/
 
+static char **
+get_ip4_rdns_domains (NMIP4Config *ip4)
+{
+	char **strv;
+	GPtrArray *domains = NULL;
+	int i;
+
+	g_return_val_if_fail (ip4 != NULL, NULL);
+
+	domains = g_ptr_array_sized_new (5);
+
+	for (i = 0; i < nm_ip4_config_get_num_addresses (ip4); i++) {
+		const NMPlatformIP4Address *address = nm_ip4_config_get_address (ip4, i);
+
+		nm_utils_get_reverse_dns_domains_ip4 (address->address, address->plen, domains);
+	}
+
+	for (i = 0; i < nm_ip4_config_get_num_routes (ip4); i++) {
+		const NMPlatformIP4Route *route = nm_ip4_config_get_route (ip4, i);
+
+		nm_utils_get_reverse_dns_domains_ip4 (route->network, route->plen, domains);
+	}
+
+	/* Terminating NULL so we can use g_strfreev() to free it */
+	g_ptr_array_add (domains, NULL);
+
+	/* Free the array and return NULL if the only element was the ending NULL */
+	strv = (char **) g_ptr_array_free (domains, (domains->len == 1));
+
+	return _nm_utils_strv_cleanup (strv, FALSE, FALSE, TRUE);
+}
+
+static char **
+get_ip6_rdns_domains (NMIP6Config *ip6)
+{
+	char **strv;
+	GPtrArray *domains = NULL;
+	int i;
+
+	g_return_val_if_fail (ip6 != NULL, NULL);
+
+	domains = g_ptr_array_sized_new (5);
+
+	for (i = 0; i < nm_ip6_config_get_num_addresses (ip6); i++) {
+		const NMPlatformIP6Address *address = nm_ip6_config_get_address (ip6, i);
+
+		nm_utils_get_reverse_dns_domains_ip6 (&address->address, address->plen, domains);
+	}
+
+	for (i = 0; i < nm_ip6_config_get_num_routes (ip6); i++) {
+		const NMPlatformIP6Route *route = nm_ip6_config_get_route (ip6, i);
+
+		nm_utils_get_reverse_dns_domains_ip6 (&route->network, route->plen, domains);
+	}
+
+	/* Terminating NULL so we can use g_strfreev() to free it */
+	g_ptr_array_add (domains, NULL);
+
+	/* Free the array and return NULL if the only element was the ending NULL */
+	strv = (char **) g_ptr_array_free (domains, (domains->len == 1));
+
+	return _nm_utils_strv_cleanup (strv, FALSE, FALSE, TRUE);
+}
+
 static void
 add_dnsmasq_nameserver (NMDnsDnsmasq *self,
                         GVariantBuilder *servers,
@@ -89,13 +156,16 @@ add_dnsmasq_nameserver (NMDnsDnsmasq *self,
 }
 
 static gboolean
-add_ip4_config (NMDnsDnsmasq *self, GVariantBuilder *servers, NMIP4Config *ip4, gboolean split)
+add_ip4_config (NMDnsDnsmasq *self, GVariantBuilder *servers, NMIP4Config *ip4,
+                const char *iface, gboolean split)
 {
-	char buf[INET_ADDRSTRLEN];
+	char buf[INET_ADDRSTRLEN + 1 + IFNAMSIZ];
+	char buf2[INET_ADDRSTRLEN];
 	in_addr_t addr;
 	int nnameservers, i_nameserver, n, i;
 	gboolean added = FALSE;
 
+	g_return_val_if_fail (iface, FALSE);
 	nnameservers = nm_ip4_config_get_num_nameservers (ip4);
 
 	if (split) {
@@ -106,7 +176,8 @@ add_ip4_config (NMDnsDnsmasq *self, GVariantBuilder *servers, NMIP4Config *ip4,
 
 		for (i_nameserver = 0; i_nameserver < nnameservers; i_nameserver++) {
 			addr = nm_ip4_config_get_nameserver (ip4, i_nameserver);
-			nm_utils_inet4_ntop (addr, buf);
+			g_snprintf (buf, sizeof (buf), "%s@%s",
+			            nm_utils_inet4_ntop (addr, buf2), iface);
 
 			/* searches are preferred over domains */
 			n = nm_ip4_config_get_num_searches (ip4);
@@ -133,22 +204,22 @@ add_ip4_config (NMDnsDnsmasq *self, GVariantBuilder *servers, NMIP4Config *ip4,
 			/* Ensure reverse-DNS works by directing queries for in-addr.arpa
 			 * domains to the split domain's nameserver.
 			 */
-			domains = nm_dns_utils_get_ip4_rdns_domains (ip4);
+			domains = get_ip4_rdns_domains (ip4);
 			if (domains) {
 				for (iter = domains; iter && *iter; iter++)
 					add_dnsmasq_nameserver (self, servers, buf, *iter);
 				g_strfreev (domains);
-				added = TRUE;
 			}
 		}
 	}
 
-	/* If no searches or domains, just add the namservers */
+	/* If no searches or domains, just add the nameservers */
 	if (!added) {
 		for (i = 0; i < nnameservers; i++) {
 			addr = nm_ip4_config_get_nameserver (ip4, i);
-			add_dnsmasq_nameserver (self, servers,
-			                        nm_utils_inet4_ntop (addr, NULL), NULL);
+			g_snprintf (buf, sizeof (buf), "%s@%s",
+			            nm_utils_inet4_ntop (addr, buf2), iface);
+			add_dnsmasq_nameserver (self, servers, buf, NULL);
 		}
 	}
 
@@ -158,23 +229,22 @@ add_ip4_config (NMDnsDnsmasq *self, GVariantBuilder *servers, NMIP4Config *ip4,
 static char *
 ip6_addr_to_string (const struct in6_addr *addr, const char *iface)
 {
-	char *buf;
+	char buf[NM_UTILS_INET_ADDRSTRLEN];
 
-	if (IN6_IS_ADDR_V4MAPPED (addr)) {
-		buf = g_malloc (INET_ADDRSTRLEN);
+	if (IN6_IS_ADDR_V4MAPPED (addr))
 		nm_utils_inet4_ntop (addr->s6_addr32[3], buf);
-	} else if (!iface || !iface[0] || !IN6_IS_ADDR_LINKLOCAL (addr)) {
-		buf = g_malloc (INET6_ADDRSTRLEN);
+	else
 		nm_utils_inet6_ntop (addr, buf);
-	} else {
-		/* Need to scope the address with %<zone-id>. Before dnsmasq 2.58,
-		 * only '@' was supported as delimiter. Since 2.58, '@' and '%'
-		 * are supported. Due to a bug, since 2.73 only '%' works properly
-		 * as "server" address.
-		 */
-		buf = g_strconcat (nm_utils_inet6_ntop (addr, NULL), "%", iface, NULL);
-	}
-	return buf;
+
+	/* Need to scope link-local addresses with %<zone-id>. Before dnsmasq 2.58,
+	 * only '@' was supported as delimiter. Since 2.58, '@' and '%' are
+	 * supported. Due to a bug, since 2.73 only '%' works properly as "server"
+	 * address.
+	 */
+	return g_strdup_printf ("%s%c%s",
+	                        buf,
+	                        IN6_IS_ADDR_LINKLOCAL (addr) ? '%' : '@',
+	                        iface);
 }
 
 static void
@@ -202,20 +272,20 @@ add_global_config (NMDnsDnsmasq *self, GVariantBuilder *dnsmasq_servers, const N
 }
 
 static gboolean
-add_ip6_config (NMDnsDnsmasq *self, GVariantBuilder *servers, NMIP6Config *ip6, gboolean split)
+add_ip6_config (NMDnsDnsmasq *self, GVariantBuilder *servers, NMIP6Config *ip6,
+                const char *iface, gboolean split)
 {
 	const struct in6_addr *addr;
 	char *buf = NULL;
 	int nnameservers, i_nameserver, n, i;
 	gboolean added = FALSE;
-	const char *iface;
 
+	g_return_val_if_fail (iface, FALSE);
 	nnameservers = nm_ip6_config_get_num_nameservers (ip6);
 
-	iface = g_object_get_data (G_OBJECT (ip6), IP_CONFIG_IFACE_TAG);
-	g_assert (iface);
-
 	if (split) {
+		char **domains, **iter;
+
 		if (nnameservers == 0)
 			return FALSE;
 
@@ -245,11 +315,21 @@ add_ip6_config (NMDnsDnsmasq *self, GVariantBuilder *servers, NMIP6Config *ip6,
 				}
 			}
 
+			/* Ensure reverse-DNS works by directing queries for ip6.arpa
+			 * domains to the split domain's nameserver.
+			 */
+			domains = get_ip6_rdns_domains (ip6);
+			if (domains) {
+				for (iter = domains; iter && *iter; iter++)
+					add_dnsmasq_nameserver (self, servers, buf, *iter);
+				g_strfreev (domains);
+			}
+
 			g_free (buf);
 		}
 	}
 
-	/* If no searches or domains, just add the namservers */
+	/* If no searches or domains, just add the nameservers */
 	if (!added) {
 		for (i = 0; i < nnameservers; i++) {
 			addr = nm_ip6_config_get_nameserver (ip6, i);
@@ -264,19 +344,71 @@ add_ip6_config (NMDnsDnsmasq *self, GVariantBuilder *servers, NMIP6Config *ip6,
 	return TRUE;
 }
 
+static gboolean
+add_ip_config_data (NMDnsDnsmasq *self, GVariantBuilder *servers, const NMDnsIPConfigData *data)
+{
+	if (NM_IS_IP4_CONFIG (data->config)) {
+		return add_ip4_config (self,
+		                       servers,
+		                       (NMIP4Config *) data->config,
+		                       data->iface,
+		                       data->type == NM_DNS_IP_CONFIG_TYPE_VPN);
+	} else if (NM_IS_IP6_CONFIG (data->config)) {
+		return add_ip6_config (self,
+		                       servers,
+		                       (NMIP6Config *) data->config,
+		                       data->iface,
+		                       data->type == NM_DNS_IP_CONFIG_TYPE_VPN);
+	} else
+		g_return_val_if_reached (FALSE);
+}
+
 static void
-dnsmasq_update_done (GObject *source, GAsyncResult *res, gpointer user_data)
+dnsmasq_clear_cache_done (GDBusProxy *proxy, GAsyncResult *res, gpointer user_data)
 {
-	NMDnsDnsmasq *self = NM_DNS_DNSMASQ (user_data);
-	NMDnsDnsmasqPrivate *priv = NM_DNS_DNSMASQ_GET_PRIVATE (self);
+	NMDnsDnsmasq *self;
 	gs_free_error GError *error = NULL;
 	gs_unref_variant GVariant *response = NULL;
 
-	response = g_dbus_proxy_call_finish (priv->dnsmasq, res, &error);
+	response = g_dbus_proxy_call_finish (proxy, res, &error);
+	if (g_error_matches (error, G_IO_ERROR, G_IO_ERROR_CANCELLED))
+		return;
+
+	self = NM_DNS_DNSMASQ (user_data);
+
 	if (!response)
-		_LOGW ("dnsmasq update failed: %s", error->message);
+		_LOGW ("dnsmasq cache clear failed: %s", error->message);
 	else
-		_LOGD ("dnsmasq update successful");
+		_LOGD ("dnsmasq update successful, cache cleared");
+}
+
+static void
+dnsmasq_update_done (GDBusProxy *proxy, GAsyncResult *res, gpointer user_data)
+{
+	NMDnsDnsmasq *self;
+	NMDnsDnsmasqPrivate *priv;
+	gs_free_error GError *error = NULL;
+	gs_unref_variant GVariant *response = NULL;
+
+	response = g_dbus_proxy_call_finish (proxy, res, &error);
+	if (g_error_matches (error, G_IO_ERROR, G_IO_ERROR_CANCELLED))
+		return;
+
+	self = NM_DNS_DNSMASQ (user_data);
+	priv = NM_DNS_DNSMASQ_GET_PRIVATE (self);
+
+	if (!response)
+		_LOGW ("dnsmasq update failed: %s", error->message);
+	else {
+		g_dbus_proxy_call (priv->dnsmasq,
+		                   "ClearCache",
+		                   NULL,
+		                   G_DBUS_CALL_FLAGS_NONE,
+		                   -1,
+		                   priv->update_cancellable,
+		                   (GAsyncReadyCallback) dnsmasq_clear_cache_done,
+		                   self);
+	}
 }
 
 static void
@@ -290,12 +422,15 @@ send_dnsmasq_update (NMDnsDnsmasq *self)
 	if (priv->running) {
 		_LOGD ("trying to update dnsmasq nameservers");
 
+		nm_clear_g_cancellable (&priv->update_cancellable);
+		priv->update_cancellable = g_cancellable_new ();
+
 		g_dbus_proxy_call (priv->dnsmasq,
 		                   "SetServersEx",
 		                   priv->set_server_ex_args,
 		                   G_DBUS_CALL_FLAGS_NONE,
 		                   -1,
-		                   NULL,
+		                   priv->update_cancellable,
 		                   (GAsyncReadyCallback) dnsmasq_update_done,
 		                   self);
 		g_clear_pointer (&priv->set_server_ex_args, g_variant_unref);
@@ -373,11 +508,16 @@ start_dnsmasq (NMDnsDnsmasq *self)
 	NMBusManager *dbus_mgr;
 	GDBusConnection *connection;
 
+	if (priv->running) {
+		/* the dnsmasq process is running. Nothing to do. */
+		return;
+	}
 
-	if (   priv->running
-	    || priv->dnsmasq
-	    || priv->dnsmasq_cancellable)
+	if (nm_dns_plugin_child_pid ((NMDnsPlugin *) self) > 0) {
+		/* if we already have a child process spawned, don't do
+		 * it again. */
 		return;
+	}
 
 	dm_binary = nm_utils_find_helper ("dnsmasq", DNSMASQ_PATH, NULL);
 	if (!dm_binary) {
@@ -409,6 +549,13 @@ start_dnsmasq (NMDnsDnsmasq *self)
 	if (!pid)
 		return;
 
+	if (   priv->dnsmasq
+	    || priv->dnsmasq_cancellable) {
+		/* we already have a proxy or are about to create it.
+		 * We are done. */
+		return;
+	}
+
 	dbus_mgr = nm_bus_manager_get ();
 	g_return_if_fail (dbus_mgr);
 
@@ -429,15 +576,12 @@ start_dnsmasq (NMDnsDnsmasq *self)
 
 static gboolean
 update (NMDnsPlugin *plugin,
-        const GSList *vpn_configs,
-        const GSList *dev_configs,
-        const GSList *other_configs,
+        const NMDnsIPConfigData **configs,
         const NMGlobalDnsConfig *global_config,
         const char *hostname)
 {
 	NMDnsDnsmasq *self = NM_DNS_DNSMASQ (plugin);
 	NMDnsDnsmasqPrivate *priv = NM_DNS_DNSMASQ_GET_PRIVATE (self);
-	const GSList *iter;
 	GVariantBuilder servers;
 
 	start_dnsmasq (self);
@@ -447,28 +591,9 @@ update (NMDnsPlugin *plugin,
 	if (global_config)
 		add_global_config (self, &servers, global_config);
 	else {
-		/* Use split DNS for VPN configs */
-		for (iter = vpn_configs; iter; iter = g_slist_next (iter)) {
-			if (NM_IS_IP4_CONFIG (iter->data))
-				add_ip4_config (self, &servers, iter->data, TRUE);
-			else if (NM_IS_IP6_CONFIG (iter->data))
-				add_ip6_config (self, &servers, iter->data, TRUE);
-		}
-
-		/* Now add interface configs without split DNS */
-		for (iter = dev_configs; iter; iter = g_slist_next (iter)) {
-			if (NM_IS_IP4_CONFIG (iter->data))
-				add_ip4_config (self, &servers, iter->data, FALSE);
-			else if (NM_IS_IP6_CONFIG (iter->data))
-				add_ip6_config (self, &servers, iter->data, FALSE);
-		}
-
-		/* And any other random configs */
-		for (iter = other_configs; iter; iter = g_slist_next (iter)) {
-			if (NM_IS_IP4_CONFIG (iter->data))
-				add_ip4_config (self, &servers, iter->data, FALSE);
-			else if (NM_IS_IP6_CONFIG (iter->data))
-				add_ip6_config (self, &servers, iter->data, FALSE);
+		while (*configs) {
+			add_ip_config_data (self, &servers, *configs);
+			configs++;
 		}
 	}
 
@@ -482,39 +607,23 @@ update (NMDnsPlugin *plugin,
 
 /****************************************************************/
 
-static const char *
-dm_exit_code_to_msg (int status)
-{
-	if (status == 1)
-		return "Configuration problem";
-	else if (status == 2)
-		return "Network access problem (address in use; permissions; etc)";
-	else if (status == 3)
-		return "Filesystem problem (missing file/directory; permissions; etc)";
-	else if (status == 4)
-		return "Memory allocation failure";
-	else if (status == 5)
-		return "Other problem";
-	else if (status >= 11)
-		return "Lease-script 'init' process failure";
-	return "Unknown error";
-}
-
 static void
 child_quit (NMDnsPlugin *plugin, gint status)
 {
 	NMDnsDnsmasq *self = NM_DNS_DNSMASQ (plugin);
+	NMDnsDnsmasqPrivate *priv = NM_DNS_DNSMASQ_GET_PRIVATE (self);
 	gboolean failed = TRUE;
 	int err;
 
 	if (WIFEXITED (status)) {
 		err = WEXITSTATUS (status);
 		if (err) {
-			_LOGW ("dnsmasq exited with error: %s (%d)",
-			       dm_exit_code_to_msg (err),
-			       err);
-		} else
+			_LOGW ("dnsmasq exited with error: %s",
+			       nm_utils_dnsmasq_status_to_string (err, NULL, 0));
+		} else {
+			_LOGD ("dnsmasq exited normally");
 			failed = FALSE;
+		}
 	} else if (WIFSTOPPED (status))
 		_LOGW ("dnsmasq stopped unexpectedly with signal %d", WSTOPSIG (status));
 	else if (WIFSIGNALED (status))
@@ -522,6 +631,8 @@ child_quit (NMDnsPlugin *plugin, gint status)
 	else
 		_LOGW ("dnsmasq died from an unknown cause");
 
+	priv->running = FALSE;
+
 	if (failed)
 		g_signal_emit_by_name (self, NM_DNS_PLUGIN_FAILED);
 }
@@ -559,6 +670,7 @@ dispose (GObject *object)
 	NMDnsDnsmasqPrivate *priv = NM_DNS_DNSMASQ_GET_PRIVATE (object);
 
 	nm_clear_g_cancellable (&priv->dnsmasq_cancellable);
+	nm_clear_g_cancellable (&priv->update_cancellable);
 
 	g_clear_object (&priv->dnsmasq);
 
diff --git a/src/dns-manager/nm-dns-manager.c b/src/dns-manager/nm-dns-manager.c
index b42af167..3efd5ac1 100644
--- a/src/dns-manager/nm-dns-manager.c
+++ b/src/dns-manager/nm-dns-manager.c
@@ -61,23 +61,13 @@
 #define DOMAIN_IS_VALID(domain) (*(domain))
 #endif
 
-G_DEFINE_TYPE (NMDnsManager, nm_dns_manager, G_TYPE_OBJECT)
-
-#define NM_DNS_MANAGER_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), \
-                                       NM_TYPE_DNS_MANAGER, \
-                                       NMDnsManagerPrivate))
-
 #define HASH_LEN 20
 
-#ifdef RESOLVCONF_PATH
-#define RESOLVCONF_SELECTED
-#else
+#ifndef RESOLVCONF_PATH
 #define RESOLVCONF_PATH "/sbin/resolvconf"
 #endif
 
-#ifdef NETCONFIG_PATH
-#define NETCONFIG_SELECTED
-#else
+#ifndef NETCONFIG_PATH
 #define NETCONFIG_PATH "/sbin/netconfig"
 #endif
 
@@ -85,7 +75,19 @@ G_DEFINE_TYPE (NMDnsManager, nm_dns_manager, G_TYPE_OBJECT)
 #define PLUGIN_RATELIMIT_BURST       5
 #define PLUGIN_RATELIMIT_DELAY       300
 
-NM_DEFINE_SINGLETON_INSTANCE (NMDnsManager);
+enum {
+	CONFIG_CHANGED,
+
+	LAST_SIGNAL
+};
+
+static guint signals[LAST_SIGNAL] = { 0 };
+
+typedef enum {
+	SR_SUCCESS,
+	SR_NOTFOUND,
+	SR_ERROR
+} SpawnResult;
 
 /*********************************************************************************************/
 
@@ -112,22 +114,17 @@ NM_DEFINE_SINGLETON_INSTANCE (NMDnsManager);
 /*********************************************************************************************/
 
 typedef struct {
-	NMIP4Config *ip4_vpn_config;
-	NMIP4Config *ip4_device_config;
-	NMIP6Config *ip6_vpn_config;
-	NMIP6Config *ip6_device_config;
-	GSList *configs;
+	GPtrArray *configs;
+	NMDnsIPConfigData *best_conf4, *best_conf6;
+	gboolean need_sort;
+
 	char *hostname;
 	guint updates_queue;
 
 	guint8 hash[HASH_LEN];  /* SHA1 hash of current DNS config */
 	guint8 prev_hash[HASH_LEN];  /* Hash when begin_updates() was called */
 
-	NMDnsManagerResolvConfMode resolv_conf_mode;
 	NMDnsManagerResolvConfManager rc_manager;
-	char *last_mode;
-	bool last_immutable:1;
-	bool mode_initialized:1;
 	NMDnsPlugin *plugin;
 
 	NMConfig *config;
@@ -141,20 +138,33 @@ typedef struct {
 	} plugin_ratelimit;
 } NMDnsManagerPrivate;
 
-enum {
-	CONFIG_CHANGED,
+struct _NMDnsManager {
+	GObject parent;
+	NMDnsManagerPrivate _priv;
+};
 
-	LAST_SIGNAL
+struct _NMDnsManagerClass {
+	GObjectClass parent;
 };
 
-typedef enum {
-	SR_SUCCESS,
-	SR_NOTFOUND,
-	SR_ERROR
-} SpawnResult;
+G_DEFINE_TYPE (NMDnsManager, nm_dns_manager, G_TYPE_OBJECT)
 
-static guint signals[LAST_SIGNAL] = { 0 };
+NM_DEFINE_SINGLETON_INSTANCE (NMDnsManager);
 
+#define NM_DNS_MANAGER_GET_PRIVATE(self) \
+	({ \
+		/* preserve the const-ness of self. Unfortunately, that
+		 * way, @self cannot be a void pointer */ \
+		typeof (self) _self = (self); \
+		\
+		/* Get compiler error if variable is of wrong type */ \
+		_nm_unused const NMDnsManager *_self2 = (_self); \
+		\
+		nm_assert (NM_IS_DNS_MANAGER (_self)); \
+		&_self->_priv; \
+	})
+
+/*****************************************************************************/
 
 typedef struct {
 	GPtrArray *nameservers;
@@ -166,13 +176,88 @@ typedef struct {
 
 NM_UTILS_LOOKUP_STR_DEFINE_STATIC (_rc_manager_to_string, NMDnsManagerResolvConfManager,
 	NM_UTILS_LOOKUP_DEFAULT_WARN (NULL),
-	NM_UTILS_LOOKUP_STR_ITEM (NM_DNS_MANAGER_RESOLV_CONF_MAN_NONE,       "none"),
-	NM_UTILS_LOOKUP_STR_ITEM (NM_DNS_MANAGER_RESOLV_CONF_MAN_FILE,       "file"),
-	NM_UTILS_LOOKUP_STR_ITEM (NM_DNS_MANAGER_RESOLV_CONF_MAN_RESOLVCONF, "resolvconf"),
-	NM_UTILS_LOOKUP_STR_ITEM (NM_DNS_MANAGER_RESOLV_CONF_MAN_NETCONFIG,  "netconfig"),
-	NM_UTILS_LOOKUP_ITEM_IGNORE (_NM_DNS_MANAGER_RESOLV_CONF_MAN_INTERNAL_ONLY),
+	NM_UTILS_LOOKUP_STR_ITEM (NM_DNS_MANAGER_RESOLV_CONF_MAN_UNKNOWN,        "unknown"),
+	NM_UTILS_LOOKUP_STR_ITEM (NM_DNS_MANAGER_RESOLV_CONF_MAN_UNMANAGED,      "unmanaged"),
+	NM_UTILS_LOOKUP_STR_ITEM (NM_DNS_MANAGER_RESOLV_CONF_MAN_IMMUTABLE,      "immutable"),
+	NM_UTILS_LOOKUP_STR_ITEM (NM_DNS_MANAGER_RESOLV_CONF_MAN_SYMLINK,        "symlink"),
+	NM_UTILS_LOOKUP_STR_ITEM (NM_DNS_MANAGER_RESOLV_CONF_MAN_FILE,           "file"),
+	NM_UTILS_LOOKUP_STR_ITEM (NM_DNS_MANAGER_RESOLV_CONF_MAN_RESOLVCONF,     "resolvconf"),
+	NM_UTILS_LOOKUP_STR_ITEM (NM_DNS_MANAGER_RESOLV_CONF_MAN_NETCONFIG,      "netconfig"),
 );
 
+NM_UTILS_LOOKUP_STR_DEFINE_STATIC (_config_type_to_string, NMDnsIPConfigType,
+	NM_UTILS_LOOKUP_DEFAULT_WARN ("<unknown>"),
+	NM_UTILS_LOOKUP_STR_ITEM (NM_DNS_IP_CONFIG_TYPE_DEFAULT, "default"),
+	NM_UTILS_LOOKUP_STR_ITEM (NM_DNS_IP_CONFIG_TYPE_BEST_DEVICE, "best"),
+	NM_UTILS_LOOKUP_STR_ITEM (NM_DNS_IP_CONFIG_TYPE_VPN, "vpn"),
+);
+
+static NMDnsIPConfigData *
+ip_config_data_new (gpointer config, NMDnsIPConfigType type, const char *iface)
+{
+	NMDnsIPConfigData *data;
+
+	data = g_slice_new0 (NMDnsIPConfigData);
+	data->config = g_object_ref (config);
+	data->iface = g_strdup (iface);
+	data->type = type;
+
+	return data;
+}
+
+static void
+ip_config_data_destroy (gpointer ptr)
+{
+	NMDnsIPConfigData *data = ptr;
+
+	if (!data)
+		return;
+
+	g_object_unref (data->config);
+	g_free (data->iface);
+	g_slice_free (NMDnsIPConfigData, data);
+}
+
+static gint
+ip_config_data_compare (const NMDnsIPConfigData *a, const NMDnsIPConfigData *b)
+{
+	gboolean a_v4, b_v4;
+	gint a_prio, b_prio;
+
+	a_v4 = NM_IS_IP4_CONFIG (a->config);
+	b_v4 = NM_IS_IP4_CONFIG (b->config);
+
+	a_prio = a_v4 ?
+		nm_ip4_config_get_dns_priority ((NMIP4Config *) a->config) :
+		nm_ip6_config_get_dns_priority ((NMIP6Config *) a->config);
+
+	b_prio = b_v4 ?
+		nm_ip4_config_get_dns_priority ((NMIP4Config *) b->config) :
+		nm_ip6_config_get_dns_priority ((NMIP6Config *) b->config);
+
+	/* Configurations with lower priority value first */
+	if (a_prio < b_prio)
+		return -1;
+	else if (a_prio > b_prio)
+		return 1;
+
+	/* Sort also according to type */
+	if (a->type > b->type)
+		return -1;
+	else if (a->type < b->type)
+		return 1;
+
+	return 0;
+}
+
+static gint
+ip_config_data_ptr_compare (gconstpointer a, gconstpointer b)
+{
+	const NMDnsIPConfigData *const *ptr_a = a, *const *ptr_b = b;
+
+	return ip_config_data_compare (*ptr_a, *ptr_b);
+}
+
 static void
 add_string_item (GPtrArray *array, const char *str)
 {
@@ -257,12 +342,9 @@ merge_one_ip4_config (NMResolvConfData *rc, NMIP4Config *src)
 }
 
 static void
-merge_one_ip6_config (NMResolvConfData *rc, NMIP6Config *src)
+merge_one_ip6_config (NMResolvConfData *rc, NMIP6Config *src, const char *iface)
 {
 	guint32 num, num_domains, num_searches, i;
-	const char *iface;
-
-	iface = g_object_get_data (G_OBJECT (src), IP_CONFIG_IFACE_TAG);
 
 	num = nm_ip6_config_get_num_nameservers (src);
 	for (i = 0; i < num; i++) {
@@ -276,7 +358,7 @@ merge_one_ip6_config (NMResolvConfData *rc, NMIP6Config *src)
 			nm_utils_inet4_ntop (addr->s6_addr32[3], buf);
 		else {
 			nm_utils_inet6_ntop (addr, buf);
-			if (iface && IN6_IS_ADDR_LINKLOCAL (addr)) {
+			if (IN6_IS_ADDR_LINKLOCAL (addr)) {
 				g_strlcat (buf, "%", sizeof (buf));
 				g_strlcat (buf, iface, sizeof (buf));
 			}
@@ -316,6 +398,19 @@ merge_one_ip6_config (NMResolvConfData *rc, NMIP6Config *src)
 	}
 }
 
+static void
+merge_one_ip_config_data (NMDnsManager *self,
+                          NMResolvConfData *rc,
+                          NMDnsIPConfigData *data)
+{
+	if (NM_IS_IP4_CONFIG (data->config))
+		merge_one_ip4_config (rc, (NMIP4Config *) data->config);
+	else if (NM_IS_IP6_CONFIG (data->config))
+		merge_one_ip6_config (rc, (NMIP6Config *) data->config, data->iface);
+	else
+		g_return_if_reached ();
+}
+
 static GPid
 run_netconfig (NMDnsManager *self, GError **error, gint *stdin_fd)
 {
@@ -470,12 +565,16 @@ write_resolv_conf_contents (FILE *f,
                             const char *content,
                             GError **error)
 {
+	int errsv;
+
 	if (fprintf (f, "%s", content) < 0) {
+		errsv = errno;
 		g_set_error (error,
 		             NM_MANAGER_ERROR,
 		             NM_MANAGER_ERROR_FAILED,
 		             "Could not write " _PATH_RESCONF ": %s",
-		             g_strerror (errno));
+		             g_strerror (errsv));
+		errno = errsv;
 		return FALSE;
 	}
 
@@ -574,6 +673,9 @@ update_resolv_conf (NMDnsManager *self,
 	gboolean success;
 	gs_free char *content = NULL;
 	SpawnResult write_file_result = SR_SUCCESS;
+	int errsv;
+	const char *rc_path = _PATH_RESCONF;
+	nm_auto_free char *rc_path_real = NULL;
 
 	/* If we are not managing /etc/resolv.conf and it points to
 	 * MY_RESOLV_CONF, don't write the private DNS configuration to
@@ -582,12 +684,12 @@ update_resolv_conf (NMDnsManager *self,
 	 *
 	 * This is the only situation, where we don't try to update our
 	 * internal resolv.conf file. */
-	if (rc_manager == _NM_DNS_MANAGER_RESOLV_CONF_MAN_INTERNAL_ONLY) {
+	if (rc_manager == NM_DNS_MANAGER_RESOLV_CONF_MAN_UNMANAGED) {
 		gs_free char *path = g_file_read_link (_PATH_RESCONF, NULL);
 
 		if (g_strcmp0 (path, MY_RESOLV_CONF) == 0) {
-			_LOGD ("not updating " MY_RESOLV_CONF
-			       " since it points to " _PATH_RESCONF);
+			_LOGD ("update-resolv-conf: not updating " _PATH_RESCONF
+			       " since it points to " MY_RESOLV_CONF);
 			return SR_SUCCESS;
 		}
 	}
@@ -595,29 +697,50 @@ update_resolv_conf (NMDnsManager *self,
 	content = create_resolv_conf (searches, nameservers, options);
 
 	if (rc_manager == NM_DNS_MANAGER_RESOLV_CONF_MAN_FILE) {
+		GError *local = NULL;
+
+		rc_path_real = realpath (rc_path, NULL);
+		if (rc_path_real)
+			rc_path = rc_path_real;
+
 		/* we first write to /etc/resolv.conf directly. If that fails,
 		 * we still continue to write to runstatedir but remember the
 		 * error. */
-		if (!g_file_set_contents (_PATH_RESCONF, content, -1, error)) {
+		if (!g_file_set_contents (rc_path, content, -1, &local)) {
+			_LOGT ("update-resolv-conf: write to %s failed (rc-manager=%s, %s)",
+			       rc_path, _rc_manager_to_string (rc_manager), local->message);
 			write_file_result = SR_ERROR;
+			g_propagate_error (error, local);
 			error = NULL;
+		} else {
+			_LOGT ("update-resolv-conf: write to %s succeeded (rc-manager=%s)",
+			       rc_path, _rc_manager_to_string (rc_manager));
 		}
 	}
 
 	if ((f = fopen (MY_RESOLV_CONF_TMP, "w")) == NULL) {
+		errsv = errno;
 		g_set_error (error,
 		             NM_MANAGER_ERROR,
 		             NM_MANAGER_ERROR_FAILED,
 		             "Could not open %s: %s",
 		             MY_RESOLV_CONF_TMP,
-		             g_strerror (errno));
+		             g_strerror (errsv));
+		_LOGT ("update-resolv-conf: open temporary file %s failed (%s)",
+		       MY_RESOLV_CONF_TMP, g_strerror (errsv));
 		return SR_ERROR;
 	}
 
 	success = write_resolv_conf_contents (f, content, error);
+	if (!success) {
+		errsv = errno;
+		_LOGT ("update-resolv-conf: write temporary file %s failed (%s)",
+		       MY_RESOLV_CONF_TMP, g_strerror (errsv));
+	}
 
 	if (fclose (f) < 0) {
 		if (success) {
+			errsv = errno;
 			/* only set an error here if write_resolv_conf() was successful,
 			 * since its error is more important.
 			 */
@@ -626,39 +749,66 @@ update_resolv_conf (NMDnsManager *self,
 			             NM_MANAGER_ERROR_FAILED,
 			             "Could not close %s: %s",
 			             MY_RESOLV_CONF_TMP,
-			             g_strerror (errno));
+			             g_strerror (errsv));
+			_LOGT ("update-resolv-conf: close temporary file %s failed (%s)",
+			       MY_RESOLV_CONF_TMP, g_strerror (errsv));
 		}
 		return SR_ERROR;
 	} else if (!success)
 		return SR_ERROR;
 
 	if (rename (MY_RESOLV_CONF_TMP, MY_RESOLV_CONF) < 0) {
+		errsv = errno;
 		g_set_error (error,
 		             NM_MANAGER_ERROR,
 		             NM_MANAGER_ERROR_FAILED,
 		             "Could not replace %s: %s",
 		             MY_RESOLV_CONF,
 		             g_strerror (errno));
+		_LOGT ("update-resolv-conf: failed to rename temporary file %s to %s (%s)",
+		       MY_RESOLV_CONF_TMP, MY_RESOLV_CONF, g_strerror (errsv));
 		return SR_ERROR;
 	}
 
-	if (rc_manager == NM_DNS_MANAGER_RESOLV_CONF_MAN_FILE)
+	if (rc_manager == NM_DNS_MANAGER_RESOLV_CONF_MAN_FILE) {
+		_LOGT ("update-resolv-conf: write internal file %s succeeded (rc-manager=%s)",
+		       rc_path, _rc_manager_to_string (rc_manager));
 		return write_file_result;
+	}
 
-	if (rc_manager != NM_DNS_MANAGER_RESOLV_CONF_MAN_NONE)
+	if (rc_manager != NM_DNS_MANAGER_RESOLV_CONF_MAN_SYMLINK) {
+		_LOGT ("update-resolv-conf: write internal file %s succeeded", MY_RESOLV_CONF);
 		return SR_SUCCESS;
+	}
 
 	/* A symlink pointing to NM's own resolv.conf (MY_RESOLV_CONF) is always
 	 * overwritten to ensure that changes are indicated with inotify.  Symlinks
 	 * pointing to any other file are never overwritten.
 	 */
-	if (lstat (_PATH_RESCONF, &st) != -1) {
+	if (lstat (_PATH_RESCONF, &st) != 0) {
+		errsv = errno;
+		if (errsv != ENOENT) {
+			/* NM cannot read /etc/resolv.conf */
+			_LOGT ("update-resolv-conf: write internal file %s succeeded but lstat(%s) failed (%s)",
+			       MY_RESOLV_CONF, _PATH_RESCONF, g_strerror (errsv));
+			g_set_error (error,
+			             NM_MANAGER_ERROR,
+			             NM_MANAGER_ERROR_FAILED,
+			             "Could not lstat %s: %s",
+			             _PATH_RESCONF,
+			             g_strerror (errsv));
+			return SR_ERROR;
+		}
+	} else {
 		if (S_ISLNK (st.st_mode)) {
 			if (stat (_PATH_RESCONF, &st) != -1) {
 				gs_free char *path = g_file_read_link (_PATH_RESCONF, NULL);
 
-				if (g_strcmp0 (path, MY_RESOLV_CONF) != 0) {
+				if (!path || !nm_streq (path, MY_RESOLV_CONF)) {
 					/* It's not NM's symlink; do nothing */
+					_LOGT ("update-resolv-conf: write internal file %s succeeded "
+					       "but don't update %s as it points to %s",
+					       MY_RESOLV_CONF, _PATH_RESCONF, path ?: "");
 					return SR_SUCCESS;
 				}
 
@@ -669,56 +819,64 @@ update_resolv_conf (NMDnsManager *self,
 				 * some other program is probably managing resolv.conf and
 				 * NM should not touch it.
 				 */
+				_LOGT ("update-resolv-conf: write internal file %s succeeded "
+				       "but don't update %s as the symlinks points somewhere else",
+				       MY_RESOLV_CONF, _PATH_RESCONF);
 				return SR_SUCCESS;
 			}
 		}
-	} else if (errno != ENOENT) {
-		/* NM cannot read /etc/resolv.conf */
-		g_set_error (error,
-		             NM_MANAGER_ERROR,
-		             NM_MANAGER_ERROR_FAILED,
-		             "Could not lstat %s: %s",
-		             _PATH_RESCONF,
-		             g_strerror (errno));
-		return SR_ERROR;
 	}
 
 	/* By this point, either /etc/resolv.conf does not exist, is a regular
 	 * file, or is a symlink already owned by NM.  In all cases /etc/resolv.conf
 	 * is replaced with a symlink pointing to NM's resolv.conf in /var/run/.
 	 */
-	if (unlink (RESOLV_CONF_TMP) == -1 && errno != ENOENT) {
+	if (   unlink (RESOLV_CONF_TMP) != 0
+	    && ((errsv = errno) != ENOENT)) {
 		g_set_error (error,
 		             NM_MANAGER_ERROR,
 		             NM_MANAGER_ERROR_FAILED,
 		             "Could not unlink %s: %s",
 		             RESOLV_CONF_TMP,
-		             g_strerror (errno));
+		             g_strerror (errsv));
+		_LOGT ("update-resolv-conf: write internal file %s succeeded "
+		       "but canot delete temporary file %s: %s",
+		       MY_RESOLV_CONF, RESOLV_CONF_TMP, g_strerror (errsv));
 		return SR_ERROR;
 	}
 
 	if (symlink (MY_RESOLV_CONF, RESOLV_CONF_TMP) == -1) {
+		errsv = errno;
 		g_set_error (error,
 		             NM_MANAGER_ERROR,
 		             NM_MANAGER_ERROR_FAILED,
 		             "Could not create symlink %s pointing to %s: %s",
 		             RESOLV_CONF_TMP,
 		             MY_RESOLV_CONF,
-		             g_strerror (errno));
+		             g_strerror (errsv));
+		_LOGT ("update-resolv-conf: write internal file %s succeeded "
+		       "but failed to symlink %s: %s",
+		       MY_RESOLV_CONF, RESOLV_CONF_TMP, g_strerror (errsv));
 		return SR_ERROR;
 	}
 
 	if (rename (RESOLV_CONF_TMP, _PATH_RESCONF) == -1) {
+		errsv = errno;
 		g_set_error (error,
 		             NM_MANAGER_ERROR,
 		             NM_MANAGER_ERROR_FAILED,
 		             "Could not rename %s to %s: %s",
 		             RESOLV_CONF_TMP,
 		             _PATH_RESCONF,
-		             g_strerror (errno));
+		             g_strerror (errsv));
+		_LOGT ("update-resolv-conf: write internal file %s succeeded "
+		       "but failed to rename temporary symlink %s to %s: %s",
+		       MY_RESOLV_CONF, RESOLV_CONF_TMP, _PATH_RESCONF, g_strerror (errsv));
 		return SR_ERROR;
 	}
 
+	_LOGT ("update-resolv-conf: write internal file %s succeeded and update symlink %s",
+	       MY_RESOLV_CONF, _PATH_RESCONF);
 	return SR_SUCCESS;
 }
 
@@ -727,79 +885,29 @@ compute_hash (NMDnsManager *self, const NMGlobalDnsConfig *global, guint8 buffer
 {
 	NMDnsManagerPrivate *priv = NM_DNS_MANAGER_GET_PRIVATE (self);
 	GChecksum *sum;
-	GSList *iter;
 	gsize len = HASH_LEN;
+	guint i;
 
 	sum = g_checksum_new (G_CHECKSUM_SHA1);
 	g_assert (len == g_checksum_type_get_length (G_CHECKSUM_SHA1));
 
 	if (global)
 		nm_global_dns_config_update_checksum (global, sum);
+	else {
+		for (i = 0; i < priv->configs->len; i++) {
+			NMDnsIPConfigData *data = priv->configs->pdata[i];
 
-	if (priv->ip4_vpn_config)
-		nm_ip4_config_hash (priv->ip4_vpn_config, sum, TRUE);
-	if (priv->ip4_device_config)
-		nm_ip4_config_hash (priv->ip4_device_config, sum, TRUE);
-
-	if (priv->ip6_vpn_config)
-		nm_ip6_config_hash (priv->ip6_vpn_config, sum, TRUE);
-	if (priv->ip6_device_config)
-		nm_ip6_config_hash (priv->ip6_device_config, sum, TRUE);
-
-	/* add any other configs we know about */
-	for (iter = priv->configs; iter; iter = g_slist_next (iter)) {
-		if (NM_IN_SET (iter->data, priv->ip4_vpn_config,
-		                           priv->ip4_device_config,
-		                           priv->ip6_vpn_config,
-		                           priv->ip6_device_config))
-			continue;
-
-		if (NM_IS_IP4_CONFIG (iter->data))
-			nm_ip4_config_hash (NM_IP4_CONFIG (iter->data), sum, TRUE);
-		else if (NM_IS_IP6_CONFIG (iter->data))
-			nm_ip6_config_hash (NM_IP6_CONFIG (iter->data), sum, TRUE);
+			if (NM_IS_IP4_CONFIG (data->config))
+				nm_ip4_config_hash ((NMIP4Config *) data->config, sum, TRUE);
+			else if (NM_IS_IP6_CONFIG (data->config))
+				nm_ip6_config_hash ((NMIP6Config *) data->config, sum, TRUE);
+		}
 	}
 
 	g_checksum_get_digest (sum, buffer, &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 (!NM_IN_SET (iter->data, priv->ip4_vpn_config,
-		                            priv->ip4_device_config,
-		                            priv->ip6_vpn_config,
-		                            priv->ip6_device_config))
-			*out_other_configs = g_slist_append (*out_other_configs, iter->data);
-	}
-}
-
 static gboolean
 merge_global_dns_config (NMResolvConfData *rc, NMGlobalDnsConfig *global_conf)
 {
@@ -832,6 +940,44 @@ merge_global_dns_config (NMResolvConfData *rc, NMGlobalDnsConfig *global_conf)
 	return TRUE;
 }
 
+static const char *
+get_nameserver_list (void *config, GString **str)
+{
+	NMIP4Config *ip4;
+	NMIP6Config *ip6;
+	guint num, i;
+
+	nm_assert (str);
+
+	if (*str)
+		g_string_truncate (*str, 0);
+	else
+		*str = g_string_sized_new (64);
+
+	if (NM_IS_IP4_CONFIG (config)) {
+		ip4 = (NMIP4Config *) config;
+		num = nm_ip4_config_get_num_nameservers (ip4);
+		for (i = 0; i < num; i++) {
+			g_string_append (*str,
+			                 nm_utils_inet4_ntop (nm_ip4_config_get_nameserver (ip4, i),
+			                                      NULL));
+			g_string_append_c (*str, ' ');
+		}
+	} else if (NM_IS_IP6_CONFIG (config)) {
+		ip6 = (NMIP6Config *) config;
+		num = nm_ip6_config_get_num_nameservers (ip6);
+		for (i = 0; i < num; i++) {
+			g_string_append (*str,
+			                 nm_utils_inet6_ntop (nm_ip6_config_get_nameserver (ip6, i),
+			                                      NULL));
+			g_string_append_c (*str, ' ');
+		}
+	} else
+		g_return_val_if_reached (NULL);
+
+	return (*str)->str;
+}
+
 static gboolean
 update_dns (NMDnsManager *self,
             gboolean no_caching,
@@ -839,7 +985,6 @@ update_dns (NMDnsManager *self,
 {
 	NMDnsManagerPrivate *priv;
 	NMResolvConfData rc;
-	GSList *iter;
 	const char *nis_domain = NULL;
 	char **searches = NULL;
 	char **options = NULL;
@@ -851,13 +996,16 @@ update_dns (NMDnsManager *self,
 	SpawnResult result = SR_ERROR;
 	NMConfigData *data;
 	NMGlobalDnsConfig *global_config;
+	gs_free NMDnsIPConfigData **plugin_confs = NULL;
+	nm_auto_free_gstring GString *tmp_gstring = NULL;
 
 	g_return_val_if_fail (!error || !*error, FALSE);
 
 	priv = NM_DNS_MANAGER_GET_PRIVATE (self);
 	nm_clear_g_source (&priv->plugin_ratelimit.timer);
 
-	if (priv->resolv_conf_mode == NM_DNS_MANAGER_RESOLV_CONF_UNMANAGED) {
+	if (NM_IN_SET (priv->rc_manager, NM_DNS_MANAGER_RESOLV_CONF_MAN_UNMANAGED,
+	                                 NM_DNS_MANAGER_RESOLV_CONF_MAN_IMMUTABLE)) {
 		update = FALSE;
 		_LOGD ("update-dns: not updating resolv.conf");
 	} else {
@@ -868,6 +1016,11 @@ update_dns (NMDnsManager *self,
 	data = nm_config_get_data (priv->config);
 	global_config = nm_config_data_get_global_dns_config (data);
 
+	if (priv->need_sort) {
+		g_ptr_array_sort (priv->configs, ip_config_data_ptr_compare);
+		priv->need_sort = FALSE;
+	}
+
 	/* Update hash with config we're applying */
 	compute_hash (self, global_config, priv->hash);
 
@@ -880,34 +1033,41 @@ update_dns (NMDnsManager *self,
 	if (global_config)
 		merge_global_dns_config (&rc, global_config);
 	else {
-		if (priv->ip4_vpn_config)
-			merge_one_ip4_config (&rc, priv->ip4_vpn_config);
-		if (priv->ip4_device_config)
-			merge_one_ip4_config (&rc, priv->ip4_device_config);
-
-		if (priv->ip6_vpn_config)
-			merge_one_ip6_config (&rc, priv->ip6_vpn_config);
-		if (priv->ip6_device_config)
-			merge_one_ip6_config (&rc, priv->ip6_device_config);
-
-		for (iter = priv->configs; iter; iter = g_slist_next (iter)) {
-			if (NM_IN_SET (iter->data, priv->ip4_vpn_config,
-			                           priv->ip4_device_config,
-			                           priv->ip6_vpn_config,
-			                           priv->ip6_device_config))
-				continue;
+		int prio, prev_prio = 0;
+		NMDnsIPConfigData *current;
+		gboolean skip = FALSE, v4;
+
+		plugin_confs = g_new (NMDnsIPConfigData *, priv->configs->len + 1);
+
+		for (i = 0; i < priv->configs->len; i++) {
+			current = priv->configs->pdata[i];
+			v4 = NM_IS_IP4_CONFIG (current->config);
+
+			prio = v4 ?
+				nm_ip4_config_get_dns_priority ((NMIP4Config *) current->config) :
+				nm_ip6_config_get_dns_priority ((NMIP6Config *) current->config);
 
-			if (NM_IS_IP4_CONFIG (iter->data)) {
-				NMIP4Config *config = NM_IP4_CONFIG (iter->data);
+			if (prev_prio < 0 && prio != prev_prio) {
+				skip = TRUE;
+				plugin_confs[i] = NULL;
+			}
+
+			prev_prio = prio;
 
-				merge_one_ip4_config (&rc, config);
-			} else if (NM_IS_IP6_CONFIG (iter->data)) {
-				NMIP6Config *config = NM_IP6_CONFIG (iter->data);
+			_LOGT ("config: %8d %-7s v%c %-16s %s: %s",
+			       prio,
+			       _config_type_to_string (current->type),
+			       v4 ? '4' : '6',
+			       current->iface,
+			       skip ? "<SKIP>" : "",
+			       get_nameserver_list (current->config, &tmp_gstring));
 
-				merge_one_ip6_config (&rc, config);
-			} else
-				g_assert_not_reached ();
+			if (!skip) {
+				merge_one_ip_config_data (self, &rc, current);
+				plugin_confs[i] = current;
+			}
 		}
+		plugin_confs[i] = NULL;
 	}
 
 	/* If the hostname is a FQDN ("dcbw.example.com"), then add the domain part of it
@@ -970,7 +1130,6 @@ update_dns (NMDnsManager *self,
 	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) {
@@ -981,14 +1140,9 @@ update_dns (NMDnsManager *self,
 			caching = TRUE;
 		}
 
-		if (!global_config)
-			build_plugin_config_lists (self, &vpn_configs, &dev_configs, &other_configs);
-
 		_LOGD ("update-dns: updating plugin %s", plugin_name);
 		if (!nm_dns_plugin_update (plugin,
-		                           vpn_configs,
-		                           dev_configs,
-		                           other_configs,
+		                           (const NMDnsIPConfigData **) plugin_confs,
 		                           global_config,
 		                           priv->hostname)) {
 			_LOGW ("update-dns: plugin %s update failed", plugin_name);
@@ -998,9 +1152,6 @@ update_dns (NMDnsManager *self,
 			 */
 			caching = FALSE;
 		}
-		g_slist_free (vpn_configs);
-		g_slist_free (dev_configs);
-		g_slist_free (other_configs);
 
 	skip:
 		;
@@ -1019,7 +1170,7 @@ update_dns (NMDnsManager *self,
 
 	if (update) {
 		switch (priv->rc_manager) {
-		case NM_DNS_MANAGER_RESOLV_CONF_MAN_NONE:
+		case NM_DNS_MANAGER_RESOLV_CONF_MAN_SYMLINK:
 		case NM_DNS_MANAGER_RESOLV_CONF_MAN_FILE:
 			result = update_resolv_conf (self, searches, nameservers, options, error, priv->rc_manager);
 			resolv_conf_updated = TRUE;
@@ -1038,7 +1189,7 @@ update_dns (NMDnsManager *self,
 		if (result == SR_NOTFOUND) {
 			_LOGD ("update-dns: program not available, writing to resolv.conf");
 			g_clear_error (error);
-			result = update_resolv_conf (self, searches, nameservers, options, error, NM_DNS_MANAGER_RESOLV_CONF_MAN_NONE);
+			result = update_resolv_conf (self, searches, nameservers, options, error, NM_DNS_MANAGER_RESOLV_CONF_MAN_SYMLINK);
 			resolv_conf_updated = TRUE;
 		}
 	}
@@ -1046,7 +1197,7 @@ update_dns (NMDnsManager *self,
 	/* Unless we've already done it, update private resolv.conf in NMRUNDIR
 	   ignoring any errors */
 	if (!resolv_conf_updated)
-		update_resolv_conf (self, searches, nameservers, options, NULL, _NM_DNS_MANAGER_RESOLV_CONF_MAN_INTERNAL_ONLY);
+		update_resolv_conf (self, searches, nameservers, options, NULL, NM_DNS_MANAGER_RESOLV_CONF_MAN_UNMANAGED);
 
 	/* signal that resolv.conf was changed */
 	if (update && result == SR_SUCCESS)
@@ -1124,150 +1275,148 @@ plugin_child_quit (NMDnsPlugin *plugin, int exit_status, gpointer user_data)
 	plugin_child_quit_update_dns (self);
 }
 
-gboolean
-nm_dns_manager_add_ip4_config (NMDnsManager *self,
-                               const char *iface,
-                               NMIP4Config *config,
-                               NMDnsIPConfigType cfg_type)
+static void
+ip_config_dns_priority_changed (gpointer config,
+                                GParamSpec *pspec,
+                                NMDnsManager *self)
 {
-	NMDnsManagerPrivate *priv;
-	GError *error = NULL;
-
-	g_return_val_if_fail (self != NULL, FALSE);
-	g_return_val_if_fail (config != NULL, FALSE);
-
-	priv = NM_DNS_MANAGER_GET_PRIVATE (self);
-
-	g_object_set_data_full (G_OBJECT (config), IP_CONFIG_IFACE_TAG, g_strdup (iface), g_free);
-
-	switch (cfg_type) {
-	case NM_DNS_IP_CONFIG_TYPE_VPN:
-		priv->ip4_vpn_config = config;
-		break;
-	case NM_DNS_IP_CONFIG_TYPE_BEST_DEVICE:
-		priv->ip4_device_config = config;
-		break;
-	default:
-		break;
-	}
+	NM_DNS_MANAGER_GET_PRIVATE (self)->need_sort = TRUE;
+}
 
-	/* Don't allow the same zone added twice */
-	if (!g_slist_find (priv->configs, config))
-		priv->configs = g_slist_append (priv->configs, g_object_ref (config));
+static void
+forget_data (NMDnsManager *self, NMDnsIPConfigData *data)
+{
+	NMDnsManagerPrivate *priv = NM_DNS_MANAGER_GET_PRIVATE (self);
 
-	if (!priv->updates_queue && !update_dns (self, FALSE, &error)) {
-		_LOGW ("could not commit DNS changes: %s", error->message);
-		g_clear_error (&error);
-	}
+	if (data == priv->best_conf4)
+		priv->best_conf4 = NULL;
+	else if (data == priv->best_conf6)
+		priv->best_conf6 = NULL;
 
-	return TRUE;
+	g_signal_handlers_disconnect_by_func (data->config, ip_config_dns_priority_changed, self);
 }
 
-gboolean
-nm_dns_manager_remove_ip4_config (NMDnsManager *self, NMIP4Config *config)
+static gboolean
+nm_dns_manager_add_ip_config (NMDnsManager *self,
+                              const char *iface,
+                              gpointer config,
+                              NMDnsIPConfigType cfg_type)
 {
 	NMDnsManagerPrivate *priv;
 	GError *error = NULL;
+	NMDnsIPConfigData *data;
+	gboolean v4 = NM_IS_IP4_CONFIG (config);
+	guint i;
 
-	g_return_val_if_fail (self != NULL, FALSE);
-	g_return_val_if_fail (config != NULL, FALSE);
+	g_return_val_if_fail (NM_IS_DNS_MANAGER (self), FALSE);
+	g_return_val_if_fail (config, FALSE);
+	g_return_val_if_fail (iface && iface[0], FALSE);
 
 	priv = NM_DNS_MANAGER_GET_PRIVATE (self);
 
-	/* Can't remove it if it wasn't in the list to begin with */
-	if (!g_slist_find (priv->configs, config))
-		return FALSE;
-
-	priv->configs = g_slist_remove (priv->configs, config);
-
-	if (config == priv->ip4_vpn_config)
-		priv->ip4_vpn_config = NULL;
-	if (config == priv->ip4_device_config)
-		priv->ip4_device_config = NULL;
+	for (i = 0; i < priv->configs->len; i++) {
+		data = priv->configs->pdata[i];
+		if (data->config == config) {
+			if (   nm_streq (data->iface, iface)
+			    && data->type == cfg_type)
+				return FALSE;
+			else {
+				forget_data (self, data);
+				g_ptr_array_remove_index_fast (priv->configs, i);
+				break;
+			}
+		}
+	}
 
-	g_object_unref (config);
+	data = ip_config_data_new (config, cfg_type, iface);
+	g_ptr_array_add (priv->configs, data);
+	g_signal_connect (config,
+	                  v4 ?
+	                    "notify::" NM_IP4_CONFIG_DNS_PRIORITY :
+	                    "notify::" NM_IP6_CONFIG_DNS_PRIORITY,
+	                  (GCallback) ip_config_dns_priority_changed, self);
+	priv->need_sort = TRUE;
+
+	if (cfg_type == NM_DNS_IP_CONFIG_TYPE_BEST_DEVICE) {
+		/* Only one best-device per IP version is allowed */
+		if (v4) {
+			if (priv->best_conf4)
+				priv->best_conf4->type = NM_DNS_IP_CONFIG_TYPE_DEFAULT;
+			priv->best_conf4 = data;
+		} else {
+			if (priv->best_conf6)
+				priv->best_conf6->type = NM_DNS_IP_CONFIG_TYPE_DEFAULT;
+			priv->best_conf6 = data;
+		}
+	}
 
 	if (!priv->updates_queue && !update_dns (self, FALSE, &error)) {
 		_LOGW ("could not commit DNS changes: %s", error->message);
 		g_clear_error (&error);
 	}
 
-	g_object_set_data (G_OBJECT (config), IP_CONFIG_IFACE_TAG, NULL);
-
 	return TRUE;
 }
 
 gboolean
+nm_dns_manager_add_ip4_config (NMDnsManager *self,
+                               const char *iface,
+                               NMIP4Config *config,
+                               NMDnsIPConfigType cfg_type)
+{
+	return nm_dns_manager_add_ip_config (self, iface, config, cfg_type);
+}
+
+gboolean
 nm_dns_manager_add_ip6_config (NMDnsManager *self,
                                const char *iface,
                                NMIP6Config *config,
                                NMDnsIPConfigType cfg_type)
 {
+	return nm_dns_manager_add_ip_config (self, iface, config, cfg_type);
+}
+
+static gboolean
+nm_dns_manager_remove_ip_config (NMDnsManager *self, gpointer config)
+{
 	NMDnsManagerPrivate *priv;
 	GError *error = NULL;
+	NMDnsIPConfigData *data;
+	guint i;
 
-	g_return_val_if_fail (self != NULL, FALSE);
-	g_return_val_if_fail (config != NULL, FALSE);
+	g_return_val_if_fail (NM_IS_DNS_MANAGER (self), FALSE);
+	g_return_val_if_fail (config, FALSE);
 
 	priv = NM_DNS_MANAGER_GET_PRIVATE (self);
 
-	g_object_set_data_full (G_OBJECT (config), IP_CONFIG_IFACE_TAG, g_strdup (iface), g_free);
+	for (i = 0; i < priv->configs->len; i++) {
+		data = priv->configs->pdata[i];
 
-	switch (cfg_type) {
-	case NM_DNS_IP_CONFIG_TYPE_VPN:
-		priv->ip6_vpn_config = config;
-		break;
-	case NM_DNS_IP_CONFIG_TYPE_BEST_DEVICE:
-		priv->ip6_device_config = config;
-		break;
-	default:
-		break;
-	}
+		if (data->config == config) {
+			forget_data (self, data);
+			g_ptr_array_remove_index (priv->configs, i);
 
-	/* Don't allow the same zone added twice */
-	if (!g_slist_find (priv->configs, config))
-		priv->configs = g_slist_append (priv->configs, g_object_ref (config));
+			if (!priv->updates_queue && !update_dns (self, FALSE, &error)) {
+				_LOGW ("could not commit DNS changes: %s", error->message);
+				g_clear_error (&error);
+			}
 
-	if (!priv->updates_queue && !update_dns (self, FALSE, &error)) {
-		_LOGW ("could not commit DNS changes: %s", error->message);
-		g_clear_error (&error);
+			return TRUE;
+		}
 	}
+	return FALSE;
+}
 
-	return TRUE;
+gboolean
+nm_dns_manager_remove_ip4_config (NMDnsManager *self, NMIP4Config *config)
+{
+	return nm_dns_manager_remove_ip_config (self, config);
 }
 
 gboolean
 nm_dns_manager_remove_ip6_config (NMDnsManager *self, NMIP6Config *config)
 {
-	NMDnsManagerPrivate *priv;
-	GError *error = NULL;
-
-	g_return_val_if_fail (self != NULL, FALSE);
-	g_return_val_if_fail (config != NULL, FALSE);
-
-	priv = NM_DNS_MANAGER_GET_PRIVATE (self);
-
-	/* Can't remove it if it wasn't in the list to begin with */
-	if (!g_slist_find (priv->configs, config))
-		return FALSE;
-
-	priv->configs = g_slist_remove (priv->configs, config);
-
-	if (config == priv->ip6_vpn_config)
-		priv->ip6_vpn_config = NULL;
-	if (config == priv->ip6_device_config)
-		priv->ip6_device_config = NULL;
-
-	g_object_unref (config);
-
-	if (!priv->updates_queue && !update_dns (self, FALSE, &error)) {
-		_LOGW ("could not commit DNS changes: %s", error->message);
-		g_clear_error (&error);
-	}
-
-	g_object_set_data (G_OBJECT (config), IP_CONFIG_IFACE_TAG, NULL);
-
-	return TRUE;
+	return nm_dns_manager_remove_ip_config (self, config);
 }
 
 void
@@ -1308,10 +1457,21 @@ nm_dns_manager_set_hostname (NMDnsManager *self,
 	}
 }
 
-NMDnsManagerResolvConfMode
-nm_dns_manager_get_resolv_conf_mode (NMDnsManager *self)
+gboolean
+nm_dns_manager_get_resolv_conf_explicit (NMDnsManager *self)
 {
-	return NM_DNS_MANAGER_GET_PRIVATE (self)->resolv_conf_mode;
+	NMDnsManagerPrivate *priv;
+
+	g_return_val_if_fail (NM_IS_DNS_MANAGER (self), FALSE);
+
+	priv = NM_DNS_MANAGER_GET_PRIVATE (self);
+
+	if (   NM_IN_SET (priv->rc_manager, NM_DNS_MANAGER_RESOLV_CONF_MAN_UNMANAGED,
+	                                    NM_DNS_MANAGER_RESOLV_CONF_MAN_IMMUTABLE)
+	    || priv->plugin)
+		return FALSE;
+
+	return TRUE;
 }
 
 void
@@ -1344,6 +1504,11 @@ nm_dns_manager_end_updates (NMDnsManager *self, const char *func)
 	priv = NM_DNS_MANAGER_GET_PRIVATE (self);
 	g_return_if_fail (priv->updates_queue > 0);
 
+	if (priv->need_sort) {
+		g_ptr_array_sort (priv->configs, ip_config_data_ptr_compare);
+		priv->need_sort = FALSE;
+	}
+
 	compute_hash (self, nm_config_data_get_global_dns_config (nm_config_get_data (priv->config)), new);
 	changed = (memcmp (new, priv->prev_hash, sizeof (new)) != 0) ? TRUE : FALSE;
 	_LOGD ("(%s): DNS configuration %s", func, changed ? "changed" : "did not change");
@@ -1366,122 +1531,153 @@ nm_dns_manager_end_updates (NMDnsManager *self, const char *func)
 
 /******************************************************************/
 
-static bool
-_get_resconf_immutable (int *immutable_cached)
+static gboolean
+_clear_plugin (NMDnsManager *self)
+{
+	NMDnsManagerPrivate *priv = NM_DNS_MANAGER_GET_PRIVATE (self);
+
+	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);
+		nm_dns_plugin_stop (priv->plugin);
+		g_clear_object (&priv->plugin);
+		return TRUE;
+	}
+	priv->plugin_ratelimit.ts = 0;
+	nm_clear_g_source (&priv->plugin_ratelimit.timer);
+	return FALSE;
+}
+
+static NMDnsManagerResolvConfManager
+_check_resconf_immutable (NMDnsManagerResolvConfManager rc_manager)
 {
+	struct stat st;
 	int fd, flags;
-	int immutable;
+	bool immutable = FALSE;
+
+	switch (rc_manager) {
+	case NM_DNS_MANAGER_RESOLV_CONF_MAN_UNKNOWN:
+	case NM_DNS_MANAGER_RESOLV_CONF_MAN_IMMUTABLE:
+		nm_assert_not_reached ();
+		/* fall-through */
+	case NM_DNS_MANAGER_RESOLV_CONF_MAN_UNMANAGED:
+		return NM_DNS_MANAGER_RESOLV_CONF_MAN_UNMANAGED;
+	default:
+
+		if (lstat (_PATH_RESCONF, &st) != 0)
+			return rc_manager;
+
+		if (S_ISLNK (st.st_mode)) {
+			/* only regular files and directories can have extended file attributes. */
+			switch (rc_manager) {
+			case NM_DNS_MANAGER_RESOLV_CONF_MAN_SYMLINK:
+				/* we don't care whether the link-target is immutable.
+				 * If the symlink points to another file, rc-manager=symlink anyway backs off.
+				 * Otherwise, we would only check whether our internal resolv.conf is immutable. */
+				return NM_DNS_MANAGER_RESOLV_CONF_MAN_SYMLINK;
+			case NM_DNS_MANAGER_RESOLV_CONF_MAN_UNKNOWN:
+			case NM_DNS_MANAGER_RESOLV_CONF_MAN_UNMANAGED:
+			case NM_DNS_MANAGER_RESOLV_CONF_MAN_IMMUTABLE:
+				nm_assert_not_reached ();
+				/* fall-through */
+			case NM_DNS_MANAGER_RESOLV_CONF_MAN_FILE:
+			case NM_DNS_MANAGER_RESOLV_CONF_MAN_RESOLVCONF:
+			case NM_DNS_MANAGER_RESOLV_CONF_MAN_NETCONFIG:
+				break;
+			}
+		}
 
-	immutable = *immutable_cached;
-	if (!NM_IN_SET (immutable, FALSE, TRUE)) {
-		immutable = FALSE;
 		fd = open (_PATH_RESCONF, O_RDONLY);
 		if (fd != -1) {
 			if (ioctl (fd, FS_IOC_GETFLAGS, &flags) != -1)
 				immutable = NM_FLAGS_HAS (flags, FS_IMMUTABLE_FL);
 			close (fd);
 		}
-		*immutable_cached = immutable;
+		return immutable ? NM_DNS_MANAGER_RESOLV_CONF_MAN_IMMUTABLE : rc_manager;
 	}
-	return immutable;
 }
 
 NM_DEFINE_SINGLETON_GETTER (NMDnsManager, nm_dns_manager_get, NM_TYPE_DNS_MANAGER);
 
 static void
-init_resolv_conf_mode (NMDnsManager *self)
+init_resolv_conf_mode (NMDnsManager *self, gboolean force_reload_plugin)
 {
 	NMDnsManagerPrivate *priv = NM_DNS_MANAGER_GET_PRIVATE (self);
-	const char *mode, *mode_unknown;
-	int immutable = -1;
+	NMDnsManagerResolvConfManager rc_manager;
+	const char *mode;
+	gboolean plugin_changed = FALSE;
 
 	mode = nm_config_data_get_dns_mode (nm_config_get_data (priv->config));
 
-	if (   priv->mode_initialized
-	    && nm_streq0 (mode, priv->last_mode)
-	    && (   nm_streq0 (mode, "none")
-	        || priv->last_immutable == _get_resconf_immutable (&immutable))) {
-		/* we call init_resolv_conf_mode() on every SIGHUP to possibly reload
-		 * when either "mode" or "immutable" changed. However, we don't want to
-		 * re-create the plugin, when the paramters didn't actually change. So
-		 * detect that we would recreate the same plugin and return early. */
-		return;
-	}
-
-	priv->mode_initialized = TRUE;
-	g_free (priv->last_mode);
-	priv->last_mode = g_strdup (mode);
-	priv->last_immutable = FALSE;
-	g_clear_object (&priv->plugin);
-	priv->resolv_conf_mode = NM_DNS_MANAGER_RESOLV_CONF_UNMANAGED;
-
-	if (nm_streq0 (mode, "none")) {
-		_LOGI ("%s%s", "set resolv-conf-mode: ", "none");
-		return;
+	if (nm_streq0 (mode, "none"))
+		rc_manager = NM_DNS_MANAGER_RESOLV_CONF_MAN_UNMANAGED;
+	else {
+		const char *man;
+
+		rc_manager = NM_DNS_MANAGER_RESOLV_CONF_MAN_UNKNOWN;
+		man = nm_config_data_get_rc_manager (nm_config_get_data (priv->config));
+
+again:
+		if (!man) {
+			/* nop */
+		} else if (NM_IN_STRSET (man, "symlink", "none"))
+			rc_manager = NM_DNS_MANAGER_RESOLV_CONF_MAN_SYMLINK;
+		else if (nm_streq (man, "file"))
+			rc_manager = NM_DNS_MANAGER_RESOLV_CONF_MAN_FILE;
+		else if (nm_streq (man, "resolvconf"))
+			rc_manager = NM_DNS_MANAGER_RESOLV_CONF_MAN_RESOLVCONF;
+		else if (nm_streq (man, "netconfig"))
+			rc_manager = NM_DNS_MANAGER_RESOLV_CONF_MAN_NETCONFIG;
+		else if (nm_streq (man, "unmanaged"))
+			rc_manager = NM_DNS_MANAGER_RESOLV_CONF_MAN_UNMANAGED;
+
+		if (rc_manager == NM_DNS_MANAGER_RESOLV_CONF_MAN_UNKNOWN) {
+			if (man) {
+				_LOGW ("init: unknown resolv.conf manager \"%s\", fallback to \"%s\"",
+				       man, ""NM_CONFIG_DEFAULT_DNS_RC_MANAGER);
+			}
+			man = ""NM_CONFIG_DEFAULT_DNS_RC_MANAGER;
+			rc_manager = NM_DNS_MANAGER_RESOLV_CONF_MAN_SYMLINK;
+			goto again;
+		}
 	}
 
-	priv->last_immutable = _get_resconf_immutable (&immutable);
+	rc_manager = _check_resconf_immutable (rc_manager);
 
-	if (NM_IN_STRSET (mode, "dnsmasq", "unbound")) {
-		if (!immutable)
-			priv->resolv_conf_mode = NM_DNS_MANAGER_RESOLV_CONF_PROXY;
-		if (nm_streq (mode, "dnsmasq"))
+	if (nm_streq0 (mode, "dnsmasq")) {
+		if (force_reload_plugin || !NM_IS_DNS_DNSMASQ (priv->plugin)) {
+			_clear_plugin (self);
 			priv->plugin = nm_dns_dnsmasq_new ();
-		else
+			plugin_changed = TRUE;
+		}
+	} else if (nm_streq0 (mode, "unbound")) {
+		if (force_reload_plugin || !NM_IS_DNS_UNBOUND (priv->plugin)) {
+			_clear_plugin (self);
 			priv->plugin = nm_dns_unbound_new ();
+			plugin_changed = TRUE;
+		}
+	} else {
+		if (!NM_IN_STRSET (mode, "none", "default")) {
+			if (mode)
+				_LOGW ("init: unknown dns mode '%s'", mode);
+			mode = "default";
+		}
+		if (_clear_plugin (self))
+			plugin_changed = TRUE;
+	}
 
+	if (plugin_changed && 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);
-
-		_NMLOG (immutable ? LOGL_WARN : LOGL_INFO,
-		        "%s%s%s%s%s%s",
-		        "set resolv-conf-mode: ",
-		        immutable ? "none" : mode,
-		        ", plugin=\"", nm_dns_plugin_get_name (priv->plugin), "\"",
-		        immutable ? ", resolv.conf immutable" : "");
-		return;
 	}
 
-	if (!immutable)
-		priv->resolv_conf_mode = NM_DNS_MANAGER_RESOLV_CONF_EXPLICIT;
-
-	mode_unknown = mode && !nm_streq (mode, "default") ? mode : NULL;
-	_NMLOG (mode_unknown ? LOGL_WARN : LOGL_INFO,
-	        "%s%s%s%s%s%s",
-	        "set resolv-conf-mode: ",
-	        immutable ? "none" : "default",
-	        NM_PRINT_FMT_QUOTED (mode_unknown, " -- unknown configuration '", mode_unknown, "'", ""),
-	        immutable ? ", resolv.conf immutable" : "");
-}
-
-static void
-init_resolv_conf_manager (NMDnsManager *self)
-{
-	NMDnsManagerPrivate *priv = NM_DNS_MANAGER_GET_PRIVATE (self);
-	const char *man;
-
-	man = nm_config_data_get_rc_manager (nm_config_get_data (priv->config));
-	if (!g_strcmp0 (man, "none"))
-		priv->rc_manager = NM_DNS_MANAGER_RESOLV_CONF_MAN_NONE;
-	else if (nm_streq0 (man, "file"))
-		priv->rc_manager = NM_DNS_MANAGER_RESOLV_CONF_MAN_FILE;
-	else if (!g_strcmp0 (man, "resolvconf"))
-		priv->rc_manager = NM_DNS_MANAGER_RESOLV_CONF_MAN_RESOLVCONF;
-	else if (!g_strcmp0 (man, "netconfig"))
-		priv->rc_manager = NM_DNS_MANAGER_RESOLV_CONF_MAN_NETCONFIG;
-	else {
-#if defined(RESOLVCONF_SELECTED)
-		priv->rc_manager = NM_DNS_MANAGER_RESOLV_CONF_MAN_RESOLVCONF;
-#elif defined(NETCONFIG_SELECTED)
-		priv->rc_manager = NM_DNS_MANAGER_RESOLV_CONF_MAN_NETCONFIG;
-#else
-		priv->rc_manager = NM_DNS_MANAGER_RESOLV_CONF_MAN_NONE;
-#endif
-		if (man)
-			_LOGW ("unknown resolv.conf manager '%s'", man);
+	if (   plugin_changed
+	    || priv->rc_manager != rc_manager) {
+		priv->rc_manager = rc_manager;
+		_LOGI ("init: dns=%s, rc-manager=%s%s%s%s",
+		       mode, _rc_manager_to_string (rc_manager),
+		       NM_PRINT_FMT_QUOTED (priv->plugin, ", plugin=", nm_dns_plugin_get_name (priv->plugin), "", ""));
 	}
-
-	_LOGI ("using resolv.conf manager '%s'", _rc_manager_to_string (priv->rc_manager));
 }
 
 static void
@@ -1494,23 +1690,26 @@ config_changed_cb (NMConfig *config,
 	GError *error = NULL;
 
 	if (NM_FLAGS_ANY (changes, NM_CONFIG_CHANGE_DNS_MODE |
-	                           NM_CONFIG_CHANGE_SIGHUP)) {
+	                           NM_CONFIG_CHANGE_RC_MANAGER |
+	                           NM_CONFIG_CHANGE_CAUSE_SIGHUP |
+	                           NM_CONFIG_CHANGE_CAUSE_DNS_FULL)) {
 		/* reload the resolv-conf mode also on SIGHUP (when DNS_MODE didn't change).
 		 * The reason is, that the configuration also depends on whether resolv.conf
 		 * is immutable, thus, without the configuration changing, we always want to
 		 * re-configure the mode. */
-		init_resolv_conf_mode (self);
+		init_resolv_conf_mode (self,
+		                       NM_FLAGS_ANY (changes,   NM_CONFIG_CHANGE_CAUSE_SIGHUP
+		                                              | NM_CONFIG_CHANGE_CAUSE_DNS_FULL));
 	}
 
-	if (NM_FLAGS_HAS (changes, NM_CONFIG_CHANGE_RC_MANAGER))
-		init_resolv_conf_manager (self);
-
-	if (NM_FLAGS_ANY (changes, NM_CONFIG_CHANGE_SIGHUP |
-	                           NM_CONFIG_CHANGE_SIGUSR1 |
+	if (NM_FLAGS_ANY (changes, NM_CONFIG_CHANGE_CAUSE_SIGHUP |
+	                           NM_CONFIG_CHANGE_CAUSE_SIGUSR1 |
+	                           NM_CONFIG_CHANGE_CAUSE_DNS_RC |
+	                           NM_CONFIG_CHANGE_CAUSE_DNS_FULL |
 	                           NM_CONFIG_CHANGE_DNS_MODE |
 	                           NM_CONFIG_CHANGE_RC_MANAGER |
 	                           NM_CONFIG_CHANGE_GLOBAL_DNS_CONFIG)) {
-		if (!update_dns (self, TRUE, &error)) {
+		if (!update_dns (self, FALSE, &error)) {
 			_LOGW ("could not commit DNS changes: %s", error->message);
 			g_clear_error (&error);
 		}
@@ -1525,16 +1724,16 @@ nm_dns_manager_init (NMDnsManager *self)
 	_LOGT ("creating...");
 
 	priv->config = g_object_ref (nm_config_get ());
+	priv->configs = g_ptr_array_new_full (8, ip_config_data_destroy);
+
 	/* Set the initial hash */
-	compute_hash (self, nm_config_data_get_global_dns_config (nm_config_get_data (priv->config)),
-	              NM_DNS_MANAGER_GET_PRIVATE (self)->hash);
+	compute_hash (self, NULL, NM_DNS_MANAGER_GET_PRIVATE (self)->hash);
 
 	g_signal_connect (G_OBJECT (priv->config),
 	                  NM_CONFIG_SIGNAL_CONFIG_CHANGED,
 	                  G_CALLBACK (config_changed_cb),
 	                  self);
-	init_resolv_conf_mode (self);
-	init_resolv_conf_manager (self);
+	init_resolv_conf_mode (self, TRUE);
 }
 
 static void
@@ -1542,17 +1741,13 @@ dispose (GObject *object)
 {
 	NMDnsManager *self = NM_DNS_MANAGER (object);
 	NMDnsManagerPrivate *priv = NM_DNS_MANAGER_GET_PRIVATE (self);
+	NMDnsIPConfigData *data;
 	GError *error = NULL;
+	guint i;
 
 	_LOGT ("disposing");
 
-	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);
-	}
-
-	g_clear_pointer (&priv->last_mode, g_free);
+	_clear_plugin (self);
 
 	/* 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
@@ -1570,8 +1765,16 @@ dispose (GObject *object)
 		g_clear_object (&priv->config);
 	}
 
-	g_slist_free_full (priv->configs, g_object_unref);
-	priv->configs = NULL;
+	if (priv->configs) {
+		for (i = 0; i < priv->configs->len; i++) {
+			data = priv->configs->pdata[i];
+			forget_data (self, data);
+		}
+		g_ptr_array_free (priv->configs, TRUE);
+		priv->configs = NULL;
+	}
+
+	nm_clear_g_source (&priv->plugin_ratelimit.timer);
 
 	G_OBJECT_CLASS (nm_dns_manager_parent_class)->dispose (object);
 }
@@ -1579,7 +1782,8 @@ dispose (GObject *object)
 static void
 finalize (GObject *object)
 {
-	NMDnsManagerPrivate *priv = NM_DNS_MANAGER_GET_PRIVATE (object);
+	NMDnsManager *self = NM_DNS_MANAGER (object);
+	NMDnsManagerPrivate *priv = NM_DNS_MANAGER_GET_PRIVATE (self);
 
 	g_free (priv->hostname);
 
@@ -1591,8 +1795,6 @@ nm_dns_manager_class_init (NMDnsManagerClass *klass)
 {
 	GObjectClass *object_class = G_OBJECT_CLASS (klass);
 
-	g_type_class_add_private (object_class, sizeof (NMDnsManagerPrivate));
-
 	/* virtual methods */
 	object_class->dispose = dispose;
 	object_class->finalize = finalize;
@@ -1602,8 +1804,7 @@ nm_dns_manager_class_init (NMDnsManagerClass *klass)
 	    g_signal_new (NM_DNS_MANAGER_CONFIG_CHANGED,
 	                  G_OBJECT_CLASS_TYPE (object_class),
 	                  G_SIGNAL_RUN_FIRST,
-	                  G_STRUCT_OFFSET (NMDnsManagerClass, config_changed),
-	                  NULL, NULL,
+	                  0, NULL, NULL,
 	                  g_cclosure_marshal_VOID__VOID,
 	                  G_TYPE_NONE, 0);
 }
diff --git a/src/dns-manager/nm-dns-manager.h b/src/dns-manager/nm-dns-manager.h
index f1293f7e..50f050e5 100644
--- a/src/dns-manager/nm-dns-manager.h
+++ b/src/dns-manager/nm-dns-manager.h
@@ -28,13 +28,24 @@
 #include "nm-ip4-config.h"
 #include "nm-ip6-config.h"
 
+G_BEGIN_DECLS
+
 typedef enum {
 	NM_DNS_IP_CONFIG_TYPE_DEFAULT = 0,
 	NM_DNS_IP_CONFIG_TYPE_BEST_DEVICE,
 	NM_DNS_IP_CONFIG_TYPE_VPN
 } NMDnsIPConfigType;
 
-G_BEGIN_DECLS
+enum {
+	NM_DNS_PRIORITY_DEFAULT_NORMAL  = 100,
+	NM_DNS_PRIORITY_DEFAULT_VPN     = 50,
+};
+
+typedef struct {
+	gpointer config;
+	NMDnsIPConfigType type;
+	char *iface;
+} NMDnsIPConfigData;
 
 #define NM_TYPE_DNS_MANAGER (nm_dns_manager_get_type ())
 #define NM_DNS_MANAGER(o) (G_TYPE_CHECK_INSTANCE_CAST ((o), NM_TYPE_DNS_MANAGER, NMDnsManager))
@@ -45,16 +56,8 @@ G_BEGIN_DECLS
 
 #define NM_DNS_MANAGER_CONFIG_CHANGED "config-changed"
 
-typedef struct {
-	GObject parent;
-} NMDnsManager;
-
-typedef struct {
-	GObjectClass parent;
-
-	/* Signals */
-	void (*config_changed) (NMDnsManager *mgr);
-} NMDnsManagerClass;
+typedef struct _NMDnsManager NMDnsManager;
+typedef struct _NMDnsManagerClass NMDnsManagerClass;
 
 GType nm_dns_manager_get_type (void);
 
@@ -84,32 +87,17 @@ void nm_dns_manager_set_hostname         (NMDnsManager *self,
                                           const char *hostname);
 
 /**
- * NMDnsManagerResolvConfMode:
- * @NM_DNS_MANAGER_RESOLV_CONF_UNMANAGED: NM is not managing resolv.conf
- * @NM_DNS_MANAGER_RESOLV_CONF_EXPLICIT: NM is managing resolv.conf by
- *   adding and removing "nameserver" lines corresponding to the currently
- *   active connections
- * @NM_DNS_MANAGER_RESOLV_CONF_PROXY: NM is managing resolv.conf by
- *   pointing it to some other service (eg, dnsmasq) that knows the
- *   nameservers corresponding to the currently active connections.
- *
- * NMDnsManager's behavior toward /etc/resolv.conf.
- */
-typedef enum {
-	NM_DNS_MANAGER_RESOLV_CONF_UNMANAGED,
-	NM_DNS_MANAGER_RESOLV_CONF_EXPLICIT,
-	NM_DNS_MANAGER_RESOLV_CONF_PROXY
-} NMDnsManagerResolvConfMode;
-
-/**
  * NMDnsManagerResolvConfManager
- * @_NM_DNS_MANAGER_RESOLV_CONF_MAN_INTERNAL_ONLY: dummy-manager
- *   to not write resolv.conf at all, only the internal file in
- *   NM's run state directory.
- * @NM_DNS_MANAGER_RESOLV_CONF_MAN_NONE: NM writes resolv.conf
+ * @NM_DNS_MANAGER_RESOLV_CONF_MAN_UNKNOWN: unspecified rc-manager.
+ * @NM_DNS_MANAGER_RESOLV_CONF_MAN_UNMANAGED: do not touch /etc/resolv.conf
+ *   (but still write the internal copy -- unless it is symlinked by
+ *   /etc/resolv.conf)
+ * @NM_DNS_MANAGER_RESOLV_CONF_MAN_IMMUTABLE: similar to "unmanaged",
+ *   but indicates that resolv.conf cannot be modified.
+ * @NM_DNS_MANAGER_RESOLV_CONF_MAN_SYMLINK: NM writes resolv.conf
  *   by symlinking it to the run state directory.
- * @NM_DNS_MANAGER_RESOLV_CONF_MAN_FILE: Like NONE, but instead of symlinking
- *   resolv.conf, write it as a file.
+ * @NM_DNS_MANAGER_RESOLV_CONF_MAN_FILE: Like SYMLINK, but instead of
+ *   symlinking /etc/resolv.conf, write it as a file.
  * @NM_DNS_MANAGER_RESOLV_CONF_MAN_RESOLVCONF: NM is managing resolv.conf
      through resolvconf
  * @NM_DNS_MANAGER_RESOLV_CONF_MAN_NETCONFIG: NM is managing resolv.conf
@@ -118,14 +106,16 @@ typedef enum {
  * NMDnsManager's management of resolv.conf
  */
 typedef enum {
-	_NM_DNS_MANAGER_RESOLV_CONF_MAN_INTERNAL_ONLY,
-	NM_DNS_MANAGER_RESOLV_CONF_MAN_NONE,
+	NM_DNS_MANAGER_RESOLV_CONF_MAN_UNKNOWN,
+	NM_DNS_MANAGER_RESOLV_CONF_MAN_UNMANAGED,
+	NM_DNS_MANAGER_RESOLV_CONF_MAN_IMMUTABLE,
+	NM_DNS_MANAGER_RESOLV_CONF_MAN_SYMLINK,
 	NM_DNS_MANAGER_RESOLV_CONF_MAN_FILE,
 	NM_DNS_MANAGER_RESOLV_CONF_MAN_RESOLVCONF,
 	NM_DNS_MANAGER_RESOLV_CONF_MAN_NETCONFIG,
 } NMDnsManagerResolvConfManager;
 
-NMDnsManagerResolvConfMode nm_dns_manager_get_resolv_conf_mode (NMDnsManager *self);
+gboolean nm_dns_manager_get_resolv_conf_explicit (NMDnsManager *self);
 
 G_END_DECLS
 
diff --git a/src/dns-manager/nm-dns-plugin.c b/src/dns-manager/nm-dns-plugin.c
index d5cb8822..f065a1ce 100644
--- a/src/dns-manager/nm-dns-plugin.c
+++ b/src/dns-manager/nm-dns-plugin.c
@@ -74,18 +74,14 @@ static guint signals[LAST_SIGNAL] = { 0 };
 
 gboolean
 nm_dns_plugin_update (NMDnsPlugin *self,
-                      const GSList *vpn_configs,
-                      const GSList *dev_configs,
-                      const GSList *other_configs,
+                      const NMDnsIPConfigData **configs,
                       const NMGlobalDnsConfig *global_config,
                       const char *hostname)
 {
 	g_return_val_if_fail (NM_DNS_PLUGIN_GET_CLASS (self)->update != NULL, FALSE);
 
 	return NM_DNS_PLUGIN_GET_CLASS (self)->update (self,
-	                                               vpn_configs,
-	                                               dev_configs,
-	                                               other_configs,
+	                                               configs,
 	                                               global_config,
 	                                               hostname);
 }
@@ -182,6 +178,17 @@ watch_cb (GPid pid, gint status, gpointer user_data)
 }
 
 GPid
+nm_dns_plugin_child_pid (NMDnsPlugin *self)
+{
+	NMDnsPluginPrivate *priv;
+
+	g_return_val_if_fail (NM_IS_DNS_PLUGIN (self), 0);
+
+	priv = NM_DNS_PLUGIN_GET_PRIVATE (self);
+	return priv->pid;
+}
+
+GPid
 nm_dns_plugin_child_spawn (NMDnsPlugin *self,
                            const char **argv,
                            const char *pidfile,
@@ -224,7 +231,7 @@ nm_dns_plugin_child_spawn (NMDnsPlugin *self,
 	_LOGD ("%s started with pid %d", progname, pid);
 	priv->watch_id = g_child_watch_add (pid, (GChildWatchFunc) watch_cb, self);
 	priv->pid = pid;
-	priv->progname = nm_unauto (&progname);
+	priv->progname = g_steal_pointer (&progname);
 	priv->pidfile = g_strdup (pidfile);
 
 	return pid;
@@ -247,6 +254,12 @@ nm_dns_plugin_child_kill (NMDnsPlugin *self)
 	return TRUE;
 }
 
+void
+nm_dns_plugin_stop (NMDnsPlugin *self)
+{
+	nm_dns_plugin_child_kill (self);
+}
+
 /********************************************/
 
 static void
@@ -259,7 +272,7 @@ dispose (GObject *object)
 {
 	NMDnsPlugin *self = NM_DNS_PLUGIN (object);
 
-	nm_dns_plugin_child_kill (self);
+	nm_dns_plugin_stop (self);
 
 	G_OBJECT_CLASS (nm_dns_plugin_parent_class)->dispose (object);
 }
diff --git a/src/dns-manager/nm-dns-plugin.h b/src/dns-manager/nm-dns-plugin.h
index 7ecaa424..4c84b145 100644
--- a/src/dns-manager/nm-dns-plugin.h
+++ b/src/dns-manager/nm-dns-plugin.h
@@ -20,6 +20,7 @@
 #define __NETWORKMANAGER_DNS_PLUGIN_H__
 
 #include "nm-default.h"
+#include "nm-dns-manager.h"
 
 #include "nm-config-data.h"
 
@@ -33,8 +34,6 @@
 #define NM_DNS_PLUGIN_FAILED "failed"
 #define NM_DNS_PLUGIN_CHILD_QUIT "child-quit"
 
-#define IP_CONFIG_IFACE_TAG "dns-manager-iface"
-
 typedef struct {
 	GObject parent;
 } NMDnsPlugin;
@@ -44,18 +43,13 @@ typedef struct {
 
 	/* Methods */
 
-	/* Called when DNS information is changed.  'vpn_configs' is a list of
-	 * NMIP4Config or NMIP6Config objects from VPN connections, while
-	 * 'dev_configs' is a list of NMPI4Config or NMIP6Config objects from
-	 * active devices.  'other_configs' represent other IP configuration that
-	 * may be in-use.  'global_config' is the optional global DNS
-	 * configuration.  Configs of the same IP version are sorted in priority
-	 * order.
+	/* Called when DNS information is changed.  'configs' is an array
+	 * of pointers to NMDnsIPConfigData sorted by priority.
+	 * 'global_config' is the optional global DNS
+	 * configuration.
 	 */
 	gboolean (*update) (NMDnsPlugin *self,
-	                    const GSList *vpn_configs,
-	                    const GSList *dev_configs,
-	                    const GSList *other_configs,
+	                    const NMDnsIPConfigData **configs,
 	                    const NMGlobalDnsConfig *global_config,
 	                    const char *hostname);
 
@@ -92,12 +86,12 @@ gboolean nm_dns_plugin_is_caching (NMDnsPlugin *self);
 const char *nm_dns_plugin_get_name (NMDnsPlugin *self);
 
 gboolean nm_dns_plugin_update (NMDnsPlugin *self,
-                               const GSList *vpn_configs,
-                               const GSList *dev_configs,
-                               const GSList *other_configs,
+                               const NMDnsIPConfigData **configs,
                                const NMGlobalDnsConfig *global_config,
                                const char *hostname);
 
+void nm_dns_plugin_stop (NMDnsPlugin *self);
+
 /* For subclasses/plugins */
 
 /* Spawn a child process and watch for it to quit.  'argv' is the NULL-terminated
@@ -111,6 +105,8 @@ GPid nm_dns_plugin_child_spawn (NMDnsPlugin *self,
                                 const char *pidfile,
                                 const char *kill_match);
 
+GPid nm_dns_plugin_child_pid (NMDnsPlugin *self);
+
 gboolean nm_dns_plugin_child_kill (NMDnsPlugin *self);
 
 #endif /* __NETWORKMANAGER_DNS_PLUGIN_H__ */
diff --git a/src/dns-manager/nm-dns-unbound.c b/src/dns-manager/nm-dns-unbound.c
index 4c1af103..66a287fd 100644
--- a/src/dns-manager/nm-dns-unbound.c
+++ b/src/dns-manager/nm-dns-unbound.c
@@ -28,9 +28,7 @@ G_DEFINE_TYPE (NMDnsUnbound, nm_dns_unbound, NM_TYPE_DNS_PLUGIN)
 
 static gboolean
 update (NMDnsPlugin *plugin,
-        const GSList *vpn_configs,
-        const GSList *dev_configs,
-        const GSList *other_configs,
+        const NMDnsIPConfigData **configs,
         const NMGlobalDnsConfig *global_config,
         const char *hostname)
 {
diff --git a/src/dns-manager/nm-dns-utils.c b/src/dns-manager/nm-dns-utils.c
deleted file mode 100644
index e920611a..00000000
--- a/src/dns-manager/nm-dns-utils.c
+++ /dev/null
@@ -1,105 +0,0 @@
-/* -*- Mode: C; tab-width: 4; indent-tabs-mode: t; c-basic-offset: 4 -*- */
-/* 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) 2010 Red Hat, Inc.
- *
- */
-
-#include "nm-default.h"
-
-#include <arpa/inet.h>
-#include <string.h>
-
-#include "nm-dns-utils.h"
-#include "nm-platform.h"
-#include "nm-utils.h"
-
-static void
-add_ip4_to_rdns_array (guint32 ip, GPtrArray *domains) /* network byte order */
-{
-	guint32 defprefix;
-	guchar *p;
-	char *str = NULL;
-	int i;
-
-	defprefix = nm_utils_ip4_get_default_prefix (ip);
-
-	/* Convert to host byte order, mask the host bits, and convert back */
-	ip = ntohl (ip);
-	ip &= 0xFFFFFFFF << (32 - defprefix);
-	ip = htonl (ip);
-	p = (guchar *) &ip;
-
-	if (defprefix == 8)
-		str = g_strdup_printf ("%u.in-addr.arpa", p[0] & 0xFF);
-	else if (defprefix == 16)
-		str = g_strdup_printf ("%u.%u.in-addr.arpa", p[1] & 0xFF, p[0] & 0xFF);
-	else if (defprefix == 24)
-		str = g_strdup_printf ("%u.%u.%u.in-addr.arpa", p[2] & 0xFF, p[1] & 0xFF, p[0] & 0xFF);
-
-	if (!str) {
-		g_return_if_fail (str != NULL);
-		return;
-	}
-
-	/* Suppress duplicates */
-	for (i = 0; i < domains->len; i++) {
-		if (strcmp (str, g_ptr_array_index (domains, i)) == 0)
-			break;
-	}
-
-	if (i == domains->len)
-		g_ptr_array_add (domains, str);
-	else
-		g_free (str);
-}
-
-char **
-nm_dns_utils_get_ip4_rdns_domains (NMIP4Config *ip4)
-{
-	GPtrArray *domains = NULL;
-	int i;
-
-	g_return_val_if_fail (ip4 != NULL, NULL);
-
-	domains = g_ptr_array_sized_new (5);
-
-	/* To calculate the reverse DNS domains for this IP4 config, we take
-	 * all the IP addresses and routes in the config, calculate the network
-	 * portion, and convert that to classful, and use the network bits for
-	 * the final domain.  FIXME: better handle classless routing, which might
-	 * require us to add multiple domains for each actual network prefix to
-	 * cover all the separate networks in that block.
-	 */
-
-	for (i = 0; i < nm_ip4_config_get_num_addresses (ip4); i++) {
-		const NMPlatformIP4Address *address = nm_ip4_config_get_address (ip4, i);
-
-		add_ip4_to_rdns_array (address->address, domains);
-	}
-
-	for (i = 0; i < nm_ip4_config_get_num_routes (ip4); i++) {
-		const NMPlatformIP4Route *route = nm_ip4_config_get_route (ip4, i);
-
-		add_ip4_to_rdns_array (route->network, domains);
-	}
-
-	/* Terminating NULL so we can use g_strfreev() to free it */
-	g_ptr_array_add (domains, NULL);
-
-	/* Free the array and return NULL if the only element was the ending NULL */
-	return (char **) g_ptr_array_free (domains, (domains->len == 1));
-}
-
diff --git a/src/dns-manager/nm-dns-utils.h b/src/dns-manager/nm-dns-utils.h
deleted file mode 100644
index 75c6b060..00000000
--- a/src/dns-manager/nm-dns-utils.h
+++ /dev/null
@@ -1,28 +0,0 @@
-/* -*- Mode: C; tab-width: 4; indent-tabs-mode: t; c-basic-offset: 4 -*- */
-/* 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) 2010 Red Hat, Inc.
- *
- */
-
-#ifndef __NETWORKMANAGER_DNS_UTILS_H__
-#define __NETWORKMANAGER_DNS_UTILS_H__
-
-#include "nm-ip4-config.h"
-
-char **nm_dns_utils_get_ip4_rdns_domains (NMIP4Config *ip4);
-
-#endif  /* NM_DNS_UTILS_H */
-
diff --git a/src/dnsmasq-manager/nm-dnsmasq-manager.c b/src/dnsmasq-manager/nm-dnsmasq-manager.c
index 764aba29..12395db6 100644
--- a/src/dnsmasq-manager/nm-dnsmasq-manager.c
+++ b/src/dnsmasq-manager/nm-dnsmasq-manager.c
@@ -165,36 +165,6 @@ nm_cmd_line_add_string (NMCmdLine *cmd, const char *str)
 /*******************************************/
 
 static void
-dm_exit_code (guint dm_exit_status)
-{
-	char *msg = "Unknown error";
-
-	switch (dm_exit_status) {
-	case 1:
-		msg = "Configuration problem";
-		break;
-	case 2:
-		msg = "Network access problem (address in use; permissions; etc)";
-		break;
-	case 3:
-		msg = "Filesystem problem (missing file/directory; permissions; etc)";
-		break;
-	case 4:
-		msg = "Memory allocation failure";
-		break;
-	case 5:
-		msg = "Other problem";
-		break;
-	default:
-		if (dm_exit_status >= 11)
-			msg = "Lease-script 'init' process failure";
-		break;
-	}
-
-	_LOGW ("dnsmasq exited with error: %s (%d)", msg, dm_exit_status);
-}
-
-static void
 dm_watch_cb (GPid pid, gint status, gpointer user_data)
 {
 	NMDnsMasqManager *manager = NM_DNSMASQ_MANAGER (user_data);
@@ -203,8 +173,10 @@ dm_watch_cb (GPid pid, gint status, gpointer user_data)
 
 	if (WIFEXITED (status)) {
 		err = WEXITSTATUS (status);
-		if (err != 0)
-			dm_exit_code (err);
+		if (err != 0) {
+			_LOGW ("dnsmasq exited with error: %s",
+			       nm_utils_dnsmasq_status_to_string (err, NULL, 0));
+		}
 	} else if (WIFSTOPPED (status)) {
 		_LOGW ("dnsmasq stopped unexpectedly with signal %d", WSTOPSIG (status));
 	} else if (WIFSIGNALED (status)) {
diff --git a/src/dnsmasq-manager/tests/Makefile.in b/src/dnsmasq-manager/tests/Makefile.in
index d6b57edb..38344a8b 100644
--- a/src/dnsmasq-manager/tests/Makefile.in
+++ b/src/dnsmasq-manager/tests/Makefile.in
@@ -521,6 +521,7 @@ NEWT_LIBS = @NEWT_LIBS@
 NM = @NM@
 NMEDIT = @NMEDIT@
 NM_CONFIG_DEFAULT_AUTH_POLKIT_TEXT = @NM_CONFIG_DEFAULT_AUTH_POLKIT_TEXT@
+NM_CONFIG_DEFAULT_DNS_RC_MANAGER = @NM_CONFIG_DEFAULT_DNS_RC_MANAGER@
 NM_CONFIG_DEFAULT_LOGGING_AUDIT_TEXT = @NM_CONFIG_DEFAULT_LOGGING_AUDIT_TEXT@
 NM_CONFIG_LOGGING_BACKEND_DEFAULT_TEXT = @NM_CONFIG_LOGGING_BACKEND_DEFAULT_TEXT@
 NM_MAJOR_VERSION = @NM_MAJOR_VERSION@
diff --git a/src/main.c b/src/main.c
index 4616155d..e243baa8 100644
--- a/src/main.c
+++ b/src/main.c
@@ -188,14 +188,31 @@ _init_nm_debug (const char *debug)
 void
 nm_main_config_reload (int signal)
 {
+	NMConfigChangeFlags reload_flags;
+
+	switch (signal) {
+	case SIGHUP:
+		reload_flags = NM_CONFIG_CHANGE_CAUSE_SIGHUP;
+		break;
+	case SIGUSR1:
+		reload_flags = NM_CONFIG_CHANGE_CAUSE_SIGUSR1;
+		break;
+	case SIGUSR2:
+		reload_flags = NM_CONFIG_CHANGE_CAUSE_SIGUSR2;
+		break;
+	default:
+		g_return_if_reached ();
+	}
+
 	nm_log_info (LOGD_CORE, "reload configuration (signal %s)...", strsignal (signal));
+
 	/* The signal handler thread is only installed after
 	 * creating NMConfig instance, and on shut down we
 	 * no longer run the mainloop (to reach this point).
 	 *
 	 * Hence, a NMConfig singleton instance must always be
 	 * available. */
-	nm_config_reload (nm_config_get (), signal);
+	nm_config_reload (nm_config_get (), reload_flags);
 }
 
 static void
diff --git a/src/nm-active-connection.c b/src/nm-active-connection.c
index e9076136..2b7847b2 100644
--- a/src/nm-active-connection.c
+++ b/src/nm-active-connection.c
@@ -21,6 +21,8 @@
 #include "nm-default.h"
 
 #include "nm-active-connection.h"
+
+#include "nm-common-macros.h"
 #include "nm-dbus-interface.h"
 #include "nm-device.h"
 #include "nm-settings-connection.h"
@@ -70,8 +72,7 @@ typedef struct {
 	gpointer user_data2;
 } NMActiveConnectionPrivate;
 
-enum {
-	PROP_0,
+NM_GOBJECT_PROPERTIES_DEFINE (NMActiveConnection,
 	PROP_CONNECTION,
 	PROP_ID,
 	PROP_UUID,
@@ -93,9 +94,7 @@ enum {
 	PROP_INT_SUBJECT,
 	PROP_INT_MASTER,
 	PROP_INT_MASTER_READY,
-
-	LAST_PROP
-};
+);
 
 enum {
 	DEVICE_CHANGED,
@@ -137,6 +136,45 @@ NM_UTILS_LOOKUP_STR_DEFINE_STATIC (_state_to_string, NMActiveConnectionState,
 
 /****************************************************************/
 
+static void
+_settings_connection_updated (NMSettingsConnection *connection,
+                              gboolean by_user,
+                              gpointer user_data)
+{
+	NMActiveConnection *self = user_data;
+
+	/* we don't know which properties actually changed. Just to be sure,
+	 * notify about all possible properties. After all, an update of a
+	 * connection is a rare event. */
+
+	_notify (self, PROP_ID);
+
+	/* it's a bit odd to update the TYPE of an active connection. But the alternative
+	 * is unexpected too. */
+	_notify (self, PROP_TYPE);
+
+	/* currently, the UUID and the exported CONNECTION path cannot change. Later, we might
+	 * want to support a re-link operation, which associates an active-connection with a different
+	 * settings-connection. */
+}
+
+static void
+_set_settings_connection (NMActiveConnection *self, NMSettingsConnection *connection)
+{
+	NMActiveConnectionPrivate *priv = NM_ACTIVE_CONNECTION_GET_PRIVATE (self);
+
+	if (priv->settings_connection == connection)
+		return;
+	if (priv->settings_connection) {
+		g_signal_handlers_disconnect_by_func (priv->settings_connection, _settings_connection_updated, self);
+		g_clear_object (&priv->settings_connection);
+	}
+	if (connection) {
+		priv->settings_connection = g_object_ref (connection);
+		g_signal_connect (connection, NM_SETTINGS_CONNECTION_UPDATED_INTERNAL, (GCallback) _settings_connection_updated, self);
+	}
+}
+
 NMActiveConnectionState
 nm_active_connection_get_state (NMActiveConnection *self)
 {
@@ -164,7 +202,7 @@ nm_active_connection_set_state (NMActiveConnection *self,
 	old_state = priv->state;
 	priv->state = new_state;
 	priv->state_set = TRUE;
-	g_object_notify (G_OBJECT (self), NM_ACTIVE_CONNECTION_STATE);
+	_notify (self, PROP_STATE);
 
 	check_master_ready (self);
 
@@ -186,10 +224,10 @@ nm_active_connection_set_state (NMActiveConnection *self,
 
 	if (   new_state == NM_ACTIVE_CONNECTION_STATE_ACTIVATED
 	    || old_state == NM_ACTIVE_CONNECTION_STATE_ACTIVATED) {
-		g_object_notify (G_OBJECT (self), NM_ACTIVE_CONNECTION_IP4_CONFIG);
-		g_object_notify (G_OBJECT (self), NM_ACTIVE_CONNECTION_DHCP4_CONFIG);
-		g_object_notify (G_OBJECT (self), NM_ACTIVE_CONNECTION_IP6_CONFIG);
-		g_object_notify (G_OBJECT (self), NM_ACTIVE_CONNECTION_DHCP6_CONFIG);
+		_notify (self, PROP_IP4_CONFIG);
+		_notify (self, PROP_DHCP4_CONFIG);
+		_notify (self, PROP_IP6_CONFIG);
+		_notify (self, PROP_DHCP6_CONFIG);
 	}
 
 	if (priv->state == NM_ACTIVE_CONNECTION_STATE_DEACTIVATED) {
@@ -198,7 +236,7 @@ nm_active_connection_set_state (NMActiveConnection *self,
 		 * which will be NULL due to conditions in get_property().
 		 */
 		_device_cleanup (self);
-		g_object_notify (G_OBJECT (self), NM_ACTIVE_CONNECTION_DEVICES);
+		_notify (self, PROP_DEVICES);
 	}
 }
 
@@ -276,7 +314,7 @@ nm_active_connection_set_settings_connection (NMActiveConnection *self,
 	 * For example, we'd have to cancel all pending seret requests. */
 	g_return_if_fail (!nm_exported_object_is_exported (NM_EXPORTED_OBJECT (self)));
 
-	priv->settings_connection = g_object_ref (connection);
+	_set_settings_connection (self, connection);
 	priv->applied_connection = nm_simple_connection_new_clone (NM_CONNECTION (priv->settings_connection));
 	nm_connection_clear_secrets (priv->applied_connection);
 }
@@ -339,7 +377,7 @@ nm_active_connection_set_specific_object (NMActiveConnection *self,
 
 	g_free (priv->specific_object);
 	priv->specific_object = g_strdup (specific_object);
-	g_object_notify (G_OBJECT (self), NM_ACTIVE_CONNECTION_SPECIFIC_OBJECT);
+	_notify (self, PROP_SPECIFIC_OBJECT);
 }
 
 void
@@ -356,7 +394,7 @@ nm_active_connection_set_default (NMActiveConnection *self, gboolean is_default)
 		return;
 
 	priv->is_default = is_default;
-	g_object_notify (G_OBJECT (self), NM_ACTIVE_CONNECTION_DEFAULT);
+	_notify (self, PROP_DEFAULT);
 }
 
 gboolean
@@ -381,7 +419,7 @@ nm_active_connection_set_default6 (NMActiveConnection *self, gboolean is_default
 		return;
 
 	priv->is_default6 = is_default6;
-	g_object_notify (G_OBJECT (self), NM_ACTIVE_CONNECTION_DEFAULT6);
+	_notify (self, PROP_DEFAULT6);
 }
 
 gboolean
@@ -524,11 +562,11 @@ nm_active_connection_set_device (NMActiveConnection *self, NMDevice *device)
 		g_warn_if_fail (priv->state > NM_ACTIVE_CONNECTION_STATE_UNKNOWN);
 		priv->device = NULL;
 	}
-	g_object_notify (G_OBJECT (self), NM_ACTIVE_CONNECTION_INT_DEVICE);
+	_notify (self, PROP_INT_DEVICE);
 
 	g_signal_emit (self, signals[DEVICE_CHANGED], 0, priv->device, old_device);
 
-	g_object_notify (G_OBJECT (self), NM_ACTIVE_CONNECTION_DEVICES);
+	_notify (self, PROP_DEVICES);
 
 	return TRUE;
 }
@@ -589,13 +627,13 @@ check_master_ready (NMActiveConnection *self)
 
 	if (signalling) {
 		priv->master_ready = TRUE;
-		g_object_notify (G_OBJECT (self), NM_ACTIVE_CONNECTION_INT_MASTER_READY);
+		_notify (self, PROP_INT_MASTER_READY);
 
 		/* Also notify clients to recheck the exported 'master' property to
 		 * ensure that if the master connection was created without a device
 		 * that we notify clients when the master device is known.
 		 */
-		g_object_notify (G_OBJECT (self), NM_ACTIVE_CONNECTION_MASTER);
+		_notify (self, PROP_MASTER);
 	}
 }
 
@@ -921,7 +959,8 @@ static void
 set_property (GObject *object, guint prop_id,
               const GValue *value, GParamSpec *pspec)
 {
-	NMActiveConnectionPrivate *priv = NM_ACTIVE_CONNECTION_GET_PRIVATE (object);
+	NMActiveConnection *self = (NMActiveConnection *) object;
+	NMActiveConnectionPrivate *priv = NM_ACTIVE_CONNECTION_GET_PRIVATE (self);
 	const char *tmp;
 	NMSettingsConnection *con;
 
@@ -930,20 +969,20 @@ set_property (GObject *object, guint prop_id,
 		/* construct-only */
 		con = g_value_get_object (value);
 		if (con) {
-			priv->settings_connection = g_object_ref (con);
-			priv->applied_connection = nm_simple_connection_new_clone (NM_CONNECTION (con));
+			_set_settings_connection (self, con);
+			priv->applied_connection = nm_simple_connection_new_clone ((NMConnection *) priv->settings_connection);
 			nm_connection_clear_secrets (priv->applied_connection);
 		}
 		break;
 	case PROP_INT_DEVICE:
 		/* construct-only */
-		nm_active_connection_set_device (NM_ACTIVE_CONNECTION (object), g_value_get_object (value));
+		nm_active_connection_set_device (self, g_value_get_object (value));
 		break;
 	case PROP_INT_SUBJECT:
 		priv->subject = g_value_dup_object (value);
 		break;
 	case PROP_INT_MASTER:
-		nm_active_connection_set_master (NM_ACTIVE_CONNECTION (object), g_value_get_object (value));
+		nm_active_connection_set_master (self, g_value_get_object (value));
 		break;
 	case PROP_SPECIFIC_OBJECT:
 		tmp = g_value_get_string (value);
@@ -1083,7 +1122,7 @@ dispose (GObject *object)
 	g_free (priv->specific_object);
 	priv->specific_object = NULL;
 
-	g_clear_object (&priv->settings_connection);
+	_set_settings_connection (self, NULL);
 	g_clear_object (&priv->applied_connection);
 
 	_device_cleanup (self);
@@ -1120,171 +1159,153 @@ nm_active_connection_class_init (NMActiveConnectionClass *ac_class)
 	object_class->dispose = dispose;
 
 	/* D-Bus exported properties */
-	g_object_class_install_property
-		(object_class, PROP_CONNECTION,
-		 g_param_spec_string (NM_ACTIVE_CONNECTION_CONNECTION, "", "",
-		                      NULL,
-		                      G_PARAM_READABLE |
-		                      G_PARAM_STATIC_STRINGS));
-
-	g_object_class_install_property
-		(object_class, PROP_ID,
-		 g_param_spec_string (NM_ACTIVE_CONNECTION_ID, "", "",
-		                      NULL,
-		                      G_PARAM_READABLE |
-		                      G_PARAM_STATIC_STRINGS));
-
-	g_object_class_install_property
-		(object_class, PROP_UUID,
-		 g_param_spec_string (NM_ACTIVE_CONNECTION_UUID, "", "",
-		                      NULL,
-		                      G_PARAM_READABLE |
-		                      G_PARAM_STATIC_STRINGS));
-
-	g_object_class_install_property
-		(object_class, PROP_TYPE,
-		 g_param_spec_string (NM_ACTIVE_CONNECTION_TYPE, "", "",
-		                      NULL,
-		                      G_PARAM_READABLE |
-		                      G_PARAM_STATIC_STRINGS));
-
-	g_object_class_install_property
-		(object_class, PROP_SPECIFIC_OBJECT,
-		 g_param_spec_string (NM_ACTIVE_CONNECTION_SPECIFIC_OBJECT, "", "",
-		                      NULL,
-		                      G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY |
-		                      G_PARAM_STATIC_STRINGS));
-
-	g_object_class_install_property
-		(object_class, PROP_DEVICES,
-		 g_param_spec_boxed (NM_ACTIVE_CONNECTION_DEVICES, "", "",
-		                     G_TYPE_STRV,
-		                     G_PARAM_READABLE |
-		                     G_PARAM_STATIC_STRINGS));
-
-	g_object_class_install_property
-		(object_class, PROP_STATE,
-		 g_param_spec_uint (NM_ACTIVE_CONNECTION_STATE, "", "",
-		                    NM_ACTIVE_CONNECTION_STATE_UNKNOWN,
-		                    NM_ACTIVE_CONNECTION_STATE_DEACTIVATING,
-		                    NM_ACTIVE_CONNECTION_STATE_UNKNOWN,
-		                    G_PARAM_READABLE |
-		                    G_PARAM_STATIC_STRINGS));
-
-	g_object_class_install_property
-		(object_class, PROP_DEFAULT,
-		 g_param_spec_boolean (NM_ACTIVE_CONNECTION_DEFAULT, "", "",
-		                       FALSE,
-		                       G_PARAM_READWRITE |
-		                       G_PARAM_STATIC_STRINGS));
-
-	g_object_class_install_property
-		(object_class, PROP_IP4_CONFIG,
-		 g_param_spec_string (NM_ACTIVE_CONNECTION_IP4_CONFIG, "", "",
-		                      NULL,
-		                      G_PARAM_READABLE |
-		                      G_PARAM_STATIC_STRINGS));
-
-	g_object_class_install_property
-		(object_class, PROP_DHCP4_CONFIG,
-		 g_param_spec_string (NM_ACTIVE_CONNECTION_DHCP4_CONFIG, "", "",
-		                      NULL,
-		                      G_PARAM_READABLE |
-		                      G_PARAM_STATIC_STRINGS));
-
-	g_object_class_install_property
-		(object_class, PROP_DEFAULT6,
-		 g_param_spec_boolean (NM_ACTIVE_CONNECTION_DEFAULT6, "", "",
-		                       FALSE,
-		                       G_PARAM_READWRITE |
-		                       G_PARAM_STATIC_STRINGS));
-
-	g_object_class_install_property
-		(object_class, PROP_IP6_CONFIG,
-		 g_param_spec_string (NM_ACTIVE_CONNECTION_IP6_CONFIG, "", "",
-		                      NULL,
-		                      G_PARAM_READABLE |
-		                      G_PARAM_STATIC_STRINGS));
-
-	g_object_class_install_property
-		(object_class, PROP_DHCP6_CONFIG,
-		 g_param_spec_string (NM_ACTIVE_CONNECTION_DHCP6_CONFIG, "", "",
-		                      NULL,
-		                      G_PARAM_READABLE |
-		                      G_PARAM_STATIC_STRINGS));
-
-	g_object_class_install_property
-		(object_class, PROP_VPN,
-		 g_param_spec_boolean (NM_ACTIVE_CONNECTION_VPN, "", "",
-		                       FALSE,
-		                       G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY |
-		                       G_PARAM_STATIC_STRINGS));
-
-	g_object_class_install_property
-		(object_class, PROP_MASTER,
-		 g_param_spec_string (NM_ACTIVE_CONNECTION_MASTER, "", "",
-		                      NULL,
-		                      G_PARAM_READABLE |
-		                      G_PARAM_STATIC_STRINGS));
+	obj_properties[PROP_CONNECTION] =
+	     g_param_spec_string (NM_ACTIVE_CONNECTION_CONNECTION, "", "",
+	                          NULL,
+	                          G_PARAM_READABLE |
+	                          G_PARAM_STATIC_STRINGS);
+
+	obj_properties[PROP_ID] =
+	     g_param_spec_string (NM_ACTIVE_CONNECTION_ID, "", "",
+	                          NULL,
+	                          G_PARAM_READABLE |
+	                          G_PARAM_STATIC_STRINGS);
+
+	obj_properties[PROP_UUID] =
+	     g_param_spec_string (NM_ACTIVE_CONNECTION_UUID, "", "",
+	                          NULL,
+	                          G_PARAM_READABLE |
+	                          G_PARAM_STATIC_STRINGS);
+
+	obj_properties[PROP_TYPE] =
+	     g_param_spec_string (NM_ACTIVE_CONNECTION_TYPE, "", "",
+	                          NULL,
+	                          G_PARAM_READABLE |
+	                          G_PARAM_STATIC_STRINGS);
+
+	obj_properties[PROP_SPECIFIC_OBJECT] =
+	     g_param_spec_string (NM_ACTIVE_CONNECTION_SPECIFIC_OBJECT, "", "",
+	                          NULL,
+	                          G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY |
+	                          G_PARAM_STATIC_STRINGS);
+
+	obj_properties[PROP_DEVICES] =
+	     g_param_spec_boxed (NM_ACTIVE_CONNECTION_DEVICES, "", "",
+	                         G_TYPE_STRV,
+	                         G_PARAM_READABLE |
+	                         G_PARAM_STATIC_STRINGS);
+
+	obj_properties[PROP_STATE] =
+	     g_param_spec_uint (NM_ACTIVE_CONNECTION_STATE, "", "",
+	                        NM_ACTIVE_CONNECTION_STATE_UNKNOWN,
+	                        NM_ACTIVE_CONNECTION_STATE_DEACTIVATING,
+	                        NM_ACTIVE_CONNECTION_STATE_UNKNOWN,
+	                        G_PARAM_READABLE |
+	                        G_PARAM_STATIC_STRINGS);
+
+	obj_properties[PROP_DEFAULT] =
+	     g_param_spec_boolean (NM_ACTIVE_CONNECTION_DEFAULT, "", "",
+	                           FALSE,
+	                           G_PARAM_READWRITE |
+	                           G_PARAM_STATIC_STRINGS);
+
+	obj_properties[PROP_IP4_CONFIG] =
+	     g_param_spec_string (NM_ACTIVE_CONNECTION_IP4_CONFIG, "", "",
+	                          NULL,
+	                          G_PARAM_READABLE |
+	                          G_PARAM_STATIC_STRINGS);
+
+	obj_properties[PROP_DHCP4_CONFIG] =
+	     g_param_spec_string (NM_ACTIVE_CONNECTION_DHCP4_CONFIG, "", "",
+	                          NULL,
+	                          G_PARAM_READABLE |
+	                          G_PARAM_STATIC_STRINGS);
+
+	obj_properties[PROP_DEFAULT6] =
+	     g_param_spec_boolean (NM_ACTIVE_CONNECTION_DEFAULT6, "", "",
+	                           FALSE,
+	                           G_PARAM_READWRITE |
+	                           G_PARAM_STATIC_STRINGS);
+
+	obj_properties[PROP_IP6_CONFIG] =
+	     g_param_spec_string (NM_ACTIVE_CONNECTION_IP6_CONFIG, "", "",
+	                          NULL,
+	                          G_PARAM_READABLE |
+	                          G_PARAM_STATIC_STRINGS);
+
+	obj_properties[PROP_DHCP6_CONFIG] =
+	     g_param_spec_string (NM_ACTIVE_CONNECTION_DHCP6_CONFIG, "", "",
+	                          NULL,
+	                          G_PARAM_READABLE |
+	                          G_PARAM_STATIC_STRINGS);
+
+	obj_properties[PROP_VPN] =
+	     g_param_spec_boolean (NM_ACTIVE_CONNECTION_VPN, "", "",
+	                           FALSE,
+	                           G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY |
+	                           G_PARAM_STATIC_STRINGS);
+
+	obj_properties[PROP_MASTER] =
+	     g_param_spec_string (NM_ACTIVE_CONNECTION_MASTER, "", "",
+	                          NULL,
+	                          G_PARAM_READABLE |
+	                          G_PARAM_STATIC_STRINGS);
 
 	/* Internal properties */
-	g_object_class_install_property
-		(object_class, PROP_INT_SETTINGS_CONNECTION,
-		 g_param_spec_object (NM_ACTIVE_CONNECTION_INT_SETTINGS_CONNECTION, "", "",
-		                      NM_TYPE_SETTINGS_CONNECTION,
-		                      G_PARAM_WRITABLE | G_PARAM_CONSTRUCT_ONLY |
-		                      G_PARAM_STATIC_STRINGS));
-
-	g_object_class_install_property
-		(object_class, PROP_INT_DEVICE,
-		 g_param_spec_object (NM_ACTIVE_CONNECTION_INT_DEVICE, "", "",
-		                      NM_TYPE_DEVICE,
-		                      G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY |
-		                      G_PARAM_STATIC_STRINGS));
-
-	g_object_class_install_property
-		(object_class, PROP_INT_SUBJECT,
-		 g_param_spec_object (NM_ACTIVE_CONNECTION_INT_SUBJECT, "", "",
-		                      NM_TYPE_AUTH_SUBJECT,
-		                      G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY |
-		                      G_PARAM_STATIC_STRINGS));
-
-	g_object_class_install_property
-		(object_class, PROP_INT_MASTER,
-		 g_param_spec_object (NM_ACTIVE_CONNECTION_INT_MASTER, "", "",
-		                      NM_TYPE_ACTIVE_CONNECTION,
-		                      G_PARAM_READWRITE |
-		                      G_PARAM_STATIC_STRINGS));
-
-	g_object_class_install_property
-		(object_class, PROP_INT_MASTER_READY,
-		 g_param_spec_boolean (NM_ACTIVE_CONNECTION_INT_MASTER_READY, "", "",
-		                       FALSE, G_PARAM_READABLE |
-		                       G_PARAM_STATIC_STRINGS));
+	obj_properties[PROP_INT_SETTINGS_CONNECTION] =
+	     g_param_spec_object (NM_ACTIVE_CONNECTION_INT_SETTINGS_CONNECTION, "", "",
+	                          NM_TYPE_SETTINGS_CONNECTION,
+	                          G_PARAM_WRITABLE | G_PARAM_CONSTRUCT_ONLY |
+	                          G_PARAM_STATIC_STRINGS);
+
+	obj_properties[PROP_INT_DEVICE] =
+	     g_param_spec_object (NM_ACTIVE_CONNECTION_INT_DEVICE, "", "",
+	                          NM_TYPE_DEVICE,
+	                          G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY |
+	                          G_PARAM_STATIC_STRINGS);
+
+	obj_properties[PROP_INT_SUBJECT] =
+	     g_param_spec_object (NM_ACTIVE_CONNECTION_INT_SUBJECT, "", "",
+	                          NM_TYPE_AUTH_SUBJECT,
+	                          G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY |
+	                          G_PARAM_STATIC_STRINGS);
+
+	obj_properties[PROP_INT_MASTER] =
+	     g_param_spec_object (NM_ACTIVE_CONNECTION_INT_MASTER, "", "",
+	                          NM_TYPE_ACTIVE_CONNECTION,
+	                          G_PARAM_READWRITE |
+	                          G_PARAM_STATIC_STRINGS);
+
+	obj_properties[PROP_INT_MASTER_READY] =
+	     g_param_spec_boolean (NM_ACTIVE_CONNECTION_INT_MASTER_READY, "", "",
+	                           FALSE, G_PARAM_READABLE |
+	                           G_PARAM_STATIC_STRINGS);
+
+	g_object_class_install_properties (object_class, _PROPERTY_ENUMS_LAST, obj_properties);
 
 	signals[DEVICE_CHANGED] =
-		g_signal_new (NM_ACTIVE_CONNECTION_DEVICE_CHANGED,
-		              G_OBJECT_CLASS_TYPE (object_class),
-		              G_SIGNAL_RUN_FIRST,
-		              G_STRUCT_OFFSET (NMActiveConnectionClass, device_changed),
-		              NULL, NULL, NULL,
-		              G_TYPE_NONE, 2, NM_TYPE_DEVICE, NM_TYPE_DEVICE);
+	    g_signal_new (NM_ACTIVE_CONNECTION_DEVICE_CHANGED,
+	                  G_OBJECT_CLASS_TYPE (object_class),
+	                  G_SIGNAL_RUN_FIRST,
+	                  G_STRUCT_OFFSET (NMActiveConnectionClass, device_changed),
+	                  NULL, NULL, NULL,
+	                  G_TYPE_NONE, 2, NM_TYPE_DEVICE, NM_TYPE_DEVICE);
 
 	signals[DEVICE_METERED_CHANGED] =
-		g_signal_new (NM_ACTIVE_CONNECTION_DEVICE_METERED_CHANGED,
-		              G_OBJECT_CLASS_TYPE (object_class),
-		              G_SIGNAL_RUN_FIRST,
-		              G_STRUCT_OFFSET (NMActiveConnectionClass, device_metered_changed),
-		              NULL, NULL, NULL,
-		              G_TYPE_NONE, 1, G_TYPE_UINT);
+	    g_signal_new (NM_ACTIVE_CONNECTION_DEVICE_METERED_CHANGED,
+	                  G_OBJECT_CLASS_TYPE (object_class),
+	                  G_SIGNAL_RUN_FIRST,
+	                  G_STRUCT_OFFSET (NMActiveConnectionClass, device_metered_changed),
+	                  NULL, NULL, NULL,
+	                  G_TYPE_NONE, 1, G_TYPE_UINT);
 
 	signals[PARENT_ACTIVE] =
-		g_signal_new (NM_ACTIVE_CONNECTION_PARENT_ACTIVE,
-		              G_OBJECT_CLASS_TYPE (object_class),
-		              G_SIGNAL_RUN_FIRST,
-		              G_STRUCT_OFFSET (NMActiveConnectionClass, parent_active),
-		              NULL, NULL, NULL,
-		              G_TYPE_NONE, 1, NM_TYPE_ACTIVE_CONNECTION);
+	    g_signal_new (NM_ACTIVE_CONNECTION_PARENT_ACTIVE,
+	                  G_OBJECT_CLASS_TYPE (object_class),
+	                  G_SIGNAL_RUN_FIRST,
+	                  G_STRUCT_OFFSET (NMActiveConnectionClass, parent_active),
+	                  NULL, NULL, NULL,
+	                  G_TYPE_NONE, 1, NM_TYPE_ACTIVE_CONNECTION);
 
 	nm_exported_object_class_add_interface (NM_EXPORTED_OBJECT_CLASS (ac_class),
 	                                        NMDBUS_TYPE_ACTIVE_CONNECTION_SKELETON,
diff --git a/src/nm-audit-manager.h b/src/nm-audit-manager.h
index ed53be69..9aef417f 100644
--- a/src/nm-audit-manager.h
+++ b/src/nm-audit-manager.h
@@ -53,6 +53,7 @@ typedef struct {
 #define NM_AUDIT_OP_CONN_DEACTIVATE         "connection-deactivate"
 #define NM_AUDIT_OP_CONN_CLEAR_SECRETS      "connection-clear-secrets"
 
+#define NM_AUDIT_OP_RELOAD                  "reload"
 #define NM_AUDIT_OP_SLEEP_CONTROL           "sleep-control"
 #define NM_AUDIT_OP_NET_CONTROL             "networking-control"
 #define NM_AUDIT_OP_RADIO_CONTROL           "radio-control"
diff --git a/src/nm-auth-utils.c b/src/nm-auth-utils.c
index 928e88b0..e1761cab 100644
--- a/src/nm-auth-utils.c
+++ b/src/nm-auth-utils.c
@@ -20,10 +20,11 @@
 
 #include "nm-default.h"
 
+#include "nm-auth-utils.h"
+
 #include <string.h>
 
 #include "nm-setting-connection.h"
-#include "nm-auth-utils.h"
 #include "nm-auth-subject.h"
 #include "nm-auth-manager.h"
 #include "nm-session-monitor.h"
diff --git a/src/nm-auth-utils.h b/src/nm-auth-utils.h
index 6eb0fda0..89ed79cc 100644
--- a/src/nm-auth-utils.h
+++ b/src/nm-auth-utils.h
@@ -21,22 +21,7 @@
 #ifndef __NETWORKMANAGER_MANAGER_AUTH_H__
 #define __NETWORKMANAGER_MANAGER_AUTH_H__
 
-#include <nm-connection.h>
-#include "nm-default.h"
-
-#define NM_AUTH_PERMISSION_ENABLE_DISABLE_NETWORK     "org.freedesktop.NetworkManager.enable-disable-network"
-#define NM_AUTH_PERMISSION_SLEEP_WAKE                 "org.freedesktop.NetworkManager.sleep-wake"
-#define NM_AUTH_PERMISSION_ENABLE_DISABLE_WIFI        "org.freedesktop.NetworkManager.enable-disable-wifi"
-#define NM_AUTH_PERMISSION_ENABLE_DISABLE_WWAN        "org.freedesktop.NetworkManager.enable-disable-wwan"
-#define NM_AUTH_PERMISSION_ENABLE_DISABLE_WIMAX       "org.freedesktop.NetworkManager.enable-disable-wimax"
-#define NM_AUTH_PERMISSION_NETWORK_CONTROL            "org.freedesktop.NetworkManager.network-control"
-#define NM_AUTH_PERMISSION_WIFI_SHARE_PROTECTED       "org.freedesktop.NetworkManager.wifi.share.protected"
-#define NM_AUTH_PERMISSION_WIFI_SHARE_OPEN            "org.freedesktop.NetworkManager.wifi.share.open"
-#define NM_AUTH_PERMISSION_SETTINGS_MODIFY_SYSTEM     "org.freedesktop.NetworkManager.settings.modify.system"
-#define NM_AUTH_PERMISSION_SETTINGS_MODIFY_OWN        "org.freedesktop.NetworkManager.settings.modify.own"
-#define NM_AUTH_PERMISSION_SETTINGS_MODIFY_HOSTNAME   "org.freedesktop.NetworkManager.settings.modify.hostname"
-#define NM_AUTH_PERMISSION_SETTINGS_MODIFY_GLOBAL_DNS "org.freedesktop.NetworkManager.settings.modify.global-dns"
-
+#include "nm-connection.h"
 
 typedef struct NMAuthChain NMAuthChain;
 
diff --git a/src/nm-config-data.c b/src/nm-config-data.c
index 1702b551..28057b47 100644
--- a/src/nm-config-data.c
+++ b/src/nm-config-data.c
@@ -1201,6 +1201,8 @@ nm_config_data_diff (NMConfigData *old_data, NMConfigData *new_data)
 	if (!global_dns_equal (priv_old->global_dns, priv_new->global_dns))
 		changes |= NM_CONFIG_CHANGE_GLOBAL_DNS_CONFIG;
 
+	nm_assert (!NM_FLAGS_ANY (changes, NM_CONFIG_CHANGE_CAUSES));
+
 	return changes;
 }
 
diff --git a/src/nm-config-data.h b/src/nm-config-data.h
index 2decfdb4..e01ad6ea 100644
--- a/src/nm-config-data.h
+++ b/src/nm-config-data.h
@@ -21,11 +21,6 @@
 #ifndef NM_CONFIG_DATA_H
 #define NM_CONFIG_DATA_H
 
-
-#include "nm-default.h"
-
-G_BEGIN_DECLS
-
 #define NM_TYPE_CONFIG_DATA            (nm_config_data_get_type ())
 #define NM_CONFIG_DATA(obj)            (G_TYPE_CHECK_INSTANCE_CAST ((obj), NM_TYPE_CONFIG_DATA, NMConfigData))
 #define NM_CONFIG_DATA_CLASS(klass)    (G_TYPE_CHECK_CLASS_CAST ((klass),  NM_TYPE_CONFIG_DATA, NMConfigDataClass))
@@ -44,7 +39,26 @@ G_BEGIN_DECLS
 #define NM_CONFIG_DATA_NO_AUTO_DEFAULT       "no-auto-default"
 #define NM_CONFIG_DATA_DNS_MODE              "dns"
 
-typedef enum { /*<flags >*/
+/* The flags for Reload. Currently these are internal defines,
+ * only their numeric value matters and must be stable as
+ * they are public API! Also, the enum must fit in uint32. */
+enum { /*< skip >*/
+	NM_MANAGER_RELOAD_FLAGS_NONE                            = 0,
+
+	/* reload the configuration from disk */
+	NM_MANAGER_RELOAD_FLAGS_CONF                            = (1LL << 0),
+
+	/* write DNS configuration to resolv.conf */
+	NM_MANAGER_RELOAD_FLAGS_DNS_RC                          = (1LL << 1),
+
+	/* restart the DNS plugin (includes DNS_RC) */
+	NM_MANAGER_RELOAD_FLAGS_DNS_FULL                        = (1LL << 2),
+
+	_NM_MANAGER_RELOAD_FLAGS_ALL,
+	NM_MANAGER_RELOAD_FLAGS_ALL = ((_NM_MANAGER_RELOAD_FLAGS_ALL - 1) << 1) - 1,
+};
+
+typedef enum { /*< flags >*/
 	NM_CONFIG_GET_VALUE_NONE                   = 0,
 
 	/* use g_key_file_get_value() instead of g_key_file_get_string(). */
@@ -64,22 +78,54 @@ typedef enum { /*<flags >*/
 typedef enum { /*< flags >*/
 	NM_CONFIG_CHANGE_NONE                      = 0,
 
-	NM_CONFIG_CHANGE_SIGHUP                    = (1L << 0),
-	NM_CONFIG_CHANGE_SIGUSR1                   = (1L << 1),
-	NM_CONFIG_CHANGE_SIGUSR2                   = (1L << 2),
-
-	NM_CONFIG_CHANGE_CONFIG_FILES              = (1L << 3),
-	NM_CONFIG_CHANGE_VALUES                    = (1L << 4),
-	NM_CONFIG_CHANGE_VALUES_USER               = (1L << 5),
-	NM_CONFIG_CHANGE_VALUES_INTERN             = (1L << 6),
-	NM_CONFIG_CHANGE_CONNECTIVITY              = (1L << 7),
-	NM_CONFIG_CHANGE_NO_AUTO_DEFAULT           = (1L << 8),
-	NM_CONFIG_CHANGE_DNS_MODE                  = (1L << 9),
-	NM_CONFIG_CHANGE_RC_MANAGER                = (1L << 10),
-	NM_CONFIG_CHANGE_GLOBAL_DNS_CONFIG         = (1L << 11),
-
-	_NM_CONFIG_CHANGE_LAST,
-	NM_CONFIG_CHANGE_ALL                       = ((_NM_CONFIG_CHANGE_LAST - 1) << 1) - 1,
+	/**************************************************************************
+	 * The external cause which triggered the reload/configuration-change
+	 *************************************************************************/
+
+	NM_CONFIG_CHANGE_CAUSE_SIGHUP              = (1L << 0),
+	NM_CONFIG_CHANGE_CAUSE_SIGUSR1             = (1L << 1),
+	NM_CONFIG_CHANGE_CAUSE_SIGUSR2             = (1L << 2),
+	NM_CONFIG_CHANGE_CAUSE_NO_AUTO_DEFAULT     = (1L << 3),
+	NM_CONFIG_CHANGE_CAUSE_SET_VALUES          = (1L << 4),
+	NM_CONFIG_CHANGE_CAUSE_CONF                = (1L << 5),
+	NM_CONFIG_CHANGE_CAUSE_DNS_RC              = (1L << 6),
+	NM_CONFIG_CHANGE_CAUSE_DNS_FULL            = (1L << 7),
+
+	NM_CONFIG_CHANGE_CAUSES                    = ((1L << 8) - 1),
+
+	/**************************************************************************
+	 * Following flags describe which property of the configuration changed:
+	 *************************************************************************/
+
+	/* main-file or config-description changed */
+	NM_CONFIG_CHANGE_CONFIG_FILES              = (1L << 10),
+
+
+	/* any configuration on disk changed */
+	NM_CONFIG_CHANGE_VALUES                    = (1L << 11),
+
+	/* any user configuration on disk changed (NetworkManager.conf) */
+	NM_CONFIG_CHANGE_VALUES_USER               = (1L << 12),
+
+	/* any internal configuration on disk changed (NetworkManager-intern.conf) */
+	NM_CONFIG_CHANGE_VALUES_INTERN             = (1L << 13),
+
+
+	/* configuration regarding connectivity changed */
+	NM_CONFIG_CHANGE_CONNECTIVITY              = (1L << 14),
+
+	/* configuration regarding no-auto-default changed */
+	NM_CONFIG_CHANGE_NO_AUTO_DEFAULT           = (1L << 15),
+
+	/* configuration regarding dns-mode changed */
+	NM_CONFIG_CHANGE_DNS_MODE                  = (1L << 16),
+
+	/* configuration regarding rc-manager changed */
+	NM_CONFIG_CHANGE_RC_MANAGER                = (1L << 17),
+
+	/* configuration regarding global dns-config changed */
+	NM_CONFIG_CHANGE_GLOBAL_DNS_CONFIG         = (1L << 18),
+
 } NMConfigChangeFlags;
 
 struct _NMConfigData {
@@ -164,7 +210,5 @@ GKeyFile *_nm_config_data_get_keyfile (const NMConfigData *self);
 GKeyFile *_nm_config_data_get_keyfile_user (const NMConfigData *self);
 GKeyFile *_nm_config_data_get_keyfile_intern (const NMConfigData *self);
 
-G_END_DECLS
-
 #endif /* NM_CONFIG_DATA_H */
 
diff --git a/src/nm-config.c b/src/nm-config.c
index 8bca6870..247b9a89 100644
--- a/src/nm-config.c
+++ b/src/nm-config.c
@@ -21,10 +21,11 @@
 
 #include "nm-default.h"
 
+#include "nm-config.h"
+
 #include <string.h>
 #include <stdio.h>
 
-#include "nm-config.h"
 #include "nm-utils.h"
 #include "nm-device.h"
 #include "NetworkManagerUtils.h"
@@ -109,7 +110,7 @@ G_DEFINE_TYPE_WITH_CODE (NMConfig, nm_config, G_TYPE_OBJECT,
 
 /************************************************************************/
 
-static void _set_config_data (NMConfig *self, NMConfigData *new_data, int signal);
+static void _set_config_data (NMConfig *self, NMConfigData *new_data, NMConfigChangeFlags reload_flags);
 
 /************************************************************************/
 
@@ -393,7 +394,7 @@ nm_config_set_no_auto_default_for_device (NMConfig *self, NMDevice *device)
 	/* unref no_auto_default_set here. Note that _set_config_data() probably invalidates the content of the array. */
 	g_ptr_array_unref (no_auto_default_new);
 
-	_set_config_data (self, new_data, 0);
+	_set_config_data (self, new_data, NM_CONFIG_CHANGE_CAUSE_NO_AUTO_DEFAULT);
 }
 
 /************************************************************************/
@@ -634,6 +635,7 @@ read_config (GKeyFile *keyfile, gboolean is_base_config, const char *dirname, co
 
 	kf = nm_config_create_keyfile ();
 	if (!g_key_file_load_from_file (kf, path, G_KEY_FILE_NONE, error)) {
+		g_prefix_error (error, "%s: ", path);
 		g_key_file_free (kf);
 		return FALSE;
 	}
@@ -646,7 +648,7 @@ read_config (GKeyFile *keyfile, gboolean is_base_config, const char *dirname, co
 	/* the config-group is internal to every configuration snippets. It doesn't make sense
 	 * to merge the into the global configuration, and it doesn't make sense to preserve the
 	 * group beyond this point. */
-	g_key_file_remove_group (keyfile, NM_CONFIG_KEYFILE_GROUP_CONFIG, NULL);
+	g_key_file_remove_group (kf, NM_CONFIG_KEYFILE_GROUP_CONFIG, NULL);
 
 	/* Override the current settings with the new ones */
 	groups = g_key_file_get_groups (kf, &ngroups);
@@ -815,8 +817,7 @@ read_base_config (GKeyFile *keyfile,
 	}
 
 	if (!g_error_matches (my_error, G_KEY_FILE_ERROR, G_KEY_FILE_ERROR_NOT_FOUND)) {
-		nm_log_warn (LOGD_CORE, "Old default config file %s invalid: %s\n",
-		             DEFAULT_CONFIG_MAIN_FILE_OLD,
+		nm_log_warn (LOGD_CORE, "Old default config file invalid: %s\n",
 		             my_error->message);
 	}
 	g_clear_error (&my_error);
@@ -828,8 +829,7 @@ read_base_config (GKeyFile *keyfile,
 	}
 
 	if (!g_error_matches (my_error, G_KEY_FILE_ERROR, G_KEY_FILE_ERROR_NOT_FOUND)) {
-		nm_log_warn (LOGD_CORE, "Default config file %s invalid: %s\n",
-		             DEFAULT_CONFIG_MAIN_FILE,
+		nm_log_warn (LOGD_CORE, "Default config file invalid: %s\n",
 		             my_error->message);
 		g_propagate_error (error, my_error);
 		return FALSE;
@@ -1640,7 +1640,7 @@ nm_config_set_values (NMConfig *self,
 			nm_log_dbg (LOGD_CORE, "don't persistate internal configuration (no file set, use --intern-config?)");
 	}
 	if (new_data)
-		_set_config_data (self, new_data, 0);
+		_set_config_data (self, new_data, NM_CONFIG_CHANGE_CAUSE_SET_VALUES);
 
 	g_key_file_unref (keyfile_new);
 }
@@ -1648,7 +1648,7 @@ nm_config_set_values (NMConfig *self,
 /************************************************************************/
 
 void
-nm_config_reload (NMConfig *self, int signal)
+nm_config_reload (NMConfig *self, NMConfigChangeFlags reload_flags)
 {
 	NMConfigPrivate *priv;
 	GError *error = NULL;
@@ -1660,11 +1660,16 @@ nm_config_reload (NMConfig *self, int signal)
 	gboolean intern_config_needs_rewrite;
 
 	g_return_if_fail (NM_IS_CONFIG (self));
+	g_return_if_fail (   reload_flags
+	                  && !NM_FLAGS_ANY (reload_flags, ~NM_CONFIG_CHANGE_CAUSES)
+	                  && !NM_FLAGS_ANY (reload_flags,   NM_CONFIG_CHANGE_CAUSE_NO_AUTO_DEFAULT
+	                                                  | NM_CONFIG_CHANGE_CAUSE_SET_VALUES));
 
 	priv = NM_CONFIG_GET_PRIVATE (self);
 
-	if (signal != SIGHUP) {
-		_set_config_data (self, NULL, signal);
+	if (!NM_FLAGS_ANY (reload_flags, NM_CONFIG_CHANGE_CAUSE_SIGHUP | NM_CONFIG_CHANGE_CAUSE_CONF)) {
+		/* unless SIGHUP is specified, we don't reload the configuration from disc. */
+		_set_config_data (self, NULL, reload_flags);
 		return;
 	}
 
@@ -1681,7 +1686,7 @@ nm_config_reload (NMConfig *self, int signal)
 	if (!keyfile) {
 		nm_log_err (LOGD_CORE, "Failed to reload the configuration: %s", error->message);
 		g_clear_error (&error);
-		_set_config_data (self, NULL, signal);
+		_set_config_data (self, NULL, reload_flags);
 		return;
 	}
 
@@ -1703,13 +1708,20 @@ nm_config_reload (NMConfig *self, int signal)
 	if (keyfile_intern)
 		g_key_file_unref (keyfile_intern);
 
-	_set_config_data (self, new_data, signal);
+	_set_config_data (self, new_data, reload_flags);
 }
 
 NM_UTILS_FLAGS2STR_DEFINE (nm_config_change_flags_to_string, NMConfigChangeFlags,
-	NM_UTILS_FLAGS2STR (NM_CONFIG_CHANGE_SIGHUP, "SIGHUP"),
-	NM_UTILS_FLAGS2STR (NM_CONFIG_CHANGE_SIGUSR1, "SIGUSR1"),
-	NM_UTILS_FLAGS2STR (NM_CONFIG_CHANGE_SIGUSR2, "SIGUSR2"),
+
+	NM_UTILS_FLAGS2STR (NM_CONFIG_CHANGE_CAUSE_CONF, "CONF"),
+	NM_UTILS_FLAGS2STR (NM_CONFIG_CHANGE_CAUSE_DNS_RC, "DNS_RC"),
+	NM_UTILS_FLAGS2STR (NM_CONFIG_CHANGE_CAUSE_DNS_FULL, "DNS_FULL"),
+	NM_UTILS_FLAGS2STR (NM_CONFIG_CHANGE_CAUSE_SIGHUP, "SIGHUP"),
+	NM_UTILS_FLAGS2STR (NM_CONFIG_CHANGE_CAUSE_SIGUSR1, "SIGUSR1"),
+	NM_UTILS_FLAGS2STR (NM_CONFIG_CHANGE_CAUSE_SIGUSR2, "SIGUSR2"),
+	NM_UTILS_FLAGS2STR (NM_CONFIG_CHANGE_CAUSE_NO_AUTO_DEFAULT, "NO_AUTO_DEFAULT"),
+	NM_UTILS_FLAGS2STR (NM_CONFIG_CHANGE_CAUSE_SET_VALUES, "SET_VALUES"),
+
 	NM_UTILS_FLAGS2STR (NM_CONFIG_CHANGE_CONFIG_FILES, "config-files"),
 	NM_UTILS_FLAGS2STR (NM_CONFIG_CHANGE_VALUES, "values"),
 	NM_UTILS_FLAGS2STR (NM_CONFIG_CHANGE_VALUES_USER, "values-user"),
@@ -1722,27 +1734,19 @@ NM_UTILS_FLAGS2STR_DEFINE (nm_config_change_flags_to_string, NMConfigChangeFlags
 );
 
 static void
-_set_config_data (NMConfig *self, NMConfigData *new_data, int signal)
+_set_config_data (NMConfig *self, NMConfigData *new_data, NMConfigChangeFlags reload_flags)
 {
 	NMConfigPrivate *priv = NM_CONFIG_GET_PRIVATE (self);
 	NMConfigData *old_data = priv->config_data;
 	NMConfigChangeFlags changes, changes_diff;
 	gboolean had_new_data = !!new_data;
 
-	switch (signal) {
-	case SIGHUP:
-		changes = NM_CONFIG_CHANGE_SIGHUP;
-		break;
-	case SIGUSR1:
-		changes = NM_CONFIG_CHANGE_SIGUSR1;
-		break;
-	case SIGUSR2:
-		changes = NM_CONFIG_CHANGE_SIGUSR2;
-		break;
-	default:
-		changes = NM_CONFIG_CHANGE_NONE;
-		break;
-	}
+	nm_assert (reload_flags);
+	nm_assert (!NM_FLAGS_ANY (reload_flags, ~NM_CONFIG_CHANGE_CAUSES));
+	nm_assert (   NM_IN_SET (reload_flags, NM_CONFIG_CHANGE_CAUSE_NO_AUTO_DEFAULT, NM_CONFIG_CHANGE_CAUSE_SET_VALUES)
+	           || !NM_FLAGS_ANY (reload_flags, NM_CONFIG_CHANGE_CAUSE_NO_AUTO_DEFAULT | NM_CONFIG_CHANGE_CAUSE_SET_VALUES));
+
+	changes = reload_flags;
 
 	if (new_data) {
 		changes_diff = nm_config_data_diff (old_data, new_data);
@@ -1752,12 +1756,19 @@ _set_config_data (NMConfig *self, NMConfigData *new_data, int signal)
 			changes |= changes_diff;
 	}
 
-	if (changes == NM_CONFIG_CHANGE_NONE)
+	if (   NM_IN_SET (reload_flags,
+	                  NM_CONFIG_CHANGE_CAUSE_NO_AUTO_DEFAULT,
+	                  NM_CONFIG_CHANGE_CAUSE_SET_VALUES,
+	                  NM_CONFIG_CHANGE_CAUSE_CONF)
+	    && !new_data) {
+		/* no relevant changes that should be propagated. Return silently. */
 		return;
+	}
 
 	if (new_data) {
-		nm_log_info (LOGD_CORE, "config: update %s (%s)", nm_config_data_get_config_description (new_data),
-		             nm_config_change_flags_to_string (changes, NULL, 0));
+		nm_log_info (LOGD_CORE, "config: signal %s (%s)",
+		             nm_config_change_flags_to_string (changes, NULL, 0),
+		             nm_config_data_get_config_description (new_data));
 		nm_config_data_log (new_data, "CONFIG: ", "  ", NULL);
 		priv->config_data = new_data;
 	} else if (had_new_data)
diff --git a/src/nm-config.h b/src/nm-config.h
index 8bbab2ac..9a153e48 100644
--- a/src/nm-config.h
+++ b/src/nm-config.h
@@ -22,12 +22,8 @@
 #ifndef __NETWORKMANAGER_CONFIG_H__
 #define __NETWORKMANAGER_CONFIG_H__
 
-
-#include "nm-default.h"
 #include "nm-config-data.h"
 
-G_BEGIN_DECLS
-
 #define NM_TYPE_CONFIG            (nm_config_get_type ())
 #define NM_CONFIG(obj)            (G_TYPE_CHECK_INSTANCE_CAST ((obj), NM_TYPE_CONFIG, NMConfig))
 #define NM_CONFIG_CLASS(klass)    (G_TYPE_CHECK_CLASS_CAST ((klass),  NM_TYPE_CONFIG, NMConfigClass))
@@ -129,7 +125,7 @@ void nm_config_set_no_auto_default_for_device  (NMConfig *config, NMDevice *devi
 
 NMConfig *nm_config_new (const NMConfigCmdLineOptions *cli, char **atomic_section_prefixes, GError **error);
 NMConfig *nm_config_setup (const NMConfigCmdLineOptions *cli, char **atomic_section_prefixes, GError **error);
-void nm_config_reload (NMConfig *config, int signal);
+void nm_config_reload (NMConfig *config, NMConfigChangeFlags reload_flags);
 
 gint nm_config_parse_boolean (const char *str, gint default_value);
 
@@ -159,7 +155,5 @@ gboolean nm_config_set_global_dns (NMConfig *self, NMGlobalDnsConfig *global_dns
 extern guint _nm_config_match_nm_version;
 extern char *_nm_config_match_env;
 
-G_END_DECLS
-
 #endif /* __NETWORKMANAGER_CONFIG_H__ */
 
diff --git a/src/nm-connection-provider.c b/src/nm-connection-provider.c
index 2e258bd5..e04cab92 100644
--- a/src/nm-connection-provider.c
+++ b/src/nm-connection-provider.c
@@ -106,24 +106,21 @@ nm_connection_provider_default_init (NMConnectionProviderInterface *g_iface)
 	g_signal_new (NM_CP_SIGNAL_CONNECTION_ADDED,
 	              iface_type,
 	              G_SIGNAL_RUN_FIRST,
-	              G_STRUCT_OFFSET (NMConnectionProviderInterface, connection_added),
-	              NULL, NULL,
+	              0, NULL, NULL,
 	              g_cclosure_marshal_VOID__OBJECT,
 	              G_TYPE_NONE, 1, G_TYPE_OBJECT);
 
 	g_signal_new (NM_CP_SIGNAL_CONNECTION_UPDATED,
 	              iface_type,
 	              G_SIGNAL_RUN_FIRST,
-	              G_STRUCT_OFFSET (NMConnectionProviderInterface, connection_updated),
-	              NULL, NULL,
+	              0, NULL, NULL,
 	              g_cclosure_marshal_VOID__OBJECT,
 	              G_TYPE_NONE, 1, G_TYPE_OBJECT);
 
 	g_signal_new (NM_CP_SIGNAL_CONNECTION_REMOVED,
 	              iface_type,
 	              G_SIGNAL_RUN_FIRST,
-	              G_STRUCT_OFFSET (NMConnectionProviderInterface, connection_removed),
-	              NULL, NULL,
+	              0, NULL, NULL,
 	              g_cclosure_marshal_VOID__OBJECT,
 	              G_TYPE_NONE, 1, G_TYPE_OBJECT);
 }
diff --git a/src/nm-connection-provider.h b/src/nm-connection-provider.h
index 2485c56f..b31af05f 100644
--- a/src/nm-connection-provider.h
+++ b/src/nm-connection-provider.h
@@ -63,14 +63,6 @@ typedef struct {
 
 	NMConnection * (*get_connection_by_uuid) (NMConnectionProvider *self,
 	                                          const char *uuid);
-
-	/* Signals */
-	void (*connection_added)   (NMConnectionProvider *self, NMConnection *connection);
-
-	void (*connection_updated) (NMConnectionProvider *self, NMConnection *connection);
-
-	void (*connection_removed) (NMConnectionProvider *self, NMConnection *connection);
-
 } NMConnectionProviderInterface;
 
 GType nm_connection_provider_get_type (void);
diff --git a/src/nm-core-utils.c b/src/nm-core-utils.c
index ef44a139..e9365c0c 100644
--- a/src/nm-core-utils.c
+++ b/src/nm-core-utils.c
@@ -1145,6 +1145,40 @@ nm_utils_find_helper(const char *progname, const char *try_first, GError **error
 
 /******************************************************************************************/
 
+/**
+ * nm_utils_read_link_absolute:
+ * @link_file: file name of the symbolic link
+ * @error: error reason in case of failure
+ *
+ * Uses to g_file_read_link()/readlink() to read the symlink
+ * and returns the result as absolute path.
+ **/
+char *
+nm_utils_read_link_absolute (const char *link_file, GError **error)
+{
+	char *ln, *dirname, *ln_abs;
+
+	ln = g_file_read_link (link_file, error);
+	if (!ln)
+		return NULL;
+	if (g_path_is_absolute (ln))
+		return ln;
+
+	dirname = g_path_get_dirname (link_file);
+	if (!g_path_is_absolute (link_file)) {
+		gs_free char *dirname_rel = dirname;
+		gs_free char *current_dir = g_get_current_dir ();
+
+		dirname = g_build_filename (current_dir, dirname_rel, NULL);
+	}
+	ln_abs = g_build_filename (dirname, ln, NULL);
+	g_free (dirname);
+	g_free (ln);
+	return ln_abs;
+}
+
+/******************************************************************************************/
+
 #define MAC_TAG "mac:"
 #define INTERFACE_NAME_TAG "interface-name:"
 #define DEVICE_TYPE_TAG "type:"
@@ -2612,7 +2646,7 @@ nm_utils_machine_id_read (void)
 	if (contents[i] != '\0')
 		return FALSE;
 
-	return nm_unauto (&contents);
+	return g_steal_pointer (&contents);
 }
 
 /*****************************************************************************/
@@ -3085,3 +3119,145 @@ nm_utils_lifetime_get (guint32 timestamp,
 	return TRUE;
 }
 
+const char *
+nm_utils_dnsmasq_status_to_string (int status, char *dest, guint size)
+{
+	static char buffer[128];
+	char *msg, *ret;
+	gs_free char *msg_free = NULL;
+	int len;
+
+	if (status == 0)
+		msg = "Success";
+	else if (status == 1)
+		msg = "Configuration problem";
+	else if (status == 2)
+		msg = "Network access problem (address in use, permissions)";
+	else if (status == 3)
+		msg = "Filesystem problem (missing file/directory, permissions)";
+	else if (status == 4)
+		msg = "Memory allocation failure";
+	else if (status == 5)
+		msg = "Other problem";
+	else if (status >= 11)
+		msg = msg_free = g_strdup_printf ("Lease script failed with error %d", status - 10);
+	else
+		msg = "Unknown problem";
+
+	if (dest) {
+		ret = dest;
+		len = size;
+	} else {
+		ret = buffer;
+		len = sizeof (buffer);
+	}
+
+	g_snprintf (ret, len, "%s (%d)", msg, status);
+
+	return ret;
+}
+
+/**
+ * nm_utils_get_reverse_dns_domains_ip4:
+ * @addr: IP address in network order
+ * @plen: prefix length
+ * @domains: array for results
+ *
+ * Creates reverse DNS domains for the given address and prefix length, and
+ * append them to @domains.
+ */
+void
+nm_utils_get_reverse_dns_domains_ip4 (guint32 addr, guint8 plen, GPtrArray *domains)
+{
+	guint32 ip, ip2, mask;
+	guchar *p;
+	guint octets;
+	guint i;
+	gsize len0, len;
+	char *str, *s;
+
+	g_return_if_fail (domains);
+	g_return_if_fail (plen <= 32);
+
+	if (!plen)
+		return;
+
+	octets = (plen - 1) / 8 + 1;
+	ip = ntohl (addr);
+	mask = 0xFFFFFFFF << (32 - plen);
+	ip &= mask;
+	ip2 = ip;
+
+	len0 = NM_STRLEN ("in-addr.arpa") + (4 * octets) + 1;
+	while ((ip2 & mask) == ip) {
+		addr = htonl (ip2);
+		p = (guchar *) &addr;
+
+		len = len0;
+		str = s = g_malloc (len);
+		for (i = octets; i > 0; i--)
+			nm_utils_strbuf_append (&s, &len, "%u.", p[i - 1] & 0xff);
+		nm_utils_strbuf_append_str (&s, &len, "in-addr.arpa");
+
+		g_ptr_array_add (domains, str);
+
+		ip2 += 1 << ((32 - plen) & ~7);
+	}
+}
+
+/**
+ * nm_utils_get_reverse_dns_domains_ip6:
+ * @addr: IPv6 address
+ * @plen: prefix length
+ * @domains: array for results
+ *
+ * Creates reverse DNS domains for the given address and prefix length, and
+ * append them to @domains.
+ */
+void
+nm_utils_get_reverse_dns_domains_ip6 (const struct in6_addr *ip, guint8 plen, GPtrArray *domains)
+{
+	struct in6_addr addr;
+	guint nibbles, bits, entries;
+	int i, j;
+	gsize len0, len;
+	char *str, *s;
+
+	g_return_if_fail (domains);
+	g_return_if_fail (plen <= 128);
+
+	if (!plen)
+		return;
+
+	memcpy (&addr, ip, sizeof (struct in6_addr));
+	nm_utils_ip6_address_clear_host_address (&addr, &addr, plen);
+
+	/* Number of nibbles to include in domains */
+	nibbles = (plen - 1) / 4 + 1;
+	/* Prefix length in nibble */
+	bits = plen - ((plen - 1) / 4 * 4);
+	/* Number of domains */
+	entries = 1 << (4 - bits);
+
+	len0 = NM_STRLEN ("ip6.arpa") + (2 * nibbles) + 1;
+
+#define N_SHIFT(x) ((x) % 2 ? 0 : 4)
+
+	for (i = 0; i < entries; i++) {
+		len = len0;
+		str = s = g_malloc (len);
+
+		for (j = nibbles - 1; j >= 0; j--)
+			nm_utils_strbuf_append (&s,
+			                        &len,
+			                        "%x.",
+			                        (addr.s6_addr[j / 2] >> N_SHIFT (j)) & 0xf);
+		nm_utils_strbuf_append_str (&s, &len, "ip6.arpa");
+
+		g_ptr_array_add (domains, str);
+
+		addr.s6_addr[(nibbles - 1) / 2] += 1 << N_SHIFT (nibbles - 1);
+	}
+
+#undef N_SHIFT
+}
diff --git a/src/nm-core-utils.h b/src/nm-core-utils.h
index ad0f995f..a1213d2a 100644
--- a/src/nm-core-utils.h
+++ b/src/nm-core-utils.h
@@ -134,6 +134,8 @@ const char *nm_utils_find_helper (const char *progname,
                                   const char *try_first,
                                   GError **error);
 
+char *nm_utils_read_link_absolute (const char *link_file, GError **error);
+
 typedef enum {
 	NM_MATCH_SPEC_NO_MATCH  = 0,
 	NM_MATCH_SPEC_MATCH     = 1,
@@ -394,4 +396,9 @@ gboolean nm_utils_lifetime_get (guint32 timestamp,
 
 gboolean nm_utils_ip4_address_is_link_local (in_addr_t addr);
 
+const char *nm_utils_dnsmasq_status_to_string (int status, char *dest, guint size);
+
+void nm_utils_get_reverse_dns_domains_ip4 (guint32 ip, guint8 plen, GPtrArray *domains);
+void nm_utils_get_reverse_dns_domains_ip6 (const struct in6_addr *ip, guint8 plen, GPtrArray *domains);
+
 #endif /* __NM_CORE_UTILS_H__ */
diff --git a/src/nm-default-route-manager.c b/src/nm-default-route-manager.c
index 3ee634a7..6f72ee84 100644
--- a/src/nm-default-route-manager.c
+++ b/src/nm-default-route-manager.c
@@ -727,16 +727,8 @@ _ipx_update_default_route (const VTableIP *vtable, NMDefaultRouteManager *self,
 
 	if (device)
 		ip_ifindex = nm_device_get_ip_ifindex (device);
-	else {
-		ip_ifindex = nm_vpn_connection_get_ip_ifindex (vpn);
-
-		if (ip_ifindex <= 0) {
-			NMDevice *parent = nm_active_connection_get_device (NM_ACTIVE_CONNECTION (vpn));
-
-			if (parent)
-				ip_ifindex = nm_device_get_ip_ifindex (parent);
-		}
-	}
+	else
+		ip_ifindex = nm_vpn_connection_get_ip_ifindex (vpn, TRUE);
 
 	entries = vtable->get_entries (priv);
 	entry = _entry_find_by_source (entries, source, &entry_idx);
@@ -818,7 +810,7 @@ _ipx_update_default_route (const VTableIP *vtable, NMDefaultRouteManager *self,
 					}
 				}
 			}
-			if (nm_vpn_connection_get_ip_ifindex (vpn) > 0)
+			if (nm_vpn_connection_get_ip_ifindex (vpn, FALSE) > 0)
 				synced = TRUE;
 			else {
 				/* a VPN connection without tunnel device cannot have a non-synced, missing default route.
@@ -1149,7 +1141,7 @@ _ipx_get_best_config (const VTableIP *vtable,
 			if (out_ac)
 				*out_ac = NM_ACTIVE_CONNECTION (vpn);
 			if (out_ip_iface)
-				*out_ip_iface = nm_vpn_connection_get_ip_iface (vpn);
+				*out_ip_iface = nm_vpn_connection_get_ip_iface (vpn, TRUE);
 		} else {
 			NMDevice *device = entry->source.device;
 			NMActRequest *req;
diff --git a/src/nm-enum-types.c b/src/nm-enum-types.c
index b3c82c63..b2f91dca 100644
--- a/src/nm-enum-types.c
+++ b/src/nm-enum-types.c
@@ -35,7 +35,6 @@
 #include "nm-dns-unbound.h" 
 #include "nm-dns-manager.h" 
 #include "nm-dns-plugin.h" 
-#include "nm-dns-utils.h" 
 #include "nm-dnsmasq-manager.h" 
 #include "nm-dnsmasq-utils.h" 
 #include "nmp-netns.h" 
@@ -188,26 +187,6 @@ nm_dns_ip_config_type_get_type (void)
   return g_define_type_id__volatile;
 }
 GType
-nm_dns_manager_resolv_conf_mode_get_type (void)
-{
-  static volatile gsize g_define_type_id__volatile = 0;
-
-  if (g_once_init_enter (&g_define_type_id__volatile))
-    {
-      static const GEnumValue values[] = {
-        { NM_DNS_MANAGER_RESOLV_CONF_UNMANAGED, "NM_DNS_MANAGER_RESOLV_CONF_UNMANAGED", "unmanaged" },
-        { NM_DNS_MANAGER_RESOLV_CONF_EXPLICIT, "NM_DNS_MANAGER_RESOLV_CONF_EXPLICIT", "explicit" },
-        { NM_DNS_MANAGER_RESOLV_CONF_PROXY, "NM_DNS_MANAGER_RESOLV_CONF_PROXY", "proxy" },
-        { 0, NULL, NULL }
-      };
-      GType g_define_type_id =
-        g_enum_register_static (g_intern_static_string ("NMDnsManagerResolvConfMode"), values);
-      g_once_init_leave (&g_define_type_id__volatile, g_define_type_id);
-    }
-
-  return g_define_type_id__volatile;
-}
-GType
 nm_dns_manager_resolv_conf_manager_get_type (void)
 {
   static volatile gsize g_define_type_id__volatile = 0;
@@ -215,11 +194,13 @@ nm_dns_manager_resolv_conf_manager_get_type (void)
   if (g_once_init_enter (&g_define_type_id__volatile))
     {
       static const GEnumValue values[] = {
-        { _NM_DNS_MANAGER_RESOLV_CONF_MAN_INTERNAL_ONLY, "_NM_DNS_MANAGER_RESOLV_CONF_MAN_INTERNAL_ONLY", "-nm-dns-manager-resolv-conf-man-internal-only" },
-        { NM_DNS_MANAGER_RESOLV_CONF_MAN_NONE, "NM_DNS_MANAGER_RESOLV_CONF_MAN_NONE", "nm-dns-manager-resolv-conf-man-none" },
-        { NM_DNS_MANAGER_RESOLV_CONF_MAN_FILE, "NM_DNS_MANAGER_RESOLV_CONF_MAN_FILE", "nm-dns-manager-resolv-conf-man-file" },
-        { NM_DNS_MANAGER_RESOLV_CONF_MAN_RESOLVCONF, "NM_DNS_MANAGER_RESOLV_CONF_MAN_RESOLVCONF", "nm-dns-manager-resolv-conf-man-resolvconf" },
-        { NM_DNS_MANAGER_RESOLV_CONF_MAN_NETCONFIG, "NM_DNS_MANAGER_RESOLV_CONF_MAN_NETCONFIG", "nm-dns-manager-resolv-conf-man-netconfig" },
+        { NM_DNS_MANAGER_RESOLV_CONF_MAN_UNKNOWN, "NM_DNS_MANAGER_RESOLV_CONF_MAN_UNKNOWN", "unknown" },
+        { NM_DNS_MANAGER_RESOLV_CONF_MAN_UNMANAGED, "NM_DNS_MANAGER_RESOLV_CONF_MAN_UNMANAGED", "unmanaged" },
+        { NM_DNS_MANAGER_RESOLV_CONF_MAN_IMMUTABLE, "NM_DNS_MANAGER_RESOLV_CONF_MAN_IMMUTABLE", "immutable" },
+        { NM_DNS_MANAGER_RESOLV_CONF_MAN_SYMLINK, "NM_DNS_MANAGER_RESOLV_CONF_MAN_SYMLINK", "symlink" },
+        { NM_DNS_MANAGER_RESOLV_CONF_MAN_FILE, "NM_DNS_MANAGER_RESOLV_CONF_MAN_FILE", "file" },
+        { NM_DNS_MANAGER_RESOLV_CONF_MAN_RESOLVCONF, "NM_DNS_MANAGER_RESOLV_CONF_MAN_RESOLVCONF", "resolvconf" },
+        { NM_DNS_MANAGER_RESOLV_CONF_MAN_NETCONFIG, "NM_DNS_MANAGER_RESOLV_CONF_MAN_NETCONFIG", "netconfig" },
         { 0, NULL, NULL }
       };
       GType g_define_type_id =
@@ -523,21 +504,25 @@ nm_config_change_flags_get_type (void)
   if (g_once_init_enter (&g_define_type_id__volatile))
     {
       static const GFlagsValue values[] = {
-        { NM_CONFIG_CHANGE_NONE, "NM_CONFIG_CHANGE_NONE", "nm-config-change-none" },
-        { NM_CONFIG_CHANGE_SIGHUP, "NM_CONFIG_CHANGE_SIGHUP", "nm-config-change-sighup" },
-        { NM_CONFIG_CHANGE_SIGUSR1, "NM_CONFIG_CHANGE_SIGUSR1", "nm-config-change-sigusr1" },
-        { NM_CONFIG_CHANGE_SIGUSR2, "NM_CONFIG_CHANGE_SIGUSR2", "nm-config-change-sigusr2" },
-        { NM_CONFIG_CHANGE_CONFIG_FILES, "NM_CONFIG_CHANGE_CONFIG_FILES", "nm-config-change-config-files" },
-        { NM_CONFIG_CHANGE_VALUES, "NM_CONFIG_CHANGE_VALUES", "nm-config-change-values" },
-        { NM_CONFIG_CHANGE_VALUES_USER, "NM_CONFIG_CHANGE_VALUES_USER", "nm-config-change-values-user" },
-        { NM_CONFIG_CHANGE_VALUES_INTERN, "NM_CONFIG_CHANGE_VALUES_INTERN", "nm-config-change-values-intern" },
-        { NM_CONFIG_CHANGE_CONNECTIVITY, "NM_CONFIG_CHANGE_CONNECTIVITY", "nm-config-change-connectivity" },
-        { NM_CONFIG_CHANGE_NO_AUTO_DEFAULT, "NM_CONFIG_CHANGE_NO_AUTO_DEFAULT", "nm-config-change-no-auto-default" },
-        { NM_CONFIG_CHANGE_DNS_MODE, "NM_CONFIG_CHANGE_DNS_MODE", "nm-config-change-dns-mode" },
-        { NM_CONFIG_CHANGE_RC_MANAGER, "NM_CONFIG_CHANGE_RC_MANAGER", "nm-config-change-rc-manager" },
-        { NM_CONFIG_CHANGE_GLOBAL_DNS_CONFIG, "NM_CONFIG_CHANGE_GLOBAL_DNS_CONFIG", "nm-config-change-global-dns-config" },
-        { _NM_CONFIG_CHANGE_LAST, "_NM_CONFIG_CHANGE_LAST", "-nm-config-change-last" },
-        { NM_CONFIG_CHANGE_ALL, "NM_CONFIG_CHANGE_ALL", "nm-config-change-all" },
+        { NM_CONFIG_CHANGE_NONE, "NM_CONFIG_CHANGE_NONE", "none" },
+        { NM_CONFIG_CHANGE_CAUSE_SIGHUP, "NM_CONFIG_CHANGE_CAUSE_SIGHUP", "cause-sighup" },
+        { NM_CONFIG_CHANGE_CAUSE_SIGUSR1, "NM_CONFIG_CHANGE_CAUSE_SIGUSR1", "cause-sigusr1" },
+        { NM_CONFIG_CHANGE_CAUSE_SIGUSR2, "NM_CONFIG_CHANGE_CAUSE_SIGUSR2", "cause-sigusr2" },
+        { NM_CONFIG_CHANGE_CAUSE_NO_AUTO_DEFAULT, "NM_CONFIG_CHANGE_CAUSE_NO_AUTO_DEFAULT", "cause-no-auto-default" },
+        { NM_CONFIG_CHANGE_CAUSE_SET_VALUES, "NM_CONFIG_CHANGE_CAUSE_SET_VALUES", "cause-set-values" },
+        { NM_CONFIG_CHANGE_CAUSE_CONF, "NM_CONFIG_CHANGE_CAUSE_CONF", "cause-conf" },
+        { NM_CONFIG_CHANGE_CAUSE_DNS_RC, "NM_CONFIG_CHANGE_CAUSE_DNS_RC", "cause-dns-rc" },
+        { NM_CONFIG_CHANGE_CAUSE_DNS_FULL, "NM_CONFIG_CHANGE_CAUSE_DNS_FULL", "cause-dns-full" },
+        { NM_CONFIG_CHANGE_CAUSES, "NM_CONFIG_CHANGE_CAUSES", "causes" },
+        { NM_CONFIG_CHANGE_CONFIG_FILES, "NM_CONFIG_CHANGE_CONFIG_FILES", "config-files" },
+        { NM_CONFIG_CHANGE_VALUES, "NM_CONFIG_CHANGE_VALUES", "values" },
+        { NM_CONFIG_CHANGE_VALUES_USER, "NM_CONFIG_CHANGE_VALUES_USER", "values-user" },
+        { NM_CONFIG_CHANGE_VALUES_INTERN, "NM_CONFIG_CHANGE_VALUES_INTERN", "values-intern" },
+        { NM_CONFIG_CHANGE_CONNECTIVITY, "NM_CONFIG_CHANGE_CONNECTIVITY", "connectivity" },
+        { NM_CONFIG_CHANGE_NO_AUTO_DEFAULT, "NM_CONFIG_CHANGE_NO_AUTO_DEFAULT", "no-auto-default" },
+        { NM_CONFIG_CHANGE_DNS_MODE, "NM_CONFIG_CHANGE_DNS_MODE", "dns-mode" },
+        { NM_CONFIG_CHANGE_RC_MANAGER, "NM_CONFIG_CHANGE_RC_MANAGER", "rc-manager" },
+        { NM_CONFIG_CHANGE_GLOBAL_DNS_CONFIG, "NM_CONFIG_CHANGE_GLOBAL_DNS_CONFIG", "global-dns-config" },
         { 0, NULL, NULL }
       };
       GType g_define_type_id =
diff --git a/src/nm-enum-types.h b/src/nm-enum-types.h
index 8fe52e19..36a9c270 100644
--- a/src/nm-enum-types.h
+++ b/src/nm-enum-types.h
@@ -18,8 +18,6 @@ GType nm_dhcp_state_get_type (void) G_GNUC_CONST;
 #define NM_TYPE_DHCP_STATE (nm_dhcp_state_get_type ())
 GType nm_dns_ip_config_type_get_type (void) G_GNUC_CONST;
 #define NM_TYPE_DNS_IP_CONFIG_TYPE (nm_dns_ip_config_type_get_type ())
-GType nm_dns_manager_resolv_conf_mode_get_type (void) G_GNUC_CONST;
-#define NM_TYPE_DNS_MANAGER_RESOLV_CONF_MODE (nm_dns_manager_resolv_conf_mode_get_type ())
 GType nm_dns_manager_resolv_conf_manager_get_type (void) G_GNUC_CONST;
 #define NM_TYPE_DNS_MANAGER_RESOLV_CONF_MANAGER (nm_dns_manager_resolv_conf_manager_get_type ())
 GType nm_dns_masq_status_get_type (void) G_GNUC_CONST;
diff --git a/src/nm-ip4-config.c b/src/nm-ip4-config.c
index 75caf7e3..0ae7d0d4 100644
--- a/src/nm-ip4-config.c
+++ b/src/nm-ip4-config.c
@@ -58,6 +58,7 @@ typedef struct _NMIP4ConfigPrivate {
 	int ifindex;
 	gint64 route_metric;
 	gboolean metered;
+	gint dns_priority;
 } NMIP4ConfigPrivate;
 
 /* internal guint32 are assigned to gobject properties of type uint. Ensure, that uint is large enough */
@@ -76,6 +77,7 @@ NM_GOBJECT_PROPERTIES_DEFINE (NMIP4Config,
 	PROP_SEARCHES,
 	PROP_DNS_OPTIONS,
 	PROP_WINS_SERVERS,
+	PROP_DNS_PRIORITY,
 );
 
 NMIP4Config *
@@ -427,7 +429,7 @@ nm_ip4_config_merge_setting (NMIP4Config *config, NMSettingIPConfig *setting, gu
 {
 	NMIP4ConfigPrivate *priv;
 	guint naddresses, nroutes, nnameservers, nsearches;
-	int i;
+	int i, priority;
 
 	if (!setting)
 		return;
@@ -526,6 +528,10 @@ nm_ip4_config_merge_setting (NMIP4Config *config, NMSettingIPConfig *setting, gu
 		i++;
 	}
 
+	priority = nm_setting_ip_config_get_dns_priority (setting);
+	if (priority)
+		nm_ip4_config_set_dns_priority (config, priority);
+
 	g_object_thaw_notify (G_OBJECT (config));
 }
 
@@ -635,6 +641,11 @@ nm_ip4_config_create_setting (const NMIP4Config *config)
 		nm_setting_ip_config_add_dns_option (s_ip4, option);
 	}
 
+	g_object_set (s_ip4,
+	              NM_SETTING_IP_CONFIG_DNS_PRIORITY,
+	              nm_ip4_config_get_dns_priority (config),
+	              NULL);
+
 	return NM_SETTING (s_ip4);
 }
 
@@ -725,6 +736,10 @@ nm_ip4_config_merge (NMIP4Config *dst, const NMIP4Config *src, NMIPConfigMergeFl
 	nm_ip4_config_set_metered (dst, nm_ip4_config_get_metered (dst) ||
 	                                nm_ip4_config_get_metered (src));
 
+	/* DNS priority */
+	if (nm_ip4_config_get_dns_priority (src))
+		nm_ip4_config_set_dns_priority (dst, nm_ip4_config_get_dns_priority (src));
+
 	g_object_thaw_notify (G_OBJECT (dst));
 }
 
@@ -948,6 +963,10 @@ nm_ip4_config_subtract (NMIP4Config *dst, const NMIP4Config *src)
 			nm_ip4_config_del_wins (dst, idx);
 	}
 
+	/* DNS priority */
+	if (nm_ip4_config_get_dns_priority (src) == nm_ip4_config_get_dns_priority (dst))
+		nm_ip4_config_set_dns_priority (dst, 0);
+
 	g_object_thaw_notify (G_OBJECT (dst));
 }
 
@@ -1188,6 +1207,12 @@ nm_ip4_config_replace (NMIP4Config *dst, const NMIP4Config *src, gboolean *relev
 		has_relevant_changes = TRUE;
 	}
 
+	/* DNS priority */
+	if (src_priv->dns_priority != dst_priv->dns_priority) {
+		nm_ip4_config_set_dns_priority (dst, src_priv->dns_priority);
+		has_minor_changes = TRUE;
+	}
+
 	/* mss */
 	if (src_priv->mss != dst_priv->mss) {
 		nm_ip4_config_set_mss (dst, src_priv->mss);
@@ -1311,6 +1336,7 @@ nm_ip4_config_dump (const NMIP4Config *config, const char *detail)
 	for (i = 0; i < nm_ip4_config_get_num_dns_options (config); i++)
 		g_message (" dnsopt: %s", nm_ip4_config_get_dns_option (config, i));
 
+	g_message (" dnspri: %d", nm_ip4_config_get_dns_priority (config));
 
 	g_message ("    mss: %"G_GUINT32_FORMAT, nm_ip4_config_get_mss (config));
 	g_message ("    mtu: %"G_GUINT32_FORMAT, nm_ip4_config_get_mtu (config));
@@ -1901,6 +1927,27 @@ nm_ip4_config_get_dns_option (const NMIP4Config *config, guint i)
 /******************************************************************/
 
 void
+nm_ip4_config_set_dns_priority (NMIP4Config *config, gint priority)
+{
+	NMIP4ConfigPrivate *priv = NM_IP4_CONFIG_GET_PRIVATE (config);
+
+	if (priority != priv->dns_priority) {
+		priv->dns_priority = priority;
+		_notify (config, PROP_DNS_PRIORITY);
+	}
+}
+
+gint
+nm_ip4_config_get_dns_priority (const NMIP4Config *config)
+{
+	const NMIP4ConfigPrivate *priv = NM_IP4_CONFIG_GET_PRIVATE (config);
+
+	return priv->dns_priority;
+}
+
+/******************************************************************/
+
+void
 nm_ip4_config_set_mss (NMIP4Config *config, guint32 mss)
 {
 	NMIP4ConfigPrivate *priv = NM_IP4_CONFIG_GET_PRIVATE (config);
@@ -2151,7 +2198,6 @@ nm_ip4_config_hash (const NMIP4Config *config, GChecksum *sum, gboolean dns_only
 		s = nm_ip4_config_get_dns_option (config, i);
 		g_checksum_update (sum, (const guint8 *) s, strlen (s));
 	}
-
 }
 
 /**
@@ -2386,6 +2432,9 @@ get_property (GObject *object, guint prop_id,
 	case PROP_DNS_OPTIONS:
 		nm_utils_g_value_set_strv (value, priv->dns_options);
 		break;
+	case PROP_DNS_PRIORITY:
+		g_value_set_int (value, priv->dns_priority);
+		break;
 	case PROP_WINS_SERVERS:
 		g_value_take_variant (value,
 		                      g_variant_new_fixed_array (G_VARIANT_TYPE_UINT32,
@@ -2488,7 +2537,11 @@ nm_ip4_config_class_init (NMIP4ConfigClass *config_class)
 		                     G_TYPE_STRV,
 		                     G_PARAM_READABLE |
 		                     G_PARAM_STATIC_STRINGS);
-
+	obj_properties[PROP_DNS_PRIORITY] =
+		 g_param_spec_int (NM_IP4_CONFIG_DNS_PRIORITY, "", "",
+		                   G_MININT32, G_MAXINT32, 0,
+		                   G_PARAM_READABLE |
+		                   G_PARAM_STATIC_STRINGS);
 	obj_properties[PROP_WINS_SERVERS] =
 		g_param_spec_variant (NM_IP4_CONFIG_WINS_SERVERS, "", "",
 		                      G_VARIANT_TYPE ("au"),
diff --git a/src/nm-ip4-config.h b/src/nm-ip4-config.h
index b1a57687..e88fb141 100644
--- a/src/nm-ip4-config.h
+++ b/src/nm-ip4-config.h
@@ -55,6 +55,7 @@ typedef struct {
 #define NM_IP4_CONFIG_DOMAINS "domains"
 #define NM_IP4_CONFIG_SEARCHES "searches"
 #define NM_IP4_CONFIG_DNS_OPTIONS "dns-options"
+#define NM_IP4_CONFIG_DNS_PRIORITY "dns-priority"
 #define NM_IP4_CONFIG_WINS_SERVERS "wins-servers"
 
 /* deprecated */
@@ -137,6 +138,10 @@ void nm_ip4_config_del_dns_option (NMIP4Config *config, guint i);
 guint32 nm_ip4_config_get_num_dns_options (const NMIP4Config *config);
 const char * nm_ip4_config_get_dns_option (const NMIP4Config *config, guint i);
 
+/* DNS priority */
+void nm_ip4_config_set_dns_priority (NMIP4Config *config, gint priority);
+gint nm_ip4_config_get_dns_priority (const NMIP4Config *config);
+
 /* MSS */
 void nm_ip4_config_set_mss (NMIP4Config *config, guint32 mss);
 guint32 nm_ip4_config_get_mss (const NMIP4Config *config);
diff --git a/src/nm-ip6-config.c b/src/nm-ip6-config.c
index 8e7bd22c..86447357 100644
--- a/src/nm-ip6-config.c
+++ b/src/nm-ip6-config.c
@@ -50,6 +50,7 @@ typedef struct _NMIP6ConfigPrivate {
 	guint32 mss;
 	int ifindex;
 	gint64 route_metric;
+	gint dns_priority;
 } NMIP6ConfigPrivate;
 
 
@@ -64,6 +65,7 @@ NM_GOBJECT_PROPERTIES_DEFINE (NMIP6Config,
 	PROP_DOMAINS,
 	PROP_SEARCHES,
 	PROP_DNS_OPTIONS,
+	PROP_DNS_PRIORITY,
 );
 
 NMIP6Config *
@@ -414,7 +416,7 @@ nm_ip6_config_merge_setting (NMIP6Config *config, NMSettingIPConfig *setting, gu
 	NMIP6ConfigPrivate *priv;
 	guint naddresses, nroutes, nnameservers, nsearches;
 	const char *gateway_str;
-	int i;
+	int i, priority;
 
 	if (!setting)
 		return;
@@ -508,6 +510,10 @@ nm_ip6_config_merge_setting (NMIP6Config *config, NMSettingIPConfig *setting, gu
 		i++;
 	}
 
+	priority = nm_setting_ip_config_get_dns_priority (setting);
+	if (priority)
+		nm_ip6_config_set_dns_priority (config, priority);
+
 	g_object_thaw_notify (G_OBJECT (config));
 }
 
@@ -624,6 +630,10 @@ nm_ip6_config_create_setting (const NMIP6Config *config)
 		nm_setting_ip_config_add_dns_option (s_ip6, option);
 	}
 
+	g_object_set (s_ip6,
+	              NM_SETTING_IP_CONFIG_DNS_PRIORITY,
+	              nm_ip6_config_get_dns_priority (config),
+	              NULL);
 
 	return NM_SETTING (s_ip6);
 }
@@ -690,6 +700,10 @@ nm_ip6_config_merge (NMIP6Config *dst, const NMIP6Config *src, NMIPConfigMergeFl
 	if (nm_ip6_config_get_mss (src))
 		nm_ip6_config_set_mss (dst, nm_ip6_config_get_mss (src));
 
+	/* DNS priority */
+	if (nm_ip6_config_get_dns_priority (src))
+		nm_ip6_config_set_dns_priority (dst, nm_ip6_config_get_dns_priority (src));
+
 	g_object_thaw_notify (G_OBJECT (dst));
 }
 
@@ -883,6 +897,10 @@ nm_ip6_config_subtract (NMIP6Config *dst, const NMIP6Config *src)
 	if (nm_ip6_config_get_mss (src) == nm_ip6_config_get_mss (dst))
 		nm_ip6_config_set_mss (dst, 0);
 
+	/* DNS priority */
+	if (nm_ip6_config_get_dns_priority (src) == nm_ip6_config_get_dns_priority (dst))
+		nm_ip6_config_set_dns_priority (dst, 0);
+
 	g_object_thaw_notify (G_OBJECT (dst));
 }
 
@@ -1129,6 +1147,12 @@ nm_ip6_config_replace (NMIP6Config *dst, const NMIP6Config *src, gboolean *relev
 		has_minor_changes = TRUE;
 	}
 
+	/* DNS priority */
+	if (src_priv->dns_priority != dst_priv->dns_priority) {
+		nm_ip6_config_set_dns_priority (dst, src_priv->dns_priority);
+		has_minor_changes = TRUE;
+	}
+
 #if NM_MORE_ASSERTS
 	/* config_equal does not compare *all* the fields, therefore, we might have has_minor_changes
 	 * regardless of config_equal. But config_equal must correspond to has_relevant_changes. */
@@ -1189,6 +1213,8 @@ nm_ip6_config_dump (const NMIP6Config *config, const char *detail)
 	for (i = 0; i < nm_ip6_config_get_num_dns_options (config); i++)
 		g_message (" dnsopt: %s", nm_ip6_config_get_dns_option (config, i));
 
+	g_message (" dnspri: %d", nm_ip6_config_get_dns_priority (config));
+
 	g_message ("    mss: %"G_GUINT32_FORMAT, nm_ip6_config_get_mss (config));
 	g_message (" n-dflt: %d", nm_ip6_config_get_never_default (config));
 }
@@ -1761,6 +1787,27 @@ nm_ip6_config_get_dns_option (const NMIP6Config *config, guint i)
 /******************************************************************/
 
 void
+nm_ip6_config_set_dns_priority (NMIP6Config *config, gint priority)
+{
+	NMIP6ConfigPrivate *priv = NM_IP6_CONFIG_GET_PRIVATE (config);
+
+	if (priority != priv->dns_priority) {
+		priv->dns_priority = priority;
+		_notify (config, PROP_DNS_PRIORITY);
+	}
+}
+
+gint
+nm_ip6_config_get_dns_priority (const NMIP6Config *config)
+{
+	const NMIP6ConfigPrivate *priv = NM_IP6_CONFIG_GET_PRIVATE (config);
+
+	return priv->dns_priority;
+}
+
+/******************************************************************/
+
+void
 nm_ip6_config_set_mss (NMIP6Config *config, guint32 mss)
 {
 	NMIP6ConfigPrivate *priv = NM_IP6_CONFIG_GET_PRIVATE (config);
@@ -1839,7 +1886,6 @@ nm_ip6_config_hash (const NMIP6Config *config, GChecksum *sum, gboolean dns_only
 		s = nm_ip6_config_get_dns_option (config, i);
 		g_checksum_update (sum, (const guint8 *) s, strlen (s));
 	}
-
 }
 
 /**
@@ -2079,6 +2125,9 @@ get_property (GObject *object, guint prop_id,
 	case PROP_DNS_OPTIONS:
 		nm_utils_g_value_set_strv (value, priv->dns_options);
 		break;
+	case PROP_DNS_PRIORITY:
+		g_value_set_int (value, priv->dns_priority);
+		break;
 	default:
 		G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
 		break;
@@ -2176,6 +2225,11 @@ nm_ip6_config_class_init (NMIP6ConfigClass *config_class)
 		                    G_TYPE_STRV,
 		                    G_PARAM_READABLE |
 		                    G_PARAM_STATIC_STRINGS);
+	obj_properties[PROP_DNS_PRIORITY] =
+		g_param_spec_int (NM_IP6_CONFIG_DNS_PRIORITY, "", "",
+		                  G_MININT32, G_MAXINT32, 0,
+		                  G_PARAM_READABLE |
+		                  G_PARAM_STATIC_STRINGS);
 
 	g_object_class_install_properties (object_class, _PROPERTY_ENUMS_LAST, obj_properties);
 
diff --git a/src/nm-ip6-config.h b/src/nm-ip6-config.h
index 5e66d500..010b1396 100644
--- a/src/nm-ip6-config.h
+++ b/src/nm-ip6-config.h
@@ -57,6 +57,7 @@ typedef struct {
 #define NM_IP6_CONFIG_DOMAINS "domains"
 #define NM_IP6_CONFIG_SEARCHES "searches"
 #define NM_IP6_CONFIG_DNS_OPTIONS "dns-options"
+#define NM_IP6_CONFIG_DNS_PRIORITY "dns-priority"
 
 /* deprecated */
 #define NM_IP6_CONFIG_ADDRESSES "addresses"
@@ -139,6 +140,10 @@ void nm_ip6_config_del_dns_option (NMIP6Config *config, guint i);
 guint32 nm_ip6_config_get_num_dns_options (const NMIP6Config *config);
 const char * nm_ip6_config_get_dns_option (const NMIP6Config *config, guint i);
 
+/* DNS priority */
+void nm_ip6_config_set_dns_priority (NMIP6Config *config, gint priority);
+gint nm_ip6_config_get_dns_priority (const NMIP6Config *config);
+
 /* MSS */
 void nm_ip6_config_set_mss (NMIP6Config *config, guint32 mss);
 guint32 nm_ip6_config_get_mss (const NMIP6Config *config);
diff --git a/src/nm-manager.c b/src/nm-manager.c
index e64c68af..8277f6b0 100644
--- a/src/nm-manager.c
+++ b/src/nm-manager.c
@@ -28,6 +28,7 @@
 #include <unistd.h>
 
 #include "nm-manager.h"
+#include "nm-common-macros.h"
 #include "nm-bus-manager.h"
 #include "nm-vpn-manager.h"
 #include "nm-device.h"
@@ -68,8 +69,6 @@ static NMActiveConnection *_new_active_connection (NMManager *self,
 
 static void policy_activating_device_changed (GObject *object, GParamSpec *pspec, gpointer user_data);
 
-static void rfkill_change (const char *desc, RfKillType rtype, gboolean enabled);
-
 static gboolean find_master (NMManager *self,
                              NMConnection *connection,
                              NMDevice *device,
@@ -80,8 +79,10 @@ static gboolean find_master (NMManager *self,
 
 static void nm_manager_update_state (NMManager *manager);
 
-static void connection_changed (NMSettings *settings, NMConnection *connection,
-                                NMManager *manager);
+static void connection_changed (NMManager *self, NMConnection *connection);
+static void device_sleep_cb (NMDevice *device,
+                             GParamSpec *pspec,
+                             NMManager *self);
 
 #define TAG_ACTIVE_CONNETION_ADD_AND_ACTIVATE "act-con-add-and-activate"
 
@@ -132,6 +133,7 @@ typedef struct {
 	NMSleepMonitor *sleep_monitor;
 
 	GSList *auth_chains;
+	GHashTable *sleep_devices;
 
 	/* Firmware dir monitor */
 	GFileMonitor *fw_monitor;
@@ -457,6 +459,104 @@ _config_changed_cb (NMConfig *config, NMConfigData *config_data, NMConfigChangeF
 		_notify (self, PROP_GLOBAL_DNS_CONFIGURATION);
 }
 
+static void
+_reload_auth_cb (NMAuthChain *chain,
+                 GError *error,
+                 GDBusMethodInvocation *context,
+                 gpointer user_data)
+{
+	NMManager *self = NM_MANAGER (user_data);
+	NMManagerPrivate *priv = NM_MANAGER_GET_PRIVATE (self);
+	GError *ret_error = NULL;
+	NMAuthCallResult result;
+	guint32 flags;
+	NMAuthSubject *subject;
+	char s_buf[60];
+	NMConfigChangeFlags reload_type = NM_CONFIG_CHANGE_NONE;
+
+	g_assert (context);
+
+	priv->auth_chains = g_slist_remove (priv->auth_chains, chain);
+	flags = GPOINTER_TO_UINT (nm_auth_chain_get_data (chain, "flags"));
+
+	subject = nm_auth_chain_get_subject (chain);
+
+	result = nm_auth_chain_get_result (chain, NM_AUTH_PERMISSION_RELOAD);
+	if (error) {
+		_LOGD (LOGD_CORE, "Reload request failed: %s", error->message);
+		ret_error = g_error_new (NM_MANAGER_ERROR,
+		                         NM_MANAGER_ERROR_PERMISSION_DENIED,
+		                         "Reload request failed: %s",
+		                         error->message);
+	} else if (result != NM_AUTH_CALL_RESULT_YES) {
+		ret_error = g_error_new_literal (NM_MANAGER_ERROR,
+		                                 NM_MANAGER_ERROR_PERMISSION_DENIED,
+		                                 "Not authorized to reload configuration");
+	} else {
+		if (NM_FLAGS_ANY (flags, ~NM_MANAGER_RELOAD_FLAGS_ALL)) {
+			/* invalid flags */
+		} else if (flags == 0)
+			reload_type = NM_CONFIG_CHANGE_CAUSE_SIGHUP;
+		else {
+			if (NM_FLAGS_HAS (flags, NM_MANAGER_RELOAD_FLAGS_CONF))
+				reload_type |= NM_CONFIG_CHANGE_CAUSE_CONF;
+			if (NM_FLAGS_HAS (flags, NM_MANAGER_RELOAD_FLAGS_DNS_RC))
+				reload_type |= NM_CONFIG_CHANGE_CAUSE_DNS_RC;
+			if (NM_FLAGS_HAS (flags, NM_MANAGER_RELOAD_FLAGS_DNS_FULL))
+				reload_type |= NM_CONFIG_CHANGE_CAUSE_DNS_FULL;
+		}
+
+		if (reload_type == NM_CONFIG_CHANGE_NONE) {
+			ret_error = g_error_new_literal (NM_MANAGER_ERROR,
+			                                 NM_MANAGER_ERROR_INVALID_ARGUMENTS,
+			                                 "Invalid flags for reload");
+		}
+	}
+
+	nm_audit_log_control_op (NM_AUDIT_OP_RELOAD,
+	                         nm_sprintf_buf (s_buf, "%u", flags),
+	                         ret_error == NULL, subject,
+	                         ret_error ? ret_error->message : NULL);
+
+	if (ret_error) {
+		g_dbus_method_invocation_take_error (context, ret_error);
+		goto out;
+	}
+
+	nm_config_reload (priv->config, reload_type);
+	g_dbus_method_invocation_return_value (context, NULL);
+
+out:
+	nm_auth_chain_unref (chain);
+}
+
+static void
+impl_manager_reload (NMManager *self,
+                     GDBusMethodInvocation *context,
+                     guint32 flags)
+{
+	NMManagerPrivate *priv;
+	NMAuthChain *chain;
+	GError *error = NULL;
+
+	g_return_if_fail (NM_IS_MANAGER (self));
+
+	priv = NM_MANAGER_GET_PRIVATE (self);
+
+	chain = nm_auth_chain_new_context (context, _reload_auth_cb, self);
+	if (!chain) {
+		error = g_error_new_literal (NM_MANAGER_ERROR,
+		                             NM_MANAGER_ERROR_PERMISSION_DENIED,
+		                             "Unable to authenticate request");
+		g_dbus_method_invocation_take_error (context, error);
+		return;
+	}
+
+	priv->auth_chains = g_slist_append (priv->auth_chains, chain);
+	nm_auth_chain_set_data (chain, "flags", GUINT_TO_POINTER (flags), NULL);
+	nm_auth_chain_add_call (chain, NM_AUTH_PERMISSION_RELOAD, TRUE);
+}
+
 /************************************************************************/
 
 static NMDevice *
@@ -839,19 +939,29 @@ remove_device (NMManager *self,
 	       nm_device_get_iface (device), allow_unmanage, nm_device_get_managed (device, FALSE));
 
 	if (allow_unmanage && nm_device_get_managed (device, FALSE)) {
-		NMActRequest *req = nm_device_get_act_request (device);
+		unmanage = TRUE;
 
-		/* Leave activated interfaces up when quitting so their configuration
-		 * can be taken over when NM restarts.  This ensures connectivity while
-		 * NM is stopped. Devices which do not support connection assumption
-		 * cannot be left up.
-		 */
-		if (!quitting)  /* Forced removal; device already gone */
-			unmanage = TRUE;
-		else if (!nm_device_can_assume_active_connection (device))
-			unmanage = TRUE;
-		else if (!req)
-			unmanage = TRUE;
+		if (!quitting) {
+			/* the device is already gone. Unmanage it. */
+		} else {
+			/* Leave certain devices alone when quitting so their configuration
+			 * can be taken over when NM restarts.  This ensures connectivity while
+			 * NM is stopped.
+			 */
+			if (nm_device_uses_assumed_connection (device)) {
+				/* An assume connection must be left alone */
+				unmanage = FALSE;
+			} else if (!nm_device_get_act_request (device)) {
+				/* a device without any active connection is either UNAVAILABLE or DISCONNECTED
+				 * state. Since we don't know whether the device was upped by NetworkManager,
+				 * we must leave it up on exit. */
+				unmanage = FALSE;
+			} else if (!nm_platform_link_can_assume (NM_PLATFORM_GET, nm_device_get_ifindex (device))) {
+				/* The device has no layer 3 configuration. Leave it up. */
+				unmanage = FALSE;
+			} else if (nm_device_can_assume_active_connection (device))
+				unmanage = FALSE;
+		}
 
 		if (unmanage) {
 			if (quitting)
@@ -1162,7 +1272,7 @@ retry_connections_for_parent_device (NMManager *self, NMDevice *device)
 			ifname = nm_manager_get_connection_iface (self, candidate, &parent, &error);
 			if (ifname) {
 				if (!nm_platform_link_get_by_ifname (NM_PLATFORM_GET, ifname))
-					connection_changed (priv->settings, candidate, self);
+					connection_changed (self, candidate);
 			}
 		}
 	}
@@ -1171,34 +1281,40 @@ retry_connections_for_parent_device (NMManager *self, NMDevice *device)
 }
 
 static void
-connection_changed (NMSettings *settings,
-                    NMConnection *connection,
-                    NMManager *manager)
+connection_changed (NMManager *self,
+                    NMConnection *connection)
 {
 	NMDevice *device;
 
 	if (!nm_connection_is_virtual (connection))
 		return;
 
-	device = system_create_virtual_device (manager, connection);
+	device = system_create_virtual_device (self, connection);
 	if (!device)
 		return;
 
 	/* Maybe the device that was created was needed by some other
 	 * connection's device (parent of a VLAN). Let the connections
 	 * can use the newly created device as a parent know. */
-	retry_connections_for_parent_device (manager, device);
+	retry_connections_for_parent_device (self, device);
 }
 
 static void
-connection_removed (NMSettings *settings,
-                    NMSettingsConnection *connection,
-                    NMManager *manager)
+connection_added_cb (NMSettings *settings,
+                     NMConnection *connection,
+                     NMManager *self)
 {
-	/*
-	 * Do not delete existing virtual devices to keep connectivity up.
-	 * Virtual devices are reused when NetworkManager is restarted.
-	 */
+	connection_changed (self, connection);
+}
+
+static void
+connection_updated_cb (NMSettings *settings,
+                       NMConnection *connection,
+                       gboolean by_user,
+                       NMManager *self)
+{
+	if (by_user)
+		connection_changed (self, connection);
 }
 
 static void
@@ -2777,13 +2893,13 @@ active_connection_parent_active (NMActiveConnection *active,
 			/* We can now proceed to disconnected state so that activation proceeds. */
 			unmanaged_to_disconnected (device);
 		} else {
-			nm_log_warn (LOGD_CORE, "Could not realize device '%s': %s",
-			             nm_device_get_iface (device), error->message);
+			_LOGW (LOGD_CORE, "Could not realize device '%s': %s",
+			       nm_device_get_iface (device), error->message);
 			nm_active_connection_set_state (active, NM_ACTIVE_CONNECTION_STATE_DEACTIVATED);
 		}
 	} else {
-		nm_log_warn (LOGD_CORE, "The parent connection device '%s' depended on disappeared.",
-		             nm_device_get_iface (device));
+		_LOGW (LOGD_CORE, "The parent connection device '%s' depended on disappeared.",
+		       nm_device_get_iface (device));
 		nm_active_connection_set_state (active, NM_ACTIVE_CONNECTION_STATE_DEACTIVATED);
 	}
 }
@@ -3268,7 +3384,7 @@ validate_activation_request (NMManager *self,
 		                     NM_MANAGER_ERROR,
 		                     NM_MANAGER_ERROR_CONNECTION_NOT_AVAILABLE,
 		                     "Sharing IPv6 connections is not supported yet.");
-		return NULL;
+		goto error;
 	}
 
 	/* Check whether it's a VPN or not */
@@ -3849,6 +3965,98 @@ device_is_wake_on_lan (NMDevice *device)
 	return nm_platform_link_get_wake_on_lan (NM_PLATFORM_GET, nm_device_get_ip_ifindex (device));
 }
 
+static gboolean
+sleep_devices_add (NMManager *self, NMDevice *device, gboolean suspending)
+{
+	NMManagerPrivate *priv = NM_MANAGER_GET_PRIVATE (self);
+	NMSleepMonitorInhibitorHandle *handle = NULL;
+
+	if (g_hash_table_lookup_extended (priv->sleep_devices, device, NULL, (gpointer *) &handle)) {
+		if (suspending) {
+			/* if we are suspending, always insert a new handle in sleep_devices.
+			 * Even if we had an old handle, it might be stale by now. */
+			g_hash_table_insert (priv->sleep_devices, device,
+			                     nm_sleep_monitor_inhibit_take (priv->sleep_monitor));
+			if (handle)
+				nm_sleep_monitor_inhibit_release (priv->sleep_monitor, handle);
+		}
+		return FALSE;
+	}
+
+	g_hash_table_insert (priv->sleep_devices,
+	                     g_object_ref (device),
+	                     suspending
+	                         ? nm_sleep_monitor_inhibit_take (priv->sleep_monitor)
+	                         : NULL);
+	g_signal_connect (device, "notify::" NM_DEVICE_STATE, (GCallback) device_sleep_cb, self);
+	return TRUE;
+}
+
+static gboolean
+sleep_devices_remove (NMManager *self, NMDevice *device)
+{
+	NMManagerPrivate *priv = NM_MANAGER_GET_PRIVATE (self);
+	NMSleepMonitorInhibitorHandle *handle;
+
+	if (!g_hash_table_lookup_extended (priv->sleep_devices, device, NULL, (gpointer *) &handle))
+		return FALSE;
+
+	if (handle)
+		nm_sleep_monitor_inhibit_release (priv->sleep_monitor, handle);
+
+	/* Remove device from hash */
+	g_signal_handlers_disconnect_by_func (device, device_sleep_cb, self);
+	g_hash_table_remove (priv->sleep_devices, device);
+	g_object_unref (device);
+	return TRUE;
+}
+
+static void
+sleep_devices_clear (NMManager *self)
+{
+	NMManagerPrivate *priv = NM_MANAGER_GET_PRIVATE (self);
+	NMDevice *device;
+	NMSleepMonitorInhibitorHandle *handle;
+	GHashTableIter iter;
+
+	if (!priv->sleep_devices)
+		return;
+
+	g_hash_table_iter_init (&iter, priv->sleep_devices);
+	while (g_hash_table_iter_next (&iter, (gpointer *) &device, (gpointer *) &handle)) {
+		g_signal_handlers_disconnect_by_func (device, device_sleep_cb, self);
+		if (handle)
+			nm_sleep_monitor_inhibit_release (priv->sleep_monitor, handle);
+		g_object_unref (device);
+		g_hash_table_iter_remove (&iter);
+	}
+}
+
+static void
+device_sleep_cb (NMDevice *device,
+                 GParamSpec *pspec,
+                 NMManager *self)
+{
+	switch (nm_device_get_state (device)) {
+	case NM_DEVICE_STATE_DISCONNECTED:
+		_LOGD (LOGD_SUSPEND, "sleep: unmanaging device %s", nm_device_get_ip_iface (device));
+		nm_device_set_unmanaged_by_flags_queue (device,
+		                                        NM_UNMANAGED_SLEEPING,
+		                                        TRUE,
+		                                        NM_DEVICE_STATE_REASON_SLEEPING);
+		break;
+	case NM_DEVICE_STATE_UNMANAGED:
+		_LOGD (LOGD_SUSPEND, "sleep: device %s is ready", nm_device_get_ip_iface (device));
+
+		if (!sleep_devices_remove (self, device))
+			g_return_if_reached ();
+
+		break;
+	default:
+		return;
+	}
+}
+
 static void
 do_sleep_wake (NMManager *self, gboolean sleeping_changed)
 {
@@ -3872,15 +4080,28 @@ do_sleep_wake (NMManager *self, gboolean sleeping_changed)
 			if (nm_device_is_software (device))
 				continue;
 			/* Wake-on-LAN devices will be taken down post-suspend rather than pre- */
-			if (suspending && device_is_wake_on_lan (device))
+			if (suspending && device_is_wake_on_lan (device)) {
+				_LOGD (LOGD_SUSPEND, "sleep: device %s has wake-on-lan, skipping",
+				       nm_device_get_ip_iface (device));
 				continue;
+			}
+
+			if (nm_device_is_activating (device) ||
+			    nm_device_get_state (device) == NM_DEVICE_STATE_ACTIVATED) {
+				_LOGD (LOGD_SUSPEND, "sleep: wait disconnection of device %s",
+				       nm_device_get_ip_iface (device));
 
-			nm_device_set_unmanaged_by_flags (device, NM_UNMANAGED_SLEEPING, TRUE, NM_DEVICE_STATE_REASON_SLEEPING);
+				if (sleep_devices_add (self, device, suspending))
+					nm_device_queue_state (device, NM_DEVICE_STATE_DEACTIVATING, NM_DEVICE_STATE_REASON_SLEEPING);
+			} else {
+				nm_device_set_unmanaged_by_flags (device, NM_UNMANAGED_SLEEPING, TRUE, NM_DEVICE_STATE_REASON_SLEEPING);
+			}
 		}
 	} else {
 		_LOGI (LOGD_SUSPEND, "%s...", waking_from_suspend ? "waking up" : "re-enabling");
 
 		if (waking_from_suspend) {
+			sleep_devices_clear (self);
 			/* Belatedly take down Wake-on-LAN devices; ideally we wouldn't have to do this
 			 * but for now it's the only way to make sure we re-check their connectivity.
 			 */
@@ -3941,7 +4162,11 @@ do_sleep_wake (NMManager *self, gboolean sleeping_changed)
 static void
 _internal_sleep (NMManager *self, gboolean do_sleep)
 {
-	NMManagerPrivate *priv = NM_MANAGER_GET_PRIVATE (self);
+	NMManagerPrivate *priv;
+
+	g_return_if_fail (NM_IS_MANAGER (self));
+
+	priv = NM_MANAGER_GET_PRIVATE (self);
 
 	if (priv->sleeping == do_sleep)
 		return;
@@ -4054,17 +4279,12 @@ impl_manager_sleep (NMManager *self,
 }
 
 static void
-sleeping_cb (NMSleepMonitor *monitor, gpointer user_data)
+sleeping_cb (NMSleepMonitor *monitor, gboolean is_about_to_suspend, gpointer user_data)
 {
-	nm_log_dbg (LOGD_SUSPEND, "Received sleeping signal");
-	_internal_sleep (NM_MANAGER (user_data), TRUE);
-}
+	NMManager *self = user_data;
 
-static void
-resuming_cb (NMSleepMonitor *monitor, gpointer user_data)
-{
-	nm_log_dbg (LOGD_SUSPEND, "Received resuming signal");
-	_internal_sleep (NM_MANAGER (user_data), FALSE);
+	_LOGD (LOGD_SUSPEND, "Received %s signal", is_about_to_suspend ? "sleeping" : "resuming");
+	_internal_sleep (self, is_about_to_suspend);
 }
 
 static void
@@ -4186,7 +4406,7 @@ done:
 /* Permissions */
 
 static void
-get_perm_add_result (NMAuthChain *chain, GVariantBuilder *results, const char *permission)
+get_perm_add_result (NMManager *self, NMAuthChain *chain, GVariantBuilder *results, const char *permission)
 {
 	NMAuthCallResult result;
 
@@ -4198,7 +4418,7 @@ get_perm_add_result (NMAuthChain *chain, GVariantBuilder *results, const char *p
 	else if (result == NM_AUTH_CALL_RESULT_AUTH)
 		g_variant_builder_add (results, "{ss}", permission, "auth");
 	else {
-		nm_log_dbg (LOGD_CORE, "unknown auth chain result %d", result);
+		_LOGD (LOGD_CORE, "unknown auth chain result %d", result);
 	}
 }
 
@@ -4226,17 +4446,18 @@ get_permissions_done_cb (NMAuthChain *chain,
 	} else {
 		g_variant_builder_init (&results, G_VARIANT_TYPE ("a{ss}"));
 
-		get_perm_add_result (chain, &results, NM_AUTH_PERMISSION_ENABLE_DISABLE_NETWORK);
-		get_perm_add_result (chain, &results, NM_AUTH_PERMISSION_SLEEP_WAKE);
-		get_perm_add_result (chain, &results, NM_AUTH_PERMISSION_ENABLE_DISABLE_WIFI);
-		get_perm_add_result (chain, &results, NM_AUTH_PERMISSION_ENABLE_DISABLE_WWAN);
-		get_perm_add_result (chain, &results, NM_AUTH_PERMISSION_ENABLE_DISABLE_WIMAX);
-		get_perm_add_result (chain, &results, NM_AUTH_PERMISSION_NETWORK_CONTROL);
-		get_perm_add_result (chain, &results, NM_AUTH_PERMISSION_WIFI_SHARE_PROTECTED);
-		get_perm_add_result (chain, &results, NM_AUTH_PERMISSION_WIFI_SHARE_OPEN);
-		get_perm_add_result (chain, &results, NM_AUTH_PERMISSION_SETTINGS_MODIFY_SYSTEM);
-		get_perm_add_result (chain, &results, NM_AUTH_PERMISSION_SETTINGS_MODIFY_OWN);
-		get_perm_add_result (chain, &results, NM_AUTH_PERMISSION_SETTINGS_MODIFY_HOSTNAME);
+		get_perm_add_result (self, chain, &results, NM_AUTH_PERMISSION_ENABLE_DISABLE_NETWORK);
+		get_perm_add_result (self, chain, &results, NM_AUTH_PERMISSION_SLEEP_WAKE);
+		get_perm_add_result (self, chain, &results, NM_AUTH_PERMISSION_ENABLE_DISABLE_WIFI);
+		get_perm_add_result (self, chain, &results, NM_AUTH_PERMISSION_ENABLE_DISABLE_WWAN);
+		get_perm_add_result (self, chain, &results, NM_AUTH_PERMISSION_ENABLE_DISABLE_WIMAX);
+		get_perm_add_result (self, chain, &results, NM_AUTH_PERMISSION_NETWORK_CONTROL);
+		get_perm_add_result (self, chain, &results, NM_AUTH_PERMISSION_WIFI_SHARE_PROTECTED);
+		get_perm_add_result (self, chain, &results, NM_AUTH_PERMISSION_WIFI_SHARE_OPEN);
+		get_perm_add_result (self, chain, &results, NM_AUTH_PERMISSION_SETTINGS_MODIFY_SYSTEM);
+		get_perm_add_result (self, chain, &results, NM_AUTH_PERMISSION_SETTINGS_MODIFY_OWN);
+		get_perm_add_result (self, chain, &results, NM_AUTH_PERMISSION_SETTINGS_MODIFY_HOSTNAME);
+		get_perm_add_result (self, chain, &results, NM_AUTH_PERMISSION_RELOAD);
 
 		g_dbus_method_invocation_return_value (context,
 		                                       g_variant_new ("(a{ss})", &results));
@@ -4274,6 +4495,7 @@ impl_manager_get_permissions (NMManager *self,
 	nm_auth_chain_add_call (chain, NM_AUTH_PERMISSION_SETTINGS_MODIFY_SYSTEM, FALSE);
 	nm_auth_chain_add_call (chain, NM_AUTH_PERMISSION_SETTINGS_MODIFY_OWN, FALSE);
 	nm_auth_chain_add_call (chain, NM_AUTH_PERMISSION_SETTINGS_MODIFY_HOSTNAME, FALSE);
+	nm_auth_chain_add_call (chain, NM_AUTH_PERMISSION_RELOAD, FALSE);
 }
 
 static void
@@ -4473,7 +4695,7 @@ nm_manager_start (NMManager *self, GError **error)
 	_LOGD (LOGD_CORE, "creating virtual devices...");
 	connections = nm_settings_get_connections (priv->settings);
 	for (iter = connections; iter; iter = iter->next)
-		connection_changed (priv->settings, NM_CONNECTION (iter->data), self);
+		connection_changed (self, NM_CONNECTION (iter->data));
 	g_slist_free (connections);
 
 	priv->devices_inited = TRUE;
@@ -4965,7 +5187,7 @@ struct rfkill_event {
 } __attribute__((packed));
 
 static void
-rfkill_change (const char *desc, RfKillType rtype, gboolean enabled)
+rfkill_change (NMManager *self, const char *desc, RfKillType rtype, gboolean enabled)
 {
 	int fd;
 	struct rfkill_event event;
@@ -4977,13 +5199,13 @@ rfkill_change (const char *desc, RfKillType rtype, gboolean enabled)
 	fd = open ("/dev/rfkill", O_RDWR);
 	if (fd < 0) {
 		if (errno == EACCES)
-			nm_log_warn (LOGD_RFKILL, "(%s): failed to open killswitch device", desc);
+			_LOGW (LOGD_RFKILL, "(%s): failed to open killswitch device", desc);
 		return;
 	}
 
 	if (fcntl (fd, F_SETFL, O_NONBLOCK) < 0) {
-		nm_log_warn (LOGD_RFKILL, "(%s): failed to set killswitch device for "
-		             "non-blocking operation", desc);
+		_LOGW (LOGD_RFKILL, "(%s): failed to set killswitch device for "
+		       "non-blocking operation", desc);
 		close (fd);
 		return;
 	}
@@ -5004,14 +5226,14 @@ rfkill_change (const char *desc, RfKillType rtype, gboolean enabled)
 
 	len = write (fd, &event, sizeof (event));
 	if (len < 0) {
-		nm_log_warn (LOGD_RFKILL, "(%s): failed to change WiFi killswitch state: (%d) %s",
-		             desc, errno, g_strerror (errno));
+		_LOGW (LOGD_RFKILL, "(%s): failed to change WiFi killswitch state: (%d) %s",
+		       desc, errno, g_strerror (errno));
 	} else if (len == sizeof (event)) {
-		nm_log_info (LOGD_RFKILL, "%s hardware radio set %s",
-		             desc, enabled ? "enabled" : "disabled");
+		_LOGI (LOGD_RFKILL, "%s hardware radio set %s",
+		       desc, enabled ? "enabled" : "disabled");
 	} else {
 		/* Failed to write full structure */
-		nm_log_warn (LOGD_RFKILL, "(%s): failed to change WiFi killswitch state", desc);
+		_LOGW (LOGD_RFKILL, "(%s): failed to change WiFi killswitch state", desc);
 	}
 
 	close (fd);
@@ -5064,7 +5286,7 @@ manager_radio_user_toggled (NMManager *self,
 	if (new_enabled != old_enabled) {
 		/* Try to change the kernel rfkill state */
 		if (rstate->rtype == RFKILL_TYPE_WLAN || rstate->rtype == RFKILL_TYPE_WWAN)
-			rfkill_change (rstate->desc, rstate->rtype, new_enabled);
+			rfkill_change (self, rstate->desc, rstate->rtype, new_enabled);
 
 		manager_update_radio_enabled (self, rstate, new_enabled);
 	}
@@ -5167,11 +5389,14 @@ constructed (GObject *object)
 	g_signal_connect (priv->settings, "notify::" NM_SETTINGS_HOSTNAME,
 	                  G_CALLBACK (system_hostname_changed_cb), self);
 	g_signal_connect (priv->settings, NM_SETTINGS_SIGNAL_CONNECTION_ADDED,
-	                  G_CALLBACK (connection_changed), self);
-	g_signal_connect (priv->settings, NM_SETTINGS_SIGNAL_CONNECTION_UPDATED_BY_USER,
-	                  G_CALLBACK (connection_changed), self);
-	g_signal_connect (priv->settings, NM_SETTINGS_SIGNAL_CONNECTION_REMOVED,
-	                  G_CALLBACK (connection_removed), self);
+	                  G_CALLBACK (connection_added_cb), self);
+	g_signal_connect (priv->settings, NM_SETTINGS_SIGNAL_CONNECTION_UPDATED,
+	                  G_CALLBACK (connection_updated_cb), self);
+	/*
+	 * Do not delete existing virtual devices to keep connectivity up.
+	 * Virtual devices are reused when NetworkManager is restarted.
+	 * Hence, don't react on NM_SETTINGS_SIGNAL_CONNECTION_REMOVED.
+	 */
 
 	priv->policy = nm_policy_new (self, priv->settings);
 	g_signal_connect (priv->policy, "notify::" NM_POLICY_DEFAULT_IP4_DEVICE,
@@ -5207,8 +5432,8 @@ constructed (GObject *object)
 	 * changes to the WirelessEnabled/WWANEnabled properties which toggle kernel
 	 * rfkill.
 	 */
-	rfkill_change (priv->radio_states[RFKILL_TYPE_WLAN].desc, RFKILL_TYPE_WLAN, priv->radio_states[RFKILL_TYPE_WLAN].user_enabled);
-	rfkill_change (priv->radio_states[RFKILL_TYPE_WWAN].desc, RFKILL_TYPE_WWAN, priv->radio_states[RFKILL_TYPE_WWAN].user_enabled);
+	rfkill_change (self, priv->radio_states[RFKILL_TYPE_WLAN].desc, RFKILL_TYPE_WLAN, priv->radio_states[RFKILL_TYPE_WLAN].user_enabled);
+	rfkill_change (self, priv->radio_states[RFKILL_TYPE_WWAN].desc, RFKILL_TYPE_WWAN, priv->radio_states[RFKILL_TYPE_WWAN].user_enabled);
 }
 
 static void
@@ -5249,11 +5474,9 @@ nm_manager_init (NMManager *self)
 	                  self);
 
 	/* sleep/wake handling */
-	priv->sleep_monitor = g_object_ref (nm_sleep_monitor_get ());
+	priv->sleep_monitor = nm_sleep_monitor_new ();
 	g_signal_connect (priv->sleep_monitor, NM_SLEEP_MONITOR_SLEEPING,
 	                  G_CALLBACK (sleeping_cb), self);
-	g_signal_connect (priv->sleep_monitor, NM_SLEEP_MONITOR_RESUMING,
-	                  G_CALLBACK (resuming_cb), self);
 
 	/* Listen for authorization changes */
 	g_signal_connect (nm_auth_manager_get (),
@@ -5284,6 +5507,7 @@ nm_manager_init (NMManager *self)
 	priv->timestamp_update_id = g_timeout_add_seconds (300, (GSourceFunc) periodic_update_active_connection_timestamps, self);
 
 	priv->metered = NM_METERED_UNKNOWN;
+	priv->sleep_devices = g_hash_table_new (g_direct_hash, g_direct_equal);
 }
 
 static gboolean
@@ -5492,8 +5716,8 @@ dispose (GObject *object)
 		g_signal_handlers_disconnect_by_func (priv->settings, settings_startup_complete_changed, manager);
 		g_signal_handlers_disconnect_by_func (priv->settings, system_unmanaged_devices_changed_cb, manager);
 		g_signal_handlers_disconnect_by_func (priv->settings, system_hostname_changed_cb, manager);
-		g_signal_handlers_disconnect_by_func (priv->settings, connection_changed, manager);
-		g_signal_handlers_disconnect_by_func (priv->settings, connection_removed, manager);
+		g_signal_handlers_disconnect_by_func (priv->settings, connection_added_cb, manager);
+		g_signal_handlers_disconnect_by_func (priv->settings, connection_updated_cb, manager);
 		g_clear_object (&priv->settings);
 	}
 
@@ -5507,9 +5731,11 @@ dispose (GObject *object)
 	}
 	_set_prop_filter (manager, NULL);
 
+	sleep_devices_clear (manager);
+	g_clear_pointer (&priv->sleep_devices, g_hash_table_unref);
+
 	if (priv->sleep_monitor) {
 		g_signal_handlers_disconnect_by_func (priv->sleep_monitor, sleeping_cb, manager);
-		g_signal_handlers_disconnect_by_func (priv->sleep_monitor, resuming_cb, manager);
 		g_clear_object (&priv->sleep_monitor);
 	}
 
@@ -5786,6 +6012,7 @@ nm_manager_class_init (NMManagerClass *manager_class)
 
 	nm_exported_object_class_add_interface (NM_EXPORTED_OBJECT_CLASS (manager_class),
 	                                        NMDBUS_TYPE_MANAGER_SKELETON,
+	                                        "Reload", impl_manager_reload,
 	                                        "GetDevices", impl_manager_get_devices,
 	                                        "GetAllDevices", impl_manager_get_all_devices,
 	                                        "GetDeviceByIpIface", impl_manager_get_device_by_ip_iface,
diff --git a/src/nm-policy.c b/src/nm-policy.c
index 07bcce89..9613ad82 100644
--- a/src/nm-policy.c
+++ b/src/nm-policy.c
@@ -83,6 +83,8 @@ struct _NMPolicyPrivate {
 
 	guint reset_retries_id;  /* idle handler for resetting the retries count */
 
+	guint schedule_activate_all_id; /* idle handler for schedule_activate_all(). */
+
 	char *orig_hostname; /* hostname at NM start time */
 	char *cur_hostname;  /* hostname we want to assign */
 	gboolean hostname_changed;  /* TRUE if NM ever set the hostname */
@@ -913,6 +915,7 @@ block_autoconnect_for_device (NMPolicy *self, NMDevice *device)
 			                                                       NM_DEVICE_STATE_REASON_USER_REQUESTED);
 		}
 	}
+	g_slist_free (connections);
 }
 
 static void
@@ -1015,8 +1018,6 @@ reset_connections_retries (gpointer user_data)
 	return FALSE;
 }
 
-static void schedule_activate_all (NMPolicy *self);
-
 static void
 activate_slave_connections (NMPolicy *self, NMDevice *device)
 {
@@ -1441,7 +1442,7 @@ vpn_connection_activated (NMPolicy *self, NMVpnConnection *vpn)
 
 	nm_dns_manager_begin_updates (priv->dns_manager, __func__);
 
-	ip_iface = nm_vpn_connection_get_ip_iface (vpn);
+	ip_iface = nm_vpn_connection_get_ip_iface (vpn, TRUE);
 
 	/* Add the VPN connection's IP configs from DNS */
 
@@ -1579,14 +1580,30 @@ active_connection_removed (NMManager *manager,
 
 /**************************************************************************/
 
-static void
-schedule_activate_all (NMPolicy *self)
+static gboolean
+schedule_activate_all_cb (gpointer user_data)
 {
+	NMPolicy *self = user_data;
 	NMPolicyPrivate *priv = NM_POLICY_GET_PRIVATE (self);
 	const GSList *iter;
 
+	priv->schedule_activate_all_id = 0;
+
 	for (iter = nm_manager_get_devices (priv->manager); iter; iter = g_slist_next (iter))
-		schedule_activate_check (self, NM_DEVICE (iter->data));
+		schedule_activate_check (self, iter->data);
+
+	return G_SOURCE_REMOVE;
+}
+
+static void
+schedule_activate_all (NMPolicy *self)
+{
+	NMPolicyPrivate *priv = NM_POLICY_GET_PRIVATE (self);
+
+	/* always restart the idle handler. That way, we settle
+	 * all other events before restarting to activate them. */
+	nm_clear_g_source (&priv->schedule_activate_all_id);
+	priv->schedule_activate_all_id = g_idle_add (schedule_activate_all_cb, self);
 }
 
 static void
@@ -1648,39 +1665,34 @@ dns_config_changed (NMDnsManager *dns_manager, gpointer user_data)
 
 static void
 connection_updated (NMSettings *settings,
-                    NMConnection *connection,
+                    NMSettingsConnection *connection,
+                    gboolean by_user,
                     gpointer user_data)
 {
 	NMPolicyPrivate *priv = user_data;
 	NMPolicy *self = priv->self;
-
-	schedule_activate_all (self);
-}
-
-static void
-connection_updated_by_user (NMSettings *settings,
-                            NMSettingsConnection *connection,
-                            gpointer user_data)
-{
-	NMPolicyPrivate *priv = user_data;
 	const GSList *iter;
 	NMDevice *device = NULL;
 
-	/* find device with given connection */
-	for (iter = nm_manager_get_devices (priv->manager); iter; iter = g_slist_next (iter)) {
-		NMDevice *dev = NM_DEVICE (iter->data);
+	if (by_user) {
+		/* find device with given connection */
+		for (iter = nm_manager_get_devices (priv->manager); iter; iter = g_slist_next (iter)) {
+			NMDevice *dev = NM_DEVICE (iter->data);
 
-		if (nm_device_get_settings_connection (dev) == connection) {
-			device = dev;
-			break;
+			if (nm_device_get_settings_connection (dev) == connection) {
+				device = dev;
+				break;
+			}
 		}
-	}
 
-	if (device)
-		nm_device_reapply_settings_immediately (device);
+		if (device)
+			nm_device_reapply_settings_immediately (device);
+
+		/* Reset auto retries back to default since connection was updated */
+		nm_settings_connection_reset_autoconnect_retries (connection);
+	}
 
-	/* Reset auto retries back to default since connection was updated */
-	nm_settings_connection_reset_autoconnect_retries (connection);
+	schedule_activate_all (self);
 }
 
 static void
@@ -1876,7 +1888,6 @@ constructed (GObject *object)
 
 	g_signal_connect (priv->settings, NM_SETTINGS_SIGNAL_CONNECTION_ADDED,              (GCallback) connection_added, priv);
 	g_signal_connect (priv->settings, NM_SETTINGS_SIGNAL_CONNECTION_UPDATED,            (GCallback) connection_updated, priv);
-	g_signal_connect (priv->settings, NM_SETTINGS_SIGNAL_CONNECTION_UPDATED_BY_USER,    (GCallback) connection_updated_by_user, priv);
 	g_signal_connect (priv->settings, NM_SETTINGS_SIGNAL_CONNECTION_REMOVED,            (GCallback) connection_removed, priv);
 	g_signal_connect (priv->settings, NM_SETTINGS_SIGNAL_CONNECTION_VISIBILITY_CHANGED, (GCallback) connection_visibility_changed, priv);
 	g_signal_connect (priv->settings, NM_SETTINGS_SIGNAL_AGENT_REGISTERED,              (GCallback) secret_agent_registered, priv);
@@ -1941,6 +1952,7 @@ dispose (GObject *object)
 	g_assert (connections == NULL);
 
 	nm_clear_g_source (&priv->reset_retries_id);
+	nm_clear_g_source (&priv->schedule_activate_all_id);
 
 	g_clear_pointer (&priv->orig_hostname, g_free);
 	g_clear_pointer (&priv->cur_hostname, g_free);
diff --git a/src/nm-sleep-monitor-systemd.c b/src/nm-sleep-monitor-systemd.c
deleted file mode 100644
index 064a7035..00000000
--- a/src/nm-sleep-monitor-systemd.c
+++ /dev/null
@@ -1,258 +0,0 @@
-/* -*- Mode: C; tab-width: 4; indent-tabs-mode: t; c-basic-offset: 4 -*- */
-/* This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License along
- * with this program; if not, write to the Free Software Foundation, Inc.,
- * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
- *
- * (C) Copyright 2012 Red Hat, Inc.
- * Author: Matthias Clasen <mclasen@redhat.com>
- */
-
-#include "nm-default.h"
-
-#include <errno.h>
-#include <string.h>
-#include <sys/stat.h>
-#include <gio/gunixfdlist.h>
-
-#include "nm-core-internal.h"
-#include "NetworkManagerUtils.h"
-
-#include "nm-sleep-monitor.h"
-
-#if defined (SUSPEND_RESUME_SYSTEMD) == defined (SUSPEND_RESUME_CONSOLEKIT)
-#error either define SUSPEND_RESUME_SYSTEMD or SUSPEND_RESUME_CONSOLEKIT
-#endif
-
-#ifdef SUSPEND_RESUME_SYSTEMD
-
-#define SUSPEND_DBUS_NAME               "org.freedesktop.login1"
-#define SUSPEND_DBUS_PATH               "/org/freedesktop/login1"
-#define SUSPEND_DBUS_INTERFACE          "org.freedesktop.login1.Manager"
-
-#else
-
-/* ConsoleKit2 has added the same suspend/resume DBUS API that Systemd
- * uses. http://consolekit2.github.io/ConsoleKit2/#Manager.Inhibit
- */
-
-#define SUSPEND_DBUS_NAME               "org.freedesktop.ConsoleKit"
-#define SUSPEND_DBUS_PATH               "/org/freedesktop/ConsoleKit/Manager"
-#define SUSPEND_DBUS_INTERFACE          "org.freedesktop.ConsoleKit.Manager"
-
-#endif
-
-struct _NMSleepMonitor {
-	GObject parent_instance;
-
-	GDBusProxy *sd_proxy;
-	gint inhibit_fd;
-};
-
-struct _NMSleepMonitorClass {
-	GObjectClass parent_class;
-
-	void (*sleeping) (NMSleepMonitor *monitor);
-	void (*resuming) (NMSleepMonitor *monitor);
-};
-
-
-enum {
-	SLEEPING,
-	RESUMING,
-	LAST_SIGNAL,
-};
-static guint signals[LAST_SIGNAL] = {0};
-
-G_DEFINE_TYPE (NMSleepMonitor, nm_sleep_monitor, G_TYPE_OBJECT);
-
-/********************************************************************/
-
-static gboolean
-drop_inhibitor (NMSleepMonitor *self)
-{
-	if (self->inhibit_fd >= 0) {
-		nm_log_dbg (LOGD_SUSPEND, "Dropping systemd sleep inhibitor");
-		close (self->inhibit_fd);
-		self->inhibit_fd = -1;
-		return TRUE;
-	}
-	return FALSE;
-}
-
-static void
-inhibit_done (GObject      *source,
-              GAsyncResult *result,
-              gpointer      user_data)
-{
-	GDBusProxy *sd_proxy = G_DBUS_PROXY (source);
-	NMSleepMonitor *self = user_data;
-	GError *error = NULL;
-	GVariant *res;
-	GUnixFDList *fd_list;
-
-	res = g_dbus_proxy_call_with_unix_fd_list_finish (sd_proxy, &fd_list, result, &error);
-	if (!res) {
-		g_dbus_error_strip_remote_error (error);
-		nm_log_warn (LOGD_SUSPEND, "Inhibit failed: %s", error->message);
-		g_error_free (error);
-	} else {
-		if (!fd_list || g_unix_fd_list_get_length (fd_list) != 1)
-			nm_log_warn (LOGD_SUSPEND, "Didn't get a single fd back");
-
-		self->inhibit_fd = g_unix_fd_list_get (fd_list, 0, NULL);
-
-		nm_log_dbg (LOGD_SUSPEND, "Inhibitor fd is %d", self->inhibit_fd);
-		g_object_unref (fd_list);
-		g_variant_unref (res);
-	}
-}
-
-static void
-take_inhibitor (NMSleepMonitor *self)
-{
-	g_assert (self->inhibit_fd == -1);
-
-	nm_log_dbg (LOGD_SUSPEND, "Taking systemd sleep inhibitor");
-	g_dbus_proxy_call_with_unix_fd_list (self->sd_proxy,
-	                                     "Inhibit",
-	                                     g_variant_new ("(ssss)",
-	                                                    "sleep",
-	                                                    "NetworkManager",
-	                                                    _("NetworkManager needs to turn off networks"),
-	                                                    "delay"),
-	                                     0,
-	                                     G_MAXINT,
-	                                     NULL,
-	                                     NULL,
-	                                     inhibit_done,
-	                                     self);
-}
-
-static void
-prepare_for_sleep_cb (GDBusProxy  *proxy,
-                      gboolean     is_about_to_suspend,
-                      gpointer     data)
-{
-	NMSleepMonitor *self = data;
-
-	nm_log_dbg (LOGD_SUSPEND, "Received PrepareForSleep signal: %d", is_about_to_suspend);
-
-	if (is_about_to_suspend) {
-		g_signal_emit (self, signals[SLEEPING], 0);
-		drop_inhibitor (self);
-	} else {
-		take_inhibitor (self);
-		g_signal_emit (self, signals[RESUMING], 0);
-	}
-}
-
-static void
-name_owner_cb (GObject    *object,
-               GParamSpec *pspec,
-               gpointer    user_data)
-{
-	GDBusProxy *proxy = G_DBUS_PROXY (object);
-	NMSleepMonitor *self = NM_SLEEP_MONITOR (user_data);
-	char *owner;
-
-	g_assert (proxy == self->sd_proxy);
-
-	owner = g_dbus_proxy_get_name_owner (proxy);
-	if (owner)
-		take_inhibitor (self);
-	else
-		drop_inhibitor (self);
-	g_free (owner);
-}
-
-static void
-on_proxy_acquired (GObject *object,
-                   GAsyncResult *res,
-                   NMSleepMonitor *self)
-{
-	GError *error = NULL;
-	char *owner;
-
-	self->sd_proxy = g_dbus_proxy_new_for_bus_finish (res, &error);
-	if (!self->sd_proxy) {
-		nm_log_warn (LOGD_SUSPEND, "Failed to acquire logind proxy: %s", error->message);
-		g_clear_error (&error);
-		return;
-	}
-
-	g_signal_connect (self->sd_proxy, "notify::g-name-owner", G_CALLBACK (name_owner_cb), self);
-	_nm_dbus_signal_connect (self->sd_proxy, "PrepareForSleep", G_VARIANT_TYPE ("(b)"),
-	                         G_CALLBACK (prepare_for_sleep_cb), self);
-
-	owner = g_dbus_proxy_get_name_owner (self->sd_proxy);
-	if (owner)
-		take_inhibitor (self);
-	g_free (owner);
-}
-
-static void
-nm_sleep_monitor_init (NMSleepMonitor *self)
-{
-	self->inhibit_fd = -1;
-	g_dbus_proxy_new_for_bus (G_BUS_TYPE_SYSTEM,
-	                          G_DBUS_PROXY_FLAGS_DO_NOT_AUTO_START |
-	                          G_DBUS_PROXY_FLAGS_DO_NOT_LOAD_PROPERTIES,
-	                          NULL,
-	                          SUSPEND_DBUS_NAME, SUSPEND_DBUS_PATH, SUSPEND_DBUS_INTERFACE,
-	                          NULL,
-	                          (GAsyncReadyCallback) on_proxy_acquired, self);
-}
-
-static void
-finalize (GObject *object)
-{
-	NMSleepMonitor *self = NM_SLEEP_MONITOR (object);
-
-	drop_inhibitor (self);
-	if (self->sd_proxy)
-		g_object_unref (self->sd_proxy);
-
-	if (G_OBJECT_CLASS (nm_sleep_monitor_parent_class)->finalize != NULL)
-		G_OBJECT_CLASS (nm_sleep_monitor_parent_class)->finalize (object);
-}
-
-static void
-nm_sleep_monitor_class_init (NMSleepMonitorClass *klass)
-{
-	GObjectClass *gobject_class;
-
-	gobject_class = G_OBJECT_CLASS (klass);
-
-	gobject_class->finalize = finalize;
-
-	signals[SLEEPING] = g_signal_new (NM_SLEEP_MONITOR_SLEEPING,
-	                                  NM_TYPE_SLEEP_MONITOR,
-	                                  G_SIGNAL_RUN_LAST,
-	                                  G_STRUCT_OFFSET (NMSleepMonitorClass, sleeping),
-	                                  NULL,                   /* accumulator      */
-	                                  NULL,                   /* accumulator data */
-	                                  g_cclosure_marshal_VOID__VOID,
-	                                  G_TYPE_NONE, 0);
-	signals[RESUMING] = g_signal_new (NM_SLEEP_MONITOR_RESUMING,
-	                                  NM_TYPE_SLEEP_MONITOR,
-	                                  G_SIGNAL_RUN_LAST,
-	                                  G_STRUCT_OFFSET (NMSleepMonitorClass, resuming),
-	                                  NULL,                   /* accumulator      */
-	                                  NULL,                   /* accumulator data */
-	                                  g_cclosure_marshal_VOID__VOID,
-	                                  G_TYPE_NONE, 0);
-}
-
-NM_DEFINE_SINGLETON_GETTER (NMSleepMonitor, nm_sleep_monitor_get, NM_TYPE_SLEEP_MONITOR);
-
-/* ---------------------------------------------------------------------------------------------------- */
diff --git a/src/nm-sleep-monitor-upower.c b/src/nm-sleep-monitor-upower.c
deleted file mode 100644
index 5f0ff245..00000000
--- a/src/nm-sleep-monitor-upower.c
+++ /dev/null
@@ -1,134 +0,0 @@
-/* -*- Mode: C; tab-width: 4; indent-tabs-mode: t; c-basic-offset: 4 -*- */
-/* This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License along
- * with this program; if not, write to the Free Software Foundation, Inc.,
- * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
- *
- * (C) Copyright 2012 Red Hat, Inc.
- * Author: Matthias Clasen <mclasen@redhat.com>
- */
-
-#include "nm-default.h"
-
-#include <errno.h>
-#include <string.h>
-#include <sys/stat.h>
-
-#include "nm-core-internal.h"
-
-#include "nm-sleep-monitor.h"
-
-#define UPOWER_DBUS_SERVICE "org.freedesktop.UPower"
-
-struct _NMSleepMonitor {
-	GObject parent_instance;
-
-	GDBusProxy *upower_proxy;
-};
-
-struct _NMSleepMonitorClass {
-	GObjectClass parent_class;
-
-	void (*sleeping) (NMSleepMonitor *monitor);
-	void (*resuming) (NMSleepMonitor *monitor);
-};
-
-
-enum {
-	SLEEPING,
-	RESUMING,
-	LAST_SIGNAL,
-};
-static guint signals[LAST_SIGNAL] = {0};
-
-G_DEFINE_TYPE (NMSleepMonitor, nm_sleep_monitor, G_TYPE_OBJECT);
-
-/********************************************************************/
-
-static void
-upower_sleeping_cb (GDBusProxy *proxy, gpointer user_data)
-{
-	nm_log_dbg (LOGD_SUSPEND, "Received UPower sleeping signal");
-	g_signal_emit (user_data, signals[SLEEPING], 0);
-}
-
-static void
-upower_resuming_cb (GDBusProxy *proxy, gpointer user_data)
-{
-	nm_log_dbg (LOGD_SUSPEND, "Received UPower resuming signal");
-	g_signal_emit (user_data, signals[RESUMING], 0);
-}
-
-static void
-nm_sleep_monitor_init (NMSleepMonitor *self)
-{
-	GError *error = NULL;
-
-	self->upower_proxy = g_dbus_proxy_new_for_bus_sync (G_BUS_TYPE_SYSTEM,
-	                                                    G_DBUS_PROXY_FLAGS_DO_NOT_AUTO_START |
-	                                                        G_DBUS_PROXY_FLAGS_DO_NOT_LOAD_PROPERTIES,
-	                                                    NULL,
-	                                                    UPOWER_DBUS_SERVICE,
-	                                                    "/org/freedesktop/UPower",
-	                                                    "org.freedesktop.UPower",
-	                                                    NULL, &error);
-	if (self->upower_proxy) {
-		_nm_dbus_signal_connect (self->upower_proxy, "Sleeping", NULL,
-		                         G_CALLBACK (upower_sleeping_cb), self);
-		_nm_dbus_signal_connect (self->upower_proxy, "Resuming", NULL,
-		                         G_CALLBACK (upower_resuming_cb), self);
-	} else {
-		nm_log_warn (LOGD_SUSPEND, "could not initialize UPower D-Bus proxy: %s", error->message);
-		g_error_free (error);
-	}
-}
-
-static void
-finalize (GObject *object)
-{
-	NMSleepMonitor *self = NM_SLEEP_MONITOR (object);
-
-	g_clear_object (&self->upower_proxy);
-
-	G_OBJECT_CLASS (nm_sleep_monitor_parent_class)->finalize (object);
-}
-
-static void
-nm_sleep_monitor_class_init (NMSleepMonitorClass *klass)
-{
-	GObjectClass *gobject_class;
-
-	gobject_class = G_OBJECT_CLASS (klass);
-
-	gobject_class->finalize = finalize;
-
-	signals[SLEEPING] = g_signal_new (NM_SLEEP_MONITOR_SLEEPING,
-	                                  NM_TYPE_SLEEP_MONITOR,
-	                                  G_SIGNAL_RUN_LAST,
-	                                  G_STRUCT_OFFSET (NMSleepMonitorClass, sleeping),
-	                                  NULL,                   /* accumulator      */
-	                                  NULL,                   /* accumulator data */
-	                                  g_cclosure_marshal_VOID__VOID,
-	                                  G_TYPE_NONE, 0);
-	signals[RESUMING] = g_signal_new (NM_SLEEP_MONITOR_RESUMING,
-	                                  NM_TYPE_SLEEP_MONITOR,
-	                                  G_SIGNAL_RUN_LAST,
-	                                  G_STRUCT_OFFSET (NMSleepMonitorClass, resuming),
-	                                  NULL,                   /* accumulator      */
-	                                  NULL,                   /* accumulator data */
-	                                  g_cclosure_marshal_VOID__VOID,
-	                                  G_TYPE_NONE, 0);
-}
-
-NM_DEFINE_SINGLETON_GETTER (NMSleepMonitor, nm_sleep_monitor_get, NM_TYPE_SLEEP_MONITOR);
-
-/* ---------------------------------------------------------------------------------------------------- */
diff --git a/src/nm-sleep-monitor.c b/src/nm-sleep-monitor.c
new file mode 100644
index 00000000..13ce1be0
--- /dev/null
+++ b/src/nm-sleep-monitor.c
@@ -0,0 +1,396 @@
+/* -*- Mode: C; tab-width: 4; indent-tabs-mode: t; c-basic-offset: 4 -*- */
+/* This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * (C) Copyright 2012-2016 Red Hat, Inc.
+ * Author: Matthias Clasen <mclasen@redhat.com>
+ */
+
+#include "nm-default.h"
+
+#include "nm-sleep-monitor.h"
+
+#include <errno.h>
+#include <string.h>
+#include <sys/stat.h>
+#include <gio/gunixfdlist.h>
+
+#include "nm-core-internal.h"
+#include "NetworkManagerUtils.h"
+
+
+#if defined (SUSPEND_RESUME_UPOWER)
+
+#define SUSPEND_DBUS_NAME               "org.freedesktop.UPower"
+#define SUSPEND_DBUS_PATH               "/org/freedesktop/UPower"
+#define SUSPEND_DBUS_INTERFACE          "org.freedesktop.UPower"
+#define USE_UPOWER                      1
+#define _NMLOG_PREFIX_NAME              "sleep-monitor-up"
+
+#elif defined (SUSPEND_RESUME_SYSTEMD)
+
+#define SUSPEND_DBUS_NAME               "org.freedesktop.login1"
+#define SUSPEND_DBUS_PATH               "/org/freedesktop/login1"
+#define SUSPEND_DBUS_INTERFACE          "org.freedesktop.login1.Manager"
+#define USE_UPOWER                      0
+#define _NMLOG_PREFIX_NAME              "sleep-monitor-sd"
+
+#elif defined(SUSPEND_RESUME_CONSOLEKIT)
+
+/* ConsoleKit2 has added the same suspend/resume DBUS API that Systemd
+ * uses. http://consolekit2.github.io/ConsoleKit2/#Manager.Inhibit
+ */
+
+#define SUSPEND_DBUS_NAME               "org.freedesktop.ConsoleKit"
+#define SUSPEND_DBUS_PATH               "/org/freedesktop/ConsoleKit/Manager"
+#define SUSPEND_DBUS_INTERFACE          "org.freedesktop.ConsoleKit.Manager"
+#define USE_UPOWER                      0
+#define _NMLOG_PREFIX_NAME              "sleep-monitor-ck"
+
+#else
+
+#error define one of SUSPEND_RESUME_SYSTEMD, SUSPEND_RESUME_CONSOLEKIT, or SUSPEND_RESUME_UPOWER
+
+#endif
+
+struct _NMSleepMonitor {
+	GObject parent_instance;
+
+	GDBusProxy *proxy;
+
+	/* used both during construction of proxy and during Inhibit call. */
+	GCancellable *cancellable;
+
+	gint inhibit_fd;
+	GSList *handles_active;
+	GSList *handles_stale;
+
+	gulong sig_id_1;
+	gulong sig_id_2;
+};
+
+struct _NMSleepMonitorClass {
+	GObjectClass parent_class;
+};
+
+enum {
+	SLEEPING,
+	LAST_SIGNAL,
+};
+static guint signals[LAST_SIGNAL] = {0};
+
+G_DEFINE_TYPE (NMSleepMonitor, nm_sleep_monitor, G_TYPE_OBJECT);
+
+static void sleep_signal (NMSleepMonitor *self, gboolean is_about_to_suspend);
+
+/*****************************************************************************/
+
+#define _NMLOG_DOMAIN                     LOGD_SUSPEND
+#define _NMLOG(level, ...) \
+    G_STMT_START { \
+        nm_log ((level), _NMLOG_DOMAIN, \
+                "%s: " _NM_UTILS_MACRO_FIRST (__VA_ARGS__), \
+                _NMLOG_PREFIX_NAME \
+                _NM_UTILS_MACRO_REST (__VA_ARGS__)); \
+    } G_STMT_END
+
+/*****************************************************************************/
+
+#if USE_UPOWER
+
+static void
+upower_sleeping_cb (GDBusProxy *proxy, gpointer user_data)
+{
+	sleep_signal (user_data, TRUE);
+}
+
+static void
+upower_resuming_cb (GDBusProxy *proxy, gpointer user_data)
+{
+	sleep_signal (user_data, FALSE);
+}
+
+#else /* USE_UPOWER */
+
+static void
+drop_inhibitor (NMSleepMonitor *self, gboolean force)
+{
+	if (!force && self->handles_active)
+		return;
+
+	if (self->inhibit_fd >= 0) {
+		_LOGD ("inhibit: dropping sleep inhibitor %d", self->inhibit_fd);
+		close (self->inhibit_fd);
+		self->inhibit_fd = -1;
+	}
+
+	if (self->handles_active) {
+		self->handles_stale = g_slist_concat (self->handles_stale, self->handles_active);
+		self->handles_active = NULL;
+	}
+
+	nm_clear_g_cancellable (&self->cancellable);
+}
+
+static void
+inhibit_done (GObject      *source,
+              GAsyncResult *result,
+              gpointer      user_data)
+{
+	GDBusProxy *proxy = G_DBUS_PROXY (source);
+	NMSleepMonitor *self = user_data;
+	gs_free_error GError *error = NULL;
+	gs_unref_variant GVariant *res = NULL;
+	gs_unref_object GUnixFDList *fd_list = NULL;
+
+	res = g_dbus_proxy_call_with_unix_fd_list_finish (proxy, &fd_list, result, &error);
+	if (!res) {
+		if (!g_error_matches (error, G_IO_ERROR, G_IO_ERROR_CANCELLED)) {
+			g_clear_object (&self->cancellable);
+			_LOGW ("inhibit: failed (%s)", error->message);
+		}
+		return;
+	}
+
+	g_clear_object (&self->cancellable);
+
+	if (!fd_list || g_unix_fd_list_get_length (fd_list) != 1) {
+		_LOGW ("inhibit: didn't get a single fd back");
+		return;
+	}
+
+	self->inhibit_fd = g_unix_fd_list_get (fd_list, 0, NULL);
+	_LOGD ("inhibit: inhibitor fd is %d", self->inhibit_fd);
+}
+
+static void
+take_inhibitor (NMSleepMonitor *self)
+{
+	g_return_if_fail (NM_IS_SLEEP_MONITOR (self));
+	g_return_if_fail (G_IS_DBUS_PROXY (self->proxy));
+
+	drop_inhibitor (self, TRUE);
+
+	_LOGD ("inhibit: taking sleep inhibitor...");
+	self->cancellable = g_cancellable_new ();
+	g_dbus_proxy_call_with_unix_fd_list (self->proxy,
+	                                     "Inhibit",
+	                                     g_variant_new ("(ssss)",
+	                                                    "sleep",
+	                                                    "NetworkManager",
+	                                                    "NetworkManager needs to turn off networks",
+	                                                    "delay"),
+	                                     0,
+	                                     G_MAXINT,
+	                                     NULL,
+	                                     self->cancellable,
+	                                     inhibit_done,
+	                                     self);
+}
+
+static void
+prepare_for_sleep_cb (GDBusProxy  *proxy,
+                      gboolean     is_about_to_suspend,
+                      gpointer     data)
+{
+	sleep_signal (data, is_about_to_suspend);
+}
+
+static void
+name_owner_cb (GObject    *object,
+               GParamSpec *pspec,
+               gpointer    user_data)
+{
+	GDBusProxy *proxy = G_DBUS_PROXY (object);
+	NMSleepMonitor *self = NM_SLEEP_MONITOR (user_data);
+	char *owner;
+
+	g_assert (proxy == self->proxy);
+
+	owner = g_dbus_proxy_get_name_owner (proxy);
+	if (owner)
+		take_inhibitor (self);
+	else
+		drop_inhibitor (self, TRUE);
+	g_free (owner);
+}
+#endif /* USE_UPOWER */
+
+static void
+sleep_signal (NMSleepMonitor *self,
+              gboolean is_about_to_suspend)
+{
+	g_return_if_fail (NM_IS_SLEEP_MONITOR (self));
+
+	_LOGD ("received %s signal", is_about_to_suspend ? "SLEEP" : "RESUME");
+
+#if !USE_UPOWER
+	if (!is_about_to_suspend)
+		take_inhibitor (self);
+#endif
+
+	g_signal_emit (self, signals[SLEEPING], 0, is_about_to_suspend);
+
+#if !USE_UPOWER
+	if (is_about_to_suspend)
+		drop_inhibitor (self, FALSE);
+#endif
+}
+
+/**
+ * nm_sleep_monitor_inhibit_take:
+ * @self: the #NMSleepMonitor instance
+ *
+ * Prevent the release of inhibitor lock
+ *
+ * Returns: an inhibitor handle that must be returned via
+ *   nm_sleep_monitor_inhibit_release().
+ **/
+NMSleepMonitorInhibitorHandle *
+nm_sleep_monitor_inhibit_take (NMSleepMonitor *self)
+{
+	g_return_val_if_fail (NM_IS_SLEEP_MONITOR (self), NULL);
+
+	self->handles_active = g_slist_prepend (self->handles_active, NULL);
+	return (NMSleepMonitorInhibitorHandle *) self->handles_active;
+}
+
+/**
+ * nm_sleep_monitor_inhibit_release:
+ * @self: the #NMSleepMonitor instance
+ * @handle: the #NMSleepMonitorInhibitorHandle inhibitor handle.
+ *
+ * Allow again the release of inhibitor lock
+ **/
+void
+nm_sleep_monitor_inhibit_release (NMSleepMonitor *self,
+                                  NMSleepMonitorInhibitorHandle *handle)
+{
+	GSList *l;
+
+	g_return_if_fail (NM_IS_SLEEP_MONITOR (self));
+	g_return_if_fail (handle);
+
+	l = (GSList *) handle;
+
+	if (g_slist_position (self->handles_active, l) < 0) {
+		if (g_slist_position (self->handles_stale, l) < 0)
+			g_return_if_reached ();
+		self->handles_stale = g_slist_delete_link (self->handles_stale, l);
+		return;
+	}
+
+	self->handles_active = g_slist_delete_link (self->handles_active, l);
+
+#if !USE_UPOWER
+	drop_inhibitor (self, FALSE);
+#endif
+}
+
+static void
+on_proxy_acquired (GObject *object,
+                   GAsyncResult *res,
+                   NMSleepMonitor *self)
+{
+	GError *error = NULL;
+	GDBusProxy *proxy;
+
+	proxy = g_dbus_proxy_new_for_bus_finish (res, &error);
+	if (!proxy) {
+		if (!g_error_matches (error, G_IO_ERROR, G_IO_ERROR_CANCELLED))
+			_LOGW ("failed to acquire D-Bus proxy: %s", error->message);
+		g_clear_error (&error);
+		return;
+	}
+	self->proxy = proxy;
+	g_clear_object (&self->cancellable);
+
+#if USE_UPOWER
+	self->sig_id_1 = _nm_dbus_signal_connect (self->proxy, "Sleeping", NULL,
+	                                          G_CALLBACK (upower_sleeping_cb), self);
+	self->sig_id_2 = _nm_dbus_signal_connect (self->proxy, "Resuming", NULL,
+	                                          G_CALLBACK (upower_resuming_cb), self);
+#else
+	self->sig_id_1 = g_signal_connect (self->proxy, "notify::g-name-owner",
+	                                   G_CALLBACK (name_owner_cb), self);
+	self->sig_id_2 = _nm_dbus_signal_connect (self->proxy, "PrepareForSleep",
+	                                          G_VARIANT_TYPE ("(b)"),
+	                                          G_CALLBACK (prepare_for_sleep_cb), self);
+	{
+		gs_free char *owner = NULL;
+
+		owner = g_dbus_proxy_get_name_owner (self->proxy);
+		if (owner)
+			take_inhibitor (self);
+	}
+#endif
+}
+
+static void
+nm_sleep_monitor_init (NMSleepMonitor *self)
+{
+	self->inhibit_fd = -1;
+	self->cancellable = g_cancellable_new ();
+	g_dbus_proxy_new_for_bus (G_BUS_TYPE_SYSTEM,
+	                          G_DBUS_PROXY_FLAGS_DO_NOT_AUTO_START |
+	                          G_DBUS_PROXY_FLAGS_DO_NOT_LOAD_PROPERTIES,
+	                          NULL,
+	                          SUSPEND_DBUS_NAME, SUSPEND_DBUS_PATH, SUSPEND_DBUS_INTERFACE,
+	                          self->cancellable,
+	                          (GAsyncReadyCallback) on_proxy_acquired, self);
+}
+
+NMSleepMonitor *
+nm_sleep_monitor_new (void)
+{
+	return g_object_new (NM_TYPE_SLEEP_MONITOR, NULL);
+}
+
+static void
+dispose (GObject *object)
+{
+	NMSleepMonitor *self = NM_SLEEP_MONITOR (object);
+
+#if !USE_UPOWER
+	drop_inhibitor (self, TRUE);
+#endif
+
+	nm_clear_g_cancellable (&self->cancellable);
+
+	if (self->proxy) {
+		nm_clear_g_signal_handler (self->proxy, &self->sig_id_1);
+		nm_clear_g_signal_handler (self->proxy, &self->sig_id_2);
+		g_clear_object (&self->proxy);
+	}
+
+	G_OBJECT_CLASS (nm_sleep_monitor_parent_class)->dispose (object);
+}
+
+static void
+nm_sleep_monitor_class_init (NMSleepMonitorClass *klass)
+{
+	GObjectClass *gobject_class;
+
+	gobject_class = G_OBJECT_CLASS (klass);
+
+	gobject_class->dispose = dispose;
+
+	signals[SLEEPING] = g_signal_new (NM_SLEEP_MONITOR_SLEEPING,
+	                                  NM_TYPE_SLEEP_MONITOR,
+	                                  G_SIGNAL_RUN_LAST,
+	                                  0, NULL, NULL,
+	                                  g_cclosure_marshal_VOID__BOOLEAN,
+	                                  G_TYPE_NONE, 1, G_TYPE_BOOLEAN);
+}
+
diff --git a/src/nm-sleep-monitor.h b/src/nm-sleep-monitor.h
index 21e6b844..140f964f 100644
--- a/src/nm-sleep-monitor.h
+++ b/src/nm-sleep-monitor.h
@@ -13,16 +13,13 @@
  * with this program; if not, write to the Free Software Foundation, Inc.,
  * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
  *
- * (C) Copyright 2012 Red Hat, Inc.
+ * (C) Copyright 2012-2016 Red Hat, Inc.
  * Author: Matthias Clasen <mclasen@redhat.com>
  */
 
 #ifndef __NETWORKMANAGER_SLEEP_MONITOR_H__
 #define __NETWORKMANAGER_SLEEP_MONITOR_H__
 
-
-#include "nm-default.h"
-
 G_BEGIN_DECLS
 
 #define NM_TYPE_SLEEP_MONITOR         (nm_sleep_monitor_get_type ())
@@ -33,12 +30,17 @@ G_BEGIN_DECLS
 #define NM_IS_SLEEP_MONITOR_CLASS(k)  (G_TYPE_CHECK_CLASS_TYPE ((k), NM_TYPE_SLEEP_MONITOR))
 
 #define NM_SLEEP_MONITOR_SLEEPING "sleeping"
-#define NM_SLEEP_MONITOR_RESUMING "resuming"
 
 typedef struct _NMSleepMonitorClass    NMSleepMonitorClass;
 
 GType           nm_sleep_monitor_get_type     (void) G_GNUC_CONST;
-NMSleepMonitor *nm_sleep_monitor_get          (void);
+NMSleepMonitor *nm_sleep_monitor_new          (void);
+
+typedef struct _NMSleepMonitorInhibitorHandle NMSleepMonitorInhibitorHandle;
+
+NMSleepMonitorInhibitorHandle *nm_sleep_monitor_inhibit_take    (NMSleepMonitor *self);
+void                           nm_sleep_monitor_inhibit_release (NMSleepMonitor *self,
+                                                                 NMSleepMonitorInhibitorHandle *handle);
 
 G_END_DECLS
 
diff --git a/src/platform/Makefile.in b/src/platform/Makefile.in
index 854c6712..a528da66 100644
--- a/src/platform/Makefile.in
+++ b/src/platform/Makefile.in
@@ -324,6 +324,7 @@ NEWT_LIBS = @NEWT_LIBS@
 NM = @NM@
 NMEDIT = @NMEDIT@
 NM_CONFIG_DEFAULT_AUTH_POLKIT_TEXT = @NM_CONFIG_DEFAULT_AUTH_POLKIT_TEXT@
+NM_CONFIG_DEFAULT_DNS_RC_MANAGER = @NM_CONFIG_DEFAULT_DNS_RC_MANAGER@
 NM_CONFIG_DEFAULT_LOGGING_AUDIT_TEXT = @NM_CONFIG_DEFAULT_LOGGING_AUDIT_TEXT@
 NM_CONFIG_LOGGING_BACKEND_DEFAULT_TEXT = @NM_CONFIG_LOGGING_BACKEND_DEFAULT_TEXT@
 NM_MAJOR_VERSION = @NM_MAJOR_VERSION@
diff --git a/src/platform/nm-linux-platform.c b/src/platform/nm-linux-platform.c
index c5045503..f6f7be80 100644
--- a/src/platform/nm-linux-platform.c
+++ b/src/platform/nm-linux-platform.c
@@ -1439,6 +1439,8 @@ _new_from_nl_link (NMPlatform *platform, const NMPCache *cache, struct nlmsghdr
 	gboolean *completed_from_cache = cache ? &completed_from_cache_val : NULL;
 	const NMPObject *link_cached = NULL;
 	NMPObject *lnk_data = NULL;
+	gboolean address_complete_from_cache = TRUE;
+	gboolean lnk_data_complete_from_cache = TRUE;
 
 	if (!nlmsg_valid_hdr (nlh, sizeof (*ifi)))
 		return NULL;
@@ -1503,6 +1505,7 @@ _new_from_nl_link (NMPlatform *platform, const NMPCache *cache, struct nlmsghdr
 			memcpy (obj->link.addr.data, nla_data (tb[IFLA_ADDRESS]), l);
 			obj->link.addr.len = l;
 		}
+		address_complete_from_cache = FALSE;
 	}
 
 	if (tb[IFLA_AF_SPEC]) {
@@ -1552,28 +1555,34 @@ _new_from_nl_link (NMPlatform *platform, const NMPCache *cache, struct nlmsghdr
 		lnk_data = _parse_lnk_vxlan (nl_info_kind, nl_info_data);
 		break;
 	default:
-		goto lnk_data_handled;
+		lnk_data_complete_from_cache = FALSE;
+		break;
 	}
 
-	/* We always try to look into the cache and reuse the object there.
-	 * We do that, because we consider the lnk object as immutable and don't
-	 * modify it after creating. Hence we can share it and reuse.
-	 *
-	 * Also, sometimes the info-data is missing for updates. In this case
-	 * we want to keep the previously received lnk_data. */
-	if (completed_from_cache) {
+	if (   completed_from_cache
+	    && (   lnk_data_complete_from_cache
+	        || address_complete_from_cache)) {
 		_lookup_cached_link (cache, obj->link.ifindex, completed_from_cache, &link_cached);
-		if (   link_cached
-		    && link_cached->link.type == obj->link.type
-		    && link_cached->_link.netlink.lnk
-		    && (   !lnk_data
-		        || nmp_object_equal (lnk_data, link_cached->_link.netlink.lnk))) {
-			nmp_object_unref (lnk_data);
-			lnk_data = nmp_object_ref (link_cached->_link.netlink.lnk);
+		if (link_cached) {
+			if (   lnk_data_complete_from_cache
+			    && link_cached->link.type == obj->link.type
+			    && link_cached->_link.netlink.lnk
+			    && (   !lnk_data
+			        || nmp_object_equal (lnk_data, link_cached->_link.netlink.lnk))) {
+				/* We always try to look into the cache and reuse the object there.
+				 * We do that, because we consider the lnk object as immutable and don't
+				 * modify it after creating. Hence we can share it and reuse.
+				 *
+				 * Also, sometimes the info-data is missing for updates. In this case
+				 * we want to keep the previously received lnk_data. */
+				nmp_object_unref (lnk_data);
+				lnk_data = nmp_object_ref (link_cached->_link.netlink.lnk);
+			}
+			if (address_complete_from_cache)
+				obj->link.addr = link_cached->link.addr;
 		}
 	}
 
-lnk_data_handled:
 	obj->_link.netlink.lnk = lnk_data;
 
 	obj->_link.netlink.is_in_netlink = TRUE;
@@ -3283,9 +3292,14 @@ cache_pre_hook (NMPCache *cache, const NMPObject *old, const NMPObject *new, NMP
 			if (   ops_type == NMP_CACHE_OPS_UPDATED
 			    && old && new /* <-- nonsensical, make coverity happy */
 			    && old->_link.netlink.is_in_netlink
-			    && NM_FLAGS_HAS (old->link.n_ifi_flags, IFF_LOWER_UP)
 			    && new->_link.netlink.is_in_netlink
-			    && !NM_FLAGS_HAS (new->link.n_ifi_flags, IFF_LOWER_UP)) {
+			    && (   (   NM_FLAGS_HAS (old->link.n_ifi_flags, IFF_UP)
+			            && !NM_FLAGS_HAS (new->link.n_ifi_flags, IFF_UP))
+			        || (   NM_FLAGS_HAS (old->link.n_ifi_flags, IFF_LOWER_UP)
+			            && !NM_FLAGS_HAS (new->link.n_ifi_flags, IFF_LOWER_UP)))) {
+				/* FIXME: I suspect that IFF_LOWER_UP must not be considered, and I
+				 * think kernel does send RTM_DELROUTE events for IPv6 routes, so
+				 * we might not need to refresh IPv6 routes. */
 				delayed_action_schedule (platform,
 				                         DELAYED_ACTION_TYPE_REFRESH_ALL_IP4_ROUTES |
 				                         DELAYED_ACTION_TYPE_REFRESH_ALL_IP6_ROUTES,
@@ -5140,13 +5154,30 @@ static WifiData *
 wifi_get_wifi_data (NMPlatform *platform, int ifindex)
 {
 	NMLinuxPlatformPrivate *priv = NM_LINUX_PLATFORM_GET_PRIVATE (platform);
+	const NMPlatformLink *pllink;
 	WifiData *wifi_data;
 
 	wifi_data = g_hash_table_lookup (priv->wifi_data, GINT_TO_POINTER (ifindex));
-	if (!wifi_data) {
-		const NMPlatformLink *pllink;
+	pllink = nm_platform_link_get (platform, ifindex);
 
-		pllink = nm_platform_link_get (platform, ifindex);
+	/* @wifi_data contains an interface name which is used for WEXT queries. If
+	 * the interface name changes we should at least replace the name in the
+	 * existing structure; but probably a complete reinitialization is better
+	 * because during the initial creation there can be race conditions while
+	 * the interface is renamed by udev.
+	 */
+	if (wifi_data && pllink) {
+		if (!nm_streq (wifi_utils_get_iface (wifi_data), pllink->name)) {
+			_LOGD ("wifi: interface %s renamed to %s, dropping old data for ifindex %d",
+			       wifi_utils_get_iface (wifi_data),
+			       pllink->name,
+			       ifindex);
+			g_hash_table_remove (priv->wifi_data, GINT_TO_POINTER (ifindex));
+			wifi_data = NULL;
+		}
+	}
+
+	if (!wifi_data) {
 		if (pllink) {
 			if (pllink->type == NM_LINK_TYPE_WIFI)
 				wifi_data = wifi_utils_init (pllink->name, ifindex, TRUE);
@@ -5778,6 +5809,13 @@ continue_reading:
 	errno = 0;
 	n = nl_recv (sk, &nla, &buf, &creds);
 
+	if (n <= 0) {
+		/* workaround libnl3 <= 3.2.15 returning danling pointers in case nl_recv()
+		 * fails. Fixed by libnl3 69468517d0de1675d80f24661ff57a5dbac7275c. */
+		buf = NULL;
+		creds = NULL;
+	}
+
 	switch (n) {
 	case 0:
 		/* Work around a libnl bug fixed in 3.2.22 (375a6294) */
diff --git a/src/platform/nm-platform.h b/src/platform/nm-platform.h
index 658b709a..19724f1c 100644
--- a/src/platform/nm-platform.h
+++ b/src/platform/nm-platform.h
@@ -138,7 +138,7 @@ struct _NMPlatformLink {
 	/* rtnl_link_get_arptype(), ifinfomsg.ifi_type. */
 	guint32 arptype;
 
-	/* rtnl_link_get_addr() */
+	/* rtnl_link_get_addr(), IFLA_ADDRESS */
 	struct {
 		guint8 data[20]; /* NM_UTILS_HWADDR_LEN_MAX */
 		guint8 len;
diff --git a/src/platform/tests/Makefile.in b/src/platform/tests/Makefile.in
index 60cd6d82..49f2fa09 100644
--- a/src/platform/tests/Makefile.in
+++ b/src/platform/tests/Makefile.in
@@ -621,6 +621,7 @@ NEWT_LIBS = @NEWT_LIBS@
 NM = @NM@
 NMEDIT = @NMEDIT@
 NM_CONFIG_DEFAULT_AUTH_POLKIT_TEXT = @NM_CONFIG_DEFAULT_AUTH_POLKIT_TEXT@
+NM_CONFIG_DEFAULT_DNS_RC_MANAGER = @NM_CONFIG_DEFAULT_DNS_RC_MANAGER@
 NM_CONFIG_DEFAULT_LOGGING_AUDIT_TEXT = @NM_CONFIG_DEFAULT_LOGGING_AUDIT_TEXT@
 NM_CONFIG_LOGGING_BACKEND_DEFAULT_TEXT = @NM_CONFIG_LOGGING_BACKEND_DEFAULT_TEXT@
 NM_MAJOR_VERSION = @NM_MAJOR_VERSION@
diff --git a/src/platform/wifi/wifi-utils.c b/src/platform/wifi/wifi-utils.c
index 38e5a054..4f04041a 100644
--- a/src/platform/wifi/wifi-utils.c
+++ b/src/platform/wifi/wifi-utils.c
@@ -70,6 +70,22 @@ wifi_utils_init (const char *iface, int ifindex, gboolean check_scan)
 	return ret;
 }
 
+int
+wifi_utils_get_ifindex (WifiData *data)
+{
+	g_return_val_if_fail (data != NULL, -1);
+
+	return data->ifindex;
+}
+
+const char *
+wifi_utils_get_iface (WifiData *data)
+{
+	g_return_val_if_fail (data != NULL, NULL);
+
+	return data->iface;
+}
+
 NMDeviceWifiCapabilities
 wifi_utils_get_caps (WifiData *data)
 {
diff --git a/src/platform/wifi/wifi-utils.h b/src/platform/wifi/wifi-utils.h
index 21dac9e9..9555bbee 100644
--- a/src/platform/wifi/wifi-utils.h
+++ b/src/platform/wifi/wifi-utils.h
@@ -33,6 +33,10 @@ gboolean wifi_utils_is_wifi (const char *iface, const char *sysfs_path);
 
 WifiData *wifi_utils_init (const char *iface, int ifindex, gboolean check_scan);
 
+int wifi_utils_get_ifindex (WifiData *data);
+
+const char *wifi_utils_get_iface (WifiData *data);
+
 void wifi_utils_deinit (WifiData *data);
 
 NMDeviceWifiCapabilities wifi_utils_get_caps (WifiData *data);
diff --git a/src/ppp-manager/Makefile.in b/src/ppp-manager/Makefile.in
index 9a3cff62..c80ae6bc 100644
--- a/src/ppp-manager/Makefile.in
+++ b/src/ppp-manager/Makefile.in
@@ -350,6 +350,7 @@ NEWT_LIBS = @NEWT_LIBS@
 NM = @NM@
 NMEDIT = @NMEDIT@
 NM_CONFIG_DEFAULT_AUTH_POLKIT_TEXT = @NM_CONFIG_DEFAULT_AUTH_POLKIT_TEXT@
+NM_CONFIG_DEFAULT_DNS_RC_MANAGER = @NM_CONFIG_DEFAULT_DNS_RC_MANAGER@
 NM_CONFIG_DEFAULT_LOGGING_AUDIT_TEXT = @NM_CONFIG_DEFAULT_LOGGING_AUDIT_TEXT@
 NM_CONFIG_LOGGING_BACKEND_DEFAULT_TEXT = @NM_CONFIG_LOGGING_BACKEND_DEFAULT_TEXT@
 NM_MAJOR_VERSION = @NM_MAJOR_VERSION@
diff --git a/src/rdisc/Makefile.in b/src/rdisc/Makefile.in
index 0ab39873..ebf72fb7 100644
--- a/src/rdisc/Makefile.in
+++ b/src/rdisc/Makefile.in
@@ -324,6 +324,7 @@ NEWT_LIBS = @NEWT_LIBS@
 NM = @NM@
 NMEDIT = @NMEDIT@
 NM_CONFIG_DEFAULT_AUTH_POLKIT_TEXT = @NM_CONFIG_DEFAULT_AUTH_POLKIT_TEXT@
+NM_CONFIG_DEFAULT_DNS_RC_MANAGER = @NM_CONFIG_DEFAULT_DNS_RC_MANAGER@
 NM_CONFIG_DEFAULT_LOGGING_AUDIT_TEXT = @NM_CONFIG_DEFAULT_LOGGING_AUDIT_TEXT@
 NM_CONFIG_LOGGING_BACKEND_DEFAULT_TEXT = @NM_CONFIG_LOGGING_BACKEND_DEFAULT_TEXT@
 NM_MAJOR_VERSION = @NM_MAJOR_VERSION@
diff --git a/src/rdisc/tests/Makefile.in b/src/rdisc/tests/Makefile.in
index 7d452119..895d7063 100644
--- a/src/rdisc/tests/Makefile.in
+++ b/src/rdisc/tests/Makefile.in
@@ -525,6 +525,7 @@ NEWT_LIBS = @NEWT_LIBS@
 NM = @NM@
 NMEDIT = @NMEDIT@
 NM_CONFIG_DEFAULT_AUTH_POLKIT_TEXT = @NM_CONFIG_DEFAULT_AUTH_POLKIT_TEXT@
+NM_CONFIG_DEFAULT_DNS_RC_MANAGER = @NM_CONFIG_DEFAULT_DNS_RC_MANAGER@
 NM_CONFIG_DEFAULT_LOGGING_AUDIT_TEXT = @NM_CONFIG_DEFAULT_LOGGING_AUDIT_TEXT@
 NM_CONFIG_LOGGING_BACKEND_DEFAULT_TEXT = @NM_CONFIG_LOGGING_BACKEND_DEFAULT_TEXT@
 NM_MAJOR_VERSION = @NM_MAJOR_VERSION@
diff --git a/src/settings/nm-agent-manager.c b/src/settings/nm-agent-manager.c
index 48a7da7b..54ca2f55 100644
--- a/src/settings/nm-agent-manager.c
+++ b/src/settings/nm-agent-manager.c
@@ -20,11 +20,13 @@
 
 #include "nm-default.h"
 
+#include "nm-agent-manager.h"
+
 #include <string.h>
 #include <pwd.h>
 
+#include "nm-common-macros.h"
 #include "nm-dbus-interface.h"
-#include "nm-agent-manager.h"
 #include "nm-secret-agent.h"
 #include "nm-auth-utils.h"
 #include "nm-setting-vpn.h"
diff --git a/src/settings/nm-agent-manager.h b/src/settings/nm-agent-manager.h
index 2f505537..8240a2b5 100644
--- a/src/settings/nm-agent-manager.h
+++ b/src/settings/nm-agent-manager.h
@@ -21,7 +21,7 @@
 #ifndef __NETWORKMANAGER_AGENT_MANAGER_H__
 #define __NETWORKMANAGER_AGENT_MANAGER_H__
 
-#include <nm-connection.h>
+#include "nm-connection.h"
 
 #include "nm-exported-object.h"
 #include "nm-secret-agent.h"
diff --git a/src/settings/nm-secret-agent.c b/src/settings/nm-secret-agent.c
index bfa7b506..8bc88fd4 100644
--- a/src/settings/nm-secret-agent.c
+++ b/src/settings/nm-secret-agent.c
@@ -362,6 +362,9 @@ nm_secret_agent_get_secrets (NMSecretAgent *self,
 	r = request_new (self, "GetSecrets", path, setting_name, callback, callback_data);
 	r->is_get_secrets = TRUE;
 	g_hash_table_add (priv->requests, r);
+
+	/* Increase the timeout only for this call */
+	g_dbus_proxy_set_default_timeout (G_DBUS_PROXY (priv->proxy), 120000);
 	nmdbus_secret_agent_call_get_secrets (priv->proxy,
 	                                      dict,
 	                                      path,
@@ -370,6 +373,7 @@ nm_secret_agent_get_secrets (NMSecretAgent *self,
 	                                      flags,
 	                                      r->cancellable,
 	                                      get_callback, r);
+	g_dbus_proxy_set_default_timeout (G_DBUS_PROXY (priv->proxy), -1);
 
 	return r;
 }
diff --git a/src/settings/nm-settings-connection.c b/src/settings/nm-settings-connection.c
index 6bed3fe5..5b3a3999 100644
--- a/src/settings/nm-settings-connection.c
+++ b/src/settings/nm-settings-connection.c
@@ -21,10 +21,12 @@
 
 #include "nm-default.h"
 
+#include "nm-settings-connection.h"
+
 #include <string.h>
 
+#include "nm-common-macros.h"
 #include "nm-dbus-interface.h"
-#include "nm-settings-connection.h"
 #include "nm-session-monitor.h"
 #include "nm-auth-utils.h"
 #include "nm-auth-subject.h"
@@ -70,19 +72,18 @@ G_DEFINE_TYPE_WITH_CODE (NMSettingsConnection, nm_settings_connection, NM_TYPE_E
                                                NM_TYPE_SETTINGS_CONNECTION, \
                                                NMSettingsConnectionPrivate))
 
-enum {
-	PROP_0 = 0,
+NM_GOBJECT_PROPERTIES_DEFINE (NMSettingsConnection,
 	PROP_VISIBLE,
 	PROP_UNSAVED,
 	PROP_READY,
 	PROP_FLAGS,
 	PROP_FILENAME,
-};
+);
 
 enum {
 	UPDATED,
 	REMOVED,
-	UPDATED_BY_USER,
+	UPDATED_INTERNAL,
 	LAST_SIGNAL
 };
 static guint signals[LAST_SIGNAL] = { 0 };
@@ -97,8 +98,6 @@ typedef struct {
 	NMSettingsConnectionFlags flags;
 	gboolean ready;
 
-	guint updated_idle_id;
-
 	GSList *pending_auths; /* List of pending authentication requests */
 	gboolean visible; /* Is this connection is visible by some session? */
 
@@ -133,6 +132,15 @@ typedef struct {
 
 /*******************************************************************/
 
+static void
+_emit_updated (NMSettingsConnection *self, gboolean by_user)
+{
+	g_signal_emit (self, signals[UPDATED], 0);
+	g_signal_emit (self, signals[UPDATED_INTERNAL], 0, by_user);
+}
+
+/*******************************************************************/
+
 gboolean
 nm_settings_connection_has_unmodified_applied_connection (NMSettingsConnection *self,
                                                           NMConnection *applied_connection,
@@ -292,7 +300,7 @@ set_visible (NMSettingsConnection *self, gboolean new_visible)
 	if (new_visible == priv->visible)
 		return;
 	priv->visible = new_visible;
-	g_object_notify (G_OBJECT (self), NM_SETTINGS_CONNECTION_VISIBLE);
+	_notify (self, PROP_VISIBLE);
 }
 
 gboolean
@@ -465,14 +473,6 @@ secrets_cleared_cb (NMSettingsConnection *self)
 	priv->agent_secrets = NULL;
 }
 
-static gboolean
-emit_updated (NMSettingsConnection *self)
-{
-	NM_SETTINGS_CONNECTION_GET_PRIVATE (self)->updated_idle_id = 0;
-	g_signal_emit (self, signals[UPDATED], 0);
-	return FALSE;
-}
-
 static void
 set_unsaved (NMSettingsConnection *self, gboolean now_unsaved)
 {
@@ -491,16 +491,10 @@ set_unsaved (NMSettingsConnection *self, gboolean now_unsaved)
 }
 
 static void
-changed_cb (NMSettingsConnection *self, gpointer user_data)
+connection_changed_cb (NMSettingsConnection *self, gpointer unused)
 {
-	gboolean update_unsaved = !!user_data;
-
-	NMSettingsConnectionPrivate *priv = NM_SETTINGS_CONNECTION_GET_PRIVATE (self);
-
-	if (update_unsaved)
-		set_unsaved (self, TRUE);
-	if (priv->updated_idle_id == 0)
-		priv->updated_idle_id = g_idle_add ((GSourceFunc) emit_updated, self);
+	set_unsaved (self, TRUE);
+	_emit_updated (self, FALSE);
 }
 
 /* Update the settings of this connection to match that of 'new_connection',
@@ -543,7 +537,7 @@ nm_settings_connection_replace_settings (NMSettingsConnection *self,
 	/* Disconnect the changed signal to ensure we don't set Unsaved when
 	 * it's not required.
 	 */
-	g_signal_handlers_block_by_func (self, G_CALLBACK (changed_cb), GUINT_TO_POINTER (TRUE));
+	g_signal_handlers_block_by_func (self, G_CALLBACK (connection_changed_cb), NULL);
 
 	if (log_diff_name)
 		nm_utils_log_connection_diff (new_connection, NM_CONNECTION (self), LOGL_DEBUG, LOGD_CORE, log_diff_name, "++ ");
@@ -580,11 +574,12 @@ nm_settings_connection_replace_settings (NMSettingsConnection *self,
 	/* Manually emit changed signal since we disconnected the handler, but
 	 * only update Unsaved if the caller wanted us to.
 	 */
-	changed_cb (self, GUINT_TO_POINTER (update_unsaved));
+	if (update_unsaved)
+		set_unsaved (self, TRUE);
 
-	g_signal_emit (self, signals[UPDATED_BY_USER], 0);
+	g_signal_handlers_unblock_by_func (self, G_CALLBACK (connection_changed_cb), NULL);
 
-	g_signal_handlers_unblock_by_func (self, G_CALLBACK (changed_cb), GUINT_TO_POINTER (TRUE));
+	_emit_updated (self, TRUE);
 
 	return success;
 }
@@ -2099,9 +2094,9 @@ nm_settings_connection_set_flags_all (NMSettingsConnection *self, NMSettingsConn
 	old_flags = priv->flags;
 	if (old_flags != flags) {
 		priv->flags = flags;
-		g_object_notify (G_OBJECT (self), NM_SETTINGS_CONNECTION_FLAGS);
+		_notify (self, PROP_FLAGS);
 		if (NM_FLAGS_HAS (old_flags, NM_SETTINGS_CONNECTION_FLAGS_UNSAVED) != NM_FLAGS_HAS (flags, NM_SETTINGS_CONNECTION_FLAGS_UNSAVED))
-			g_object_notify (G_OBJECT (self), NM_SETTINGS_CONNECTION_UNSAVED);
+			_notify (self, PROP_UNSAVED);
 	}
 	return old_flags;
 }
@@ -2506,7 +2501,7 @@ nm_settings_connection_set_ready (NMSettingsConnection *self,
 	ready = !!ready;
 	if (priv->ready != ready) {
 		priv->ready = ready;
-		g_object_notify (G_OBJECT (self), NM_SETTINGS_CONNECTION_READY);
+		_notify (self, PROP_READY);
 	}
 }
 
@@ -2527,7 +2522,7 @@ nm_settings_connection_set_filename (NMSettingsConnection *self,
 	if (g_strcmp0 (filename, priv->filename) != 0) {
 		g_free (priv->filename);
 		priv->filename = g_strdup (filename);
-		g_object_notify (G_OBJECT (self), NM_SETTINGS_CONNECTION_FILENAME);
+		_notify (self, PROP_FILENAME);
 	}
 }
 
@@ -2582,7 +2577,7 @@ nm_settings_connection_init (NMSettingsConnection *self)
 	priv->autoconnect_blocked_reason = NM_DEVICE_STATE_REASON_NONE;
 
 	g_signal_connect (self, NM_CONNECTION_SECRETS_CLEARED, G_CALLBACK (secrets_cleared_cb), NULL);
-	g_signal_connect (self, NM_CONNECTION_CHANGED, G_CALLBACK (changed_cb), GUINT_TO_POINTER (TRUE));
+	g_signal_connect (self, NM_CONNECTION_CHANGED, G_CALLBACK (connection_changed_cb), NULL);
 }
 
 static void
@@ -2613,14 +2608,12 @@ dispose (GObject *object)
 		}
 	}
 
-	nm_clear_g_source (&priv->updated_idle_id);
-
 	/* Disconnect handlers.
-	 * changed_cb() has to be disconnected *before* nm_connection_clear_secrets(),
+	 * connection_changed_cb() has to be disconnected *before* nm_connection_clear_secrets(),
 	 * because nm_connection_clear_secrets() emits NM_CONNECTION_CHANGED signal.
 	 */
 	g_signal_handlers_disconnect_by_func (self, G_CALLBACK (secrets_cleared_cb), NULL);
-	g_signal_handlers_disconnect_by_func (self, G_CALLBACK (changed_cb), GUINT_TO_POINTER (TRUE));
+	g_signal_handlers_disconnect_by_func (self, G_CALLBACK (connection_changed_cb), NULL);
 
 	nm_connection_clear_secrets (NM_CONNECTION (self));
 	g_clear_object (&priv->system_secrets);
@@ -2719,72 +2712,68 @@ nm_settings_connection_class_init (NMSettingsConnectionClass *class)
 	class->supports_secrets = supports_secrets;
 
 	/* Properties */
-	g_object_class_install_property
-		(object_class, PROP_VISIBLE,
-		 g_param_spec_boolean (NM_SETTINGS_CONNECTION_VISIBLE, "", "",
-		                       FALSE,
-		                       G_PARAM_READABLE |
-		                       G_PARAM_STATIC_STRINGS));
-
-	g_object_class_install_property
-		(object_class, PROP_UNSAVED,
-		 g_param_spec_boolean (NM_SETTINGS_CONNECTION_UNSAVED, "", "",
-		                       FALSE,
-		                       G_PARAM_READABLE |
-		                       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,
+	obj_properties[PROP_VISIBLE] =
+	     g_param_spec_boolean (NM_SETTINGS_CONNECTION_VISIBLE, "", "",
+	                           FALSE,
+	                           G_PARAM_READABLE |
+	                           G_PARAM_STATIC_STRINGS);
+
+	obj_properties[PROP_UNSAVED] =
+	     g_param_spec_boolean (NM_SETTINGS_CONNECTION_UNSAVED, "", "",
+	                           FALSE,
+	                           G_PARAM_READABLE |
+	                           G_PARAM_STATIC_STRINGS);
+
+	obj_properties[PROP_READY] =
+	     g_param_spec_boolean (NM_SETTINGS_CONNECTION_READY, "", "",
+	                           TRUE,
+	                           G_PARAM_READWRITE |
+	                           G_PARAM_STATIC_STRINGS);
+
+	obj_properties[PROP_FLAGS] =
 	     g_param_spec_uint (NM_SETTINGS_CONNECTION_FLAGS, "", "",
 	                        NM_SETTINGS_CONNECTION_FLAGS_NONE,
 	                        NM_SETTINGS_CONNECTION_FLAGS_ALL,
 	                        NM_SETTINGS_CONNECTION_FLAGS_NONE,
 	                        G_PARAM_READWRITE |
-	                        G_PARAM_STATIC_STRINGS));
+	                        G_PARAM_STATIC_STRINGS);
+
+	obj_properties[PROP_FILENAME] =
+	     g_param_spec_string (NM_SETTINGS_CONNECTION_FILENAME, "", "",
+	                          NULL,
+	                          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));
+	g_object_class_install_properties (object_class, _PROPERTY_ENUMS_LAST, obj_properties);
 
 	/* Signals */
 
-	/* Emitted when the connection is changed for any reason */
 	signals[UPDATED] =
-		g_signal_new (NM_SETTINGS_CONNECTION_UPDATED,
-		              G_TYPE_FROM_CLASS (class),
-		              G_SIGNAL_RUN_FIRST,
-		              0,
-		              NULL, NULL,
-		              g_cclosure_marshal_VOID__VOID,
-		              G_TYPE_NONE, 0);
-
-	/* Emitted when connection is changed from D-Bus */
-	signals[UPDATED_BY_USER] =
-		g_signal_new (NM_SETTINGS_CONNECTION_UPDATED_BY_USER,
-		              G_TYPE_FROM_CLASS (class),
-		              G_SIGNAL_RUN_FIRST,
-		              0, NULL, NULL,
-		              g_cclosure_marshal_VOID__VOID,
-		              G_TYPE_NONE, 0);
-
-	signals[REMOVED] = 
-		g_signal_new (NM_SETTINGS_CONNECTION_REMOVED,
-		              G_TYPE_FROM_CLASS (class),
-		              G_SIGNAL_RUN_FIRST,
-		              0,
-		              NULL, NULL,
-		              g_cclosure_marshal_VOID__VOID,
-		              G_TYPE_NONE, 0);
+	    g_signal_new (NM_SETTINGS_CONNECTION_UPDATED,
+	                  G_TYPE_FROM_CLASS (class),
+	                  G_SIGNAL_RUN_FIRST,
+	                  0,
+	                  NULL, NULL,
+	                  g_cclosure_marshal_VOID__VOID,
+	                  G_TYPE_NONE, 0);
+
+	/* internal signal, with an argument (gboolean by_user). */
+	signals[UPDATED_INTERNAL] =
+	    g_signal_new (NM_SETTINGS_CONNECTION_UPDATED_INTERNAL,
+	                  G_TYPE_FROM_CLASS (class),
+	                  G_SIGNAL_RUN_FIRST,
+	                  0, NULL, NULL,
+	                  g_cclosure_marshal_VOID__BOOLEAN,
+	                  G_TYPE_NONE, 1, G_TYPE_BOOLEAN);
+
+	signals[REMOVED] =
+	    g_signal_new (NM_SETTINGS_CONNECTION_REMOVED,
+	                  G_TYPE_FROM_CLASS (class),
+	                  G_SIGNAL_RUN_FIRST,
+	                  0,
+	                  NULL, NULL,
+	                  g_cclosure_marshal_VOID__VOID,
+	                  G_TYPE_NONE, 0);
 
 	nm_exported_object_class_add_interface (NM_EXPORTED_OBJECT_CLASS (class),
 	                                        NMDBUS_TYPE_SETTINGS_CONNECTION_SKELETON,
diff --git a/src/settings/nm-settings-connection.h b/src/settings/nm-settings-connection.h
index 5c12a8ac..c45505d9 100644
--- a/src/settings/nm-settings-connection.h
+++ b/src/settings/nm-settings-connection.h
@@ -43,8 +43,8 @@ G_BEGIN_DECLS
 #define NM_SETTINGS_CONNECTION_GET_SECRETS "get-secrets"
 #define NM_SETTINGS_CONNECTION_CANCEL_SECRETS "cancel-secrets"
 
-/* Emitted when connection is changed by a user action */
-#define NM_SETTINGS_CONNECTION_UPDATED_BY_USER "updated-by-user"
+/* Internal signals */
+#define NM_SETTINGS_CONNECTION_UPDATED_INTERNAL "updated-internal"
 
 /* Properties */
 #define NM_SETTINGS_CONNECTION_VISIBLE  "visible"
diff --git a/src/settings/nm-settings.c b/src/settings/nm-settings.c
index 65148994..73c678a6 100644
--- a/src/settings/nm-settings.c
+++ b/src/settings/nm-settings.c
@@ -36,6 +36,7 @@
 #include <selinux/selinux.h>
 #endif
 
+#include "nm-common-macros.h"
 #include "nm-dbus-interface.h"
 #include "nm-connection.h"
 #include "nm-setting-8021x.h"
@@ -157,7 +158,6 @@ typedef struct {
 
 	struct {
 		char *value;
-		char *file;
 		GFileMonitor *monitor;
 		GFileMonitor *dhcp_monitor;
 		gulong monitor_id;
@@ -171,7 +171,6 @@ typedef struct {
 enum {
 	CONNECTION_ADDED,
 	CONNECTION_UPDATED,
-	CONNECTION_UPDATED_BY_USER,
 	CONNECTION_REMOVED,
 	CONNECTION_VISIBILITY_CHANGED,
 	AGENT_REGISTERED,
@@ -181,16 +180,13 @@ enum {
 };
 static guint signals[LAST_SIGNAL] = { 0 };
 
-enum {
-	PROP_0,
+NM_GOBJECT_PROPERTIES_DEFINE (NMSettings,
 	PROP_UNMANAGED_SPECS,
 	PROP_HOSTNAME,
 	PROP_CAN_MODIFY,
 	PROP_CONNECTIONS,
 	PROP_STARTUP_COMPLETE,
-
-	LAST_PROP
-};
+);
 
 static void
 check_startup_complete (NMSettings *self)
@@ -209,7 +205,7 @@ check_startup_complete (NMSettings *self)
 	}
 
 	priv->startup_complete = TRUE;
-	g_object_notify (G_OBJECT (self), NM_SETTINGS_STARTUP_COMPLETE);
+	_notify (self, PROP_STARTUP_COMPLETE);
 }
 
 static void
@@ -589,11 +585,11 @@ nm_settings_get_hostname (NMSettings *self)
 #endif
 
 #if defined(HOSTNAME_PERSIST_GENTOO)
-	hostname = read_hostname_gentoo (priv->hostname.file);
+	hostname = read_hostname_gentoo (HOSTNAME_FILE);
 #elif defined(HOSTNAME_PERSIST_SLACKWARE)
-	hostname = read_hostname_slackware (priv->hostname.file);
+	hostname = read_hostname_slackware (HOSTNAME_FILE);
 #else
-	if (g_file_get_contents (priv->hostname.file, &hostname, NULL, NULL))
+	if (g_file_get_contents (HOSTNAME_FILE, &hostname, NULL, NULL))
 		g_strchomp (hostname);
 #endif
 
@@ -652,7 +648,7 @@ unmanaged_specs_changed (NMSettingsPlugin *config,
 
 	update_specs (self, &priv->unmanaged_specs,
 	              nm_settings_plugin_get_unmanaged_specs);
-	g_object_notify (G_OBJECT (self), NM_SETTINGS_UNMANAGED_SPECS);
+	_notify (self, PROP_UNMANAGED_SPECS);
 }
 
 static void
@@ -883,27 +879,17 @@ next:
 }
 
 static void
-connection_updated (NMSettingsConnection *connection, gpointer user_data)
+connection_updated (NMSettingsConnection *connection, gboolean by_user, gpointer user_data)
 {
-	/* Re-emit for listeners like NMPolicy */
 	g_signal_emit (NM_SETTINGS (user_data),
 	               signals[CONNECTION_UPDATED],
 	               0,
-	               connection);
+	               connection,
+	               by_user);
 	g_signal_emit_by_name (NM_SETTINGS (user_data), NM_CP_SIGNAL_CONNECTION_UPDATED, connection);
 }
 
 static void
-connection_updated_by_user (NMSettingsConnection *connection, gpointer user_data)
-{
-	/* Re-emit for listeners like NMPolicy */
-	g_signal_emit (NM_SETTINGS (user_data),
-	               signals[CONNECTION_UPDATED_BY_USER],
-	               0,
-	               connection);
-}
-
-static void
 connection_visibility_changed (NMSettingsConnection *connection,
                                GParamSpec *pspec,
                                gpointer user_data)
@@ -933,7 +919,6 @@ connection_removed (NMSettingsConnection *connection, gpointer user_data)
 
 	g_signal_handlers_disconnect_by_func (connection, G_CALLBACK (connection_removed), self);
 	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);
 	g_object_unref (self);
@@ -946,7 +931,7 @@ connection_removed (NMSettingsConnection *connection, gpointer user_data)
 
 	/* Re-emit for listeners like NMPolicy */
 	g_signal_emit_by_name (self, NM_CP_SIGNAL_CONNECTION_REMOVED, connection);
-	g_object_notify (G_OBJECT (self), NM_SETTINGS_CONNECTIONS);
+	_notify (self, PROP_CONNECTIONS);
 	if (nm_exported_object_is_exported (NM_EXPORTED_OBJECT (connection)))
 		nm_exported_object_unexport (NM_EXPORTED_OBJECT (connection));
 
@@ -1065,10 +1050,8 @@ claim_connection (NMSettings *self, NMSettingsConnection *connection)
 	g_object_ref (self);
 	g_signal_connect (connection, NM_SETTINGS_CONNECTION_REMOVED,
 	                  G_CALLBACK (connection_removed), self);
-	g_signal_connect (connection, NM_SETTINGS_CONNECTION_UPDATED,
+	g_signal_connect (connection, NM_SETTINGS_CONNECTION_UPDATED_INTERNAL,
 	                  G_CALLBACK (connection_updated), self);
-	g_signal_connect (connection, NM_SETTINGS_CONNECTION_UPDATED_BY_USER,
-	                  G_CALLBACK (connection_updated_by_user), self);
 	g_signal_connect (connection, "notify::" NM_SETTINGS_CONNECTION_VISIBLE,
 	                  G_CALLBACK (connection_visibility_changed),
 	                  self);
@@ -1096,7 +1079,7 @@ claim_connection (NMSettings *self, NMSettingsConnection *connection)
 		/* Internal added signal */
 		g_signal_emit (self, signals[CONNECTION_ADDED], 0, connection);
 		g_signal_emit_by_name (self, NM_CP_SIGNAL_CONNECTION_ADDED, connection);
-		g_object_notify (G_OBJECT (self), NM_SETTINGS_CONNECTIONS);
+		_notify (self, PROP_CONNECTIONS);
 
 		/* Exported D-Bus signal */
 		g_signal_emit (self, signals[NEW_CONNECTION], 0, connection);
@@ -1111,7 +1094,7 @@ claim_connection (NMSettings *self, NMSettingsConnection *connection)
  * not save to disk
  * @error: on return, a location to store any errors that may occur
  *
- * Creates a new #NMSettingsConnection for the given source @connection.  
+ * Creates a new #NMSettingsConnection for the given source @connection.
  * The returned object is owned by @self and the caller must reference
  * the object to continue using it.
  *
@@ -1635,7 +1618,7 @@ write_hostname (NMSettingsPrivate *priv, const char *hostname)
 	char *hostname_eol;
 	gboolean ret;
 	gs_free_error GError *error = NULL;
-	const char *file = priv->hostname.file;
+	const char *file = HOSTNAME_FILE;
 	gs_free char *link_path = NULL;
 	gs_unref_variant GVariant *var = NULL;
 	struct stat file_stat;
@@ -1664,7 +1647,7 @@ write_hostname (NMSettingsPrivate *priv, const char *hostname)
 	 */
 	if (   lstat (file, &file_stat) == 0
 	    && S_ISLNK (file_stat.st_mode)
-	    && (link_path = g_file_read_link (file, NULL)))
+	    && (link_path = nm_utils_read_link_absolute (file, NULL)))
 		file = link_path;
 
 #if HAVE_SELINUX
@@ -1830,7 +1813,7 @@ hostname_maybe_changed (NMSettings *settings)
 		       NM_PRINT_FMT_QUOTED (new_hostname, "\"", new_hostname, "\"", "(none)"));
 		g_free (priv->hostname.value);
 		priv->hostname.value = new_hostname;
-		g_object_notify (G_OBJECT (settings), NM_SETTINGS_HOSTNAME);
+		_notify (settings, PROP_HOSTNAME);
 	} else
 		g_free (new_hostname);
 }
@@ -1932,10 +1915,13 @@ default_wired_connection_removed_cb (NMSettingsConnection *connection, NMSetting
 }
 
 static void
-default_wired_connection_updated_by_user_cb (NMSettingsConnection *connection, NMSettings *self)
+default_wired_connection_updated_by_user_cb (NMSettingsConnection *connection, gboolean by_user, NMSettings *self)
 {
 	NMDevice *device;
 
+	if (!by_user)
+		return;
+
 	/* The connection has been changed by the user, it should no longer be
 	 * considered a default wired connection, and should no longer affect
 	 * the no-auto-default configuration option.
@@ -2010,7 +1996,7 @@ device_realized (NMDevice *device, GParamSpec *pspec, NMSettings *self)
 	g_object_set_data (G_OBJECT (added), DEFAULT_WIRED_DEVICE_TAG, device);
 	g_object_set_data (G_OBJECT (device), DEFAULT_WIRED_CONNECTION_TAG, added);
 
-	g_signal_connect (added, NM_SETTINGS_CONNECTION_UPDATED_BY_USER,
+	g_signal_connect (added, NM_SETTINGS_CONNECTION_UPDATED_INTERNAL,
 	                  G_CALLBACK (default_wired_connection_updated_by_user_cb), self);
 	g_signal_connect (added, NM_SETTINGS_CONNECTION_REMOVED,
 	                  G_CALLBACK (default_wired_connection_removed_cb), self);
@@ -2174,7 +2160,8 @@ hostnamed_properties_changed (GDBusProxy *proxy,
                               char **invalidated_properties,
                               gpointer user_data)
 {
-	NMSettingsPrivate *priv = NM_SETTINGS_GET_PRIVATE (user_data);
+	NMSettings *self = user_data;
+	NMSettingsPrivate *priv = NM_SETTINGS_GET_PRIVATE (self);
 	GVariant *v_hostname;
 	const char *hostname;
 
@@ -2191,7 +2178,7 @@ hostnamed_properties_changed (GDBusProxy *proxy,
 		       NM_PRINT_FMT_QUOTED (hostname, "\"", hostname, "\"", "(none)"));
 		g_free (priv->hostname.value);
 		priv->hostname.value = g_strdup (hostname);
-		g_object_notify (G_OBJECT (user_data), NM_SETTINGS_HOSTNAME);
+		_notify (self, PROP_HOSTNAME);
 		nm_dispatcher_call (DISPATCHER_ACTION_HOSTNAME, NULL, NULL, NULL, NULL, NULL, NULL);
 	}
 
@@ -2205,11 +2192,10 @@ setup_hostname_file_monitors (NMSettings *self)
 	GFileMonitor *monitor;
 	GFile *file;
 
-	priv->hostname.file = HOSTNAME_FILE;
 	priv->hostname.value = nm_settings_get_hostname (self);
 
 	/* monitor changes to hostname file */
-	file = g_file_new_for_path (priv->hostname.file);
+	file = g_file_new_for_path (HOSTNAME_FILE);
 	monitor = g_file_monitor_file (file, G_FILE_MONITOR_NONE, NULL, NULL);
 	g_object_unref (file);
 	if (monitor) {
@@ -2296,7 +2282,7 @@ nm_settings_start (NMSettings *self, GError **error)
 		setup_hostname_file_monitors (self);
 
 	priv->started = TRUE;
-	g_object_notify (G_OBJECT (self), NM_SETTINGS_HOSTNAME);
+	_notify (self, PROP_HOSTNAME);
 	return TRUE;
 }
 
@@ -2447,96 +2433,86 @@ nm_settings_class_init (NMSettingsClass *class)
 
 	/* properties */
 
-	g_object_class_install_property
-		(object_class, PROP_UNMANAGED_SPECS,
-		 g_param_spec_boxed (NM_SETTINGS_UNMANAGED_SPECS, "", "",
-		                     G_TYPE_STRV,
-		                     G_PARAM_READABLE |
-		                     G_PARAM_STATIC_STRINGS));
-
-	g_object_class_install_property
-		(object_class, PROP_HOSTNAME,
-		 g_param_spec_string (NM_SETTINGS_HOSTNAME, "", "",
-		                      NULL,
-		                      G_PARAM_READABLE |
-		                      G_PARAM_STATIC_STRINGS));
-
-	g_object_class_install_property
-		(object_class, PROP_CAN_MODIFY,
-		 g_param_spec_boolean (NM_SETTINGS_CAN_MODIFY, "", "",
-		                       FALSE,
-		                       G_PARAM_READABLE |
-		                       G_PARAM_STATIC_STRINGS));
-
-	g_object_class_install_property
-		(object_class, PROP_CONNECTIONS,
-		 g_param_spec_boxed (NM_SETTINGS_CONNECTIONS, "", "",
-		                     G_TYPE_STRV,
-		                     G_PARAM_READABLE |
-		                     G_PARAM_STATIC_STRINGS));
+	obj_properties[PROP_UNMANAGED_SPECS] =
+	    g_param_spec_boxed (NM_SETTINGS_UNMANAGED_SPECS, "", "",
+	                        G_TYPE_STRV,
+	                        G_PARAM_READABLE |
+	                        G_PARAM_STATIC_STRINGS);
+
+	obj_properties[PROP_HOSTNAME] =
+	    g_param_spec_string (NM_SETTINGS_HOSTNAME, "", "",
+	                         NULL,
+	                         G_PARAM_READABLE |
+	                         G_PARAM_STATIC_STRINGS);
+
+	obj_properties[PROP_CAN_MODIFY] =
+	    g_param_spec_boolean (NM_SETTINGS_CAN_MODIFY, "", "",
+	                          FALSE,
+	                          G_PARAM_READABLE |
+	                          G_PARAM_STATIC_STRINGS);
+
+	obj_properties[PROP_CONNECTIONS] =
+	    g_param_spec_boxed (NM_SETTINGS_CONNECTIONS, "", "",
+	                        G_TYPE_STRV,
+	                        G_PARAM_READABLE |
+	                        G_PARAM_STATIC_STRINGS);
+
+	obj_properties[PROP_STARTUP_COMPLETE] =
+	    g_param_spec_boolean (NM_SETTINGS_STARTUP_COMPLETE, "", "",
+	                          FALSE,
+	                          G_PARAM_READABLE |
+	                          G_PARAM_STATIC_STRINGS);
+
+	g_object_class_install_properties (object_class, _PROPERTY_ENUMS_LAST, obj_properties);
 
 	/* signals */
-	signals[CONNECTION_ADDED] = 
-	                g_signal_new (NM_SETTINGS_SIGNAL_CONNECTION_ADDED,
-	                              G_OBJECT_CLASS_TYPE (object_class),
-	                              G_SIGNAL_RUN_FIRST,
-	                              G_STRUCT_OFFSET (NMSettingsClass, connection_added),
-	                              NULL, NULL,
-	                              g_cclosure_marshal_VOID__OBJECT,
-	                              G_TYPE_NONE, 1, NM_TYPE_SETTINGS_CONNECTION);
-
-	signals[CONNECTION_UPDATED] = 
-	                g_signal_new (NM_SETTINGS_SIGNAL_CONNECTION_UPDATED,
-	                              G_OBJECT_CLASS_TYPE (object_class),
-	                              G_SIGNAL_RUN_FIRST,
-	                              G_STRUCT_OFFSET (NMSettingsClass, connection_updated),
-	                              NULL, NULL,
-	                              g_cclosure_marshal_VOID__OBJECT,
-	                              G_TYPE_NONE, 1, NM_TYPE_SETTINGS_CONNECTION);
-
-	signals[CONNECTION_UPDATED_BY_USER] =
-	                g_signal_new (NM_SETTINGS_SIGNAL_CONNECTION_UPDATED_BY_USER,
-	                              G_OBJECT_CLASS_TYPE (object_class),
-	                              G_SIGNAL_RUN_FIRST,
-	                              0,
-	                              NULL, NULL,
-	                              g_cclosure_marshal_VOID__OBJECT,
-	                              G_TYPE_NONE, 1, NM_TYPE_SETTINGS_CONNECTION);
-
-	signals[CONNECTION_REMOVED] = 
-	                g_signal_new (NM_SETTINGS_SIGNAL_CONNECTION_REMOVED,
-	                              G_OBJECT_CLASS_TYPE (object_class),
-	                              G_SIGNAL_RUN_FIRST,
-	                              G_STRUCT_OFFSET (NMSettingsClass, connection_removed),
-	                              NULL, NULL,
-	                              g_cclosure_marshal_VOID__OBJECT,
-	                              G_TYPE_NONE, 1, NM_TYPE_SETTINGS_CONNECTION);
-
-	signals[CONNECTION_VISIBILITY_CHANGED] = 
-	                g_signal_new (NM_SETTINGS_SIGNAL_CONNECTION_VISIBILITY_CHANGED,
-	                              G_OBJECT_CLASS_TYPE (object_class),
-	                              G_SIGNAL_RUN_FIRST,
-	                              G_STRUCT_OFFSET (NMSettingsClass, connection_visibility_changed),
-	                              NULL, NULL,
-	                              g_cclosure_marshal_VOID__OBJECT,
-	                              G_TYPE_NONE, 1, NM_TYPE_SETTINGS_CONNECTION);
+	signals[CONNECTION_ADDED] =
+	    g_signal_new (NM_SETTINGS_SIGNAL_CONNECTION_ADDED,
+	                  G_OBJECT_CLASS_TYPE (object_class),
+	                  G_SIGNAL_RUN_FIRST,
+	                  0, NULL, NULL,
+	                  g_cclosure_marshal_VOID__OBJECT,
+	                  G_TYPE_NONE, 1, NM_TYPE_SETTINGS_CONNECTION);
+
+	signals[CONNECTION_UPDATED] =
+	    g_signal_new (NM_SETTINGS_SIGNAL_CONNECTION_UPDATED,
+	                  G_OBJECT_CLASS_TYPE (object_class),
+	                  G_SIGNAL_RUN_FIRST,
+	                  0, NULL, NULL,
+	                  NULL,
+	                  G_TYPE_NONE, 2, NM_TYPE_SETTINGS_CONNECTION, G_TYPE_BOOLEAN);
+
+	signals[CONNECTION_REMOVED] =
+	    g_signal_new (NM_SETTINGS_SIGNAL_CONNECTION_REMOVED,
+	                  G_OBJECT_CLASS_TYPE (object_class),
+	                  G_SIGNAL_RUN_FIRST,
+	                  0, NULL, NULL,
+	                  g_cclosure_marshal_VOID__OBJECT,
+	                  G_TYPE_NONE, 1, NM_TYPE_SETTINGS_CONNECTION);
+
+	signals[CONNECTION_VISIBILITY_CHANGED] =
+	    g_signal_new (NM_SETTINGS_SIGNAL_CONNECTION_VISIBILITY_CHANGED,
+	                  G_OBJECT_CLASS_TYPE (object_class),
+	                  G_SIGNAL_RUN_FIRST,
+	                  0, NULL, NULL,
+	                  g_cclosure_marshal_VOID__OBJECT,
+	                  G_TYPE_NONE, 1, NM_TYPE_SETTINGS_CONNECTION);
 
 	signals[AGENT_REGISTERED] =
-		g_signal_new (NM_SETTINGS_SIGNAL_AGENT_REGISTERED,
-		              G_OBJECT_CLASS_TYPE (object_class),
-		              G_SIGNAL_RUN_FIRST,
-		              G_STRUCT_OFFSET (NMSettingsClass, agent_registered),
-		              NULL, NULL,
-		              g_cclosure_marshal_VOID__OBJECT,
-		              G_TYPE_NONE, 1, NM_TYPE_SECRET_AGENT);
-
-
-	signals[NEW_CONNECTION] = 
-	                g_signal_new ("new-connection",
-	                              G_OBJECT_CLASS_TYPE (object_class),
-	                              G_SIGNAL_RUN_FIRST, 0, NULL, NULL,
-	                              g_cclosure_marshal_VOID__OBJECT,
-	                              G_TYPE_NONE, 1, NM_TYPE_SETTINGS_CONNECTION);
+	    g_signal_new (NM_SETTINGS_SIGNAL_AGENT_REGISTERED,
+	                  G_OBJECT_CLASS_TYPE (object_class),
+	                  G_SIGNAL_RUN_FIRST,
+	                  0, NULL, NULL,
+	                  g_cclosure_marshal_VOID__OBJECT,
+	                  G_TYPE_NONE, 1, NM_TYPE_SECRET_AGENT);
+
+
+	signals[NEW_CONNECTION] =
+	    g_signal_new ("new-connection",
+	                  G_OBJECT_CLASS_TYPE (object_class),
+	                  G_SIGNAL_RUN_FIRST, 0, NULL, NULL,
+	                  g_cclosure_marshal_VOID__OBJECT,
+	                  G_TYPE_NONE, 1, NM_TYPE_SETTINGS_CONNECTION);
 
 	nm_exported_object_class_add_interface (NM_EXPORTED_OBJECT_CLASS (class),
 	                                        NMDBUS_TYPE_SETTINGS_SKELETON,
diff --git a/src/settings/nm-settings.h b/src/settings/nm-settings.h
index 051c2094..5d41e5bc 100644
--- a/src/settings/nm-settings.h
+++ b/src/settings/nm-settings.h
@@ -41,11 +41,10 @@
 #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_STARTUP_COMPLETE "startup-complete"
 
 #define NM_SETTINGS_SIGNAL_CONNECTION_ADDED              "connection-added"
 #define NM_SETTINGS_SIGNAL_CONNECTION_UPDATED            "connection-updated"
-#define NM_SETTINGS_SIGNAL_CONNECTION_UPDATED_BY_USER    "connection-updated-by-user"
 #define NM_SETTINGS_SIGNAL_CONNECTION_REMOVED            "connection-removed"
 #define NM_SETTINGS_SIGNAL_CONNECTION_VISIBILITY_CHANGED "connection-visibility-changed"
 #define NM_SETTINGS_SIGNAL_AGENT_REGISTERED              "agent-registered"
@@ -56,19 +55,6 @@ struct _NMSettings {
 
 typedef struct {
 	NMExportedObjectClass parent_class;
-
-	/* Signals */
-	void (*properties_changed) (NMSettings *self, GHashTable *properties);
-
-	void (*connection_added)   (NMSettings *self, NMSettingsConnection *connection);
-
-	void (*connection_updated) (NMSettings *self, NMSettingsConnection *connection);
-
-	void (*connection_removed) (NMSettings *self, NMSettingsConnection *connection);
-
-	void (*connection_visibility_changed) (NMSettings *self, NMSettingsConnection *connection);
-
-	void (*agent_registered) (NMSettings *self, NMSecretAgent *agent);
 } NMSettingsClass;
 
 typedef void (*NMSettingsSetHostnameCb) (const char *name, gboolean result, gpointer user_data);
diff --git a/src/settings/plugins/Makefile.in b/src/settings/plugins/Makefile.in
index 643e0da7..e770ccde 100644
--- a/src/settings/plugins/Makefile.in
+++ b/src/settings/plugins/Makefile.in
@@ -328,6 +328,7 @@ NEWT_LIBS = @NEWT_LIBS@
 NM = @NM@
 NMEDIT = @NMEDIT@
 NM_CONFIG_DEFAULT_AUTH_POLKIT_TEXT = @NM_CONFIG_DEFAULT_AUTH_POLKIT_TEXT@
+NM_CONFIG_DEFAULT_DNS_RC_MANAGER = @NM_CONFIG_DEFAULT_DNS_RC_MANAGER@
 NM_CONFIG_DEFAULT_LOGGING_AUDIT_TEXT = @NM_CONFIG_DEFAULT_LOGGING_AUDIT_TEXT@
 NM_CONFIG_LOGGING_BACKEND_DEFAULT_TEXT = @NM_CONFIG_LOGGING_BACKEND_DEFAULT_TEXT@
 NM_MAJOR_VERSION = @NM_MAJOR_VERSION@
diff --git a/src/settings/plugins/ibft/Makefile.in b/src/settings/plugins/ibft/Makefile.in
index 7142cf1d..fe124670 100644
--- a/src/settings/plugins/ibft/Makefile.in
+++ b/src/settings/plugins/ibft/Makefile.in
@@ -395,6 +395,7 @@ NEWT_LIBS = @NEWT_LIBS@
 NM = @NM@
 NMEDIT = @NMEDIT@
 NM_CONFIG_DEFAULT_AUTH_POLKIT_TEXT = @NM_CONFIG_DEFAULT_AUTH_POLKIT_TEXT@
+NM_CONFIG_DEFAULT_DNS_RC_MANAGER = @NM_CONFIG_DEFAULT_DNS_RC_MANAGER@
 NM_CONFIG_DEFAULT_LOGGING_AUDIT_TEXT = @NM_CONFIG_DEFAULT_LOGGING_AUDIT_TEXT@
 NM_CONFIG_LOGGING_BACKEND_DEFAULT_TEXT = @NM_CONFIG_LOGGING_BACKEND_DEFAULT_TEXT@
 NM_MAJOR_VERSION = @NM_MAJOR_VERSION@
diff --git a/src/settings/plugins/ibft/tests/Makefile.in b/src/settings/plugins/ibft/tests/Makefile.in
index 1869b502..c3fef788 100644
--- a/src/settings/plugins/ibft/tests/Makefile.in
+++ b/src/settings/plugins/ibft/tests/Makefile.in
@@ -523,6 +523,7 @@ NEWT_LIBS = @NEWT_LIBS@
 NM = @NM@
 NMEDIT = @NMEDIT@
 NM_CONFIG_DEFAULT_AUTH_POLKIT_TEXT = @NM_CONFIG_DEFAULT_AUTH_POLKIT_TEXT@
+NM_CONFIG_DEFAULT_DNS_RC_MANAGER = @NM_CONFIG_DEFAULT_DNS_RC_MANAGER@
 NM_CONFIG_DEFAULT_LOGGING_AUDIT_TEXT = @NM_CONFIG_DEFAULT_LOGGING_AUDIT_TEXT@
 NM_CONFIG_LOGGING_BACKEND_DEFAULT_TEXT = @NM_CONFIG_LOGGING_BACKEND_DEFAULT_TEXT@
 NM_MAJOR_VERSION = @NM_MAJOR_VERSION@
diff --git a/src/settings/plugins/ifcfg-rh/Makefile.in b/src/settings/plugins/ifcfg-rh/Makefile.in
index 54a2b805..a87ee94c 100644
--- a/src/settings/plugins/ifcfg-rh/Makefile.in
+++ b/src/settings/plugins/ifcfg-rh/Makefile.in
@@ -405,6 +405,7 @@ NEWT_LIBS = @NEWT_LIBS@
 NM = @NM@
 NMEDIT = @NMEDIT@
 NM_CONFIG_DEFAULT_AUTH_POLKIT_TEXT = @NM_CONFIG_DEFAULT_AUTH_POLKIT_TEXT@
+NM_CONFIG_DEFAULT_DNS_RC_MANAGER = @NM_CONFIG_DEFAULT_DNS_RC_MANAGER@
 NM_CONFIG_DEFAULT_LOGGING_AUDIT_TEXT = @NM_CONFIG_DEFAULT_LOGGING_AUDIT_TEXT@
 NM_CONFIG_LOGGING_BACKEND_DEFAULT_TEXT = @NM_CONFIG_LOGGING_BACKEND_DEFAULT_TEXT@
 NM_MAJOR_VERSION = @NM_MAJOR_VERSION@
diff --git a/src/settings/plugins/ifcfg-rh/plugin.c b/src/settings/plugins/ifcfg-rh/plugin.c
index 1fb6b789..63184eb5 100644
--- a/src/settings/plugins/ifcfg-rh/plugin.c
+++ b/src/settings/plugins/ifcfg-rh/plugin.c
@@ -943,8 +943,8 @@ config_changed_cb (NMConfig *config,
 	 * On SIGHUP and SIGUSR1 try to re-connect to D-Bus. So in the unlikely
 	 * event that the D-Bus conneciton is broken, that allows for recovery
 	 * without need for restarting NetworkManager. */
-	if (   NM_FLAGS_HAS (changes, NM_CONFIG_CHANGE_SIGHUP)
-	    || NM_FLAGS_HAS (changes, NM_CONFIG_CHANGE_SIGUSR1)) {
+	if (NM_FLAGS_ANY (changes,   NM_CONFIG_CHANGE_CAUSE_SIGHUP
+	                           | NM_CONFIG_CHANGE_CAUSE_SIGUSR1)) {
 		if (!SETTINGS_PLUGIN_IFCFG_GET_PRIVATE (self)->dbus.connection)
 			_dbus_setup (self);
 	}
diff --git a/src/settings/plugins/ifcfg-rh/reader.c b/src/settings/plugins/ifcfg-rh/reader.c
index 39e981f9..fe762db1 100644
--- a/src/settings/plugins/ifcfg-rh/reader.c
+++ b/src/settings/plugins/ifcfg-rh/reader.c
@@ -984,6 +984,8 @@ make_ip4_setting (shvarFile *ifcfg,
 				goto done;
 			(void) nm_setting_ip_config_add_address (s_ip4, addr);
 			nm_ip_address_unref (addr);
+			if (never_default)
+				PARSE_WARNING ("GATEWAY will be ignored when DEFROUTE is disabled");
 			g_object_set (s_ip4, NM_SETTING_IP_CONFIG_GATEWAY, gateway, NULL);
 		}
 		return NM_SETTING (s_ip4);
@@ -1082,6 +1084,9 @@ make_ip4_setting (shvarFile *ifcfg,
 	}
 	g_object_set (s_ip4, NM_SETTING_IP_CONFIG_GATEWAY, gateway, NULL);
 
+	if (gateway && never_default)
+		PARSE_WARNING ("GATEWAY will be ignored when DEFROUTE is disabled");
+
 	/* DNS servers
 	 * Pick up just IPv4 addresses (IPv6 addresses are taken by make_ip6_setting())
 	 */
diff --git a/src/settings/plugins/ifcfg-rh/tests/Makefile.in b/src/settings/plugins/ifcfg-rh/tests/Makefile.in
index d822e2e1..4bc35da2 100644
--- a/src/settings/plugins/ifcfg-rh/tests/Makefile.in
+++ b/src/settings/plugins/ifcfg-rh/tests/Makefile.in
@@ -577,6 +577,7 @@ NEWT_LIBS = @NEWT_LIBS@
 NM = @NM@
 NMEDIT = @NMEDIT@
 NM_CONFIG_DEFAULT_AUTH_POLKIT_TEXT = @NM_CONFIG_DEFAULT_AUTH_POLKIT_TEXT@
+NM_CONFIG_DEFAULT_DNS_RC_MANAGER = @NM_CONFIG_DEFAULT_DNS_RC_MANAGER@
 NM_CONFIG_DEFAULT_LOGGING_AUDIT_TEXT = @NM_CONFIG_DEFAULT_LOGGING_AUDIT_TEXT@
 NM_CONFIG_LOGGING_BACKEND_DEFAULT_TEXT = @NM_CONFIG_LOGGING_BACKEND_DEFAULT_TEXT@
 NM_MAJOR_VERSION = @NM_MAJOR_VERSION@
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 e98ea93c..74f3bf05 100644
--- a/src/settings/plugins/ifcfg-rh/tests/network-scripts/Makefile.in
+++ b/src/settings/plugins/ifcfg-rh/tests/network-scripts/Makefile.in
@@ -264,6 +264,7 @@ NEWT_LIBS = @NEWT_LIBS@
 NM = @NM@
 NMEDIT = @NMEDIT@
 NM_CONFIG_DEFAULT_AUTH_POLKIT_TEXT = @NM_CONFIG_DEFAULT_AUTH_POLKIT_TEXT@
+NM_CONFIG_DEFAULT_DNS_RC_MANAGER = @NM_CONFIG_DEFAULT_DNS_RC_MANAGER@
 NM_CONFIG_DEFAULT_LOGGING_AUDIT_TEXT = @NM_CONFIG_DEFAULT_LOGGING_AUDIT_TEXT@
 NM_CONFIG_LOGGING_BACKEND_DEFAULT_TEXT = @NM_CONFIG_LOGGING_BACKEND_DEFAULT_TEXT@
 NM_MAJOR_VERSION = @NM_MAJOR_VERSION@
diff --git a/src/settings/plugins/ifnet/Makefile.in b/src/settings/plugins/ifnet/Makefile.in
index 4b496f54..9f99e957 100644
--- a/src/settings/plugins/ifnet/Makefile.in
+++ b/src/settings/plugins/ifnet/Makefile.in
@@ -396,6 +396,7 @@ NEWT_LIBS = @NEWT_LIBS@
 NM = @NM@
 NMEDIT = @NMEDIT@
 NM_CONFIG_DEFAULT_AUTH_POLKIT_TEXT = @NM_CONFIG_DEFAULT_AUTH_POLKIT_TEXT@
+NM_CONFIG_DEFAULT_DNS_RC_MANAGER = @NM_CONFIG_DEFAULT_DNS_RC_MANAGER@
 NM_CONFIG_DEFAULT_LOGGING_AUDIT_TEXT = @NM_CONFIG_DEFAULT_LOGGING_AUDIT_TEXT@
 NM_CONFIG_LOGGING_BACKEND_DEFAULT_TEXT = @NM_CONFIG_LOGGING_BACKEND_DEFAULT_TEXT@
 NM_MAJOR_VERSION = @NM_MAJOR_VERSION@
diff --git a/src/settings/plugins/ifnet/tests/Makefile.in b/src/settings/plugins/ifnet/tests/Makefile.in
index 1a152870..4646a342 100644
--- a/src/settings/plugins/ifnet/tests/Makefile.in
+++ b/src/settings/plugins/ifnet/tests/Makefile.in
@@ -529,6 +529,7 @@ NEWT_LIBS = @NEWT_LIBS@
 NM = @NM@
 NMEDIT = @NMEDIT@
 NM_CONFIG_DEFAULT_AUTH_POLKIT_TEXT = @NM_CONFIG_DEFAULT_AUTH_POLKIT_TEXT@
+NM_CONFIG_DEFAULT_DNS_RC_MANAGER = @NM_CONFIG_DEFAULT_DNS_RC_MANAGER@
 NM_CONFIG_DEFAULT_LOGGING_AUDIT_TEXT = @NM_CONFIG_DEFAULT_LOGGING_AUDIT_TEXT@
 NM_CONFIG_LOGGING_BACKEND_DEFAULT_TEXT = @NM_CONFIG_LOGGING_BACKEND_DEFAULT_TEXT@
 NM_MAJOR_VERSION = @NM_MAJOR_VERSION@
diff --git a/src/settings/plugins/ifupdown/Makefile.in b/src/settings/plugins/ifupdown/Makefile.in
index 1f8c7e1b..8b153c6d 100644
--- a/src/settings/plugins/ifupdown/Makefile.in
+++ b/src/settings/plugins/ifupdown/Makefile.in
@@ -395,6 +395,7 @@ NEWT_LIBS = @NEWT_LIBS@
 NM = @NM@
 NMEDIT = @NMEDIT@
 NM_CONFIG_DEFAULT_AUTH_POLKIT_TEXT = @NM_CONFIG_DEFAULT_AUTH_POLKIT_TEXT@
+NM_CONFIG_DEFAULT_DNS_RC_MANAGER = @NM_CONFIG_DEFAULT_DNS_RC_MANAGER@
 NM_CONFIG_DEFAULT_LOGGING_AUDIT_TEXT = @NM_CONFIG_DEFAULT_LOGGING_AUDIT_TEXT@
 NM_CONFIG_LOGGING_BACKEND_DEFAULT_TEXT = @NM_CONFIG_LOGGING_BACKEND_DEFAULT_TEXT@
 NM_MAJOR_VERSION = @NM_MAJOR_VERSION@
diff --git a/src/settings/plugins/ifupdown/tests/Makefile.in b/src/settings/plugins/ifupdown/tests/Makefile.in
index 06e9b61e..f744e620 100644
--- a/src/settings/plugins/ifupdown/tests/Makefile.in
+++ b/src/settings/plugins/ifupdown/tests/Makefile.in
@@ -524,6 +524,7 @@ NEWT_LIBS = @NEWT_LIBS@
 NM = @NM@
 NMEDIT = @NMEDIT@
 NM_CONFIG_DEFAULT_AUTH_POLKIT_TEXT = @NM_CONFIG_DEFAULT_AUTH_POLKIT_TEXT@
+NM_CONFIG_DEFAULT_DNS_RC_MANAGER = @NM_CONFIG_DEFAULT_DNS_RC_MANAGER@
 NM_CONFIG_DEFAULT_LOGGING_AUDIT_TEXT = @NM_CONFIG_DEFAULT_LOGGING_AUDIT_TEXT@
 NM_CONFIG_LOGGING_BACKEND_DEFAULT_TEXT = @NM_CONFIG_LOGGING_BACKEND_DEFAULT_TEXT@
 NM_MAJOR_VERSION = @NM_MAJOR_VERSION@
diff --git a/src/settings/plugins/keyfile/Makefile.in b/src/settings/plugins/keyfile/Makefile.in
index 65410336..bace6af4 100644
--- a/src/settings/plugins/keyfile/Makefile.in
+++ b/src/settings/plugins/keyfile/Makefile.in
@@ -364,6 +364,7 @@ NEWT_LIBS = @NEWT_LIBS@
 NM = @NM@
 NMEDIT = @NMEDIT@
 NM_CONFIG_DEFAULT_AUTH_POLKIT_TEXT = @NM_CONFIG_DEFAULT_AUTH_POLKIT_TEXT@
+NM_CONFIG_DEFAULT_DNS_RC_MANAGER = @NM_CONFIG_DEFAULT_DNS_RC_MANAGER@
 NM_CONFIG_DEFAULT_LOGGING_AUDIT_TEXT = @NM_CONFIG_DEFAULT_LOGGING_AUDIT_TEXT@
 NM_CONFIG_LOGGING_BACKEND_DEFAULT_TEXT = @NM_CONFIG_LOGGING_BACKEND_DEFAULT_TEXT@
 NM_MAJOR_VERSION = @NM_MAJOR_VERSION@
diff --git a/src/settings/plugins/keyfile/tests/Makefile.in b/src/settings/plugins/keyfile/tests/Makefile.in
index eb7a99d2..89708a18 100644
--- a/src/settings/plugins/keyfile/tests/Makefile.in
+++ b/src/settings/plugins/keyfile/tests/Makefile.in
@@ -568,6 +568,7 @@ NEWT_LIBS = @NEWT_LIBS@
 NM = @NM@
 NMEDIT = @NMEDIT@
 NM_CONFIG_DEFAULT_AUTH_POLKIT_TEXT = @NM_CONFIG_DEFAULT_AUTH_POLKIT_TEXT@
+NM_CONFIG_DEFAULT_DNS_RC_MANAGER = @NM_CONFIG_DEFAULT_DNS_RC_MANAGER@
 NM_CONFIG_DEFAULT_LOGGING_AUDIT_TEXT = @NM_CONFIG_DEFAULT_LOGGING_AUDIT_TEXT@
 NM_CONFIG_LOGGING_BACKEND_DEFAULT_TEXT = @NM_CONFIG_LOGGING_BACKEND_DEFAULT_TEXT@
 NM_MAJOR_VERSION = @NM_MAJOR_VERSION@
diff --git a/src/settings/plugins/keyfile/tests/keyfiles/Makefile.in b/src/settings/plugins/keyfile/tests/keyfiles/Makefile.in
index 56f0735f..8be2893c 100644
--- a/src/settings/plugins/keyfile/tests/keyfiles/Makefile.in
+++ b/src/settings/plugins/keyfile/tests/keyfiles/Makefile.in
@@ -264,6 +264,7 @@ NEWT_LIBS = @NEWT_LIBS@
 NM = @NM@
 NMEDIT = @NMEDIT@
 NM_CONFIG_DEFAULT_AUTH_POLKIT_TEXT = @NM_CONFIG_DEFAULT_AUTH_POLKIT_TEXT@
+NM_CONFIG_DEFAULT_DNS_RC_MANAGER = @NM_CONFIG_DEFAULT_DNS_RC_MANAGER@
 NM_CONFIG_DEFAULT_LOGGING_AUDIT_TEXT = @NM_CONFIG_DEFAULT_LOGGING_AUDIT_TEXT@
 NM_CONFIG_LOGGING_BACKEND_DEFAULT_TEXT = @NM_CONFIG_LOGGING_BACKEND_DEFAULT_TEXT@
 NM_MAJOR_VERSION = @NM_MAJOR_VERSION@
diff --git a/src/supplicant-manager/tests/Makefile.in b/src/supplicant-manager/tests/Makefile.in
index 5e521ae0..7c822d91 100644
--- a/src/supplicant-manager/tests/Makefile.in
+++ b/src/supplicant-manager/tests/Makefile.in
@@ -562,6 +562,7 @@ NEWT_LIBS = @NEWT_LIBS@
 NM = @NM@
 NMEDIT = @NMEDIT@
 NM_CONFIG_DEFAULT_AUTH_POLKIT_TEXT = @NM_CONFIG_DEFAULT_AUTH_POLKIT_TEXT@
+NM_CONFIG_DEFAULT_DNS_RC_MANAGER = @NM_CONFIG_DEFAULT_DNS_RC_MANAGER@
 NM_CONFIG_DEFAULT_LOGGING_AUDIT_TEXT = @NM_CONFIG_DEFAULT_LOGGING_AUDIT_TEXT@
 NM_CONFIG_LOGGING_BACKEND_DEFAULT_TEXT = @NM_CONFIG_LOGGING_BACKEND_DEFAULT_TEXT@
 NM_MAJOR_VERSION = @NM_MAJOR_VERSION@
diff --git a/src/supplicant-manager/tests/certs/Makefile.in b/src/supplicant-manager/tests/certs/Makefile.in
index 7f29bb3c..819f36cc 100644
--- a/src/supplicant-manager/tests/certs/Makefile.in
+++ b/src/supplicant-manager/tests/certs/Makefile.in
@@ -264,6 +264,7 @@ NEWT_LIBS = @NEWT_LIBS@
 NM = @NM@
 NMEDIT = @NMEDIT@
 NM_CONFIG_DEFAULT_AUTH_POLKIT_TEXT = @NM_CONFIG_DEFAULT_AUTH_POLKIT_TEXT@
+NM_CONFIG_DEFAULT_DNS_RC_MANAGER = @NM_CONFIG_DEFAULT_DNS_RC_MANAGER@
 NM_CONFIG_DEFAULT_LOGGING_AUDIT_TEXT = @NM_CONFIG_DEFAULT_LOGGING_AUDIT_TEXT@
 NM_CONFIG_LOGGING_BACKEND_DEFAULT_TEXT = @NM_CONFIG_LOGGING_BACKEND_DEFAULT_TEXT@
 NM_MAJOR_VERSION = @NM_MAJOR_VERSION@
diff --git a/src/tests/Makefile.in b/src/tests/Makefile.in
index a4a135c5..2296c2b0 100644
--- a/src/tests/Makefile.in
+++ b/src/tests/Makefile.in
@@ -632,6 +632,7 @@ NEWT_LIBS = @NEWT_LIBS@
 NM = @NM@
 NMEDIT = @NMEDIT@
 NM_CONFIG_DEFAULT_AUTH_POLKIT_TEXT = @NM_CONFIG_DEFAULT_AUTH_POLKIT_TEXT@
+NM_CONFIG_DEFAULT_DNS_RC_MANAGER = @NM_CONFIG_DEFAULT_DNS_RC_MANAGER@
 NM_CONFIG_DEFAULT_LOGGING_AUDIT_TEXT = @NM_CONFIG_DEFAULT_LOGGING_AUDIT_TEXT@
 NM_CONFIG_LOGGING_BACKEND_DEFAULT_TEXT = @NM_CONFIG_LOGGING_BACKEND_DEFAULT_TEXT@
 NM_MAJOR_VERSION = @NM_MAJOR_VERSION@
diff --git a/src/tests/config/Makefile.in b/src/tests/config/Makefile.in
index 5a4bfbd1..7197ee1f 100644
--- a/src/tests/config/Makefile.in
+++ b/src/tests/config/Makefile.in
@@ -521,6 +521,7 @@ NEWT_LIBS = @NEWT_LIBS@
 NM = @NM@
 NMEDIT = @NMEDIT@
 NM_CONFIG_DEFAULT_AUTH_POLKIT_TEXT = @NM_CONFIG_DEFAULT_AUTH_POLKIT_TEXT@
+NM_CONFIG_DEFAULT_DNS_RC_MANAGER = @NM_CONFIG_DEFAULT_DNS_RC_MANAGER@
 NM_CONFIG_DEFAULT_LOGGING_AUDIT_TEXT = @NM_CONFIG_DEFAULT_LOGGING_AUDIT_TEXT@
 NM_CONFIG_LOGGING_BACKEND_DEFAULT_TEXT = @NM_CONFIG_LOGGING_BACKEND_DEFAULT_TEXT@
 NM_MAJOR_VERSION = @NM_MAJOR_VERSION@
diff --git a/src/tests/config/test-config.c b/src/tests/config/test-config.c
index d83ff4b5..b6d88edf 100644
--- a/src/tests/config/test-config.c
+++ b/src/tests/config/test-config.c
@@ -343,7 +343,7 @@ test_config_no_auto_default (void)
 	g_assert (!nm_config_get_no_auto_default_for_device (config, dev3));
 	g_assert (nm_config_get_no_auto_default_for_device (config, dev4));
 
-	g_test_expect_message ("NetworkManager", G_LOG_LEVEL_INFO, "*config: update * (no-auto-default)*");
+	g_test_expect_message ("NetworkManager", G_LOG_LEVEL_INFO, "*config: signal NO_AUTO_DEFAULT,no-auto-default *");
 	nm_config_set_no_auto_default_for_device (config, dev3);
 	g_test_assert_expected_messages ();
 
@@ -511,9 +511,9 @@ _set_values_config_changed_cb (NMConfig *config,
 	g_assert (config_changed_data);
 	g_assert (config_changed_data->changes == NM_CONFIG_CHANGE_NONE);
 
-	if (changes == NM_CONFIG_CHANGE_SIGHUP)
+	if (changes == NM_CONFIG_CHANGE_CAUSE_SIGHUP)
 		return;
-	changes &= ~NM_CONFIG_CHANGE_SIGHUP;
+	changes &= ~NM_CONFIG_CHANGE_CAUSE_SIGHUP;
 
 	config_changed_data->changes = changes;
 
@@ -556,11 +556,11 @@ _set_values_user (NMConfig *config,
 	config_data_before = g_object_ref (nm_config_get_data (config));
 
 	if (expected_changes != NM_CONFIG_CHANGE_NONE)
-		g_test_expect_message ("NetworkManager", G_LOG_LEVEL_INFO, "*config: update *");
+		g_test_expect_message ("NetworkManager", G_LOG_LEVEL_INFO, "*config: signal *");
 	else
 		g_test_expect_message ("NetworkManager", G_LOG_LEVEL_INFO, "*config: signal SIGHUP (no changes from disk)*");
 
-	nm_config_reload (config, SIGHUP);
+	nm_config_reload (config, NM_CONFIG_CHANGE_CAUSE_SIGHUP);
 
 	g_test_assert_expected_messages ();
 
@@ -600,7 +600,7 @@ _set_values_intern (NMConfig *config,
 	                  &config_changed_data);
 
 	if (expected_changes != NM_CONFIG_CHANGE_NONE)
-		g_test_expect_message ("NetworkManager", G_LOG_LEVEL_INFO, "*config: update *");
+		g_test_expect_message ("NetworkManager", G_LOG_LEVEL_INFO, "*config: signal *");
 
 	nm_config_set_values (config, keyfile_intern, TRUE, FALSE);
 
@@ -649,14 +649,14 @@ static void
 _set_values_intern_internal_set (NMConfig *config, gboolean set_user, GKeyFile *keyfile, NMConfigChangeFlags *out_expected_changes)
 {
 	g_key_file_set_string (keyfile, NM_CONFIG_KEYFILE_GROUPPREFIX_INTERN"section1", "key", "internal-section");
-	*out_expected_changes = NM_CONFIG_CHANGE_VALUES | NM_CONFIG_CHANGE_VALUES_INTERN;
+	*out_expected_changes = NM_CONFIG_CHANGE_CAUSE_SET_VALUES | NM_CONFIG_CHANGE_VALUES | NM_CONFIG_CHANGE_VALUES_INTERN;
 }
 
 static void
 _set_values_intern_internal_check (NMConfig *config, NMConfigData *config_data, gboolean is_change_event, NMConfigChangeFlags changes, NMConfigData *old_data)
 {
 	if (is_change_event)
-		g_assert (changes == (NM_CONFIG_CHANGE_VALUES | NM_CONFIG_CHANGE_VALUES_INTERN));
+		g_assert (changes == (NM_CONFIG_CHANGE_CAUSE_SET_VALUES | NM_CONFIG_CHANGE_VALUES | NM_CONFIG_CHANGE_VALUES_INTERN));
 	assert_config_value (config_data, NM_CONFIG_KEYFILE_GROUPPREFIX_INTERN"section1", "key", "internal-section");
 }
 
@@ -690,14 +690,14 @@ _set_values_intern_atomic_section_1_set (NMConfig *config, gboolean set_user, GK
 	g_key_file_set_string (keyfile, "atomic-prefix-1.section-a", "key3", "intern-value3");
 	g_key_file_set_string (keyfile, "non-atomic-prefix-1.section-a", "nap1-key1", "intern-value1");
 	g_key_file_set_string (keyfile, "non-atomic-prefix-1.section-a", "nap1-key3", "intern-value3");
-	*out_expected_changes = NM_CONFIG_CHANGE_VALUES | NM_CONFIG_CHANGE_VALUES_INTERN;
+	*out_expected_changes = NM_CONFIG_CHANGE_CAUSE_SET_VALUES | NM_CONFIG_CHANGE_VALUES | NM_CONFIG_CHANGE_VALUES_INTERN;
 }
 
 static void
 _set_values_intern_atomic_section_1_check (NMConfig *config, NMConfigData *config_data, gboolean is_change_event, NMConfigChangeFlags changes, NMConfigData *old_data)
 {
 	if (is_change_event)
-		g_assert (changes == (NM_CONFIG_CHANGE_VALUES | NM_CONFIG_CHANGE_VALUES_INTERN));
+		g_assert (changes == (NM_CONFIG_CHANGE_CAUSE_SET_VALUES | NM_CONFIG_CHANGE_VALUES | NM_CONFIG_CHANGE_VALUES_INTERN));
 	assert_config_value (config_data, "atomic-prefix-1.section-a", "key1", "intern-value1");
 	assert_config_value (config_data, "atomic-prefix-1.section-a", "key2", NULL);
 	assert_config_value (config_data, "atomic-prefix-1.section-a", "key3", "intern-value3");
@@ -744,14 +744,14 @@ _set_values_intern_atomic_section_2_set (NMConfig *config, gboolean set_user, GK
 	g_key_file_set_string (keyfile, "non-atomic-prefix-1.section-a", "nap1-key3", "intern-value3");
 	g_key_file_set_string (keyfile, NM_CONFIG_KEYFILE_GROUPPREFIX_INTERN"with-whitespace", "key1", " b c\\,  d  ");
 	g_key_file_set_value  (keyfile, NM_CONFIG_KEYFILE_GROUPPREFIX_INTERN"with-whitespace", "key2", " b c\\,  d  ");
-	*out_expected_changes = NM_CONFIG_CHANGE_VALUES | NM_CONFIG_CHANGE_VALUES_INTERN;
+	*out_expected_changes = NM_CONFIG_CHANGE_CAUSE_SET_VALUES | NM_CONFIG_CHANGE_VALUES | NM_CONFIG_CHANGE_VALUES_INTERN;
 }
 
 static void
 _set_values_intern_atomic_section_2_check (NMConfig *config, NMConfigData *config_data, gboolean is_change_event, NMConfigChangeFlags changes, NMConfigData *old_data)
 {
 	if (is_change_event)
-		g_assert (changes == (NM_CONFIG_CHANGE_VALUES | NM_CONFIG_CHANGE_VALUES_INTERN));
+		g_assert (changes == (NM_CONFIG_CHANGE_CAUSE_SET_VALUES | NM_CONFIG_CHANGE_VALUES | NM_CONFIG_CHANGE_VALUES_INTERN));
 	g_assert (!nm_config_data_has_group (config_data, "atomic-prefix-1.section-a"));
 	assert_config_value (config_data, "atomic-prefix-1.section-b", "key1", "user-value1");
 	assert_config_value (config_data, "non-atomic-prefix-1.section-a", "nap1-key1", NULL);
@@ -862,17 +862,17 @@ test_config_signal (void)
 	                  G_CALLBACK (_test_signal_config_changed_cb),
 	                  &expected);
 
-	expected = NM_CONFIG_CHANGE_SIGUSR1;
+	expected = NM_CONFIG_CHANGE_CAUSE_SIGUSR1;
 	g_test_expect_message ("NetworkManager", G_LOG_LEVEL_INFO, "*config: signal SIGUSR1");
-	nm_config_reload (config, SIGUSR1);
+	nm_config_reload (config, expected);
 
-	expected = NM_CONFIG_CHANGE_SIGUSR2;
+	expected = NM_CONFIG_CHANGE_CAUSE_SIGUSR2;
 	g_test_expect_message ("NetworkManager", G_LOG_LEVEL_INFO, "*config: signal SIGUSR2");
-	nm_config_reload (config, SIGUSR2);
+	nm_config_reload (config, expected);
 
-	expected = NM_CONFIG_CHANGE_SIGHUP;
+	expected = NM_CONFIG_CHANGE_CAUSE_SIGHUP;
 	g_test_expect_message ("NetworkManager", G_LOG_LEVEL_INFO, "*config: signal SIGHUP (no changes from disk)*");
-	nm_config_reload (config, SIGHUP);
+	nm_config_reload (config, expected);
 
 
 	/* test with subscribing two signals...
@@ -883,9 +883,9 @@ test_config_signal (void)
 	                  NM_CONFIG_SIGNAL_CONFIG_CHANGED,
 	                  G_CALLBACK (_test_signal_config_changed_cb2),
 	                  &expected);
-	expected = NM_CONFIG_CHANGE_SIGUSR2;
+	expected = NM_CONFIG_CHANGE_CAUSE_SIGUSR2;
 	g_test_expect_message ("NetworkManager", G_LOG_LEVEL_INFO, "*config: signal SIGUSR2");
-	nm_config_reload (config, SIGUSR2);
+	nm_config_reload (config, NM_CONFIG_CHANGE_CAUSE_SIGUSR2);
 	g_signal_handlers_disconnect_by_func (config, _test_signal_config_changed_cb2, &expected);
 
 
diff --git a/src/tests/test-general.c b/src/tests/test-general.c
index a45357e8..f714deec 100644
--- a/src/tests/test-general.c
+++ b/src/tests/test-general.c
@@ -1361,6 +1361,124 @@ test_duplicate_decl_specifier (void)
 	v_result[0] = TEST_MAX (v_const[0], nmtst_get_rand_int () % 5) + v2;
 }
 
+static void
+test_reverse_dns_ip4 (void)
+{
+	guint32 addr;
+	GPtrArray *domains = g_ptr_array_new_full (8, g_free);
+
+	inet_pton (AF_INET, "7.2.3.0", &addr);
+	nm_utils_get_reverse_dns_domains_ip4 (addr, 27, domains);
+	g_assert_cmpuint (domains->len, ==, 32);
+	g_assert_cmpstr (domains->pdata[0], ==, "0.3.2.7.in-addr.arpa");
+	g_assert_cmpstr (domains->pdata[31], ==, "31.3.2.7.in-addr.arpa");
+
+	g_ptr_array_set_size (domains, 0);
+
+	inet_pton (AF_INET, "10.155.16.0", &addr);
+	nm_utils_get_reverse_dns_domains_ip4 (addr, 22, domains);
+	g_assert_cmpuint (domains->len, ==, 4);
+	g_assert_cmpstr (domains->pdata[0], ==, "16.155.10.in-addr.arpa");
+	g_assert_cmpstr (domains->pdata[1], ==, "17.155.10.in-addr.arpa");
+	g_assert_cmpstr (domains->pdata[2], ==, "18.155.10.in-addr.arpa");
+	g_assert_cmpstr (domains->pdata[3], ==, "19.155.10.in-addr.arpa");
+
+	g_ptr_array_set_size (domains, 0);
+
+	inet_pton (AF_INET, "4.5.6.7", &addr);
+	nm_utils_get_reverse_dns_domains_ip4 (addr, 32, domains);
+	g_assert_cmpuint (domains->len, ==, 1);
+	g_assert_cmpstr (domains->pdata[0], ==, "7.6.5.4.in-addr.arpa");
+
+	g_ptr_array_set_size (domains, 0);
+
+	inet_pton (AF_INET, "4.5.6.7", &addr);
+	nm_utils_get_reverse_dns_domains_ip4 (addr, 8, domains);
+	g_assert_cmpuint (domains->len, ==, 1);
+	g_assert_cmpstr (domains->pdata[0], ==, "4.in-addr.arpa");
+
+	g_ptr_array_set_size (domains, 0);
+
+	inet_pton (AF_INET, "4.180.6.7", &addr);
+	nm_utils_get_reverse_dns_domains_ip4 (addr, 9, domains);
+	g_assert_cmpuint (domains->len, ==, 128);
+	g_assert_cmpstr (domains->pdata[0], ==, "128.4.in-addr.arpa");
+	g_assert_cmpstr (domains->pdata[1], ==, "129.4.in-addr.arpa");
+	g_assert_cmpstr (domains->pdata[127], ==, "255.4.in-addr.arpa");
+
+	g_ptr_array_set_size (domains, 0);
+
+	inet_pton (AF_INET, "172.16.0.0", &addr);
+	nm_utils_get_reverse_dns_domains_ip4 (addr, 12, domains);
+	g_assert_cmpuint (domains->len, ==, 16);
+	g_assert_cmpstr (domains->pdata[0],  ==, "16.172.in-addr.arpa");
+	g_assert_cmpstr (domains->pdata[1],  ==, "17.172.in-addr.arpa");
+	g_assert_cmpstr (domains->pdata[14], ==, "30.172.in-addr.arpa");
+	g_assert_cmpstr (domains->pdata[15], ==, "31.172.in-addr.arpa");
+
+	g_ptr_array_set_size (domains, 0);
+
+	inet_pton (AF_INET, "1.2.3.4", &addr);
+	nm_utils_get_reverse_dns_domains_ip4 (addr, 0, domains);
+	g_assert_cmpuint (domains->len, ==, 0);
+
+	g_ptr_array_unref (domains);
+}
+
+static void
+test_reverse_dns_ip6 (void)
+{
+	struct in6_addr addr;
+	GPtrArray *domains = g_ptr_array_new_full (8, g_free);
+
+	inet_pton (AF_INET6, "1234::56", &addr);
+	nm_utils_get_reverse_dns_domains_ip6 (&addr, 16, domains);
+	g_assert_cmpuint (domains->len, ==, 1);
+	g_assert_cmpstr (domains->pdata[0], ==, "4.3.2.1.ip6.arpa");
+
+	g_ptr_array_set_size (domains, 0);
+
+	inet_pton (AF_INET6, "1234::56", &addr);
+	nm_utils_get_reverse_dns_domains_ip6 (&addr, 17, domains);
+	g_assert_cmpuint (domains->len, ==, 8);
+	g_assert_cmpstr (domains->pdata[0], ==, "0.4.3.2.1.ip6.arpa");
+	g_assert_cmpstr (domains->pdata[1], ==, "1.4.3.2.1.ip6.arpa");
+	g_assert_cmpstr (domains->pdata[7], ==, "7.4.3.2.1.ip6.arpa");
+
+	g_ptr_array_set_size (domains, 0);
+
+	inet_pton (AF_INET6, "2001:db8::", &addr);
+	nm_utils_get_reverse_dns_domains_ip6 (&addr, 29, domains);
+	g_assert_cmpuint (domains->len, ==, 8);
+	g_assert_cmpstr (domains->pdata[0], ==, "8.b.d.0.1.0.0.2.ip6.arpa");
+	g_assert_cmpstr (domains->pdata[1], ==, "9.b.d.0.1.0.0.2.ip6.arpa");
+	g_assert_cmpstr (domains->pdata[7], ==, "f.b.d.0.1.0.0.2.ip6.arpa");
+
+	g_ptr_array_set_size (domains, 0);
+
+	inet_pton (AF_INET6, "0123:4567:89ab:cdef::", &addr);
+	nm_utils_get_reverse_dns_domains_ip6 (&addr, 63, domains);
+	g_assert_cmpuint (domains->len, ==, 2);
+	g_assert_cmpstr (domains->pdata[0], ==, "e.e.d.c.b.a.9.8.7.6.5.4.3.2.1.0.ip6.arpa");
+	g_assert_cmpstr (domains->pdata[1], ==, "f.e.d.c.b.a.9.8.7.6.5.4.3.2.1.0.ip6.arpa");
+
+	g_ptr_array_set_size (domains, 0);
+
+	inet_pton (AF_INET6, "fec0:1234:5678:9ab0::", &addr);
+	nm_utils_get_reverse_dns_domains_ip6 (&addr, 61, domains);
+	g_assert_cmpuint (domains->len, ==, 8);
+	g_assert_cmpstr (domains->pdata[0], ==, "0.b.a.9.8.7.6.5.4.3.2.1.0.c.e.f.ip6.arpa");
+	g_assert_cmpstr (domains->pdata[7], ==, "7.b.a.9.8.7.6.5.4.3.2.1.0.c.e.f.ip6.arpa");
+
+	g_ptr_array_set_size (domains, 0);
+
+	inet_pton (AF_INET6, "0123:4567:89ab:cdee::", &addr);
+	nm_utils_get_reverse_dns_domains_ip6 (&addr, 0, domains);
+	g_assert_cmpuint (domains->len, ==, 0);
+
+	g_ptr_array_unref (domains);
+}
+
 /*****************************************************************************/
 
 NMTST_DEFINE ();
@@ -1397,6 +1515,9 @@ main (int argc, char **argv)
 	g_test_add_func ("/general/nm_match_spec_match_config", test_nm_match_spec_match_config);
 	g_test_add_func ("/general/duplicate_decl_specifier", test_duplicate_decl_specifier);
 
+	g_test_add_func ("/general/reverse_dns/ip4", test_reverse_dns_ip4);
+	g_test_add_func ("/general/reverse_dns/ip6", test_reverse_dns_ip6);
+
 	return g_test_run ();
 }
 
diff --git a/src/vpn-manager/nm-vpn-connection.c b/src/vpn-manager/nm-vpn-connection.c
index a1cd0c32..cb8474aa 100644
--- a/src/vpn-manager/nm-vpn-connection.c
+++ b/src/vpn-manager/nm-vpn-connection.c
@@ -44,6 +44,7 @@
 #include "nm-config.h"
 #include "nm-vpn-plugin-info.h"
 #include "nm-vpn-manager.h"
+#include "nm-dns-manager.h"
 
 #include "nmdbus-vpn-connection.h"
 
@@ -192,14 +193,14 @@ __LOG_create_prefix (char *buf, NMVpnConnection *self)
 	            "%s%s"     /*con-uuid*/
 	            "%s%s%s%s" /*con-id*/
 	            ",%d"      /*ifindex*/
-	            "%s%s%s%s" /*iface*/
+	            "%s%s%s" /*iface*/
 	            "]",
 	            _NMLOG_PREFIX_NAME,
 	            self,
 	            con ? "," : "--", con ? (nm_connection_get_uuid (con) ?: "??") : "",
 	            con ? "," : "", NM_PRINT_FMT_QUOTED (id, "\"", id, "\"", con ? "??" : ""),
 	            priv->ip_ifindex,
-	            priv->ip_iface ? ":" : "", NM_PRINT_FMT_QUOTED (priv->ip_iface, "(", priv->ip_iface, ")", "")
+	            NM_PRINT_FMT_QUOTED (priv->ip_iface, ":(", priv->ip_iface, ")", "")
 	            );
 
 	return buf;
@@ -909,7 +910,7 @@ print_vpn_config (NMVpnConnection *self)
 		       nm_utils_inet6_ntop (priv->ip6_external_gw, NULL));
 	}
 
-	_LOGI ("Data: Tunnel Device: %s", priv->ip_iface ? priv->ip_iface : "(none)");
+	_LOGI ("Data: Tunnel Device: %s%s%s", NM_PRINT_FMT_QUOTE_STRING (priv->ip_iface));
 
 	if (priv->ip4_config) {
 		_LOGI ("Data: IPv4 configuration:");
@@ -1022,12 +1023,11 @@ apply_parent_device_config (NMVpnConnection *self)
 		ifindex = nm_device_get_ip_ifindex (parent_dev);
 		if (priv->ip4_config) {
 			vpn4_parent_config = nm_ip4_config_new (ifindex);
-			nm_ip4_config_merge (vpn4_parent_config, priv->ip4_config, NM_IP_CONFIG_MERGE_DEFAULT);
-			nm_ip4_config_unset_gateway (vpn4_parent_config);
+			nm_ip4_config_merge (vpn4_parent_config, priv->ip4_config, NM_IP_CONFIG_MERGE_NO_DNS);
 		}
 		if (priv->ip6_config) {
 			vpn6_parent_config = nm_ip6_config_new (ifindex);
-			nm_ip6_config_merge (vpn6_parent_config, priv->ip6_config, NM_IP_CONFIG_MERGE_DEFAULT);
+			nm_ip6_config_merge (vpn6_parent_config, priv->ip6_config, NM_IP_CONFIG_MERGE_NO_DNS);
 			nm_ip6_config_set_gateway (vpn6_parent_config, NULL);
 		}
 	}
@@ -1079,7 +1079,8 @@ nm_vpn_connection_apply_config (NMVpnConnection *self)
 	nm_default_route_manager_ip6_update_default_route (priv->default_route_manager, self);
 
 	_LOGI ("VPN connection: (IP Config Get) complete");
-	_set_vpn_state (self, STATE_PRE_UP, NM_VPN_CONNECTION_STATE_REASON_NONE, FALSE);
+	if (priv->vpn_state < STATE_PRE_UP)
+		_set_vpn_state (self, STATE_PRE_UP, NM_VPN_CONNECTION_STATE_REASON_NONE, FALSE);
 	return TRUE;
 }
 
@@ -1218,6 +1219,8 @@ process_generic_config (NMVpnConnection *self, GVariant *dict)
 	}
 
 	g_clear_pointer (&priv->ip_iface, g_free);
+	priv->ip_ifindex = 0;
+
 	if (g_variant_lookup (dict, NM_VPN_PLUGIN_CONFIG_TUNDEV, "&s", &str)) {
 		/* Backwards compat with NM-openswan */
 		if (g_strcmp0 (str, "_none_") != 0)
@@ -1228,7 +1231,13 @@ process_generic_config (NMVpnConnection *self, GVariant *dict)
 		/* Grab the interface index for address/routing operations */
 		priv->ip_ifindex = nm_platform_link_get_ifindex (NM_PLATFORM_GET, priv->ip_iface);
 		if (priv->ip_ifindex <= 0) {
+			nm_platform_process_events (NM_PLATFORM_GET);
+			priv->ip_ifindex = nm_platform_link_get_ifindex (NM_PLATFORM_GET, priv->ip_iface);
+		}
+		if (priv->ip_ifindex <= 0) {
 			_LOGE ("failed to look up VPN interface index for \"%s\"", priv->ip_iface);
+			g_clear_pointer (&priv->ip_iface, g_free);
+			priv->ip_ifindex = 0;
 			nm_vpn_connection_config_maybe_complete (self, FALSE);
 			return FALSE;
 		}
@@ -1329,7 +1338,6 @@ nm_vpn_connection_ip4_config_get (NMVpnConnection *self, GVariant *dict)
 	const char *str;
 	GVariant *v;
 	gboolean b;
-	int ifindex;
 
 	g_return_if_fail (dict && g_variant_is_of_type (dict, G_VARIANT_TYPE_VARDICT));
 
@@ -1357,13 +1365,8 @@ nm_vpn_connection_ip4_config_get (NMVpnConnection *self, GVariant *dict)
 		priv->has_ip6 = FALSE;
 	}
 
-	if (priv->ip_ifindex > 0) {
-		ifindex = priv->ip_ifindex;
-	} else {
-		NMDevice *parent_dev = nm_active_connection_get_device (NM_ACTIVE_CONNECTION (self));
-		ifindex = nm_device_get_ip_ifindex (parent_dev);
-	}
-	config = nm_ip4_config_new (ifindex);
+	config = nm_ip4_config_new (nm_vpn_connection_get_ip_ifindex (self, TRUE));
+	nm_ip4_config_set_dns_priority (config, NM_DNS_PRIORITY_DEFAULT_VPN);
 
 	memset (&address, 0, sizeof (address));
 	address.plen = 24;
@@ -1464,10 +1467,15 @@ nm_vpn_connection_ip4_config_get (NMVpnConnection *self, GVariant *dict)
 	                             nm_connection_get_setting_ip4_config (_get_applied_connection (self)),
 	                             route_metric);
 
-	nm_exported_object_clear_and_unexport (&priv->ip4_config);
-	priv->ip4_config = config;
-	nm_exported_object_export (NM_EXPORTED_OBJECT (config));
-	g_object_notify (G_OBJECT (self), NM_ACTIVE_CONNECTION_IP4_CONFIG);
+	if (priv->ip4_config) {
+		nm_ip4_config_replace (priv->ip4_config, config, NULL);
+		g_object_unref (config);
+	} else {
+		priv->ip4_config = config;
+		nm_exported_object_export (NM_EXPORTED_OBJECT (config));
+		g_object_notify (G_OBJECT (self), NM_ACTIVE_CONNECTION_IP4_CONFIG);
+	}
+
 	nm_vpn_connection_config_maybe_complete (self, TRUE);
 }
 
@@ -1497,6 +1505,7 @@ nm_vpn_connection_ip6_config_get (NMVpnConnection *self, GVariant *dict)
 	}
 
 	config = nm_ip6_config_new (priv->ip_ifindex);
+	nm_ip6_config_set_dns_priority (config, NM_DNS_PRIORITY_DEFAULT_VPN);
 
 	memset (&address, 0, sizeof (address));
 	address.plen = 128;
@@ -1600,10 +1609,15 @@ next:
 	                             nm_connection_get_setting_ip6_config (_get_applied_connection (self)),
 	                             route_metric);
 
-	nm_exported_object_clear_and_unexport (&priv->ip6_config);
-	priv->ip6_config = config;
-	nm_exported_object_export (NM_EXPORTED_OBJECT (config));
-	g_object_notify (G_OBJECT (self), NM_ACTIVE_CONNECTION_IP6_CONFIG);
+	if (priv->ip6_config) {
+		nm_ip6_config_replace (priv->ip6_config, config, NULL);
+		g_object_unref (config);
+	} else {
+		priv->ip6_config = config;
+		nm_exported_object_export (NM_EXPORTED_OBJECT (config));
+		g_object_notify (G_OBJECT (self), NM_ACTIVE_CONNECTION_IP6_CONFIG);
+	}
+
 	nm_vpn_connection_config_maybe_complete (self, TRUE);
 }
 
@@ -1916,9 +1930,6 @@ _daemon_exec_timeout (gpointer data)
 	_LOGW ("Timed out waiting for the service to start");
 	priv->start_timeout = 0;
 	nm_vpn_connection_disconnect (self, NM_VPN_CONNECTION_STATE_REASON_SERVICE_START_TIMEOUT, FALSE);
-
-	g_object_unref (self);
-
 	return G_SOURCE_REMOVE;
 }
 
@@ -2085,20 +2096,67 @@ nm_vpn_connection_get_ip6_config (NMVpnConnection *self)
 	return NM_VPN_CONNECTION_GET_PRIVATE (self)->ip6_config;
 }
 
+static int
+_get_ip_iface_for_device (NMVpnConnection *self, const char **out_iface)
+{
+	NMDevice *parent_dev;
+	int ifindex;
+	const char *iface;
+
+	nm_assert (NM_IS_VPN_CONNECTION (self));
+
+	/* the ifindex and the ifname in this case should come together.
+	 * They either must be both set, or none. */
+
+	parent_dev = nm_active_connection_get_device (NM_ACTIVE_CONNECTION (self));
+	if (!parent_dev)
+		goto none;
+	ifindex = nm_device_get_ip_ifindex (parent_dev);
+	if (ifindex <= 0)
+		goto none;
+	iface = nm_device_get_ip_iface (parent_dev);
+	if (!iface)
+		goto none;
+
+	NM_SET_OUT (out_iface, iface);
+	return ifindex;
+none:
+	NM_SET_OUT (out_iface, NULL);
+	return 0;
+}
+
 const char *
-nm_vpn_connection_get_ip_iface (NMVpnConnection *self)
+nm_vpn_connection_get_ip_iface (NMVpnConnection *self, gboolean fallback_device)
 {
+	NMVpnConnectionPrivate *priv;
+	const char *iface;
+
 	g_return_val_if_fail (NM_IS_VPN_CONNECTION (self), NULL);
 
-	return NM_VPN_CONNECTION_GET_PRIVATE (self)->ip_iface;
+	priv = NM_VPN_CONNECTION_GET_PRIVATE (self);
+
+	if (priv->ip_iface || !fallback_device)
+		return priv->ip_iface;
+
+	_get_ip_iface_for_device (self, &iface);
+	return iface;
 }
 
 int
-nm_vpn_connection_get_ip_ifindex (NMVpnConnection *self)
+nm_vpn_connection_get_ip_ifindex (NMVpnConnection *self, gboolean fallback_device)
 {
-	g_return_val_if_fail (NM_IS_VPN_CONNECTION (self), -1);
+	NMVpnConnectionPrivate *priv;
+
+	g_return_val_if_fail (NM_IS_VPN_CONNECTION (self), 0);
+
+	priv = NM_VPN_CONNECTION_GET_PRIVATE (self);
+
+	if (priv->ip_ifindex > 0)
+		return priv->ip_ifindex;
+	if (!fallback_device)
+		return 0;
 
-	return NM_VPN_CONNECTION_GET_PRIVATE (self)->ip_ifindex;
+	return _get_ip_iface_for_device (self, NULL);
 }
 
 guint32
diff --git a/src/vpn-manager/nm-vpn-connection.h b/src/vpn-manager/nm-vpn-connection.h
index 19b0eb3f..68374329 100644
--- a/src/vpn-manager/nm-vpn-connection.h
+++ b/src/vpn-manager/nm-vpn-connection.h
@@ -91,8 +91,8 @@ void                 nm_vpn_connection_disconnect      (NMVpnConnection *self,
 
 NMIP4Config *        nm_vpn_connection_get_ip4_config  (NMVpnConnection *self);
 NMIP6Config *        nm_vpn_connection_get_ip6_config  (NMVpnConnection *self);
-const char *         nm_vpn_connection_get_ip_iface    (NMVpnConnection *self);
-int                  nm_vpn_connection_get_ip_ifindex  (NMVpnConnection *self);
+const char *         nm_vpn_connection_get_ip_iface    (NMVpnConnection *self, gboolean fallback_device);
+int                  nm_vpn_connection_get_ip_ifindex  (NMVpnConnection *self, gboolean fallback_device);
 guint32              nm_vpn_connection_get_ip4_internal_gateway (NMVpnConnection *self);
 struct in6_addr *    nm_vpn_connection_get_ip6_internal_gateway (NMVpnConnection *self);