summary refs log tree commit diff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/Makefile.am12
-rw-r--r--src/Makefile.in149
-rw-r--r--src/NetworkManagerUtils.c25
-rw-r--r--src/bluez-manager/Makefile.in17
-rw-r--r--src/dhcp-manager/Makefile.am1
-rw-r--r--src/dhcp-manager/Makefile.in18
-rw-r--r--src/dhcp-manager/nm-dhcp-client.c141
-rw-r--r--src/dhcp-manager/nm-dhcp-client.h18
-rw-r--r--src/dhcp-manager/nm-dhcp-dhclient-utils.c163
-rw-r--r--src/dhcp-manager/nm-dhcp-dhclient-utils.h10
-rw-r--r--src/dhcp-manager/nm-dhcp-dhclient.c77
-rw-r--r--src/dhcp-manager/nm-dhcp-dhcpcd.c7
-rw-r--r--src/dhcp-manager/nm-dhcp-manager.c11
-rw-r--r--src/dhcp-manager/nm-dhcp-manager.h2
-rw-r--r--src/dhcp-manager/tests/Makefile.am8
-rw-r--r--src/dhcp-manager/tests/Makefile.in24
-rw-r--r--src/dhcp-manager/tests/test-dhclient-commented-duid.leases2
-rw-r--r--src/dhcp-manager/tests/test-dhclient-duid.leases2
-rw-r--r--src/dhcp-manager/tests/test-dhcp-dhclient.c176
-rw-r--r--src/dns-manager/Makefile.in17
-rw-r--r--src/dns-manager/nm-dns-dnsmasq.c17
-rw-r--r--src/dns-manager/nm-dns-manager.c115
-rw-r--r--src/dns-manager/nm-dns-manager.h8
-rw-r--r--src/dns-manager/nm-dns-plugin.c6
-rw-r--r--src/dns-manager/nm-dns-plugin.h8
-rw-r--r--src/dnsmasq-manager/Makefile.in17
-rw-r--r--src/firewall-manager/Makefile.in17
-rw-r--r--src/generated/Makefile.in17
-rw-r--r--src/generated/nm-enum-types.c5
-rw-r--r--src/ip6-manager/Makefile.in17
-rw-r--r--src/ip6-manager/nm-ip6-manager.c56
-rw-r--r--src/ip6-manager/nm-ip6-manager.h2
-rw-r--r--src/logging/Makefile.in17
-rw-r--r--src/logging/nm-logging.c99
-rw-r--r--src/logging/nm-logging.h6
-rw-r--r--src/main.c29
-rw-r--r--src/modem-manager/Makefile.in17
-rw-r--r--src/modem-manager/nm-modem-cdma.c13
-rw-r--r--src/modem-manager/nm-modem-gsm.c13
-rw-r--r--src/modem-manager/nm-modem-manager.c203
-rw-r--r--src/nm-crash-logger.c87
-rw-r--r--src/nm-device-adsl.c34
-rw-r--r--src/nm-device-bond.c207
-rw-r--r--src/nm-device-bridge.c208
-rw-r--r--src/nm-device-bt.c30
-rw-r--r--src/nm-device-bt.h2
-rw-r--r--src/nm-device-ethernet.c109
-rw-r--r--src/nm-device-infiniband.c74
-rw-r--r--src/nm-device-modem.c18
-rw-r--r--src/nm-device-olpc-mesh.c96
-rw-r--r--src/nm-device-private.h9
-rw-r--r--src/nm-device-vlan.c68
-rw-r--r--src/nm-device-wifi.c98
-rw-r--r--src/nm-device-wifi.h2
-rw-r--r--src/nm-device-wired.c235
-rw-r--r--src/nm-device-wired.h8
-rw-r--r--src/nm-device.c404
-rw-r--r--src/nm-device.h8
-rw-r--r--src/nm-manager.c208
-rw-r--r--src/nm-manager.h1
-rw-r--r--src/nm-netlink-compat.c159
-rw-r--r--src/nm-netlink-compat.h249
-rw-r--r--src/nm-netlink-monitor.c24
-rw-r--r--src/nm-netlink-monitor.h4
-rw-r--r--src/nm-netlink-utils.c4
-rw-r--r--src/nm-netlink-utils.h3
-rw-r--r--src/nm-policy.c8
-rw-r--r--src/nm-system.c65
-rw-r--r--src/nm-system.h2
-rw-r--r--src/posix-signals/Makefile.in17
-rw-r--r--src/ppp-manager/Makefile.in17
-rw-r--r--src/settings/Makefile.in17
-rw-r--r--src/settings/nm-settings.c16
-rw-r--r--src/settings/plugins/Makefile.in17
-rw-r--r--src/settings/plugins/example/Makefile.in17
-rw-r--r--src/settings/plugins/ifcfg-rh/Makefile.in17
-rw-r--r--src/settings/plugins/ifcfg-rh/tests/Makefile.in17
-rw-r--r--src/settings/plugins/ifcfg-rh/tests/network-scripts/Makefile.in17
-rw-r--r--src/settings/plugins/ifcfg-suse/Makefile.in17
-rw-r--r--src/settings/plugins/ifnet/Makefile.in17
-rw-r--r--src/settings/plugins/ifnet/tests/Makefile.in17
-rw-r--r--src/settings/plugins/ifupdown/Makefile.in17
-rw-r--r--src/settings/plugins/ifupdown/tests/Makefile.in17
-rw-r--r--src/settings/plugins/keyfile/Makefile.in17
-rw-r--r--src/settings/plugins/keyfile/tests/Makefile.in17
-rw-r--r--src/settings/plugins/keyfile/tests/keyfiles/Makefile.in17
-rw-r--r--src/settings/tests/Makefile.in17
-rw-r--r--src/supplicant-manager/Makefile.in17
-rw-r--r--src/supplicant-manager/nm-supplicant-manager.c2
-rw-r--r--src/supplicant-manager/tests/Makefile.in17
-rw-r--r--src/tests/Makefile.in17
-rw-r--r--src/vpn-manager/Makefile.in17
-rw-r--r--src/vpn-manager/nm-vpn-connection.c3
-rw-r--r--src/wifi/Makefile.in17
-rw-r--r--src/wifi/wifi-utils-nl80211.c4
-rw-r--r--src/wimax/Makefile.in17
-rw-r--r--src/wimax/nm-device-wimax.c85
-rw-r--r--src/wimax/nm-device-wimax.h3
98 files changed, 2150 insertions, 2340 deletions
diff --git a/src/Makefile.am b/src/Makefile.am
index db11d6b7..cd124f6b 100644
--- a/src/Makefile.am
+++ b/src/Makefile.am
@@ -355,18 +355,6 @@ endif
 
 NetworkManager_LDFLAGS = -rdynamic
 
-libexec_PROGRAMS = nm-crash-logger
-nm_crash_logger_SOURCES = nm-crash-logger.c
-nm_crash_logger_CPPFLAGS = \
-	$(GLIB_CFLAGS) \
-	-DBINDIR=\"$(bindir)\" \
-	-DNMBINARY=\"$(nmbinary)\" \
-	-DNMDATADIR=\"$(nmdatadir)\" \
-	-DSYSCONFDIR=\"$(sysconfdir)\" \
-	-DNMSTATEDIR=\"$(nmstatedir)\"
-nm_crash_logger_LDADD = $(GLIB_LIBS)
-
-
 NetworkManagerdir = $(datadir)/NetworkManager
 NetworkManager_DATA = gdb-cmd
 
diff --git a/src/Makefile.in b/src/Makefile.in
index 0011a0d3..0a7e87f9 100644
--- a/src/Makefile.in
+++ b/src/Makefile.in
@@ -65,7 +65,6 @@ sbin_PROGRAMS = NetworkManager$(EXEEXT)
 @WITH_CONCHECK_TRUE@am__append_8 = $(LIBSOUP_CFLAGS)
 @SESSION_TRACKING_CK_TRUE@am__append_9 = -DCKDB_PATH=\"${CKDB_PATH}\"
 @WITH_CONCHECK_TRUE@am__append_10 = $(LIBSOUP_LIBS)
-libexec_PROGRAMS = nm-crash-logger$(EXEEXT)
 subdir = src
 DIST_COMMON = $(srcdir)/Makefile.am $(srcdir)/Makefile.in
 ACLOCAL_M4 = $(top_srcdir)/aclocal.m4
@@ -76,12 +75,11 @@ am__aclocal_m4_deps = $(top_srcdir)/m4/compiler_warnings.m4 \
 	$(top_srcdir)/m4/intlmacosx.m4 $(top_srcdir)/m4/intltool.m4 \
 	$(top_srcdir)/m4/introspection.m4 $(top_srcdir)/m4/lib-ld.m4 \
 	$(top_srcdir)/m4/lib-link.m4 $(top_srcdir)/m4/lib-prefix.m4 \
-	$(top_srcdir)/m4/libnl-check.m4 $(top_srcdir)/m4/libtool.m4 \
-	$(top_srcdir)/m4/ltoptions.m4 $(top_srcdir)/m4/ltsugar.m4 \
-	$(top_srcdir)/m4/ltversion.m4 $(top_srcdir)/m4/lt~obsolete.m4 \
-	$(top_srcdir)/m4/nls.m4 $(top_srcdir)/m4/po.m4 \
-	$(top_srcdir)/m4/progtest.m4 $(top_srcdir)/m4/vapigen.m4 \
-	$(top_srcdir)/configure.ac
+	$(top_srcdir)/m4/libtool.m4 $(top_srcdir)/m4/ltoptions.m4 \
+	$(top_srcdir)/m4/ltsugar.m4 $(top_srcdir)/m4/ltversion.m4 \
+	$(top_srcdir)/m4/lt~obsolete.m4 $(top_srcdir)/m4/nls.m4 \
+	$(top_srcdir)/m4/po.m4 $(top_srcdir)/m4/progtest.m4 \
+	$(top_srcdir)/m4/vapigen.m4 $(top_srcdir)/configure.ac
 am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \
 	$(ACLOCAL_M4)
 mkinstalldirs = $(install_sh) -d
@@ -115,9 +113,9 @@ am_libtest_wifi_ap_utils_la_OBJECTS =  \
 	libtest_wifi_ap_utils_la-nm-wifi-ap-utils.lo
 libtest_wifi_ap_utils_la_OBJECTS =  \
 	$(am_libtest_wifi_ap_utils_la_OBJECTS)
-am__installdirs = "$(DESTDIR)$(libexecdir)" "$(DESTDIR)$(sbindir)" \
+am__installdirs = "$(DESTDIR)$(sbindir)" \
 	"$(DESTDIR)$(NetworkManagerdir)" "$(DESTDIR)$(dbusservicedir)"
-PROGRAMS = $(libexec_PROGRAMS) $(sbin_PROGRAMS)
+PROGRAMS = $(sbin_PROGRAMS)
 am__NetworkManager_SOURCES_DIST = nm-types.h nm-call-store.c \
 	nm-call-store.h nm-device.c nm-device.h nm-device-private.h \
 	nm-device-ethernet.c nm-device-ethernet.h nm-device-adsl.c \
@@ -224,10 +222,6 @@ NetworkManager_LINK = $(LIBTOOL) $(AM_V_lt) --tag=CC \
 	$(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=link $(CCLD) \
 	$(AM_CFLAGS) $(CFLAGS) $(NetworkManager_LDFLAGS) $(LDFLAGS) -o \
 	$@
-am_nm_crash_logger_OBJECTS =  \
-	nm_crash_logger-nm-crash-logger.$(OBJEXT)
-nm_crash_logger_OBJECTS = $(am_nm_crash_logger_OBJECTS)
-nm_crash_logger_DEPENDENCIES = $(am__DEPENDENCIES_1)
 DEFAULT_INCLUDES = -I.@am__isrc@ -I$(top_builddir)
 depcomp = $(SHELL) $(top_srcdir)/build-aux/depcomp
 am__depfiles_maybe = depfiles
@@ -256,12 +250,11 @@ am__v_GEN_ = $(am__v_GEN_@AM_DEFAULT_V@)
 am__v_GEN_0 = @echo "  GEN   " $@;
 SOURCES = $(libtest_dhcp_la_SOURCES) \
 	$(libtest_policy_hosts_la_SOURCES) \
-	$(libtest_wifi_ap_utils_la_SOURCES) $(NetworkManager_SOURCES) \
-	$(nm_crash_logger_SOURCES)
+	$(libtest_wifi_ap_utils_la_SOURCES) $(NetworkManager_SOURCES)
 DIST_SOURCES = $(libtest_dhcp_la_SOURCES) \
 	$(libtest_policy_hosts_la_SOURCES) \
 	$(libtest_wifi_ap_utils_la_SOURCES) \
-	$(am__NetworkManager_SOURCES_DIST) $(nm_crash_logger_SOURCES)
+	$(am__NetworkManager_SOURCES_DIST)
 RECURSIVE_TARGETS = all-recursive check-recursive dvi-recursive \
 	html-recursive info-recursive install-data-recursive \
 	install-dvi-recursive install-exec-recursive \
@@ -437,12 +430,6 @@ LIBGCRYPT_LIBS = @LIBGCRYPT_LIBS@
 LIBICONV = @LIBICONV@
 LIBINTL = @LIBINTL@
 LIBM = @LIBM@
-LIBNL1_CFLAGS = @LIBNL1_CFLAGS@
-LIBNL1_LIBS = @LIBNL1_LIBS@
-LIBNL2_CFLAGS = @LIBNL2_CFLAGS@
-LIBNL2_LIBS = @LIBNL2_LIBS@
-LIBNL3_CFLAGS = @LIBNL3_CFLAGS@
-LIBNL3_LIBS = @LIBNL3_LIBS@
 LIBNL_CFLAGS = @LIBNL_CFLAGS@
 LIBNL_LIBS = @LIBNL_LIBS@
 LIBOBJS = @LIBOBJS@
@@ -748,16 +735,6 @@ NetworkManager_LDADD = ./generated/libnm-generated.la \
 	$(GLIB_LIBS) $(GUDEV_LIBS) $(LIBNL_LIBS) $(POLKIT_LIBS) \
 	$(SYSTEMD_LOGIN_LIBS) $(LIBM) $(LIBDL) $(am__append_10)
 NetworkManager_LDFLAGS = -rdynamic
-nm_crash_logger_SOURCES = nm-crash-logger.c
-nm_crash_logger_CPPFLAGS = \
-	$(GLIB_CFLAGS) \
-	-DBINDIR=\"$(bindir)\" \
-	-DNMBINARY=\"$(nmbinary)\" \
-	-DNMDATADIR=\"$(nmdatadir)\" \
-	-DSYSCONFDIR=\"$(sysconfdir)\" \
-	-DNMSTATEDIR=\"$(nmstatedir)\"
-
-nm_crash_logger_LDADD = $(GLIB_LIBS)
 NetworkManagerdir = $(datadir)/NetworkManager
 NetworkManager_DATA = gdb-cmd
 dbusservicedir = $(DBUS_SYS_DIR)
@@ -819,52 +796,6 @@ libtest-policy-hosts.la: $(libtest_policy_hosts_la_OBJECTS) $(libtest_policy_hos
 	$(AM_V_CCLD)$(LINK)  $(libtest_policy_hosts_la_OBJECTS) $(libtest_policy_hosts_la_LIBADD) $(LIBS)
 libtest-wifi-ap-utils.la: $(libtest_wifi_ap_utils_la_OBJECTS) $(libtest_wifi_ap_utils_la_DEPENDENCIES) $(EXTRA_libtest_wifi_ap_utils_la_DEPENDENCIES) 
 	$(AM_V_CCLD)$(LINK)  $(libtest_wifi_ap_utils_la_OBJECTS) $(libtest_wifi_ap_utils_la_LIBADD) $(LIBS)
-install-libexecPROGRAMS: $(libexec_PROGRAMS)
-	@$(NORMAL_INSTALL)
-	@list='$(libexec_PROGRAMS)'; test -n "$(libexecdir)" || list=; \
-	if test -n "$$list"; then \
-	  echo " $(MKDIR_P) '$(DESTDIR)$(libexecdir)'"; \
-	  $(MKDIR_P) "$(DESTDIR)$(libexecdir)" || exit 1; \
-	fi; \
-	for p in $$list; do echo "$$p $$p"; done | \
-	sed 's/$(EXEEXT)$$//' | \
-	while read p p1; do if test -f $$p || test -f $$p1; \
-	  then echo "$$p"; echo "$$p"; else :; fi; \
-	done | \
-	sed -e 'p;s,.*/,,;n;h' -e 's|.*|.|' \
-	    -e 'p;x;s,.*/,,;s/$(EXEEXT)$$//;$(transform);s/$$/$(EXEEXT)/' | \
-	sed 'N;N;N;s,\n, ,g' | \
-	$(AWK) 'BEGIN { files["."] = ""; dirs["."] = 1 } \
-	  { d=$$3; if (dirs[d] != 1) { print "d", d; dirs[d] = 1 } \
-	    if ($$2 == $$4) files[d] = files[d] " " $$1; \
-	    else { print "f", $$3 "/" $$4, $$1; } } \
-	  END { for (d in files) print "f", d, files[d] }' | \
-	while read type dir files; do \
-	    if test "$$dir" = .; then dir=; else dir=/$$dir; fi; \
-	    test -z "$$files" || { \
-	    echo " $(INSTALL_PROGRAM_ENV) $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=install $(INSTALL_PROGRAM) $$files '$(DESTDIR)$(libexecdir)$$dir'"; \
-	    $(INSTALL_PROGRAM_ENV) $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=install $(INSTALL_PROGRAM) $$files "$(DESTDIR)$(libexecdir)$$dir" || exit $$?; \
-	    } \
-	; done
-
-uninstall-libexecPROGRAMS:
-	@$(NORMAL_UNINSTALL)
-	@list='$(libexec_PROGRAMS)'; test -n "$(libexecdir)" || list=; \
-	files=`for p in $$list; do echo "$$p"; done | \
-	  sed -e 'h;s,^.*/,,;s/$(EXEEXT)$$//;$(transform)' \
-	      -e 's/$$/$(EXEEXT)/' `; \
-	test -n "$$list" || exit 0; \
-	echo " ( cd '$(DESTDIR)$(libexecdir)' && rm -f" $$files ")"; \
-	cd "$(DESTDIR)$(libexecdir)" && rm -f $$files
-
-clean-libexecPROGRAMS:
-	@list='$(libexec_PROGRAMS)'; test -n "$$list" || exit 0; \
-	echo " rm -f" $$list; \
-	rm -f $$list || exit $$?; \
-	test -n "$(EXEEXT)" || exit 0; \
-	list=`for p in $$list; do echo "$$p"; done | sed 's/$(EXEEXT)$$//'`; \
-	echo " rm -f" $$list; \
-	rm -f $$list
 install-sbinPROGRAMS: $(sbin_PROGRAMS)
 	@$(NORMAL_INSTALL)
 	@list='$(sbin_PROGRAMS)'; test -n "$(sbindir)" || list=; \
@@ -914,9 +845,6 @@ clean-sbinPROGRAMS:
 NetworkManager$(EXEEXT): $(NetworkManager_OBJECTS) $(NetworkManager_DEPENDENCIES) $(EXTRA_NetworkManager_DEPENDENCIES) 
 	@rm -f NetworkManager$(EXEEXT)
 	$(AM_V_CCLD)$(NetworkManager_LINK) $(NetworkManager_OBJECTS) $(NetworkManager_LDADD) $(LIBS)
-nm-crash-logger$(EXEEXT): $(nm_crash_logger_OBJECTS) $(nm_crash_logger_DEPENDENCIES) $(EXTRA_nm_crash_logger_DEPENDENCIES) 
-	@rm -f nm-crash-logger$(EXEEXT)
-	$(AM_V_CCLD)$(LINK) $(nm_crash_logger_OBJECTS) $(nm_crash_logger_LDADD) $(LIBS)
 
 mostlyclean-compile:
 	-rm -f *.$(OBJEXT)
@@ -976,7 +904,6 @@ distclean-compile:
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libtest_dhcp_la-nm-ip6-config.Plo@am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libtest_policy_hosts_la-nm-policy-hosts.Plo@am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libtest_wifi_ap_utils_la-nm-wifi-ap-utils.Plo@am__quote@
-@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/nm_crash_logger-nm-crash-logger.Po@am__quote@
 
 .c.o:
 @am__fastdepCC_TRUE@	$(AM_V_CC)$(COMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $<
@@ -1685,20 +1612,6 @@ NetworkManager-nm-sleep-monitor-upower.obj: nm-sleep-monitor-upower.c
 @AMDEP_TRUE@@am__fastdepCC_FALSE@	DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
 @am__fastdepCC_FALSE@	$(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(NetworkManager_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o NetworkManager-nm-sleep-monitor-upower.obj `if test -f 'nm-sleep-monitor-upower.c'; then $(CYGPATH_W) 'nm-sleep-monitor-upower.c'; else $(CYGPATH_W) '$(srcdir)/nm-sleep-monitor-upower.c'; fi`
 
-nm_crash_logger-nm-crash-logger.o: nm-crash-logger.c
-@am__fastdepCC_TRUE@	$(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(nm_crash_logger_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT nm_crash_logger-nm-crash-logger.o -MD -MP -MF $(DEPDIR)/nm_crash_logger-nm-crash-logger.Tpo -c -o nm_crash_logger-nm-crash-logger.o `test -f 'nm-crash-logger.c' || echo '$(srcdir)/'`nm-crash-logger.c
-@am__fastdepCC_TRUE@	$(AM_V_at)$(am__mv) $(DEPDIR)/nm_crash_logger-nm-crash-logger.Tpo $(DEPDIR)/nm_crash_logger-nm-crash-logger.Po
-@AMDEP_TRUE@@am__fastdepCC_FALSE@	$(AM_V_CC)source='nm-crash-logger.c' object='nm_crash_logger-nm-crash-logger.o' libtool=no @AMDEPBACKSLASH@
-@AMDEP_TRUE@@am__fastdepCC_FALSE@	DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
-@am__fastdepCC_FALSE@	$(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(nm_crash_logger_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o nm_crash_logger-nm-crash-logger.o `test -f 'nm-crash-logger.c' || echo '$(srcdir)/'`nm-crash-logger.c
-
-nm_crash_logger-nm-crash-logger.obj: nm-crash-logger.c
-@am__fastdepCC_TRUE@	$(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(nm_crash_logger_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT nm_crash_logger-nm-crash-logger.obj -MD -MP -MF $(DEPDIR)/nm_crash_logger-nm-crash-logger.Tpo -c -o nm_crash_logger-nm-crash-logger.obj `if test -f 'nm-crash-logger.c'; then $(CYGPATH_W) 'nm-crash-logger.c'; else $(CYGPATH_W) '$(srcdir)/nm-crash-logger.c'; fi`
-@am__fastdepCC_TRUE@	$(AM_V_at)$(am__mv) $(DEPDIR)/nm_crash_logger-nm-crash-logger.Tpo $(DEPDIR)/nm_crash_logger-nm-crash-logger.Po
-@AMDEP_TRUE@@am__fastdepCC_FALSE@	$(AM_V_CC)source='nm-crash-logger.c' object='nm_crash_logger-nm-crash-logger.obj' libtool=no @AMDEPBACKSLASH@
-@AMDEP_TRUE@@am__fastdepCC_FALSE@	DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
-@am__fastdepCC_FALSE@	$(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(nm_crash_logger_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o nm_crash_logger-nm-crash-logger.obj `if test -f 'nm-crash-logger.c'; then $(CYGPATH_W) 'nm-crash-logger.c'; else $(CYGPATH_W) '$(srcdir)/nm-crash-logger.c'; fi`
-
 mostlyclean-libtool:
 	-rm -f *.lo
 
@@ -1943,7 +1856,7 @@ check: $(BUILT_SOURCES)
 all-am: Makefile $(LTLIBRARIES) $(PROGRAMS) $(DATA)
 installdirs: installdirs-recursive
 installdirs-am:
-	for dir in "$(DESTDIR)$(libexecdir)" "$(DESTDIR)$(sbindir)" "$(DESTDIR)$(NetworkManagerdir)" "$(DESTDIR)$(dbusservicedir)"; do \
+	for dir in "$(DESTDIR)$(sbindir)" "$(DESTDIR)$(NetworkManagerdir)" "$(DESTDIR)$(dbusservicedir)"; do \
 	  test -z "$$dir" || $(MKDIR_P) "$$dir"; \
 	done
 install: $(BUILT_SOURCES)
@@ -1981,8 +1894,8 @@ maintainer-clean-generic:
 	-test -z "$(BUILT_SOURCES)" || rm -f $(BUILT_SOURCES)
 clean: clean-recursive
 
-clean-am: clean-generic clean-libexecPROGRAMS clean-libtool \
-	clean-noinstLTLIBRARIES clean-sbinPROGRAMS mostlyclean-am
+clean-am: clean-generic clean-libtool clean-noinstLTLIBRARIES \
+	clean-sbinPROGRAMS mostlyclean-am
 
 distclean: distclean-recursive
 	-rm -rf ./$(DEPDIR)
@@ -2009,7 +1922,7 @@ install-dvi: install-dvi-recursive
 
 install-dvi-am:
 
-install-exec-am: install-libexecPROGRAMS install-sbinPROGRAMS
+install-exec-am: install-sbinPROGRAMS
 
 install-html: install-html-recursive
 
@@ -2050,31 +1963,29 @@ ps: ps-recursive
 ps-am:
 
 uninstall-am: uninstall-NetworkManagerDATA uninstall-dbusserviceDATA \
-	uninstall-libexecPROGRAMS uninstall-sbinPROGRAMS
+	uninstall-sbinPROGRAMS
 
 .MAKE: $(RECURSIVE_CLEAN_TARGETS) $(RECURSIVE_TARGETS) all check \
 	ctags-recursive install install-am install-data-am \
 	install-strip tags-recursive
 
 .PHONY: $(RECURSIVE_CLEAN_TARGETS) $(RECURSIVE_TARGETS) CTAGS GTAGS \
-	all all-am check check-am clean clean-generic \
-	clean-libexecPROGRAMS clean-libtool clean-noinstLTLIBRARIES \
-	clean-sbinPROGRAMS ctags ctags-recursive distclean \
-	distclean-compile distclean-generic distclean-libtool \
-	distclean-tags distdir dvi dvi-am html html-am info info-am \
-	install install-NetworkManagerDATA install-am install-data \
-	install-data-am install-data-hook install-dbusserviceDATA \
-	install-dvi install-dvi-am install-exec install-exec-am \
-	install-html install-html-am install-info install-info-am \
-	install-libexecPROGRAMS install-man install-pdf install-pdf-am \
-	install-ps install-ps-am install-sbinPROGRAMS install-strip \
-	installcheck installcheck-am installdirs installdirs-am \
-	maintainer-clean maintainer-clean-generic mostlyclean \
-	mostlyclean-compile mostlyclean-generic mostlyclean-libtool \
-	pdf pdf-am ps ps-am tags tags-recursive uninstall \
-	uninstall-NetworkManagerDATA uninstall-am \
-	uninstall-dbusserviceDATA uninstall-libexecPROGRAMS \
-	uninstall-sbinPROGRAMS
+	all all-am check check-am clean clean-generic clean-libtool \
+	clean-noinstLTLIBRARIES clean-sbinPROGRAMS ctags \
+	ctags-recursive distclean distclean-compile distclean-generic \
+	distclean-libtool distclean-tags distdir dvi dvi-am html \
+	html-am info info-am install install-NetworkManagerDATA \
+	install-am install-data install-data-am install-data-hook \
+	install-dbusserviceDATA install-dvi install-dvi-am \
+	install-exec install-exec-am install-html install-html-am \
+	install-info install-info-am install-man install-pdf \
+	install-pdf-am install-ps install-ps-am install-sbinPROGRAMS \
+	install-strip installcheck installcheck-am installdirs \
+	installdirs-am maintainer-clean maintainer-clean-generic \
+	mostlyclean mostlyclean-compile mostlyclean-generic \
+	mostlyclean-libtool pdf pdf-am ps ps-am tags tags-recursive \
+	uninstall uninstall-NetworkManagerDATA uninstall-am \
+	uninstall-dbusserviceDATA uninstall-sbinPROGRAMS
 
 
 nm-access-point-glue.h: $(top_srcdir)/introspection/nm-access-point.xml
diff --git a/src/NetworkManagerUtils.c b/src/NetworkManagerUtils.c
index db627091..f2d72bd1 100644
--- a/src/NetworkManagerUtils.c
+++ b/src/NetworkManagerUtils.c
@@ -607,20 +607,30 @@ value_hash_add_object_property (GHashTable *hash,
 	value_hash_add (hash, key, value);
 }
 
+/**
+ * nm_utils_do_sysctl:
+ * @path: path to write @value to
+ * @value: value to write to @path
+ *
+ * Writes @value to the file at @path, trying 3 times on failure.
+ *
+ * Returns: %TRUE on success.  On failure, returns %FALSE and sets errno.
+ */
 gboolean
 nm_utils_do_sysctl (const char *path, const char *value)
 {
-	int fd, len, nwrote, tries;
+	int fd, len, nwrote, tries, saved_errno = 0;
 	char *actual;
 
 	g_return_val_if_fail (path != NULL, FALSE);
 	g_return_val_if_fail (value != NULL, FALSE);
-	g_return_val_if_fail (value[0], FALSE);
 
 	fd = open (path, O_WRONLY | O_TRUNC);
 	if (fd == -1) {
+		saved_errno = errno;
 		nm_log_warn (LOGD_CORE, "sysctl: failed to open '%s': (%d) %s",
-		             path, errno, strerror (errno));
+		             path, saved_errno, strerror (saved_errno));
+		errno = saved_errno;
 		return FALSE;
 	}
 
@@ -636,21 +646,24 @@ nm_utils_do_sysctl (const char *path, const char *value)
 	/* Try to write the entire value three times if a partial write occurs */
 	len = strlen (actual);
 	for (tries = 0, nwrote = 0; tries < 3 && nwrote != len; tries++) {
+		errno = 0;
 		nwrote = write (fd, actual, len);
 		if (nwrote == -1) {
 			if (errno == EINTR)
 				continue;
+			saved_errno = errno;
 			break;
 		}
 	}
 	g_free (actual);
+	close (fd);
 
-	if (nwrote != len) {
+	if (nwrote != len && saved_errno != EEXIST) {
 		nm_log_warn (LOGD_CORE, "sysctl: failed to set '%s' to '%s': (%d) %s",
-		             path, value, errno, strerror (errno));
+		             path, value, saved_errno, strerror (saved_errno));
 	}
 
-	close (fd);
+	errno = saved_errno;
 	return (nwrote == len);
 }
 
diff --git a/src/bluez-manager/Makefile.in b/src/bluez-manager/Makefile.in
index f80f8cb0..5606d11c 100644
--- a/src/bluez-manager/Makefile.in
+++ b/src/bluez-manager/Makefile.in
@@ -61,12 +61,11 @@ am__aclocal_m4_deps = $(top_srcdir)/m4/compiler_warnings.m4 \
 	$(top_srcdir)/m4/intlmacosx.m4 $(top_srcdir)/m4/intltool.m4 \
 	$(top_srcdir)/m4/introspection.m4 $(top_srcdir)/m4/lib-ld.m4 \
 	$(top_srcdir)/m4/lib-link.m4 $(top_srcdir)/m4/lib-prefix.m4 \
-	$(top_srcdir)/m4/libnl-check.m4 $(top_srcdir)/m4/libtool.m4 \
-	$(top_srcdir)/m4/ltoptions.m4 $(top_srcdir)/m4/ltsugar.m4 \
-	$(top_srcdir)/m4/ltversion.m4 $(top_srcdir)/m4/lt~obsolete.m4 \
-	$(top_srcdir)/m4/nls.m4 $(top_srcdir)/m4/po.m4 \
-	$(top_srcdir)/m4/progtest.m4 $(top_srcdir)/m4/vapigen.m4 \
-	$(top_srcdir)/configure.ac
+	$(top_srcdir)/m4/libtool.m4 $(top_srcdir)/m4/ltoptions.m4 \
+	$(top_srcdir)/m4/ltsugar.m4 $(top_srcdir)/m4/ltversion.m4 \
+	$(top_srcdir)/m4/lt~obsolete.m4 $(top_srcdir)/m4/nls.m4 \
+	$(top_srcdir)/m4/po.m4 $(top_srcdir)/m4/progtest.m4 \
+	$(top_srcdir)/m4/vapigen.m4 $(top_srcdir)/configure.ac
 am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \
 	$(ACLOCAL_M4)
 mkinstalldirs = $(install_sh) -d
@@ -221,12 +220,6 @@ LIBGCRYPT_LIBS = @LIBGCRYPT_LIBS@
 LIBICONV = @LIBICONV@
 LIBINTL = @LIBINTL@
 LIBM = @LIBM@
-LIBNL1_CFLAGS = @LIBNL1_CFLAGS@
-LIBNL1_LIBS = @LIBNL1_LIBS@
-LIBNL2_CFLAGS = @LIBNL2_CFLAGS@
-LIBNL2_LIBS = @LIBNL2_LIBS@
-LIBNL3_CFLAGS = @LIBNL3_CFLAGS@
-LIBNL3_LIBS = @LIBNL3_LIBS@
 LIBNL_CFLAGS = @LIBNL_CFLAGS@
 LIBNL_LIBS = @LIBNL_LIBS@
 LIBOBJS = @LIBOBJS@
diff --git a/src/dhcp-manager/Makefile.am b/src/dhcp-manager/Makefile.am
index 04ae1489..40a05834 100644
--- a/src/dhcp-manager/Makefile.am
+++ b/src/dhcp-manager/Makefile.am
@@ -52,6 +52,7 @@ libdhcp_manager_la_SOURCES = \
 libdhcp_manager_la_CPPFLAGS = \
 	$(DBUS_CFLAGS) \
 	$(GLIB_CFLAGS) \
+	-DSYSCONFDIR=\"$(sysconfdir)\" \
 	-DLIBEXECDIR=\"$(libexecdir)\" \
 	-DLOCALSTATEDIR=\"$(localstatedir)\" \
 	-DDHCLIENT_PATH=\"$(DHCLIENT_PATH)\" \
diff --git a/src/dhcp-manager/Makefile.in b/src/dhcp-manager/Makefile.in
index f161c210..acd13114 100644
--- a/src/dhcp-manager/Makefile.in
+++ b/src/dhcp-manager/Makefile.in
@@ -61,12 +61,11 @@ am__aclocal_m4_deps = $(top_srcdir)/m4/compiler_warnings.m4 \
 	$(top_srcdir)/m4/intlmacosx.m4 $(top_srcdir)/m4/intltool.m4 \
 	$(top_srcdir)/m4/introspection.m4 $(top_srcdir)/m4/lib-ld.m4 \
 	$(top_srcdir)/m4/lib-link.m4 $(top_srcdir)/m4/lib-prefix.m4 \
-	$(top_srcdir)/m4/libnl-check.m4 $(top_srcdir)/m4/libtool.m4 \
-	$(top_srcdir)/m4/ltoptions.m4 $(top_srcdir)/m4/ltsugar.m4 \
-	$(top_srcdir)/m4/ltversion.m4 $(top_srcdir)/m4/lt~obsolete.m4 \
-	$(top_srcdir)/m4/nls.m4 $(top_srcdir)/m4/po.m4 \
-	$(top_srcdir)/m4/progtest.m4 $(top_srcdir)/m4/vapigen.m4 \
-	$(top_srcdir)/configure.ac
+	$(top_srcdir)/m4/libtool.m4 $(top_srcdir)/m4/ltoptions.m4 \
+	$(top_srcdir)/m4/ltsugar.m4 $(top_srcdir)/m4/ltversion.m4 \
+	$(top_srcdir)/m4/lt~obsolete.m4 $(top_srcdir)/m4/nls.m4 \
+	$(top_srcdir)/m4/po.m4 $(top_srcdir)/m4/progtest.m4 \
+	$(top_srcdir)/m4/vapigen.m4 $(top_srcdir)/configure.ac
 am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \
 	$(ACLOCAL_M4)
 mkinstalldirs = $(install_sh) -d
@@ -269,12 +268,6 @@ LIBGCRYPT_LIBS = @LIBGCRYPT_LIBS@
 LIBICONV = @LIBICONV@
 LIBINTL = @LIBINTL@
 LIBM = @LIBM@
-LIBNL1_CFLAGS = @LIBNL1_CFLAGS@
-LIBNL1_LIBS = @LIBNL1_LIBS@
-LIBNL2_CFLAGS = @LIBNL2_CFLAGS@
-LIBNL2_LIBS = @LIBNL2_LIBS@
-LIBNL3_CFLAGS = @LIBNL3_CFLAGS@
-LIBNL3_LIBS = @LIBNL3_LIBS@
 LIBNL_CFLAGS = @LIBNL_CFLAGS@
 LIBNL_LIBS = @LIBNL_LIBS@
 LIBOBJS = @LIBOBJS@
@@ -466,6 +459,7 @@ libdhcp_manager_la_SOURCES = \
 libdhcp_manager_la_CPPFLAGS = \
 	$(DBUS_CFLAGS) \
 	$(GLIB_CFLAGS) \
+	-DSYSCONFDIR=\"$(sysconfdir)\" \
 	-DLIBEXECDIR=\"$(libexecdir)\" \
 	-DLOCALSTATEDIR=\"$(localstatedir)\" \
 	-DDHCLIENT_PATH=\"$(DHCLIENT_PATH)\" \
diff --git a/src/dhcp-manager/nm-dhcp-client.c b/src/dhcp-manager/nm-dhcp-client.c
index f721adf5..2cdd304d 100644
--- a/src/dhcp-manager/nm-dhcp-client.c
+++ b/src/dhcp-manager/nm-dhcp-client.c
@@ -25,9 +25,8 @@
 #include <errno.h>
 #include <unistd.h>
 #include <stdio.h>
-#include <netinet/in.h>
-#include <arpa/inet.h>
 #include <stdlib.h>
+#include <uuid/uuid.h>
 
 #include "nm-utils.h"
 #include "nm-logging.h"
@@ -36,9 +35,11 @@
 
 typedef struct {
 	char *       iface;
+	GByteArray * hwaddr;
 	gboolean     ipv6;
 	char *       uuid;
 	guint32      timeout;
+	GByteArray * duid;
 
 	guchar       state;
 	GPid         pid;
@@ -67,6 +68,7 @@ static guint signals[LAST_SIGNAL] = { 0 };
 enum {
 	PROP_0,
 	PROP_IFACE,
+	PROP_HWADDR,
 	PROP_IPV6,
 	PROP_UUID,
 	PROP_TIMEOUT,
@@ -182,7 +184,7 @@ nm_dhcp_client_stop_pid (GPid pid, const char *iface, guint timeout_secs)
 }
 
 static void
-stop (NMDHCPClient *self, gboolean release)
+stop (NMDHCPClient *self, gboolean release, const GByteArray *duid)
 {
 	NMDHCPClientPrivate *priv;
 
@@ -321,6 +323,96 @@ nm_dhcp_client_start_ip4 (NMDHCPClient *self,
 	return priv->pid ? TRUE : FALSE;
 }
 
+static GByteArray *
+generate_duid_from_machine_id (void)
+{
+	GByteArray *duid;
+	char *contents = NULL;
+	GError *error = NULL;
+	GChecksum *sum;
+	guint8 buffer[32]; /* SHA256 digest size */
+	gsize sumlen = sizeof (buffer);
+	const guint16 duid_type = g_htons (4);
+	uuid_t uuid;
+	int ret;
+
+	/* Get the machine ID from /etc/machine-id; it's always in /etc no matter
+	 * where our configured SYSCONFDIR is.
+	 */
+	if (!g_file_get_contents ("/etc/machine-id", &contents, NULL, &error)) {
+		nm_log_warn (LOGD_DHCP6, "Failed to read " SYSCONFDIR "/machine-id to generate DHCPv6 DUID: (%d) %s",
+			         error ? error->code : -1,
+			         error ? error->message : "(unknown)");
+		g_clear_error (&error);
+		return NULL;
+	}
+
+	contents = g_strstrip (contents);
+	ret = uuid_parse (contents, uuid);
+	g_free (contents);
+
+	if (ret != 0) {
+		nm_log_warn (LOGD_DHCP6, "Failed to parse " SYSCONFDIR "/machine-id to generate DHCPv6 DUID.");
+		return NULL;
+	}
+
+	/* Hash the machine ID so it's not leaked to the network */
+	sum = g_checksum_new (G_CHECKSUM_SHA256);
+	g_checksum_update (sum, (const guchar *) &uuid, sizeof (uuid));
+	g_checksum_get_digest (sum, buffer, &sumlen);
+	g_checksum_free (sum);
+
+	/* Generate a DHCP Unique Identifier for DHCPv6 using the
+	 * DUID-UUID method (see RFC 6355 section 4).  Format is:
+	 *
+	 * u16: type (DUID-UUID = 4)
+	 * u8[16]: UUID bytes
+	 */
+	duid = g_byte_array_sized_new (18);
+	g_byte_array_append (duid, (guint8 *) &duid_type, sizeof (duid_type));
+
+	/* Since SHA256 is 256 bits, but UUID is 128 bits, we just take the first
+	 * 128 bits of the SHA256 as the DUID-UUID.
+	 */
+	g_byte_array_append (duid, buffer, 16);
+
+	return duid;
+}
+
+static GByteArray *
+get_duid (NMDHCPClient *self)
+{
+	static GByteArray *duid = NULL;
+	GByteArray *copy = NULL;
+
+	if (G_UNLIKELY (duid == NULL))
+		duid = generate_duid_from_machine_id ();
+
+	if (G_LIKELY (duid)) {
+		copy = g_byte_array_sized_new (duid->len);
+		g_byte_array_append (copy, duid->data, duid->len);
+	}
+
+	return copy;
+}
+
+static char *
+escape_duid (const GByteArray *duid)
+{
+	guint32 i = 0;
+	GString *s;
+
+	g_return_val_if_fail (duid != NULL, NULL);
+
+	s = g_string_sized_new (40);
+	while (i < duid->len) {
+		if (s->len)
+			g_string_append_c (s, ':');
+		g_string_append_printf (s, "%02x", duid->data[i++]);
+	}
+	return g_string_free (s, FALSE);
+}
+
 gboolean
 nm_dhcp_client_start_ip6 (NMDHCPClient *self,
                           NMSettingIP6Config *s_ip6,
@@ -329,6 +421,7 @@ nm_dhcp_client_start_ip6 (NMDHCPClient *self,
                           gboolean info_only)
 {
 	NMDHCPClientPrivate *priv;
+	char *escaped;
 
 	g_return_val_if_fail (self != NULL, FALSE);
 	g_return_val_if_fail (NM_IS_DHCP_CLIENT (self), FALSE);
@@ -338,12 +431,29 @@ nm_dhcp_client_start_ip6 (NMDHCPClient *self,
 	g_return_val_if_fail (priv->ipv6 == TRUE, FALSE);
 	g_return_val_if_fail (priv->uuid != NULL, FALSE);
 
+	/* If we don't have one yet, read the default DUID for this DHCPv6 client
+	 * from the client-specific persistent configuration.
+	 */
+	if (!priv->duid)
+		priv->duid = NM_DHCP_CLIENT_GET_CLASS (self)->get_duid (self);
+
+	if (nm_logging_level_enabled (LOGL_DEBUG)) {
+		escaped = escape_duid (priv->duid);
+		nm_log_dbg (LOGD_DHCP, "(%s): DHCPv6 DUID is '%s'", priv->iface, escaped);
+		g_free (escaped);
+	}
+
 	priv->info_only = info_only;
 
 	nm_log_info (LOGD_DHCP, "Activation (%s) Beginning DHCPv6 transaction (timeout in %d seconds)",
 	             priv->iface, priv->timeout);
 
-	priv->pid = NM_DHCP_CLIENT_GET_CLASS (self)->ip6_start (self, s_ip6, dhcp_anycast_addr, hostname, info_only);
+	priv->pid = NM_DHCP_CLIENT_GET_CLASS (self)->ip6_start (self,
+	                                                        s_ip6,
+	                                                        dhcp_anycast_addr,
+	                                                        hostname,
+	                                                        info_only,
+	                                                        priv->duid);
 	if (priv->pid > 0)
 		start_monitor (self);
 
@@ -397,7 +507,7 @@ nm_dhcp_client_stop (NMDHCPClient *self, gboolean release)
 
 	/* Kill the DHCP client */
 	if (!priv->dead) {
-		NM_DHCP_CLIENT_GET_CLASS (self)->stop (self, release);
+		NM_DHCP_CLIENT_GET_CLASS (self)->stop (self, release, priv->duid);
 		priv->dead = TRUE;
 
 		nm_log_info (LOGD_DHCP, "(%s): canceled DHCP transaction, DHCP client pid %d",
@@ -1323,6 +1433,9 @@ get_property (GObject *object, guint prop_id,
 	case PROP_IFACE:
 		g_value_set_string (value, priv->iface);
 		break;
+	case PROP_HWADDR:
+		g_value_set_boxed (value, priv->hwaddr);
+		break;
 	case PROP_IPV6:
 		g_value_set_boolean (value, priv->ipv6);
 		break;
@@ -1349,6 +1462,10 @@ set_property (GObject *object, guint prop_id,
 		/* construct-only */
 		priv->iface = g_strdup (g_value_get_string (value));
 		break;
+	case PROP_HWADDR:
+		/* construct only */
+		priv->hwaddr = g_value_dup_boxed (value);
+		break;
 	case PROP_IPV6:
 		/* construct-only */
 		priv->ipv6 = g_value_get_boolean (value);
@@ -1382,6 +1499,11 @@ dispose (GObject *object)
 
 	g_hash_table_destroy (priv->options);
 	g_free (priv->iface);
+	if (priv->hwaddr)
+		g_byte_array_free (priv->hwaddr, TRUE);
+
+	if (priv->duid)
+		g_byte_array_free (priv->duid, TRUE);
 
 	G_OBJECT_CLASS (nm_dhcp_client_parent_class)->dispose (object);
 }
@@ -1399,6 +1521,7 @@ nm_dhcp_client_class_init (NMDHCPClientClass *client_class)
 	object_class->set_property = set_property;
 
 	client_class->stop = stop;
+	client_class->get_duid = get_duid;
 
 	g_object_class_install_property
 		(object_class, PROP_IFACE,
@@ -1409,6 +1532,14 @@ nm_dhcp_client_class_init (NMDHCPClientClass *client_class)
 		                      G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY));
 
 	g_object_class_install_property
+		(object_class, PROP_HWADDR,
+		 g_param_spec_boxed (NM_DHCP_CLIENT_HWADDR,
+		                     "hwaddr",
+		                     "hardware address",
+		                     G_TYPE_BYTE_ARRAY,
+		                     G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY));
+
+	g_object_class_install_property
 		(object_class, PROP_IPV6,
 		 g_param_spec_boolean (NM_DHCP_CLIENT_IPV6,
 		                       "ipv6",
diff --git a/src/dhcp-manager/nm-dhcp-client.h b/src/dhcp-manager/nm-dhcp-client.h
index b93515f4..930ec1a5 100644
--- a/src/dhcp-manager/nm-dhcp-client.h
+++ b/src/dhcp-manager/nm-dhcp-client.h
@@ -35,6 +35,7 @@
 #define NM_DHCP_CLIENT_GET_CLASS(obj)  (G_TYPE_INSTANCE_GET_CLASS ((obj), NM_TYPE_DHCP_CLIENT, NMDHCPClientClass))
 
 #define NM_DHCP_CLIENT_INTERFACE "iface"
+#define NM_DHCP_CLIENT_HWADDR    "hwaddr"
 #define NM_DHCP_CLIENT_IPV6      "ipv6"
 #define NM_DHCP_CLIENT_UUID      "uuid"
 #define NM_DHCP_CLIENT_TIMEOUT   "timeout"
@@ -85,10 +86,23 @@ typedef struct {
 	                       NMSettingIP6Config *s_ip6,
 	                       guint8 *anycast_addr,
 	                       const char *hostname,
-	                       gboolean info_only);
+	                       gboolean info_only,
+	                       const GByteArray *duid);
 
 	void (*stop)          (NMDHCPClient *self,
-	                       gboolean release);
+	                       gboolean release,
+	                       const GByteArray *duid);
+
+	/**
+	 * get_duid:
+	 * @self: the #NMDHCPClient
+	 *
+	 * Attempts to find an existing DHCPv6 DUID for this client in the DHCP
+	 * client's persistent configuration.  Returned DUID should be the binary
+	 * representation of the DUID.  If no DUID is found, %NULL should be
+	 * returned.
+	 */
+	GByteArray * (*get_duid) (NMDHCPClient *self);
 
 	/* Signals */
 	void (*state_changed) (NMDHCPClient *self, NMDHCPState state);
diff --git a/src/dhcp-manager/nm-dhcp-dhclient-utils.c b/src/dhcp-manager/nm-dhcp-dhclient-utils.c
index f3d3b1b6..8dc7902f 100644
--- a/src/dhcp-manager/nm-dhcp-dhclient-utils.c
+++ b/src/dhcp-manager/nm-dhcp-dhclient-utils.c
@@ -22,6 +22,7 @@
 #include <glib.h>
 #include <glib/gi18n.h>
 #include <string.h>
+#include <ctype.h>
 
 #include "nm-dhcp-dhclient-utils.h"
 
@@ -255,3 +256,165 @@ nm_dhcp_dhclient_create_config (const char *interface,
 	return g_string_free (new_contents, FALSE);
 }
 
+/* Roughly follow what dhclient's quotify_buf() and pretty_escape() functions do */
+char *
+nm_dhcp_dhclient_escape_duid (const GByteArray *duid)
+{
+	char *escaped;
+	const guint8 *s = duid->data;
+	char *d;
+
+	d = escaped = g_malloc0 ((duid->len * 4) + 1);
+	while (s < (duid->data + duid->len)) {
+		if (!g_ascii_isprint (*s)) {
+			*d++ = '\\';
+			*d++ = '0' + ((*s >> 6) & 0x7);
+			*d++ = '0' + ((*s >> 3) & 0x7);
+			*d++ = '0' + (*s++ & 0x7);
+		} else if (*s == '"' || *s == '\'' || *s == '$' ||
+		           *s == '`' || *s == '\\' || *s == '|' ||
+		           *s == '&') {
+			*d++ = '\\';
+			*d++ = *s++;
+		} else
+			*d++ = *s++;
+	}
+	return escaped;
+}
+
+static inline gboolean
+isoctal (const guint8 *p)
+{
+	return (   p[0] >= '0' && p[0] <= '3'
+	        && p[1] >= '0' && p[1] <= '7'
+	        && p[2] >= '0' && p[2] <= '7');
+}
+
+GByteArray *
+nm_dhcp_dhclient_unescape_duid (const char *duid)
+{
+	GByteArray *unescaped;
+	const guint8 *p = (const guint8 *) duid;
+	guint i, len;
+	guint8 octal;
+
+	len = strlen (duid);
+	unescaped = g_byte_array_sized_new (len);
+	for (i = 0; i < len; i++) {
+		if (p[i] == '\\') {
+			i++;
+			if (isdigit (p[i])) {
+				/* Octal escape sequence */
+				if (i + 2 >= len || !isoctal (p + i))
+					goto error;
+				octal = ((p[i] - '0') << 6) + ((p[i + 1] - '0') << 3) + (p[i + 2] - '0');
+				g_byte_array_append (unescaped, &octal, 1);
+				i += 2;
+			} else {
+				/* One of ", ', $, `, \, |, or & */
+				g_warn_if_fail (p[i] == '"' || p[i] == '\'' || p[i] == '$' ||
+				                p[i] == '`' || p[i] == '\\' || p[i] == '|' ||
+				                p[i] == '&');
+				g_byte_array_append (unescaped, &p[i], 1);
+			}
+		} else
+			g_byte_array_append (unescaped, &p[i], 1);
+	}
+
+	return unescaped;
+
+error:
+	g_byte_array_free (unescaped, TRUE);
+	return NULL;
+}
+
+#define DUID_PREFIX "default-duid \""
+
+GByteArray *
+nm_dhcp_dhclient_read_duid (const char *leasefile, GError **error)
+{
+	GByteArray *duid = NULL;
+	char *contents;
+	char **line, **split, *p, *e;
+
+	if (!g_file_test (leasefile, G_FILE_TEST_EXISTS))
+		return NULL;
+
+	if (!g_file_get_contents (leasefile, &contents, NULL, error))
+		return NULL;
+
+	split = g_strsplit_set (contents, "\n\r", -1);
+	for (line = split; line && *line && (duid == NULL); line++) {
+		p = g_strstrip (*line);
+		if (g_str_has_prefix (p, DUID_PREFIX)) {
+			p += strlen (DUID_PREFIX);
+
+			/* look for trailing "; */
+			e = p + strlen (p) - 2;
+			if (strcmp (e, "\";") != 0)
+				continue;
+			*e = '\0';
+
+			duid = nm_dhcp_dhclient_unescape_duid (p);
+		}
+	}
+	g_free (contents);
+	g_strfreev (split);
+
+	return duid;
+}
+
+gboolean
+nm_dhcp_dhclient_save_duid (const char *leasefile,
+                            const char *escaped_duid,
+                            GError **error)
+{
+	char **lines = NULL, **iter, *l;
+	GString *s;
+	gboolean success;
+	gsize len = 0;
+
+	g_return_val_if_fail (leasefile != NULL, FALSE);
+	g_return_val_if_fail (escaped_duid != NULL, FALSE);
+
+	if (g_file_test (leasefile, G_FILE_TEST_EXISTS)) {
+		char *contents = NULL;
+
+		if (!g_file_get_contents (leasefile, &contents, &len, error)) {
+			g_prefix_error (error, "failed to read lease file %s: ", leasefile);
+			return FALSE;
+		}
+
+		/* If the file already contains an uncommented DUID, leave it */
+		g_assert (contents);
+		lines = g_strsplit_set (contents, "\n\r", -1);
+		g_free (contents);
+		for (iter = lines; iter && *iter; iter++) {
+			l = *iter;
+			while (g_ascii_isspace (*l))
+				l++;
+			if (g_str_has_prefix (l, DUID_PREFIX)) {
+				g_strfreev (lines);
+				return TRUE;
+			}
+		}
+	}
+
+	s = g_string_sized_new (len + 50);
+	g_string_append_printf (s, DUID_PREFIX "%s\";\n", escaped_duid);
+
+	/* Preserve existing leasefile contents */
+	if (lines) {
+		for (iter = lines; iter && *iter; iter++)
+			g_string_append (s, *iter[0] ? *iter : "\n");
+		g_strfreev (lines);
+	}
+
+	success = g_file_set_contents (leasefile, s->str, -1, error);
+	if (!success)
+		g_prefix_error (error, "failed to set DUID in lease file %s: ", leasefile);
+
+	g_string_free (s, TRUE);
+	return success;
+}
+
diff --git a/src/dhcp-manager/nm-dhcp-dhclient-utils.h b/src/dhcp-manager/nm-dhcp-dhclient-utils.h
index 2f9f7c45..95cb0568 100644
--- a/src/dhcp-manager/nm-dhcp-dhclient-utils.h
+++ b/src/dhcp-manager/nm-dhcp-dhclient-utils.h
@@ -34,5 +34,15 @@ char *nm_dhcp_dhclient_create_config (const char *interface,
                                       const char *orig_path,
                                       const char *orig_contents);
 
+char *nm_dhcp_dhclient_escape_duid (const GByteArray *duid);
+
+GByteArray *nm_dhcp_dhclient_unescape_duid (const char *duid);
+
+GByteArray *nm_dhcp_dhclient_read_duid (const char *leasefile, GError **error);
+
+gboolean nm_dhcp_dhclient_save_duid (const char *leasefile,
+                                     const char *escaped_duid,
+                                     GError **error);
+
 #endif /* NM_DHCP_DHCLIENT_UTILS_H */
 
diff --git a/src/dhcp-manager/nm-dhcp-dhclient.c b/src/dhcp-manager/nm-dhcp-dhclient.c
index 347d97c4..d9f51352 100644
--- a/src/dhcp-manager/nm-dhcp-dhclient.c
+++ b/src/dhcp-manager/nm-dhcp-dhclient.c
@@ -50,6 +50,7 @@ G_DEFINE_TYPE (NMDHCPDhclient, nm_dhcp_dhclient, NM_TYPE_DHCP_CLIENT)
 typedef struct {
 	const char *path;
 	char *conf_file;
+	const char *def_leasefile;
 	char *lease_file;
 	char *pid_file;
 } NMDHCPDhclientPrivate;
@@ -445,6 +446,7 @@ dhclient_child_setup (gpointer user_data G_GNUC_UNUSED)
 static GPid
 dhclient_start (NMDHCPClient *client,
                 const char *mode_opt,
+                const GByteArray *duid,
                 gboolean release)
 {
 	NMDHCPDhclientPrivate *priv = NM_DHCP_DHCLIENT_GET_PRIVATE (client);
@@ -575,7 +577,7 @@ ip4_start (NMDHCPClient *client,
 		return -1;
 	}
 
-	return dhclient_start (client, NULL, FALSE);
+	return dhclient_start (client, NULL, NULL, FALSE);
 }
 
 static GPid
@@ -583,7 +585,8 @@ ip6_start (NMDHCPClient *client,
            NMSettingIP6Config *s_ip6,
            guint8 *dhcp_anycast_addr,
            const char *hostname,
-           gboolean info_only)
+           gboolean info_only,
+           const GByteArray *duid)
 {
 	NMDHCPDhclientPrivate *priv = NM_DHCP_DHCLIENT_GET_PRIVATE (client);
 	const char *iface;
@@ -596,16 +599,16 @@ ip6_start (NMDHCPClient *client,
 		return -1;
 	}
 
-	return dhclient_start (client, info_only ? "-S" : "-N", FALSE);
+	return dhclient_start (client, info_only ? "-S" : "-N", duid, FALSE);
 }
 
 static void
-stop (NMDHCPClient *client, gboolean release)
+stop (NMDHCPClient *client, gboolean release, const GByteArray *duid)
 {
 	NMDHCPDhclientPrivate *priv = NM_DHCP_DHCLIENT_GET_PRIVATE (client);
 
 	/* Chain up to parent */
-	NM_DHCP_CLIENT_CLASS (nm_dhcp_dhclient_parent_class)->stop (client, release);
+	NM_DHCP_CLIENT_CLASS (nm_dhcp_dhclient_parent_class)->stop (client, release, duid);
 
 	if (priv->conf_file)
 		remove (priv->conf_file);
@@ -618,7 +621,7 @@ stop (NMDHCPClient *client, gboolean release)
 	if (release) {
 		GPid rpid;
 
-		rpid = dhclient_start (client, NULL, TRUE);
+		rpid = dhclient_start (client, NULL, duid, TRUE);
 		if (rpid > 0) {
 			/* Wait a few seconds for the release to happen */
 			nm_dhcp_client_stop_pid (rpid, nm_dhcp_client_get_iface (client), 5);
@@ -626,14 +629,75 @@ stop (NMDHCPClient *client, gboolean release)
 	}
 }
 
+static GByteArray *
+get_duid (NMDHCPClient *client)
+{
+	NMDHCPDhclientPrivate *priv = NM_DHCP_DHCLIENT_GET_PRIVATE (client);
+	GByteArray *duid = NULL;
+	char *leasefile;
+	GError *error = NULL;
+
+	/* Look in interface-specific leasefile first for backwards compat */
+	leasefile = get_dhclient_leasefile (nm_dhcp_client_get_iface (client),
+	                                    nm_dhcp_client_get_uuid (client),
+	                                    TRUE);
+	nm_log_dbg (LOGD_DHCP, "Looking for DHCPv6 DUID in '%s'.", leasefile);
+	duid = nm_dhcp_dhclient_read_duid (leasefile, &error);
+	g_free (leasefile);
+
+	if (error) {
+		nm_log_warn (LOGD_DHCP, "Failed to read leasefile '%s': (%d) %s",
+		             leasefile,
+		             error ? error->code : -1,
+		             error ? error->message : "(unknown)");
+		g_clear_error (&error);
+	}
+
+	if (!duid && priv->def_leasefile) {
+		/* Otherwise read the default machine-wide DUID */
+		nm_log_dbg (LOGD_DHCP, "Looking for default DHCPv6 DUID in '%s'.", priv->def_leasefile);
+		duid = nm_dhcp_dhclient_read_duid (priv->def_leasefile, &error);
+		if (error) {
+			nm_log_warn (LOGD_DHCP, "Failed to read leasefile '%s': (%d) %s",
+			             priv->def_leasefile,
+			             error ? error->code : -1,
+			             error ? error->message : "(unknown)");
+			g_clear_error (&error);
+		}
+	}
+
+	/* return our DUID, otherwise let the parent class make a default DUID */
+	return duid ? duid : NM_DHCP_CLIENT_CLASS (nm_dhcp_dhclient_parent_class)->get_duid (client);
+}
+
 /***************************************************/
 
+static const char *def_leasefiles[] = {
+	SYSCONFDIR "/dhclient6.leases",
+	LOCALSTATEDIR "/lib/dhcp/dhclient6.leases",
+	LOCALSTATEDIR "/lib/dhclient/dhclient6.leases",
+	NULL
+};
+
 static void
 nm_dhcp_dhclient_init (NMDHCPDhclient *self)
 {
 	NMDHCPDhclientPrivate *priv = NM_DHCP_DHCLIENT_GET_PRIVATE (self);
+	const char **iter = &def_leasefiles[0];
 
 	priv->path = nm_dhcp_dhclient_get_path (DHCLIENT_PATH);
+
+	while (iter && *iter) {
+		if (g_file_test (*iter, G_FILE_TEST_EXISTS)) {
+			priv->def_leasefile = *iter;
+			break;
+		}
+		iter++;
+	}
+
+	/* Fallback option */
+	if (!priv->def_leasefile)
+		priv->def_leasefile = SYSCONFDIR "/dhclient6.leases";
 }
 
 static void
@@ -662,5 +726,6 @@ nm_dhcp_dhclient_class_init (NMDHCPDhclientClass *dhclient_class)
 	client_class->ip4_start = ip4_start;
 	client_class->ip6_start = ip6_start;
 	client_class->stop = stop;
+	client_class->get_duid = get_duid;
 }
 
diff --git a/src/dhcp-manager/nm-dhcp-dhcpcd.c b/src/dhcp-manager/nm-dhcp-dhcpcd.c
index dda96e2a..f3245ee5 100644
--- a/src/dhcp-manager/nm-dhcp-dhcpcd.c
+++ b/src/dhcp-manager/nm-dhcp-dhcpcd.c
@@ -170,19 +170,20 @@ ip6_start (NMDHCPClient *client,
            NMSettingIP6Config *s_ip6,
            guint8 *dhcp_anycast_addr,
            const char *hostname,
-           gboolean info_only)
+           gboolean info_only,
+           const GByteArray *duid)
 {
 	nm_log_warn (LOGD_DHCP6, "the dhcpcd backend does not support IPv6.");
 	return -1;
 }
 
 static void
-stop (NMDHCPClient *client, gboolean release)
+stop (NMDHCPClient *client, gboolean release, const GByteArray *duid)
 {
 	NMDHCPDhcpcdPrivate *priv = NM_DHCP_DHCPCD_GET_PRIVATE (client);
 
 	/* Chain up to parent */
-	NM_DHCP_CLIENT_CLASS (nm_dhcp_dhcpcd_parent_class)->stop (client, release);
+	NM_DHCP_CLIENT_CLASS (nm_dhcp_dhcpcd_parent_class)->stop (client, release, duid);
 
 	if (priv->pid_file)
 		remove (priv->pid_file);
diff --git a/src/dhcp-manager/nm-dhcp-manager.c b/src/dhcp-manager/nm-dhcp-manager.c
index 995bff47..1bd7f984 100644
--- a/src/dhcp-manager/nm-dhcp-manager.c
+++ b/src/dhcp-manager/nm-dhcp-manager.c
@@ -384,6 +384,7 @@ add_client (NMDHCPManager *self, NMDHCPClient *client)
 static NMDHCPClient *
 client_start (NMDHCPManager *self,
               const char *iface,
+              const GByteArray *hwaddr,
               const char *uuid,
               gboolean ipv6,
               NMSettingIP4Config *s_ip4,
@@ -417,6 +418,7 @@ client_start (NMDHCPManager *self,
 	/* And make a new one */
 	client = g_object_new (priv->client_type,
 	                       NM_DHCP_CLIENT_INTERFACE, iface,
+	                       NM_DHCP_CLIENT_HWADDR, hwaddr,
 	                       NM_DHCP_CLIENT_IPV6, ipv6,
 	                       NM_DHCP_CLIENT_UUID, uuid,
 	                       NM_DHCP_CLIENT_TIMEOUT, timeout ? timeout : DHCP_TIMEOUT,
@@ -442,13 +444,13 @@ client_start (NMDHCPManager *self,
 NMDHCPClient *
 nm_dhcp_manager_start_ip4 (NMDHCPManager *self,
                            const char *iface,
+                           const GByteArray *hwaddr,
                            const char *uuid,
                            NMSettingIP4Config *s_ip4,
                            guint32 timeout,
                            guint8 *dhcp_anycast_addr)
 {
 	NMDHCPManagerPrivate *priv;
-	NMDHCPClient *client = NULL;
 	const char *hostname = NULL;
 	gboolean send_hostname = TRUE;
 
@@ -485,15 +487,14 @@ nm_dhcp_manager_start_ip4 (NMDHCPManager *self,
 		}
 	}
 
-	client = client_start (self, iface, uuid, FALSE, s_ip4, NULL, timeout, dhcp_anycast_addr, hostname, FALSE);
-
-	return client;
+	return client_start (self, iface, hwaddr, uuid, FALSE, s_ip4, NULL, timeout, dhcp_anycast_addr, hostname, FALSE);
 }
 
 /* Caller owns a reference to the NMDHCPClient on return */
 NMDHCPClient *
 nm_dhcp_manager_start_ip6 (NMDHCPManager *self,
                            const char *iface,
+                           const GByteArray *hwaddr,
                            const char *uuid,
                            NMSettingIP6Config *s_ip6,
                            guint32 timeout,
@@ -516,7 +517,7 @@ nm_dhcp_manager_start_ip6 (NMDHCPManager *self,
 			hostname = NULL;
 	}
 
-	return client_start (self, iface, uuid, TRUE, NULL, s_ip6, timeout, dhcp_anycast_addr, hostname, info_only);
+	return client_start (self, iface, hwaddr, uuid, TRUE, NULL, s_ip6, timeout, dhcp_anycast_addr, hostname, info_only);
 }
 
 static void
diff --git a/src/dhcp-manager/nm-dhcp-manager.h b/src/dhcp-manager/nm-dhcp-manager.h
index 68db7e37..a29a33fd 100644
--- a/src/dhcp-manager/nm-dhcp-manager.h
+++ b/src/dhcp-manager/nm-dhcp-manager.h
@@ -67,6 +67,7 @@ void           nm_dhcp_manager_set_hostname_provider(NMDHCPManager *manager,
 
 NMDHCPClient * nm_dhcp_manager_start_ip4     (NMDHCPManager *manager,
                                               const char *iface,
+                                              const GByteArray *hwaddr,
                                               const char *uuid,
                                               NMSettingIP4Config *s_ip4,
                                               guint32 timeout,
@@ -74,6 +75,7 @@ NMDHCPClient * nm_dhcp_manager_start_ip4     (NMDHCPManager *manager,
 
 NMDHCPClient * nm_dhcp_manager_start_ip6     (NMDHCPManager *manager,
                                               const char *iface,
+                                              const GByteArray *hwaddr,
                                               const char *uuid,
                                               NMSettingIP6Config *s_ip6,
                                               guint32 timeout,
diff --git a/src/dhcp-manager/tests/Makefile.am b/src/dhcp-manager/tests/Makefile.am
index 251aa224..8c9d06c1 100644
--- a/src/dhcp-manager/tests/Makefile.am
+++ b/src/dhcp-manager/tests/Makefile.am
@@ -15,7 +15,8 @@ test_dhcp_dhclient_SOURCES = \
 	test-dhcp-dhclient.c
 
 test_dhcp_dhclient_CPPFLAGS = \
-	$(GLIB_CFLAGS)
+	$(GLIB_CFLAGS) \
+	-DTESTDIR="\"$(abs_srcdir)\""
 
 test_dhcp_dhclient_LDADD = \
 	-ldl \
@@ -27,3 +28,8 @@ check-local: test-dhcp-dhclient
 	$(abs_builddir)/test-dhcp-dhclient
 
 endif
+
+EXTRA_DIST = \
+	test-dhclient-duid.leases \
+	test-dhclient-commented-duid.leases
+
diff --git a/src/dhcp-manager/tests/Makefile.in b/src/dhcp-manager/tests/Makefile.in
index 32cdf4db..921ccaf3 100644
--- a/src/dhcp-manager/tests/Makefile.in
+++ b/src/dhcp-manager/tests/Makefile.in
@@ -62,12 +62,11 @@ am__aclocal_m4_deps = $(top_srcdir)/m4/compiler_warnings.m4 \
 	$(top_srcdir)/m4/intlmacosx.m4 $(top_srcdir)/m4/intltool.m4 \
 	$(top_srcdir)/m4/introspection.m4 $(top_srcdir)/m4/lib-ld.m4 \
 	$(top_srcdir)/m4/lib-link.m4 $(top_srcdir)/m4/lib-prefix.m4 \
-	$(top_srcdir)/m4/libnl-check.m4 $(top_srcdir)/m4/libtool.m4 \
-	$(top_srcdir)/m4/ltoptions.m4 $(top_srcdir)/m4/ltsugar.m4 \
-	$(top_srcdir)/m4/ltversion.m4 $(top_srcdir)/m4/lt~obsolete.m4 \
-	$(top_srcdir)/m4/nls.m4 $(top_srcdir)/m4/po.m4 \
-	$(top_srcdir)/m4/progtest.m4 $(top_srcdir)/m4/vapigen.m4 \
-	$(top_srcdir)/configure.ac
+	$(top_srcdir)/m4/libtool.m4 $(top_srcdir)/m4/ltoptions.m4 \
+	$(top_srcdir)/m4/ltsugar.m4 $(top_srcdir)/m4/ltversion.m4 \
+	$(top_srcdir)/m4/lt~obsolete.m4 $(top_srcdir)/m4/nls.m4 \
+	$(top_srcdir)/m4/po.m4 $(top_srcdir)/m4/progtest.m4 \
+	$(top_srcdir)/m4/vapigen.m4 $(top_srcdir)/configure.ac
 am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \
 	$(ACLOCAL_M4)
 mkinstalldirs = $(install_sh) -d
@@ -219,12 +218,6 @@ LIBGCRYPT_LIBS = @LIBGCRYPT_LIBS@
 LIBICONV = @LIBICONV@
 LIBINTL = @LIBINTL@
 LIBM = @LIBM@
-LIBNL1_CFLAGS = @LIBNL1_CFLAGS@
-LIBNL1_LIBS = @LIBNL1_LIBS@
-LIBNL2_CFLAGS = @LIBNL2_CFLAGS@
-LIBNL2_LIBS = @LIBNL2_LIBS@
-LIBNL3_CFLAGS = @LIBNL3_CFLAGS@
-LIBNL3_LIBS = @LIBNL3_LIBS@
 LIBNL_CFLAGS = @LIBNL_CFLAGS@
 LIBNL_LIBS = @LIBNL_LIBS@
 LIBOBJS = @LIBOBJS@
@@ -377,7 +370,8 @@ with_resolvconf = @with_resolvconf@
 @ENABLE_TESTS_TRUE@	test-dhcp-dhclient.c
 
 @ENABLE_TESTS_TRUE@test_dhcp_dhclient_CPPFLAGS = \
-@ENABLE_TESTS_TRUE@	$(GLIB_CFLAGS)
+@ENABLE_TESTS_TRUE@	$(GLIB_CFLAGS) \
+@ENABLE_TESTS_TRUE@	-DTESTDIR="\"$(abs_srcdir)\""
 
 @ENABLE_TESTS_TRUE@test_dhcp_dhclient_LDADD = \
 @ENABLE_TESTS_TRUE@	-ldl \
@@ -385,6 +379,10 @@ with_resolvconf = @with_resolvconf@
 @ENABLE_TESTS_TRUE@	$(top_builddir)/libnm-util/libnm-util.la \
 @ENABLE_TESTS_TRUE@	$(GLIB_LIBS)
 
+EXTRA_DIST = \
+	test-dhclient-duid.leases \
+	test-dhclient-commented-duid.leases
+
 all: all-am
 
 .SUFFIXES:
diff --git a/src/dhcp-manager/tests/test-dhclient-commented-duid.leases b/src/dhcp-manager/tests/test-dhclient-commented-duid.leases
new file mode 100644
index 00000000..3e46ae7d
--- /dev/null
+++ b/src/dhcp-manager/tests/test-dhclient-commented-duid.leases
@@ -0,0 +1,2 @@
+#default-duid "\000\001\000\001\030y\246\023`g \354Lp";
+
diff --git a/src/dhcp-manager/tests/test-dhclient-duid.leases b/src/dhcp-manager/tests/test-dhclient-duid.leases
new file mode 100644
index 00000000..229331d4
--- /dev/null
+++ b/src/dhcp-manager/tests/test-dhclient-duid.leases
@@ -0,0 +1,2 @@
+default-duid "\000\001\000\001\030y\246\023`g \354Lp";
+
diff --git a/src/dhcp-manager/tests/test-dhcp-dhclient.c b/src/dhcp-manager/tests/test-dhcp-dhclient.c
index a87c29aa..7eb2d358 100644
--- a/src/dhcp-manager/tests/test-dhcp-dhclient.c
+++ b/src/dhcp-manager/tests/test-dhcp-dhclient.c
@@ -20,6 +20,7 @@
 
 #include <glib.h>
 #include <string.h>
+#include <unistd.h>
 
 #include "nm-dhcp-dhclient-utils.h"
 #include "nm-utils.h"
@@ -225,6 +226,173 @@ test_existing_multiline_alsoreq (void)
 
 /*******************************************/
 
+static void
+test_one_duid (const char *escaped, const guint8 *unescaped, guint len)
+{
+	GByteArray *t;
+	char *w;
+
+	t = nm_dhcp_dhclient_unescape_duid (escaped);
+	g_assert (t);
+	g_assert_cmpint (t->len, ==, len);
+	g_assert_cmpint (memcmp (t->data, unescaped, len), ==, 0);
+	g_byte_array_free (t, TRUE);
+
+	t = g_byte_array_sized_new (len);
+	g_byte_array_append (t, unescaped, len);
+	w = nm_dhcp_dhclient_escape_duid (t);
+	g_assert (w);
+	g_assert_cmpint (strlen (escaped), ==, strlen (w));
+	g_assert_cmpstr (escaped, ==, w);
+}
+
+static void
+test_duids (void)
+{
+	const guint8 test1_u[] = { 0x00, 0x01, 0x00, 0x01, 0x13, 0x6f, 0x13, 0x6e,
+	                           0x00, 0x22, 0xfa, 0x8c, 0xd6, 0xc2 };
+	const char *test1_s = "\\000\\001\\000\\001\\023o\\023n\\000\\\"\\372\\214\\326\\302";
+
+	const guint8 test2_u[] = { 0x00, 0x01, 0x00, 0x01, 0x17, 0x57, 0xee, 0x39,
+	                           0x00, 0x23, 0x15, 0x08, 0x7E, 0xac };
+	const char *test2_s = "\\000\\001\\000\\001\\027W\\3569\\000#\\025\\010~\\254";
+
+	const guint8 test3_u[] = { 0x00, 0x01, 0x00, 0x01, 0x17, 0x58, 0xe8, 0x58,
+	                           0x00, 0x23, 0x15, 0x08, 0x7e, 0xac };
+	const char *test3_s = "\\000\\001\\000\\001\\027X\\350X\\000#\\025\\010~\\254";
+
+	const guint8 test4_u[] = { 0x00, 0x01, 0x00, 0x01, 0x15, 0xd5, 0x31, 0x97,
+	                           0x00, 0x16, 0xeb, 0x04, 0x45, 0x18 };
+	const char *test4_s = "\\000\\001\\000\\001\\025\\3251\\227\\000\\026\\353\\004E\\030";
+
+	const char *bad_s = "\\000\\001\\000\\001\\425\\3251\\227\\000\\026\\353\\004E\\030";
+
+	test_one_duid (test1_s, test1_u, sizeof (test1_u));
+	test_one_duid (test2_s, test2_u, sizeof (test2_u));
+	test_one_duid (test3_s, test3_u, sizeof (test3_u));
+	test_one_duid (test4_s, test4_u, sizeof (test4_u));
+
+	/* Invalid octal digit */
+	g_assert (nm_dhcp_dhclient_unescape_duid (bad_s) == NULL);
+}
+
+static void
+test_read_duid_from_leasefile (void)
+{
+	const guint8 expected[] = { 0x00, 0x01, 0x00, 0x01, 0x18, 0x79, 0xa6,
+	                            0x13, 0x60, 0x67, 0x20, 0xec, 0x4c, 0x70 };
+	GByteArray *duid;
+	GError *error = NULL;
+
+	duid = nm_dhcp_dhclient_read_duid (TESTDIR "/test-dhclient-duid.leases", &error);
+	g_assert_no_error (error);
+	g_assert (duid);
+	g_assert_cmpint (duid->len, ==, sizeof (expected));
+	g_assert_cmpint (memcmp (duid->data, expected, duid->len), ==, 0);
+
+	g_byte_array_free (duid, TRUE);
+}
+
+static void
+test_read_commented_duid_from_leasefile (void)
+{
+	GByteArray *duid;
+	GError *error = NULL;
+
+	duid = nm_dhcp_dhclient_read_duid (TESTDIR "/test-dhclient-commented-duid.leases", &error);
+	g_assert_no_error (error);
+	g_assert (duid == NULL);
+}
+
+static void
+test_write_duid (void)
+{
+	const char *duid = "\\000\\001\\000\\001\\027X\\350X\\000#\\025\\010~\\254";
+	const char *expected_contents = "default-duid \"\\000\\001\\000\\001\\027X\\350X\\000#\\025\\010~\\254\";\n";
+	GError *error = NULL;
+	char *contents = NULL;
+	gboolean success;
+	const char *path = "test-dhclient-write-duid.leases";
+
+	success = nm_dhcp_dhclient_save_duid (path, duid, &error);
+	g_assert_no_error (error);
+	g_assert (success);
+
+	success = g_file_get_contents (path, &contents, NULL, &error);
+	g_assert_no_error (error);
+	g_assert (success);
+
+	unlink (path);
+	g_assert_cmpstr (expected_contents, ==, contents);
+
+	g_free (contents);
+}
+
+static void
+test_write_existing_duid (void)
+{
+	const char *duid = "\\000\\001\\000\\001\\023o\\023n\\000\\\"\\372\\214\\326\\302";
+	const char *expected_contents = "default-duid \"\\000\\001\\000\\001\\027X\\350X\\000#\\025\\010~\\254\";\n";
+	GError *error = NULL;
+	char *contents = NULL;
+	gboolean success;
+	const char *path = "test-dhclient-write-existing-duid.leases";
+
+	success = g_file_set_contents (path, expected_contents, -1, &error);
+	g_assert_no_error (error);
+	g_assert (success);
+
+	/* Save other DUID; should be a no-op */
+	success = nm_dhcp_dhclient_save_duid (path, duid, &error);
+	g_assert_no_error (error);
+	g_assert (success);
+
+	/* reread original contents */
+	success = g_file_get_contents (path, &contents, NULL, &error);
+	g_assert_no_error (error);
+	g_assert (success);
+
+	unlink (path);
+	g_assert_cmpstr (expected_contents, ==, contents);
+
+	g_free (contents);
+}
+
+static void
+test_write_existing_commented_duid (void)
+{
+	#define DUID "\\000\\001\\000\\001\\023o\\023n\\000\\\"\\372\\214\\326\\302"
+	#define ORIG_CONTENTS "#default-duid \"\\000\\001\\000\\001\\027X\\350X\\000#\\025\\010~\\254\";\n"
+	const char *expected_contents = \
+		"default-duid \"" DUID "\";\n"
+		ORIG_CONTENTS;
+	GError *error = NULL;
+	char *contents = NULL;
+	gboolean success;
+	const char *path = "test-dhclient-write-existing-commented-duid.leases";
+
+	success = g_file_set_contents (path, ORIG_CONTENTS, -1, &error);
+	g_assert_no_error (error);
+	g_assert (success);
+
+	/* Save other DUID; should be a no-op */
+	success = nm_dhcp_dhclient_save_duid (path, DUID, &error);
+	g_assert_no_error (error);
+	g_assert (success);
+
+	/* reread original contents */
+	success = g_file_get_contents (path, &contents, NULL, &error);
+	g_assert_no_error (error);
+	g_assert (success);
+
+	unlink (path);
+	g_assert_cmpstr (expected_contents, ==, contents);
+
+	g_free (contents);
+}
+
+/*******************************************/
+
 #if GLIB_CHECK_VERSION(2,25,12)
 typedef GTestFixtureFunc TCFunc;
 #else
@@ -248,6 +416,14 @@ int main (int argc, char **argv)
 	g_test_suite_add (suite, TESTCASE (test_override_hostname, NULL));
 	g_test_suite_add (suite, TESTCASE (test_existing_alsoreq, NULL));
 	g_test_suite_add (suite, TESTCASE (test_existing_multiline_alsoreq, NULL));
+	g_test_suite_add (suite, TESTCASE (test_duids, NULL));
+
+	g_test_suite_add (suite, TESTCASE (test_read_duid_from_leasefile, NULL));
+	g_test_suite_add (suite, TESTCASE (test_read_commented_duid_from_leasefile, NULL));
+
+	g_test_suite_add (suite, TESTCASE (test_write_duid, NULL));
+	g_test_suite_add (suite, TESTCASE (test_write_existing_duid, NULL));
+	g_test_suite_add (suite, TESTCASE (test_write_existing_commented_duid, NULL));
 
 	return g_test_run ();
 }
diff --git a/src/dns-manager/Makefile.in b/src/dns-manager/Makefile.in
index b0ea7e77..e5dfb187 100644
--- a/src/dns-manager/Makefile.in
+++ b/src/dns-manager/Makefile.in
@@ -61,12 +61,11 @@ am__aclocal_m4_deps = $(top_srcdir)/m4/compiler_warnings.m4 \
 	$(top_srcdir)/m4/intlmacosx.m4 $(top_srcdir)/m4/intltool.m4 \
 	$(top_srcdir)/m4/introspection.m4 $(top_srcdir)/m4/lib-ld.m4 \
 	$(top_srcdir)/m4/lib-link.m4 $(top_srcdir)/m4/lib-prefix.m4 \
-	$(top_srcdir)/m4/libnl-check.m4 $(top_srcdir)/m4/libtool.m4 \
-	$(top_srcdir)/m4/ltoptions.m4 $(top_srcdir)/m4/ltsugar.m4 \
-	$(top_srcdir)/m4/ltversion.m4 $(top_srcdir)/m4/lt~obsolete.m4 \
-	$(top_srcdir)/m4/nls.m4 $(top_srcdir)/m4/po.m4 \
-	$(top_srcdir)/m4/progtest.m4 $(top_srcdir)/m4/vapigen.m4 \
-	$(top_srcdir)/configure.ac
+	$(top_srcdir)/m4/libtool.m4 $(top_srcdir)/m4/ltoptions.m4 \
+	$(top_srcdir)/m4/ltsugar.m4 $(top_srcdir)/m4/ltversion.m4 \
+	$(top_srcdir)/m4/lt~obsolete.m4 $(top_srcdir)/m4/nls.m4 \
+	$(top_srcdir)/m4/po.m4 $(top_srcdir)/m4/progtest.m4 \
+	$(top_srcdir)/m4/vapigen.m4 $(top_srcdir)/configure.ac
 am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \
 	$(ACLOCAL_M4)
 mkinstalldirs = $(install_sh) -d
@@ -222,12 +221,6 @@ LIBGCRYPT_LIBS = @LIBGCRYPT_LIBS@
 LIBICONV = @LIBICONV@
 LIBINTL = @LIBINTL@
 LIBM = @LIBM@
-LIBNL1_CFLAGS = @LIBNL1_CFLAGS@
-LIBNL1_LIBS = @LIBNL1_LIBS@
-LIBNL2_CFLAGS = @LIBNL2_CFLAGS@
-LIBNL2_LIBS = @LIBNL2_LIBS@
-LIBNL3_CFLAGS = @LIBNL3_CFLAGS@
-LIBNL3_LIBS = @LIBNL3_LIBS@
 LIBNL_CFLAGS = @LIBNL_CFLAGS@
 LIBNL_LIBS = @LIBNL_LIBS@
 LIBOBJS = @LIBOBJS@
diff --git a/src/dns-manager/nm-dns-dnsmasq.c b/src/dns-manager/nm-dns-dnsmasq.c
index e07240c5..f7e27da3 100644
--- a/src/dns-manager/nm-dns-dnsmasq.c
+++ b/src/dns-manager/nm-dns-dnsmasq.c
@@ -183,19 +183,23 @@ error:
 }
 
 static gboolean
-add_ip6_config (GString *str, NMIP6Config *ip6, gboolean split, const char *iface)
+add_ip6_config (GString *str, NMIP6Config *ip6, gboolean split)
 {
 	const struct in6_addr *addr;
 	char *buf;
 	int n, i;
 	gboolean added = FALSE;
+	const char *iface;
+
+	iface = g_object_get_data (G_OBJECT (ip6), IP_CONFIG_IFACE_TAG);
+	g_assert (iface);
 
 	if (split) {
 		if (nm_ip6_config_get_num_nameservers (ip6) == 0)
 			return FALSE;
 
 		/* FIXME: it appears that dnsmasq can only handle one nameserver
-		 * per domain (at the manpage seems to indicate that) so only use
+		 * per domain (at least the manpage seems to indicate that) so only use
 		 * the first nameserver here.
 		 */
 		addr = nm_ip6_config_get_nameserver (ip6, 0);
@@ -247,8 +251,7 @@ update (NMDnsPlugin *plugin,
         const GSList *vpn_configs,
         const GSList *dev_configs,
         const GSList *other_configs,
-        const char *hostname,
-        const char *iface)
+        const char *hostname)
 {
 	NMDnsDnsmasq *self = NM_DNS_DNSMASQ (plugin);
 	GString *conf;
@@ -274,7 +277,7 @@ update (NMDnsPlugin *plugin,
 		if (NM_IS_IP4_CONFIG (iter->data))
 			add_ip4_config (conf, NM_IP4_CONFIG (iter->data), TRUE);
 		else if (NM_IS_IP6_CONFIG (iter->data))
-			add_ip6_config (conf, NM_IP6_CONFIG (iter->data), TRUE, iface);
+			add_ip6_config (conf, NM_IP6_CONFIG (iter->data), TRUE);
 	}
 
 	/* Now add interface configs without split DNS */
@@ -282,7 +285,7 @@ update (NMDnsPlugin *plugin,
 		if (NM_IS_IP4_CONFIG (iter->data))
 			add_ip4_config (conf, NM_IP4_CONFIG (iter->data), FALSE);
 		else if (NM_IS_IP6_CONFIG (iter->data))
-			add_ip6_config (conf, NM_IP6_CONFIG (iter->data), FALSE, iface);
+			add_ip6_config (conf, NM_IP6_CONFIG (iter->data), FALSE);
 	}
 
 	/* And any other random configs */
@@ -290,7 +293,7 @@ update (NMDnsPlugin *plugin,
 		if (NM_IS_IP4_CONFIG (iter->data))
 			add_ip4_config (conf, NM_IP4_CONFIG (iter->data), FALSE);
 		else if (NM_IS_IP6_CONFIG (iter->data))
-			add_ip6_config (conf, NM_IP6_CONFIG (iter->data), FALSE, iface);
+			add_ip6_config (conf, NM_IP6_CONFIG (iter->data), FALSE);
 	}
 
 	/* Write out the config file */
diff --git a/src/dns-manager/nm-dns-manager.c b/src/dns-manager/nm-dns-manager.c
index 38691f37..b838e9f0 100644
--- a/src/dns-manager/nm-dns-manager.c
+++ b/src/dns-manager/nm-dns-manager.c
@@ -74,11 +74,7 @@ typedef struct {
 
 	GSList *plugins;
 
-	/* This is a hack because SUSE's netconfig always wants changes
-	 * associated with a network interface, but sometimes a change isn't
-	 * associated with a network interface (like hostnames).
-	 */
-	char *last_iface;
+	gboolean dns_touched;
 } NMDnsManagerPrivate;
 
 
@@ -158,14 +154,19 @@ merge_one_ip4_config (NMResolvConfData *rc, NMIP4Config *src)
 }
 
 static void
-merge_one_ip6_config (NMResolvConfData *rc, NMIP6Config *src, const char *iface)
+merge_one_ip6_config (NMResolvConfData *rc, NMIP6Config *src)
 {
 	guint32 num, i;
+	const char *iface;
+
+	iface = g_object_get_data (G_OBJECT (src), IP_CONFIG_IFACE_TAG);
+	g_assert (iface);
 
 	num = nm_ip6_config_get_num_nameservers (src);
 	for (i = 0; i < num; i++) {
 		const struct in6_addr *addr;
 		char buf[INET6_ADDRSTRLEN];
+		char *tmp;
 
 		addr = nm_ip6_config_get_nameserver (src, i);
 
@@ -176,7 +177,6 @@ merge_one_ip6_config (NMResolvConfData *rc, NMIP6Config *src, const char *iface)
 		} else {
 			if (inet_ntop (AF_INET6, addr, buf, INET6_ADDRSTRLEN) > 0) {
 				if (IN6_IS_ADDR_LINKLOCAL (addr) && strchr (buf, '%') == NULL) {
-					char *tmp;
 					tmp = g_strdup_printf ("%s%%%s", buf, iface);
 					add_string_item (rc->nameservers, tmp);
 					g_free (tmp);
@@ -261,7 +261,6 @@ dispatch_netconfig (const char *domain,
                     char **nameservers,
                     const char *nis_domain,
                     char **nis_servers,
-                    const char *iface,
                     GError **error)
 {
 	char *str, *tmp;
@@ -273,16 +272,10 @@ dispatch_netconfig (const char *domain,
 	if (pid < 0)
 		return FALSE;
 
-	// FIXME: this is wrong. We are not writing out the iface-specific
-	// resolv.conf data, we are writing out an already-fully-merged
-	// resolv.conf. Assuming netconfig works in the obvious way, then
-	// there are various failure modes, such as, eg, bringing up a VPN on
-	// eth0, then bringing up wlan0, then bringing down the VPN. Because
-	// NMDnsManager would have claimed that the VPN DNS server was also
-	// part of the wlan0 config, it will remain in resolv.conf after the
-	// VPN goes down, even though it is presumably no longer reachable
-	// at that point.
-	write_to_netconfig (fd, "INTERFACE", iface);
+	/* NM is writing already-merged DNS information to netconfig, so it
+	 * does not apply to a specific network interface.
+	 */
+	write_to_netconfig (fd, "INTERFACE", "NetworkManager");
 
 	if (searches) {
 		str = g_strjoinv (" ", searches);
@@ -404,7 +397,6 @@ static gboolean
 dispatch_resolvconf (const char *domain,
                      char **searches,
                      char **nameservers,
-                     const char *iface,
                      GError **error)
 {
 	char *cmd;
@@ -416,7 +408,7 @@ dispatch_resolvconf (const char *domain,
 
 	if (domain || searches || nameservers) {
 		cmd = g_strconcat (RESOLVCONF_PATH, " -a ", "NetworkManager", NULL);
-		nm_log_info (LOGD_DNS, "(%s): writing resolv.conf to %s", iface, RESOLVCONF_PATH);
+		nm_log_info (LOGD_DNS, "Writing DNS information to %s", RESOLVCONF_PATH);
 		if ((f = popen (cmd, "w")) == NULL)
 			g_set_error (error,
 			             NM_DNS_MANAGER_ERROR,
@@ -430,7 +422,7 @@ dispatch_resolvconf (const char *domain,
 		}
 	} else {
 		cmd = g_strconcat (RESOLVCONF_PATH, " -d ", "NetworkManager", NULL);
-		nm_log_info (LOGD_DNS, "(%s): removing resolv.conf from %s", iface, RESOLVCONF_PATH);
+		nm_log_info (LOGD_DNS, "Removing DNS information from %s", RESOLVCONF_PATH);
 		if (nm_spawn_process (cmd) == 0)
 			retval = TRUE;
 	}
@@ -445,7 +437,6 @@ static gboolean
 update_resolv_conf (const char *domain,
                     char **searches,
                     char **nameservers,
-                    const char *iface,
                     GError **error)
 {
 	char *tmp_resolv_conf;
@@ -569,7 +560,6 @@ compute_hash (NMDnsManager *self, guint8 buffer[HASH_LEN])
 
 static gboolean
 update_dns (NMDnsManager *self,
-            const char *iface,
             gboolean no_caching,
             GError **error)
 {
@@ -589,12 +579,9 @@ update_dns (NMDnsManager *self,
 
 	priv = NM_DNS_MANAGER_GET_PRIVATE (self);
 
-	nm_log_dbg (LOGD_DNS, "updating resolv.conf");
+	priv->dns_touched = TRUE;
 
-	if (iface && (iface != priv->last_iface)) {
-		g_free (priv->last_iface);
-		priv->last_iface = g_strdup (iface);
-	}
+	nm_log_dbg (LOGD_DNS, "updating resolv.conf");
 
 	/* Update hash with config we're applying */
 	compute_hash (self, priv->hash);
@@ -611,9 +598,9 @@ update_dns (NMDnsManager *self,
 		merge_one_ip4_config (&rc, priv->ip4_device_config);
 
 	if (priv->ip6_vpn_config)
-		merge_one_ip6_config (&rc, priv->ip6_vpn_config, iface);
+		merge_one_ip6_config (&rc, priv->ip6_vpn_config);
 	if (priv->ip6_device_config)
-		merge_one_ip6_config (&rc, priv->ip6_device_config, iface);
+		merge_one_ip6_config (&rc, priv->ip6_device_config);
 
 	for (iter = priv->configs; iter; iter = g_slist_next (iter)) {
 		if (   (iter->data == priv->ip4_vpn_config)
@@ -629,7 +616,7 @@ update_dns (NMDnsManager *self,
 		} else if (NM_IS_IP6_CONFIG (iter->data)) {
 			NMIP6Config *config = NM_IP6_CONFIG (iter->data);
 
-			merge_one_ip6_config (&rc, config, iface);
+			merge_one_ip6_config (&rc, config);
 		} else
 			g_assert_not_reached ();
 	}
@@ -721,8 +708,7 @@ update_dns (NMDnsManager *self,
 		                           vpn_configs,
 		                           dev_configs,
 		                           other_configs,
-		                           priv->hostname,
-					   iface)) {
+		                           priv->hostname)) {
 			nm_log_warn (LOGD_DNS, "DNS: plugin %s update failed", plugin_name);
 
 			/* If the plugin failed to update, we shouldn't write out a local
@@ -747,19 +733,18 @@ update_dns (NMDnsManager *self,
 	}
 
 #ifdef RESOLVCONF_PATH
-	success = dispatch_resolvconf (domain, searches, nameservers, iface, error);
+	success = dispatch_resolvconf (domain, searches, nameservers, error);
 #endif
 
 #ifdef NETCONFIG_PATH
 	if (success == FALSE) {
 		success = dispatch_netconfig (domain, searches, nameservers,
-		                              nis_domain, nis_servers,
-		                              iface, error);
+		                              nis_domain, nis_servers, error);
 	}
 #endif
 
 	if (success == FALSE)
-		success = update_resolv_conf (domain, searches, nameservers, iface, error);
+		success = update_resolv_conf (domain, searches, nameservers, error);
 
 	if (searches)
 		g_strfreev (searches);
@@ -775,7 +760,6 @@ static void
 plugin_failed (NMDnsPlugin *plugin, gpointer user_data)
 {
 	NMDnsManager *self = NM_DNS_MANAGER (user_data);
-	NMDnsManagerPrivate *priv = NM_DNS_MANAGER_GET_PRIVATE (self);
 	GError *error = NULL;
 
 	/* Errors with non-caching plugins aren't fatal */
@@ -783,7 +767,7 @@ plugin_failed (NMDnsPlugin *plugin, gpointer user_data)
 		return;
 
 	/* Disable caching until the next DNS update */
-	if (!update_dns (self, priv->last_iface, TRUE, &error)) {
+	if (!update_dns (self, TRUE, &error)) {
 		nm_log_warn (LOGD_DNS, "could not commit DNS changes: (%d) %s",
 		             error ? error->code : -1,
 		             error && error->message ? error->message : "(unknown)");
@@ -806,6 +790,8 @@ nm_dns_manager_add_ip4_config (NMDnsManager *mgr,
 
 	priv = NM_DNS_MANAGER_GET_PRIVATE (mgr);
 
+	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;
@@ -821,7 +807,7 @@ nm_dns_manager_add_ip4_config (NMDnsManager *mgr,
 	if (!g_slist_find (priv->configs, config))
 		priv->configs = g_slist_append (priv->configs, g_object_ref (config));
 
-	if (!priv->updates_queue && !update_dns (mgr, iface, FALSE, &error)) {
+	if (!priv->updates_queue && !update_dns (mgr, FALSE, &error)) {
 		nm_log_warn (LOGD_DNS, "could not commit DNS changes: (%d) %s",
 		             error ? error->code : -1,
 		             error && error->message ? error->message : "(unknown)");
@@ -832,15 +818,12 @@ nm_dns_manager_add_ip4_config (NMDnsManager *mgr,
 }
 
 gboolean
-nm_dns_manager_remove_ip4_config (NMDnsManager *mgr,
-                                  const char *iface,
-                                  NMIP4Config *config)
+nm_dns_manager_remove_ip4_config (NMDnsManager *mgr, NMIP4Config *config)
 {
 	NMDnsManagerPrivate *priv;
 	GError *error = NULL;
 
 	g_return_val_if_fail (mgr != NULL, FALSE);
-	g_return_val_if_fail (iface != NULL, FALSE);
 	g_return_val_if_fail (config != NULL, FALSE);
 
 	priv = NM_DNS_MANAGER_GET_PRIVATE (mgr);
@@ -858,13 +841,15 @@ nm_dns_manager_remove_ip4_config (NMDnsManager *mgr,
 
 	g_object_unref (config);
 
-	if (!priv->updates_queue && !update_dns (mgr, iface, FALSE, &error)) {
+	if (!priv->updates_queue && !update_dns (mgr, FALSE, &error)) {
 		nm_log_warn (LOGD_DNS, "could not commit DNS changes: (%d) %s",
 		             error ? error->code : -1,
 		             error && error->message ? error->message : "(unknown)");
 		g_clear_error (&error);
 	}
 
+	g_object_set_data (G_OBJECT (config), IP_CONFIG_IFACE_TAG, NULL);
+
 	return TRUE;
 }
 
@@ -883,6 +868,8 @@ nm_dns_manager_add_ip6_config (NMDnsManager *mgr,
 
 	priv = NM_DNS_MANAGER_GET_PRIVATE (mgr);
 
+	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->ip6_vpn_config = config;
@@ -898,7 +885,7 @@ nm_dns_manager_add_ip6_config (NMDnsManager *mgr,
 	if (!g_slist_find (priv->configs, config))
 		priv->configs = g_slist_append (priv->configs, g_object_ref (config));
 
-	if (!priv->updates_queue && !update_dns (mgr, iface, FALSE, &error)) {
+	if (!priv->updates_queue && !update_dns (mgr, FALSE, &error)) {
 		nm_log_warn (LOGD_DNS, "could not commit DNS changes: (%d) %s",
 		             error ? error->code : -1,
 		             error && error->message ? error->message : "(unknown)");
@@ -909,15 +896,12 @@ nm_dns_manager_add_ip6_config (NMDnsManager *mgr,
 }
 
 gboolean
-nm_dns_manager_remove_ip6_config (NMDnsManager *mgr,
-                                  const char *iface,
-                                  NMIP6Config *config)
+nm_dns_manager_remove_ip6_config (NMDnsManager *mgr, NMIP6Config *config)
 {
 	NMDnsManagerPrivate *priv;
 	GError *error = NULL;
 
 	g_return_val_if_fail (mgr != NULL, FALSE);
-	g_return_val_if_fail (iface != NULL, FALSE);
 	g_return_val_if_fail (config != NULL, FALSE);
 
 	priv = NM_DNS_MANAGER_GET_PRIVATE (mgr);
@@ -935,13 +919,15 @@ nm_dns_manager_remove_ip6_config (NMDnsManager *mgr,
 
 	g_object_unref (config);	
 
-	if (!priv->updates_queue && !update_dns (mgr, iface, FALSE, &error)) {
+	if (!priv->updates_queue && !update_dns (mgr, FALSE, &error)) {
 		nm_log_warn (LOGD_DNS, "could not commit DNS changes: (%d) %s",
 		             error ? error->code : -1,
 		             error && error->message ? error->message : "(unknown)");
 		g_clear_error (&error);
 	}
 
+	g_object_set_data (G_OBJECT (config), IP_CONFIG_IFACE_TAG, NULL);
+
 	return TRUE;
 }
 
@@ -973,7 +959,7 @@ nm_dns_manager_set_hostname (NMDnsManager *mgr,
 	 * wants one.  But hostname changes are system-wide and *not* tied to a
 	 * specific interface, so netconfig can't really handle this.  Fake it.
 	 */
-	if (!priv->updates_queue && !update_dns (mgr, priv->last_iface, FALSE, &error)) {
+	if (!priv->updates_queue && !update_dns (mgr, FALSE, &error)) {
 		nm_log_warn (LOGD_DNS, "could not commit DNS changes: (%d) %s",
 		             error ? error->code : -1,
 		             error && error->message ? error->message : "(unknown)");
@@ -1023,7 +1009,7 @@ nm_dns_manager_end_updates (NMDnsManager *mgr, const char *func)
 
 	/* Commit all the outstanding changes */
 	nm_log_dbg (LOGD_DNS, "(%s): committing DNS changes (%d)", func, priv->updates_queue);
-	if (!update_dns (mgr, priv->last_iface, FALSE, &error)) {
+	if (!update_dns (mgr, FALSE, &error)) {
 		nm_log_warn (LOGD_DNS, "could not commit DNS changes: (%d) %s",
 			         error ? error->code : -1,
 			         error && error->message ? error->message : "(unknown)");
@@ -1124,20 +1110,16 @@ dispose (GObject *object)
 		g_slist_free (priv->plugins);
 		priv->plugins = NULL;
 
-		/* If last_iface is NULL, this means we haven't done a DNS update before,
-		 * so no reason to try and take down entries from resolv.conf.
+		/* 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
+		 * DNS after disposing of all plugins.  But if we haven't done any
+		 * DNS updates yet, there's no reason to touch resolv.conf on shutdown.
 		 */
-		if (priv->last_iface != NULL) {
-			/* 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
-			 * DNS after disposing of all plugins.
-			 */
-			if (!update_dns (self, priv->last_iface, TRUE, &error)) {
-				nm_log_warn (LOGD_DNS, "could not commit DNS changes on shutdown: (%d) %s",
-				             error ? error->code : -1,
-				             error && error->message ? error->message : "(unknown)");
-				g_clear_error (&error);
-			}
+		if (priv->dns_touched && !update_dns (self, TRUE, &error)) {
+			nm_log_warn (LOGD_DNS, "could not commit DNS changes on shutdown: (%d) %s",
+			             error ? error->code : -1,
+			             error && error->message ? error->message : "(unknown)");
+			g_clear_error (&error);
 		}
 
 		g_slist_foreach (priv->configs, (GFunc) g_object_unref, NULL);
@@ -1154,7 +1136,6 @@ finalize (GObject *object)
 	NMDnsManagerPrivate *priv = NM_DNS_MANAGER_GET_PRIVATE (object);
 
 	g_free (priv->hostname);
-	g_free (priv->last_iface);
 
 	G_OBJECT_CLASS (nm_dns_manager_parent_class)->finalize (object);
 }
diff --git a/src/dns-manager/nm-dns-manager.h b/src/dns-manager/nm-dns-manager.h
index f559865b..23492012 100644
--- a/src/dns-manager/nm-dns-manager.h
+++ b/src/dns-manager/nm-dns-manager.h
@@ -75,18 +75,14 @@ gboolean nm_dns_manager_add_ip4_config (NMDnsManager *mgr,
                                         NMIP4Config *config,
                                         NMDnsIPConfigType cfg_type);
 
-gboolean nm_dns_manager_remove_ip4_config (NMDnsManager *mgr,
-                                           const char *iface,
-                                           NMIP4Config *config);
+gboolean nm_dns_manager_remove_ip4_config (NMDnsManager *mgr, NMIP4Config *config);
 
 gboolean nm_dns_manager_add_ip6_config (NMDnsManager *mgr,
                                         const char *iface,
                                         NMIP6Config *config,
                                         NMDnsIPConfigType cfg_type);
 
-gboolean nm_dns_manager_remove_ip6_config (NMDnsManager *mgr,
-                                           const char *iface,
-                                           NMIP6Config *config);
+gboolean nm_dns_manager_remove_ip6_config (NMDnsManager *mgr, NMIP6Config *config);
 
 void nm_dns_manager_set_hostname (NMDnsManager *mgr,
                                   const char *hostname);
diff --git a/src/dns-manager/nm-dns-plugin.c b/src/dns-manager/nm-dns-plugin.c
index b26f2b94..e85b2a09 100644
--- a/src/dns-manager/nm-dns-plugin.c
+++ b/src/dns-manager/nm-dns-plugin.c
@@ -56,8 +56,7 @@ nm_dns_plugin_update (NMDnsPlugin *self,
                       const GSList *vpn_configs,
                       const GSList *dev_configs,
                       const GSList *other_configs,
-                      const char *hostname,
-                      const char *iface)
+                      const char *hostname)
 {
 	g_return_val_if_fail (NM_DNS_PLUGIN_GET_CLASS (self)->update != NULL, FALSE);
 
@@ -65,8 +64,7 @@ nm_dns_plugin_update (NMDnsPlugin *self,
 	                                               vpn_configs,
 	                                               dev_configs,
 	                                               other_configs,
-	                                               hostname,
-						       iface);
+	                                               hostname);
 }
 
 static gboolean
diff --git a/src/dns-manager/nm-dns-plugin.h b/src/dns-manager/nm-dns-plugin.h
index de4ad84e..2a66557b 100644
--- a/src/dns-manager/nm-dns-plugin.h
+++ b/src/dns-manager/nm-dns-plugin.h
@@ -32,6 +32,8 @@
 #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;
@@ -53,8 +55,7 @@ typedef struct {
 	                    const GSList *vpn_configs,
 	                    const GSList *dev_configs,
 	                    const GSList *other_configs,
-	                    const char *hostname,
-	                    const char *iface);
+	                    const char *hostname);
 
 	/* Subclasses should override and return TRUE if they start a local
 	 * caching nameserver that listens on localhost and would block any
@@ -92,8 +93,7 @@ gboolean nm_dns_plugin_update (NMDnsPlugin *self,
                                const GSList *vpn_configs,
                                const GSList *dev_configs,
                                const GSList *other_configs,
-                               const char *hostname,
-                               const char *iface);
+                               const char *hostname);
 
 /* For subclasses/plugins */
 
diff --git a/src/dnsmasq-manager/Makefile.in b/src/dnsmasq-manager/Makefile.in
index 55bdc75a..69d0e825 100644
--- a/src/dnsmasq-manager/Makefile.in
+++ b/src/dnsmasq-manager/Makefile.in
@@ -61,12 +61,11 @@ am__aclocal_m4_deps = $(top_srcdir)/m4/compiler_warnings.m4 \
 	$(top_srcdir)/m4/intlmacosx.m4 $(top_srcdir)/m4/intltool.m4 \
 	$(top_srcdir)/m4/introspection.m4 $(top_srcdir)/m4/lib-ld.m4 \
 	$(top_srcdir)/m4/lib-link.m4 $(top_srcdir)/m4/lib-prefix.m4 \
-	$(top_srcdir)/m4/libnl-check.m4 $(top_srcdir)/m4/libtool.m4 \
-	$(top_srcdir)/m4/ltoptions.m4 $(top_srcdir)/m4/ltsugar.m4 \
-	$(top_srcdir)/m4/ltversion.m4 $(top_srcdir)/m4/lt~obsolete.m4 \
-	$(top_srcdir)/m4/nls.m4 $(top_srcdir)/m4/po.m4 \
-	$(top_srcdir)/m4/progtest.m4 $(top_srcdir)/m4/vapigen.m4 \
-	$(top_srcdir)/configure.ac
+	$(top_srcdir)/m4/libtool.m4 $(top_srcdir)/m4/ltoptions.m4 \
+	$(top_srcdir)/m4/ltsugar.m4 $(top_srcdir)/m4/ltversion.m4 \
+	$(top_srcdir)/m4/lt~obsolete.m4 $(top_srcdir)/m4/nls.m4 \
+	$(top_srcdir)/m4/po.m4 $(top_srcdir)/m4/progtest.m4 \
+	$(top_srcdir)/m4/vapigen.m4 $(top_srcdir)/configure.ac
 am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \
 	$(ACLOCAL_M4)
 mkinstalldirs = $(install_sh) -d
@@ -219,12 +218,6 @@ LIBGCRYPT_LIBS = @LIBGCRYPT_LIBS@
 LIBICONV = @LIBICONV@
 LIBINTL = @LIBINTL@
 LIBM = @LIBM@
-LIBNL1_CFLAGS = @LIBNL1_CFLAGS@
-LIBNL1_LIBS = @LIBNL1_LIBS@
-LIBNL2_CFLAGS = @LIBNL2_CFLAGS@
-LIBNL2_LIBS = @LIBNL2_LIBS@
-LIBNL3_CFLAGS = @LIBNL3_CFLAGS@
-LIBNL3_LIBS = @LIBNL3_LIBS@
 LIBNL_CFLAGS = @LIBNL_CFLAGS@
 LIBNL_LIBS = @LIBNL_LIBS@
 LIBOBJS = @LIBOBJS@
diff --git a/src/firewall-manager/Makefile.in b/src/firewall-manager/Makefile.in
index bf3f46c4..c221c9eb 100644
--- a/src/firewall-manager/Makefile.in
+++ b/src/firewall-manager/Makefile.in
@@ -61,12 +61,11 @@ am__aclocal_m4_deps = $(top_srcdir)/m4/compiler_warnings.m4 \
 	$(top_srcdir)/m4/intlmacosx.m4 $(top_srcdir)/m4/intltool.m4 \
 	$(top_srcdir)/m4/introspection.m4 $(top_srcdir)/m4/lib-ld.m4 \
 	$(top_srcdir)/m4/lib-link.m4 $(top_srcdir)/m4/lib-prefix.m4 \
-	$(top_srcdir)/m4/libnl-check.m4 $(top_srcdir)/m4/libtool.m4 \
-	$(top_srcdir)/m4/ltoptions.m4 $(top_srcdir)/m4/ltsugar.m4 \
-	$(top_srcdir)/m4/ltversion.m4 $(top_srcdir)/m4/lt~obsolete.m4 \
-	$(top_srcdir)/m4/nls.m4 $(top_srcdir)/m4/po.m4 \
-	$(top_srcdir)/m4/progtest.m4 $(top_srcdir)/m4/vapigen.m4 \
-	$(top_srcdir)/configure.ac
+	$(top_srcdir)/m4/libtool.m4 $(top_srcdir)/m4/ltoptions.m4 \
+	$(top_srcdir)/m4/ltsugar.m4 $(top_srcdir)/m4/ltversion.m4 \
+	$(top_srcdir)/m4/lt~obsolete.m4 $(top_srcdir)/m4/nls.m4 \
+	$(top_srcdir)/m4/po.m4 $(top_srcdir)/m4/progtest.m4 \
+	$(top_srcdir)/m4/vapigen.m4 $(top_srcdir)/configure.ac
 am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \
 	$(ACLOCAL_M4)
 mkinstalldirs = $(install_sh) -d
@@ -218,12 +217,6 @@ LIBGCRYPT_LIBS = @LIBGCRYPT_LIBS@
 LIBICONV = @LIBICONV@
 LIBINTL = @LIBINTL@
 LIBM = @LIBM@
-LIBNL1_CFLAGS = @LIBNL1_CFLAGS@
-LIBNL1_LIBS = @LIBNL1_LIBS@
-LIBNL2_CFLAGS = @LIBNL2_CFLAGS@
-LIBNL2_LIBS = @LIBNL2_LIBS@
-LIBNL3_CFLAGS = @LIBNL3_CFLAGS@
-LIBNL3_LIBS = @LIBNL3_LIBS@
 LIBNL_CFLAGS = @LIBNL_CFLAGS@
 LIBNL_LIBS = @LIBNL_LIBS@
 LIBOBJS = @LIBOBJS@
diff --git a/src/generated/Makefile.in b/src/generated/Makefile.in
index 7d55789b..98d22222 100644
--- a/src/generated/Makefile.in
+++ b/src/generated/Makefile.in
@@ -63,12 +63,11 @@ am__aclocal_m4_deps = $(top_srcdir)/m4/compiler_warnings.m4 \
 	$(top_srcdir)/m4/intlmacosx.m4 $(top_srcdir)/m4/intltool.m4 \
 	$(top_srcdir)/m4/introspection.m4 $(top_srcdir)/m4/lib-ld.m4 \
 	$(top_srcdir)/m4/lib-link.m4 $(top_srcdir)/m4/lib-prefix.m4 \
-	$(top_srcdir)/m4/libnl-check.m4 $(top_srcdir)/m4/libtool.m4 \
-	$(top_srcdir)/m4/ltoptions.m4 $(top_srcdir)/m4/ltsugar.m4 \
-	$(top_srcdir)/m4/ltversion.m4 $(top_srcdir)/m4/lt~obsolete.m4 \
-	$(top_srcdir)/m4/nls.m4 $(top_srcdir)/m4/po.m4 \
-	$(top_srcdir)/m4/progtest.m4 $(top_srcdir)/m4/vapigen.m4 \
-	$(top_srcdir)/configure.ac
+	$(top_srcdir)/m4/libtool.m4 $(top_srcdir)/m4/ltoptions.m4 \
+	$(top_srcdir)/m4/ltsugar.m4 $(top_srcdir)/m4/ltversion.m4 \
+	$(top_srcdir)/m4/lt~obsolete.m4 $(top_srcdir)/m4/nls.m4 \
+	$(top_srcdir)/m4/po.m4 $(top_srcdir)/m4/progtest.m4 \
+	$(top_srcdir)/m4/vapigen.m4 $(top_srcdir)/configure.ac
 am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \
 	$(ACLOCAL_M4)
 mkinstalldirs = $(install_sh) -d
@@ -218,12 +217,6 @@ LIBGCRYPT_LIBS = @LIBGCRYPT_LIBS@
 LIBICONV = @LIBICONV@
 LIBINTL = @LIBINTL@
 LIBM = @LIBM@
-LIBNL1_CFLAGS = @LIBNL1_CFLAGS@
-LIBNL1_LIBS = @LIBNL1_LIBS@
-LIBNL2_CFLAGS = @LIBNL2_CFLAGS@
-LIBNL2_LIBS = @LIBNL2_LIBS@
-LIBNL3_CFLAGS = @LIBNL3_CFLAGS@
-LIBNL3_LIBS = @LIBNL3_LIBS@
 LIBNL_CFLAGS = @LIBNL_CFLAGS@
 LIBNL_LIBS = @LIBNL_LIBS@
 LIBOBJS = @LIBOBJS@
diff --git a/src/generated/nm-enum-types.c b/src/generated/nm-enum-types.c
index 6d09c50a..c1eac45e 100644
--- a/src/generated/nm-enum-types.c
+++ b/src/generated/nm-enum-types.c
@@ -5,10 +5,10 @@
 
 #include "nm-enum-types.h"
 
-#include "nm-hostname-provider.h" 
 #include "nm-sleep-monitor.h" 
 #include "nm-device.h" 
 #include "nm-rfkill.h" 
+#include "NetworkManagerUtils.h" 
 #include "nm-device-vlan.h" 
 #include "nm-device-factory.h" 
 #include "nm-active-connection.h" 
@@ -26,6 +26,7 @@
 #include "nm-connection-provider.h" 
 #include "nm-device-bond.h" 
 #include "nm-wifi-ap-utils.h" 
+#include "nm-hostname-provider.h" 
 #include "nm-device-adsl.h" 
 #include "nm-policy-hosts.h" 
 #include "nm-dispatcher.h" 
@@ -42,7 +43,6 @@
 #include "nm-device-private.h" 
 #include "nm-policy.h" 
 #include "nm-manager-auth.h" 
-#include "NetworkManagerUtils.h" 
 #include "nm-config.h" 
 #include "nm-netlink-utils.h" 
 #include "nm-netlink-monitor.h" 
@@ -349,6 +349,7 @@ nm_manager_error_get_type (void)
         { NM_MANAGER_ERROR_ALREADY_ENABLED_OR_DISABLED, "NM_MANAGER_ERROR_ALREADY_ENABLED_OR_DISABLED", "AlreadyEnabledOrDisabled" },
         { NM_MANAGER_ERROR_UNSUPPORTED_CONNECTION_TYPE, "NM_MANAGER_ERROR_UNSUPPORTED_CONNECTION_TYPE", "UnsupportedConnectionType" },
         { NM_MANAGER_ERROR_DEPENDENCY_FAILED, "NM_MANAGER_ERROR_DEPENDENCY_FAILED", "DependencyFailed" },
+        { NM_MANAGER_ERROR_AUTOCONNECT_NOT_ALLOWED, "NM_MANAGER_ERROR_AUTOCONNECT_NOT_ALLOWED", "AutoconnectNotAllowed" },
         { 0, NULL, NULL }
       };
       GType g_define_type_id =
diff --git a/src/ip6-manager/Makefile.in b/src/ip6-manager/Makefile.in
index 317f27fb..e80c1103 100644
--- a/src/ip6-manager/Makefile.in
+++ b/src/ip6-manager/Makefile.in
@@ -61,12 +61,11 @@ am__aclocal_m4_deps = $(top_srcdir)/m4/compiler_warnings.m4 \
 	$(top_srcdir)/m4/intlmacosx.m4 $(top_srcdir)/m4/intltool.m4 \
 	$(top_srcdir)/m4/introspection.m4 $(top_srcdir)/m4/lib-ld.m4 \
 	$(top_srcdir)/m4/lib-link.m4 $(top_srcdir)/m4/lib-prefix.m4 \
-	$(top_srcdir)/m4/libnl-check.m4 $(top_srcdir)/m4/libtool.m4 \
-	$(top_srcdir)/m4/ltoptions.m4 $(top_srcdir)/m4/ltsugar.m4 \
-	$(top_srcdir)/m4/ltversion.m4 $(top_srcdir)/m4/lt~obsolete.m4 \
-	$(top_srcdir)/m4/nls.m4 $(top_srcdir)/m4/po.m4 \
-	$(top_srcdir)/m4/progtest.m4 $(top_srcdir)/m4/vapigen.m4 \
-	$(top_srcdir)/configure.ac
+	$(top_srcdir)/m4/libtool.m4 $(top_srcdir)/m4/ltoptions.m4 \
+	$(top_srcdir)/m4/ltsugar.m4 $(top_srcdir)/m4/ltversion.m4 \
+	$(top_srcdir)/m4/lt~obsolete.m4 $(top_srcdir)/m4/nls.m4 \
+	$(top_srcdir)/m4/po.m4 $(top_srcdir)/m4/progtest.m4 \
+	$(top_srcdir)/m4/vapigen.m4 $(top_srcdir)/configure.ac
 am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \
 	$(ACLOCAL_M4)
 mkinstalldirs = $(install_sh) -d
@@ -219,12 +218,6 @@ LIBGCRYPT_LIBS = @LIBGCRYPT_LIBS@
 LIBICONV = @LIBICONV@
 LIBINTL = @LIBINTL@
 LIBM = @LIBM@
-LIBNL1_CFLAGS = @LIBNL1_CFLAGS@
-LIBNL1_LIBS = @LIBNL1_LIBS@
-LIBNL2_CFLAGS = @LIBNL2_CFLAGS@
-LIBNL2_LIBS = @LIBNL2_LIBS@
-LIBNL3_CFLAGS = @LIBNL3_CFLAGS@
-LIBNL3_LIBS = @LIBNL3_LIBS@
 LIBNL_CFLAGS = @LIBNL_CFLAGS@
 LIBNL_LIBS = @LIBNL_LIBS@
 LIBOBJS = @LIBOBJS@
diff --git a/src/ip6-manager/nm-ip6-manager.c b/src/ip6-manager/nm-ip6-manager.c
index 490e9574..c2871e4a 100644
--- a/src/ip6-manager/nm-ip6-manager.c
+++ b/src/ip6-manager/nm-ip6-manager.c
@@ -93,6 +93,11 @@ typedef struct {
 	NMIP6Manager *manager;
 	char *iface;
 	int ifindex;
+	/* +7 since this field is used directly by stuff that expects
+	 * padding to multiples of 8 bytes.
+	 */
+	guint8 hwaddr[NM_UTILS_HWADDR_LEN_MAX + 7];
+	guint hwaddr_len;
 
 	gboolean has_linklocal;
 	gboolean has_nonlinklocal;
@@ -164,12 +169,18 @@ nm_ip6_device_destroy (NMIP6Device *device)
 }
 
 static NMIP6Device *
-nm_ip6_device_new (NMIP6Manager *manager, int ifindex)
+nm_ip6_device_new (NMIP6Manager *manager,
+                   int ifindex,
+                   const guint8 *hwaddr,
+                   guint hwaddr_len)
 {
 	NMIP6ManagerPrivate *priv = NM_IP6_MANAGER_GET_PRIVATE (manager);
 	NMIP6Device *device;
 
 	g_return_val_if_fail (ifindex > 0, NULL);
+	g_return_val_if_fail (hwaddr != NULL, NULL);
+	g_return_val_if_fail (hwaddr_len > 0, NULL);
+	g_return_val_if_fail (hwaddr_len <= NM_UTILS_HWADDR_LEN_MAX, NULL);
 
 	device = g_slice_new0 (NMIP6Device);
 	if (!device) {
@@ -186,6 +197,9 @@ nm_ip6_device_new (NMIP6Manager *manager, int ifindex)
 		goto error;
 	}
 
+	memcpy (device->hwaddr, hwaddr, hwaddr_len);
+	device->hwaddr_len = hwaddr_len;
+
 	device->manager = manager;
 
 	device->rdnss_servers = g_array_new (FALSE, FALSE, sizeof (NMIP6RDNSS));
@@ -222,28 +236,6 @@ nm_ip6_manager_get_device (NMIP6Manager *manager, int ifindex)
 	return g_hash_table_lookup (priv->devices, GINT_TO_POINTER (ifindex));
 }
 
-static int
-get_hwaddr (int ifindex, guint8 *buf)
-{
-	struct rtnl_link *lk;
-	struct nl_addr *addr;
-	int len;
-
-	lk = nm_netlink_index_to_rtnl_link (ifindex);
-	if (!lk)
-		return -1;
-
-	addr = rtnl_link_get_addr (lk);
-	len = nl_addr_get_len (addr);
-	if (len > NM_UTILS_HWADDR_LEN_MAX)
-		len = -1;
-	else
-		memcpy (buf, nl_addr_get_binary_addr (addr), len);
-
-	rtnl_link_put (lk);
-	return len;
-}
-
 static void
 device_send_router_solicitation (NMIP6Device *device, const char *why)
 {
@@ -251,8 +243,6 @@ device_send_router_solicitation (NMIP6Device *device, const char *why)
 	struct sockaddr_in6 sin6;
 	struct nd_router_solicit rs;
 	struct nd_opt_hdr lladdr_hdr;
-	guint8 hwaddr[NM_UTILS_HWADDR_LEN_MAX + 7];
-	int hwaddr_len;
 	static const guint8 local_routers_addr[] =
 		{ 0xFF, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
 		  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02 };
@@ -301,18 +291,15 @@ device_send_router_solicitation (NMIP6Device *device, const char *why)
 	iov[0].iov_len  = sizeof (rs);
 	iov[0].iov_base = &rs;
 
-	memset (hwaddr, 0, sizeof (hwaddr));
-	hwaddr_len = get_hwaddr (device->ifindex, hwaddr);
-
-	if (hwaddr_len > 0) {
+	if (device->hwaddr_len > 0) {
 		memset (&lladdr_hdr, 0, sizeof (lladdr_hdr));
 		lladdr_hdr.nd_opt_type = ND_OPT_SOURCE_LINKADDR;
-		lladdr_hdr.nd_opt_len = (sizeof (lladdr_hdr) + hwaddr_len + 7) % 8;
+		lladdr_hdr.nd_opt_len = (sizeof (lladdr_hdr) + device->hwaddr_len + 7) % 8;
 		iov[1].iov_len  = sizeof (lladdr_hdr);
 		iov[1].iov_base = &lladdr_hdr;
 
 		iov[2].iov_len  = (lladdr_hdr.nd_opt_len * 8) - 2;
-		iov[2].iov_base = hwaddr;
+		iov[2].iov_base = device->hwaddr;
 
 		mhdr.msg_iovlen = 3;
 	} else
@@ -1372,6 +1359,8 @@ netlink_notification (NMNetlinkMonitor *monitor, struct nl_msg *msg, gpointer us
 gboolean
 nm_ip6_manager_prepare_interface (NMIP6Manager *manager,
                                   int ifindex,
+                                  const guint8 *hwaddr,
+                                  guint hwaddr_len,
                                   NMSettingIP6Config *s_ip6,
                                   const char *accept_ra_path)
 {
@@ -1381,10 +1370,13 @@ nm_ip6_manager_prepare_interface (NMIP6Manager *manager,
 
 	g_return_val_if_fail (NM_IS_IP6_MANAGER (manager), FALSE);
 	g_return_val_if_fail (ifindex > 0, FALSE);
+	g_return_val_if_fail (hwaddr != NULL, FALSE);
+	g_return_val_if_fail (hwaddr_len > 0, FALSE);
+	g_return_val_if_fail (hwaddr_len <= NM_UTILS_HWADDR_LEN_MAX, FALSE);
 
 	priv = NM_IP6_MANAGER_GET_PRIVATE (manager);
 
-	device = nm_ip6_device_new (manager, ifindex);
+	device = nm_ip6_device_new (manager, ifindex, hwaddr, hwaddr_len);
 	g_return_val_if_fail (device != NULL, FALSE);
 	g_return_val_if_fail (   strchr (device->iface, '/') == NULL
 	                      && strcmp (device->iface, "all") != 0
diff --git a/src/ip6-manager/nm-ip6-manager.h b/src/ip6-manager/nm-ip6-manager.h
index 7ad0903f..886399f7 100644
--- a/src/ip6-manager/nm-ip6-manager.h
+++ b/src/ip6-manager/nm-ip6-manager.h
@@ -73,6 +73,8 @@ GType nm_ip6_manager_get_type (void);
 NMIP6Manager *nm_ip6_manager_get               (void);
 gboolean      nm_ip6_manager_prepare_interface (NMIP6Manager *manager,
                                                 int ifindex,
+                                                const guint8 *hwaddr,
+                                                guint hwaddr_len,
                                                 NMSettingIP6Config *s_ip6,
                                                 const char *accept_ra_path);
 void          nm_ip6_manager_begin_addrconf    (NMIP6Manager *manager,
diff --git a/src/logging/Makefile.in b/src/logging/Makefile.in
index 38c994c2..555d414f 100644
--- a/src/logging/Makefile.in
+++ b/src/logging/Makefile.in
@@ -61,12 +61,11 @@ am__aclocal_m4_deps = $(top_srcdir)/m4/compiler_warnings.m4 \
 	$(top_srcdir)/m4/intlmacosx.m4 $(top_srcdir)/m4/intltool.m4 \
 	$(top_srcdir)/m4/introspection.m4 $(top_srcdir)/m4/lib-ld.m4 \
 	$(top_srcdir)/m4/lib-link.m4 $(top_srcdir)/m4/lib-prefix.m4 \
-	$(top_srcdir)/m4/libnl-check.m4 $(top_srcdir)/m4/libtool.m4 \
-	$(top_srcdir)/m4/ltoptions.m4 $(top_srcdir)/m4/ltsugar.m4 \
-	$(top_srcdir)/m4/ltversion.m4 $(top_srcdir)/m4/lt~obsolete.m4 \
-	$(top_srcdir)/m4/nls.m4 $(top_srcdir)/m4/po.m4 \
-	$(top_srcdir)/m4/progtest.m4 $(top_srcdir)/m4/vapigen.m4 \
-	$(top_srcdir)/configure.ac
+	$(top_srcdir)/m4/libtool.m4 $(top_srcdir)/m4/ltoptions.m4 \
+	$(top_srcdir)/m4/ltsugar.m4 $(top_srcdir)/m4/ltversion.m4 \
+	$(top_srcdir)/m4/lt~obsolete.m4 $(top_srcdir)/m4/nls.m4 \
+	$(top_srcdir)/m4/po.m4 $(top_srcdir)/m4/progtest.m4 \
+	$(top_srcdir)/m4/vapigen.m4 $(top_srcdir)/configure.ac
 am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \
 	$(ACLOCAL_M4)
 mkinstalldirs = $(install_sh) -d
@@ -215,12 +214,6 @@ LIBGCRYPT_LIBS = @LIBGCRYPT_LIBS@
 LIBICONV = @LIBICONV@
 LIBINTL = @LIBINTL@
 LIBM = @LIBM@
-LIBNL1_CFLAGS = @LIBNL1_CFLAGS@
-LIBNL1_LIBS = @LIBNL1_LIBS@
-LIBNL2_CFLAGS = @LIBNL2_CFLAGS@
-LIBNL2_LIBS = @LIBNL2_LIBS@
-LIBNL3_CFLAGS = @LIBNL3_CFLAGS@
-LIBNL3_LIBS = @LIBNL3_LIBS@
 LIBNL_CFLAGS = @LIBNL_CFLAGS@
 LIBNL_LIBS = @LIBNL_LIBS@
 LIBOBJS = @LIBOBJS@
diff --git a/src/logging/nm-logging.c b/src/logging/nm-logging.c
index 3461412e..8c663828 100644
--- a/src/logging/nm-logging.c
+++ b/src/logging/nm-logging.c
@@ -32,22 +32,18 @@
 #include <strings.h>
 #include <string.h>
 
-#ifdef ENABLE_CRASHTRACE
-#include <execinfo.h>
-#endif
-
 #include <glib/gi18n.h>
 
 #include "nm-logging.h"
 
 #define LOGD_ALL \
-	(LOGD_HW | LOGD_RFKILL | LOGD_ETHER | LOGD_WIFI | LOGD_BT | LOGD_MB | \
+	(LOGD_PLATFORM | LOGD_RFKILL | LOGD_ETHER | LOGD_WIFI | LOGD_BT | LOGD_MB | \
 	 LOGD_DHCP4 | LOGD_DHCP6 | LOGD_PPP | LOGD_WIFI_SCAN | LOGD_IP4 | \
 	 LOGD_IP6 | LOGD_AUTOIP4 | LOGD_DNS | LOGD_VPN | LOGD_SHARING | \
 	 LOGD_SUPPLICANT | LOGD_AGENTS | LOGD_SETTINGS | LOGD_SUSPEND | \
 	 LOGD_CORE | LOGD_DEVICE | LOGD_OLPC_MESH | LOGD_WIMAX | \
 	 LOGD_INFINIBAND | LOGD_FIREWALL | LOGD_ADSL | LOGD_BOND | \
-	 LOGD_VLAN)
+	 LOGD_VLAN | LOGD_BRIDGE)
 
 #define LOGD_DEFAULT (LOGD_ALL & ~LOGD_WIFI_SCAN)
 
@@ -69,7 +65,7 @@ static const LogDesc level_descs[] = {
 
 static const LogDesc domain_descs[] = {
 	{ LOGD_NONE,      "NONE" },
-	{ LOGD_HW,        "HW" },
+	{ LOGD_PLATFORM,  "PLATFORM" },
 	{ LOGD_RFKILL,    "RFKILL" },
 	{ LOGD_ETHER,     "ETHER" },
 	{ LOGD_WIFI,      "WIFI" },
@@ -98,6 +94,7 @@ static const LogDesc domain_descs[] = {
 	{ LOGD_ADSL,      "ADSL" },
 	{ LOGD_BOND,      "BOND" },
 	{ LOGD_VLAN,      "VLAN" },
+	{ LOGD_BRIDGE,    "BRIDGE" },
 	{ 0, NULL }
 };
 
@@ -180,6 +177,12 @@ nm_logging_setup (const char *level, const char *domains, GError **error)
 				found = TRUE;
 			}
 
+			/* Check for compatibility domains */
+			if (!strcasecmp (*iter, "HW")) {
+				new_domains |= LOGD_PLATFORM;
+				found = TRUE;
+			}
+
 			if (!found) {
 				g_set_error (error, NM_LOGGING_ERROR, NM_LOGGING_ERROR_UNKNOWN_DOMAIN,
 				             _("Unknown log domain '%s'"), *iter);
@@ -271,88 +274,6 @@ _nm_log (const char *loc,
 /************************************************************************/
 
 static void
-fallback_get_backtrace (void)
-{
-#ifdef ENABLE_CRASHTRACE
-	void *frames[64];
-	Dl_info info;
-	size_t size;
-	guint32 i;
-	const char *name;
-
-	size = backtrace (frames, G_N_ELEMENTS (frames));
-
-	syslog (LOG_CRIT, "******************* START **********************************");
-	for (i = 0; i < size; i++) {
-		dladdr (frames[i], &info);
-		name = (info.dli_fname && *info.dli_fname) ? info.dli_fname : "(vdso)";
-		if (info.dli_saddr) {
-			syslog (LOG_CRIT, "Frame %d: %s (%s+0x%lx) [%p]",
-			        i, name,
-			        info.dli_sname,
-			        (gulong)((guchar *)frames[i] - (guchar *)info.dli_saddr),
-			        frames[i]);
-		} else {
-			syslog (LOG_CRIT, "Frame %d: %s (%p+0x%lx) [%p]",
-			        i, name,
-			        info.dli_fbase,
-			        (gulong)((guchar *)frames[i] - (guchar *)info.dli_saddr),
-			        frames[i]);
-		}
-	}
-	syslog (LOG_CRIT, "******************* END **********************************");
-#endif  /* ENABLE_CRASHTRACE */
-}
-
-
-static gboolean
-crashlogger_get_backtrace (void)
-{
-	gboolean success = FALSE;
-	int pid;	
-
-	pid = fork();
-	if (pid > 0)
-	{
-		/* Wait for the child to finish */
-		int estatus;
-		if (waitpid (pid, &estatus, 0) != -1)
-		{
-			/* Only succeed if the crashlogger succeeded */
-			if (WIFEXITED (estatus) && (WEXITSTATUS (estatus) == 0))
-				success = TRUE;
-		}
-	}
-	else if (pid == 0)
-	{
-		/* Child process */
-		execl (LIBEXECDIR"/nm-crash-logger",
-				LIBEXECDIR"/nm-crash-logger", NULL);
-	}
-
-	return success;
-}
-
-
-void
-nm_logging_backtrace (void)
-{
-	struct stat s;
-	gboolean fallback = TRUE;
-	
-	/* Try to use gdb via nm-crash-logger if it exists, since
-	 * we get much better information out of it.  Otherwise
-	 * fall back to execinfo.
-	 */
-	if (stat (LIBEXECDIR"/nm-crash-logger", &s) == 0)
-		fallback = crashlogger_get_backtrace () ? FALSE : TRUE;
-
-	if (fallback)
-		fallback_get_backtrace ();
-}
-
-
-static void
 nm_log_handler (const gchar *log_domain,
                 GLogLevelFlags level,
                 const gchar *message,
diff --git a/src/logging/nm-logging.h b/src/logging/nm-logging.h
index b3c583f2..2c6dadb9 100644
--- a/src/logging/nm-logging.h
+++ b/src/logging/nm-logging.h
@@ -28,7 +28,7 @@
 /* Log domains */
 enum {
 	LOGD_NONE       = 0x00000000,
-	LOGD_HW         = 0x00000001, /* Hardware detection and info */
+	LOGD_PLATFORM   = 0x00000001, /* Platform services */
 	LOGD_RFKILL     = 0x00000002,
 	LOGD_ETHER      = 0x00000004,
 	LOGD_WIFI       = 0x00000008,
@@ -57,10 +57,12 @@ enum {
 	LOGD_ADSL       = 0x04000000,
 	LOGD_BOND       = 0x08000000,
 	LOGD_VLAN       = 0x10000000,
+	LOGD_BRIDGE     = 0x20000000,
 };
 
 #define LOGD_DHCP (LOGD_DHCP4 | LOGD_DHCP6)
 #define LOGD_IP   (LOGD_IP4 | LOGD_IP6)
+#define LOGD_HW LOGD_PLATFORM
 
 /* Log levels */
 enum {
@@ -107,7 +109,6 @@ gboolean nm_logging_level_enabled (guint32 level);
 gboolean nm_logging_domain_enabled (guint32 domain);
 
 /* Undefine the nm-utils.h logging stuff to ensure errors */
-#undef nm_print_backtrace
 #undef nm_get_timestamp
 #undef nm_info
 #undef nm_info_str
@@ -120,7 +121,6 @@ gboolean nm_logging_domain_enabled (guint32 domain);
 
 gboolean nm_logging_setup     (const char *level, const char *domains, GError **error);
 void     nm_logging_start     (gboolean become_daemon);
-void     nm_logging_backtrace (void);
 void     nm_logging_shutdown  (void);
 
 #endif /* NM_LOGGING_H */
diff --git a/src/main.c b/src/main.c
index b074bd8a..85bfc272 100644
--- a/src/main.c
+++ b/src/main.c
@@ -88,22 +88,6 @@ signal_handling_thread (void *arg)
 		sigwait (&signal_set, &signo);
 
 		switch (signo) {
-		case SIGSEGV:
-		case SIGBUS:
-		case SIGILL:
-		case SIGABRT:
-		case SIGQUIT:
-			nm_log_warn (LOGD_CORE, "caught signal %d. Generating backtrace...", signo);
-			nm_logging_backtrace ();
-			exit (1);
-			break;
-		case SIGFPE:
-		case SIGPIPE:
-			nm_log_warn (LOGD_CORE, "caught signal %d, shutting down abnormally. Generating backtrace...", signo);
-			nm_logging_backtrace ();
-			quit_early = TRUE; /* for quitting before entering the main loop */
-			g_main_loop_quit (main_loop);
-			break;
 		case SIGINT:
 		case SIGTERM:
 			nm_log_info (LOGD_CORE, "caught signal %d, shutting down normally.", signo);
@@ -142,13 +126,6 @@ setup_signals (void)
 	sigemptyset (&signal_set);
 	sigaddset (&signal_set, SIGHUP);
 	sigaddset (&signal_set, SIGINT);
-	sigaddset (&signal_set, SIGQUIT);
-	sigaddset (&signal_set, SIGILL);
-	sigaddset (&signal_set, SIGABRT);
-	sigaddset (&signal_set, SIGFPE);
-	sigaddset (&signal_set, SIGBUS);
-	sigaddset (&signal_set, SIGSEGV);
-	sigaddset (&signal_set, SIGPIPE);
 	sigaddset (&signal_set, SIGTERM);
 	sigaddset (&signal_set, SIGUSR1);
 
@@ -529,16 +506,10 @@ main (int argc, char *argv[])
 	dbus_threads_init_default ();
 #endif
 
-#ifndef HAVE_DBUS_GLIB_DISABLE_LEGACY_PROP_ACCESS
-#error HAVE_DBUS_GLIB_DISABLE_LEGACY_PROP_ACCESS not defined
-#endif
-
-#if HAVE_DBUS_GLIB_DISABLE_LEGACY_PROP_ACCESS
 	/* Ensure that non-exported properties don't leak out, and that the
 	 * introspection 'access' permissions are respected.
 	 */
 	dbus_glib_global_set_disable_legacy_property_access ();
-#endif
 
 	nm_logging_start (become_daemon);
 
diff --git a/src/modem-manager/Makefile.in b/src/modem-manager/Makefile.in
index 0546ee2e..3b278c6e 100644
--- a/src/modem-manager/Makefile.in
+++ b/src/modem-manager/Makefile.in
@@ -69,12 +69,11 @@ am__aclocal_m4_deps = $(top_srcdir)/m4/compiler_warnings.m4 \
 	$(top_srcdir)/m4/intlmacosx.m4 $(top_srcdir)/m4/intltool.m4 \
 	$(top_srcdir)/m4/introspection.m4 $(top_srcdir)/m4/lib-ld.m4 \
 	$(top_srcdir)/m4/lib-link.m4 $(top_srcdir)/m4/lib-prefix.m4 \
-	$(top_srcdir)/m4/libnl-check.m4 $(top_srcdir)/m4/libtool.m4 \
-	$(top_srcdir)/m4/ltoptions.m4 $(top_srcdir)/m4/ltsugar.m4 \
-	$(top_srcdir)/m4/ltversion.m4 $(top_srcdir)/m4/lt~obsolete.m4 \
-	$(top_srcdir)/m4/nls.m4 $(top_srcdir)/m4/po.m4 \
-	$(top_srcdir)/m4/progtest.m4 $(top_srcdir)/m4/vapigen.m4 \
-	$(top_srcdir)/configure.ac
+	$(top_srcdir)/m4/libtool.m4 $(top_srcdir)/m4/ltoptions.m4 \
+	$(top_srcdir)/m4/ltsugar.m4 $(top_srcdir)/m4/ltversion.m4 \
+	$(top_srcdir)/m4/lt~obsolete.m4 $(top_srcdir)/m4/nls.m4 \
+	$(top_srcdir)/m4/po.m4 $(top_srcdir)/m4/progtest.m4 \
+	$(top_srcdir)/m4/vapigen.m4 $(top_srcdir)/configure.ac
 am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \
 	$(ACLOCAL_M4)
 mkinstalldirs = $(install_sh) -d
@@ -238,12 +237,6 @@ LIBGCRYPT_LIBS = @LIBGCRYPT_LIBS@
 LIBICONV = @LIBICONV@
 LIBINTL = @LIBINTL@
 LIBM = @LIBM@
-LIBNL1_CFLAGS = @LIBNL1_CFLAGS@
-LIBNL1_LIBS = @LIBNL1_LIBS@
-LIBNL2_CFLAGS = @LIBNL2_CFLAGS@
-LIBNL2_LIBS = @LIBNL2_LIBS@
-LIBNL3_CFLAGS = @LIBNL3_CFLAGS@
-LIBNL3_LIBS = @LIBNL3_LIBS@
 LIBNL_CFLAGS = @LIBNL_CFLAGS@
 LIBNL_LIBS = @LIBNL_LIBS@
 LIBOBJS = @LIBOBJS@
diff --git a/src/modem-manager/nm-modem-cdma.c b/src/modem-manager/nm-modem-cdma.c
index 73c87c28..6bed8c2a 100644
--- a/src/modem-manager/nm-modem-cdma.c
+++ b/src/modem-manager/nm-modem-cdma.c
@@ -201,18 +201,9 @@ get_best_auto_connection (NMModem *modem,
 
 	for (iter = connections; iter; iter = g_slist_next (iter)) {
 		NMConnection *connection = NM_CONNECTION (iter->data);
-		NMSettingConnection *s_con;
 
-		s_con = nm_connection_get_setting_connection (connection);
-		g_assert (s_con);
-
-		if (!nm_setting_connection_get_autoconnect (s_con))
-			continue;
-
-		if (strcmp (nm_setting_connection_get_connection_type (s_con), NM_SETTING_CDMA_SETTING_NAME))
-			continue;
-
-		return connection;
+		if (nm_connection_is_type (connection, NM_SETTING_CDMA_SETTING_NAME))
+			return connection;
 	}
 	return NULL;
 }
diff --git a/src/modem-manager/nm-modem-gsm.c b/src/modem-manager/nm-modem-gsm.c
index b6d3c857..be793db9 100644
--- a/src/modem-manager/nm-modem-gsm.c
+++ b/src/modem-manager/nm-modem-gsm.c
@@ -475,18 +475,9 @@ get_best_auto_connection (NMModem *modem,
 
 	for (iter = connections; iter; iter = g_slist_next (iter)) {
 		NMConnection *connection = NM_CONNECTION (iter->data);
-		NMSettingConnection *s_con;
 
-		s_con = nm_connection_get_setting_connection (connection);
-		g_assert (s_con);
-
-		if (!nm_setting_connection_get_autoconnect (s_con))
-			continue;
-
-		if (strcmp (nm_setting_connection_get_connection_type (s_con), NM_SETTING_GSM_SETTING_NAME))
-			continue;
-
-		return connection;
+		if (nm_connection_is_type (connection, NM_SETTING_GSM_SETTING_NAME))
+			return connection;
 	}
 	return NULL;
 }
diff --git a/src/modem-manager/nm-modem-manager.c b/src/modem-manager/nm-modem-manager.c
index d896b468..fc5ebfdf 100644
--- a/src/modem-manager/nm-modem-manager.c
+++ b/src/modem-manager/nm-modem-manager.c
@@ -54,6 +54,9 @@ struct _NMModemManagerPrivate {
 	guint modem_manager_1_poke_id;
 	gboolean old_modem_manager_found;
 	gboolean new_modem_manager_found;
+	guint modem_manager_1_name_owner_changed_id;
+	guint modem_manager_1_object_added_id;
+	guint modem_manager_1_object_removed_id;
 #endif
 
 	/* Common */
@@ -411,6 +414,37 @@ nm_modem_manager_name_owner_changed (NMDBusManager *dbus_mgr,
 #if WITH_MODEM_MANAGER_1
 
 static void
+modem_manager_1_clear_signals (NMModemManager *self)
+{
+	if (!self->priv->modem_manager_1)
+		return;
+
+	if (self->priv->modem_manager_1_name_owner_changed_id) {
+		if (g_signal_handler_is_connected (self->priv->modem_manager_1,
+		                                   self->priv->modem_manager_1_name_owner_changed_id))
+			g_signal_handler_disconnect (self->priv->modem_manager_1,
+			                             self->priv->modem_manager_1_name_owner_changed_id);
+		self->priv->modem_manager_1_name_owner_changed_id = 0;
+	}
+
+	if (self->priv->modem_manager_1_object_added_id) {
+		if (g_signal_handler_is_connected (self->priv->modem_manager_1,
+		                                   self->priv->modem_manager_1_object_added_id))
+			g_signal_handler_disconnect (self->priv->modem_manager_1,
+			                             self->priv->modem_manager_1_object_added_id);
+		self->priv->modem_manager_1_object_added_id = 0;
+	}
+
+	if (self->priv->modem_manager_1_object_removed_id) {
+		if (g_signal_handler_is_connected (self->priv->modem_manager_1,
+		                                   self->priv->modem_manager_1_object_removed_id))
+			g_signal_handler_disconnect (self->priv->modem_manager_1,
+			                             self->priv->modem_manager_1_object_removed_id);
+		self->priv->modem_manager_1_object_removed_id = 0;
+	}
+}
+
+static void
 clear_modem_manager_1_support (NMModemManager *self)
 {
 	if (self->priv->modem_manager_1_poke_id) {
@@ -418,6 +452,7 @@ clear_modem_manager_1_support (NMModemManager *self)
 		self->priv->modem_manager_1_poke_id = 0;
 	}
 
+	modem_manager_1_clear_signals (self);
 	g_clear_object (&self->priv->modem_manager_1);
 	g_clear_object (&self->priv->dbus_connection);
 }
@@ -505,26 +540,101 @@ modem_manager_1_available (NMModemManager *self)
 
 static void schedule_modem_manager_1_relaunch (NMModemManager *self,
                                                guint n_seconds);
+static void ensure_client                     (NMModemManager *self);
 
 static void
 modem_manager_1_name_owner_changed (MMManager *modem_manager_1,
                                     GParamSpec *pspec,
                                     NMModemManager *self)
 {
+	gchar *name_owner;
+
 	/* Quit poking, if any */
 	if (self->priv->modem_manager_1_poke_id) {
 		g_source_remove (self->priv->modem_manager_1_poke_id);
 		self->priv->modem_manager_1_poke_id = 0;
 	}
 
-	if (!g_dbus_object_manager_client_get_name_owner (G_DBUS_OBJECT_MANAGER_CLIENT (modem_manager_1))) {
+	name_owner = g_dbus_object_manager_client_get_name_owner (G_DBUS_OBJECT_MANAGER_CLIENT (modem_manager_1));
+	if (!name_owner) {
 		nm_log_info (LOGD_MB, "ModemManager disappeared from bus");
 		schedule_modem_manager_1_relaunch (self, 0);
 		return;
 	}
 
 	/* Available! */
-	modem_manager_1_available (self);
+	g_free (name_owner);
+
+	/* Hack alert: GDBusObjectManagerClient won't signal neither 'object-added'
+	 * nor 'object-removed' if it was created while there was no ModemManager in
+	 * the bus. This hack avoids this issue until we get a GIO with the fix
+	 * included... */
+	modem_manager_1_clear_signals (self);
+	g_clear_object (&self->priv->modem_manager_1);
+	ensure_client (self);
+
+	/* Whenever GDBusObjectManagerClient is fixed, we can just do the following:
+	 * modem_manager_1_available (self);
+	 */
+}
+
+static void
+modem_manager_1_poke_cb (GDBusConnection *connection,
+                         GAsyncResult *res,
+                         NMModemManager *self)
+{
+	GError *error = NULL;
+	GVariant *result;
+
+	result = g_dbus_connection_call_finish (connection, res, &error);
+	if (error) {
+		/* Ignore common errors when MM is not installed and such */
+		if (   !g_error_matches (error, G_DBUS_ERROR, G_DBUS_ERROR_SERVICE_UNKNOWN)
+		    && !g_error_matches (error, G_DBUS_ERROR, G_DBUS_ERROR_SPAWN_EXEC_FAILED)
+		    && !g_error_matches (error, G_DBUS_ERROR, G_DBUS_ERROR_SPAWN_FORK_FAILED)
+		    && !g_error_matches (error, G_DBUS_ERROR, G_DBUS_ERROR_SPAWN_FAILED)
+		    && !g_error_matches (error, G_DBUS_ERROR, G_DBUS_ERROR_TIMEOUT)
+		    && !g_error_matches (error, G_DBUS_ERROR, G_DBUS_ERROR_SPAWN_SERVICE_NOT_FOUND)) {
+			nm_log_warn (LOGD_MB, "error poking ModemManager: %s", error->message);
+		}
+
+		g_error_free (error);
+		/* Setup timeout to relaunch */
+		schedule_modem_manager_1_relaunch (self, MODEM_POKE_INTERVAL);
+	} else
+		g_variant_unref (result);
+
+	/* Balance refcount */
+	g_object_unref (self);
+}
+
+static void
+modem_manager_1_poke (NMModemManager *self)
+{
+	gchar *name_owner;
+
+	/* If there is no current owner right away, ensure we poke to get one */
+	name_owner = g_dbus_object_manager_client_get_name_owner (G_DBUS_OBJECT_MANAGER_CLIENT (self->priv->modem_manager_1));
+	if (name_owner) {
+		/* Available! */
+		modem_manager_1_available (self);
+		g_free (name_owner);
+		return;
+	}
+
+	/* Poke! */
+	g_dbus_connection_call (self->priv->dbus_connection,
+	                        "org.freedesktop.ModemManager1",
+	                        "/org/freedesktop/ModemManager1",
+	                        "org.freedesktop.DBus.Peer",
+	                        "Ping",
+	                        NULL, /* inputs */
+	                        NULL, /* outputs */
+	                        G_DBUS_CALL_FLAGS_NONE,
+	                        -1,
+	                        NULL, /* cancellable */
+	                        (GAsyncReadyCallback)modem_manager_1_poke_cb, /* callback */
+	                        g_object_ref (self)); /* user_data */
 }
 
 static void
@@ -539,14 +649,10 @@ manager_new_ready (GObject *source,
 	g_assert (!self->priv->modem_manager_1);
 	self->priv->modem_manager_1 = mm_manager_new_finish (res, &error);
 	if (!self->priv->modem_manager_1) {
-		if (   !g_error_matches (error, G_DBUS_ERROR, G_DBUS_ERROR_SERVICE_UNKNOWN)
-		    && !g_error_matches (error, G_DBUS_ERROR, G_DBUS_ERROR_SPAWN_EXEC_FAILED)
-		    && !g_error_matches (error, G_DBUS_ERROR, G_DBUS_ERROR_SPAWN_FORK_FAILED)
-		    && !g_error_matches (error, G_DBUS_ERROR, G_DBUS_ERROR_SPAWN_FAILED)
-		    && !g_error_matches (error, G_DBUS_ERROR, G_DBUS_ERROR_TIMEOUT)
-		    && !g_error_matches (error, G_DBUS_ERROR, G_DBUS_ERROR_SPAWN_SERVICE_NOT_FOUND)) {
-			nm_log_warn (LOGD_MB, "error creating ModemManager client: %s", error->message);
-		}
+		/* We're not really supposed to get any error here. If we do get one,
+		 * though, just re-schedule the MMManager creation after some time.
+		 * During this period, name-owner changes won't be followed. */
+		nm_log_warn (LOGD_MB, "error creating ModemManager client: %s", error->message);
 		g_error_free (error);
 		/* Setup timeout to relaunch */
 		schedule_modem_manager_1_relaunch (self, MODEM_POKE_INTERVAL);
@@ -554,32 +660,24 @@ manager_new_ready (GObject *source,
 		/* If we found the old MM, abort */
 		clear_modem_manager_1_support (self);
 	} else {
-		gchar *name_owner;
-
-		g_signal_connect (self->priv->modem_manager_1,
-		                  "notify::name-owner",
-		                  G_CALLBACK (modem_manager_1_name_owner_changed),
-		                  self);
-		g_signal_connect (self->priv->modem_manager_1,
-		                  "object-added",
-		                  G_CALLBACK (modem_object_added),
-		                  self);
-		g_signal_connect (self->priv->modem_manager_1,
-		                  "object-removed",
-		                  G_CALLBACK (modem_object_removed),
-		                  self);
-
-		/* If there is no current owner right away, ensure we poke until we get
-		 * one */
-		name_owner = g_dbus_object_manager_client_get_name_owner (G_DBUS_OBJECT_MANAGER_CLIENT (self->priv->modem_manager_1));
-		if (!name_owner) {
-			/* Setup timeout to wait for an owner */
-			schedule_modem_manager_1_relaunch (self, MODEM_POKE_INTERVAL);
-		} else {
-			/* Available! */
-			modem_manager_1_available (self);
-			g_free (name_owner);
-		}
+		/* Setup signals in the GDBusObjectManagerClient */
+		self->priv->modem_manager_1_name_owner_changed_id =
+			g_signal_connect (self->priv->modem_manager_1,
+			                  "notify::name-owner",
+			                  G_CALLBACK (modem_manager_1_name_owner_changed),
+			                  self);
+		self->priv->modem_manager_1_object_added_id =
+			g_signal_connect (self->priv->modem_manager_1,
+			                  "object-added",
+			                  G_CALLBACK (modem_object_added),
+			                  self);
+		self->priv->modem_manager_1_object_removed_id =
+			g_signal_connect (self->priv->modem_manager_1,
+			                  "object-removed",
+			                  G_CALLBACK (modem_object_removed),
+			                  self);
+		/* Poke the MMManager! */
+		modem_manager_1_poke (self);
 	}
 
 	/* Balance refcount */
@@ -587,19 +685,24 @@ manager_new_ready (GObject *source,
 }
 
 static void
-recreate_client (NMModemManager *self)
+ensure_client (NMModemManager *self)
 {
 	g_assert (self->priv->dbus_connection);
 
-	/* Re-create the GDBusObjectManagerClient so that we request again the owner
-	 * for the well-known name.
-	 * Note that we pass an extra reference always */
-	g_clear_object (&self->priv->modem_manager_1);
-	mm_manager_new (self->priv->dbus_connection,
-	                G_DBUS_OBJECT_MANAGER_CLIENT_FLAGS_NONE,
-	                NULL,
-	                (GAsyncReadyCallback)manager_new_ready,
-	                g_object_ref (self));
+	/* Create the GDBusObjectManagerClient. We do not request to autostart, as
+	 * we don't really want the MMManager creation to fail. We can always poke
+	 * later on if we want to request the autostart */
+	if (!self->priv->modem_manager_1) {
+		mm_manager_new (self->priv->dbus_connection,
+		                G_DBUS_OBJECT_MANAGER_CLIENT_FLAGS_DO_NOT_AUTO_START,
+		                NULL,
+		                (GAsyncReadyCallback)manager_new_ready,
+		                g_object_ref (self));
+		return;
+	}
+
+	/* If already available, poke! */
+	modem_manager_1_poke (self);
 }
 
 static void
@@ -622,7 +725,7 @@ bus_get_ready (GObject *source,
 		clear_modem_manager_1_support (self);
 	} else {
 		/* Got the bus, create new ModemManager client. */
-		recreate_client (self);
+		ensure_client (self);
 	}
 
 	/* Balance refcount */
@@ -632,8 +735,6 @@ bus_get_ready (GObject *source,
 static gboolean
 ensure_bus (NMModemManager *self)
 {
-	nm_log_dbg (LOGD_MB, "Requesting to (re)launch ModemManager...");
-
 	/* Clear poke ID */
 	self->priv->modem_manager_1_poke_id = 0;
 
@@ -643,8 +744,8 @@ ensure_bus (NMModemManager *self)
 		           (GAsyncReadyCallback)bus_get_ready,
 		           g_object_ref (self));
 	else
-		/* If bus is already available, launch client re-creation */
-		recreate_client (self);
+		/* If bus is already available, ensure client */
+		ensure_client (self);
 
 	return FALSE;
 }
diff --git a/src/nm-crash-logger.c b/src/nm-crash-logger.c
deleted file mode 100644
index f10e9ffe..00000000
--- a/src/nm-crash-logger.c
+++ /dev/null
@@ -1,87 +0,0 @@
-/* -*- Mode: C; tab-width: 4; indent-tabs-mode: t; c-basic-offset: 4 -*- */
-/* NetworkManager -- Network link manager
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License along
- * with this program; if not, write to the Free Software Foundation, Inc.,
- * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
- *
- * Copyright (C) 2006 - 2008 Red Hat, Inc.
- */
-
-
-#include <glib.h>
-#include <stdio.h>
-#include <unistd.h>
-#include <errno.h>
-#include <sys/wait.h>
-#include <stdlib.h>
-#include <syslog.h>
-
-int main (int argc, char ** argv)
-{
-	GPid		gdb_pid;
-	int		out;
-	char		nm_pid[16];
-	char		line[256];
-	int		gdb_stat;
-	int		bytes_read;
-	gboolean	done = FALSE;
-	char *	args[] = { BINDIR "/gdb",
-                          "--batch", 
-                          "--quiet",
-                          "--command=" NMDATADIR "/gdb-cmd",
-                          NMBINARY,
-                          NULL, NULL };
-
-	snprintf (nm_pid, sizeof (nm_pid), "%d", getppid ());
-	args[5] = &nm_pid[0];
-	if (!g_spawn_async_with_pipes (NULL, args, NULL, G_SPAWN_DO_NOT_REAP_CHILD, NULL, NULL,
-				       &gdb_pid, NULL, &out, NULL, NULL))
-	{
-		exit (1);
-	}
-
-	openlog ("NetworkManager", LOG_CONS | LOG_PERROR, LOG_DAEMON);
-	syslog (LOG_CRIT, "******************* START **********************************");
-	while (!done)
-	{
-		line[sizeof (line) - 1] = '\0';
-		bytes_read = read (out, line, sizeof (line) - 1);
-		if (bytes_read > 0)
-		{
-			char *end = &line[0];
-			char *start = &line[0];
-
-			/* Can't just funnel the output to syslog, have to do a separate
-			 * syslog () for each line in the output.
-			 */
-			line[bytes_read] = '\0';
-			while (*end != '\0')
-			{
-				if (*end == '\n')
-				{
-					*end = '\0';
-					syslog (LOG_CRIT, "%s", start);
-					start = end + 1;
-				}
-				end++;
-			}
-		}
-		else if ((bytes_read <= 0) || ((errno != EINTR) && (errno != EAGAIN)))
-			done = TRUE;
-	}
-	syslog (LOG_CRIT, "******************* END **********************************");
-	close (out);
-	waitpid (gdb_pid, &gdb_stat, 0);
-	exit (0);
-}
diff --git a/src/nm-device-adsl.c b/src/nm-device-adsl.c
index 29d30cd0..db678d9f 100644
--- a/src/nm-device-adsl.c
+++ b/src/nm-device-adsl.c
@@ -82,6 +82,7 @@ typedef struct {
 	int           brfd;
 	int           nas_ifindex;
 	char *        nas_ifname;
+	guint8        nas_hw_addr[ETH_ALEN];
 } NMDeviceAdslPrivate;
 
 enum {
@@ -207,22 +208,12 @@ get_best_auto_connection (NMDevice *dev,
 
 	for (iter = connections; iter; iter = g_slist_next (iter)) {
 		NMConnection *connection = NM_CONNECTION (iter->data);
-		NMSettingConnection *s_con;
-		NMSettingAdsl *s_adsl;
 
 		if (!nm_connection_is_type (connection, NM_SETTING_ADSL_SETTING_NAME))
 			continue;
 
-		s_adsl = nm_connection_get_setting_adsl (connection);
-		if (!s_adsl)
-			continue;
-
-		s_con = nm_connection_get_setting_connection (connection);
-		g_assert (s_con);
-		if (!nm_setting_connection_get_autoconnect (s_con))
-			continue;
-
-		return connection;
+		if (nm_connection_get_setting_adsl (connection))
+			return connection;
 	}
 	return NULL;
 }
@@ -233,6 +224,7 @@ static void
 set_nas_iface (NMDeviceAdsl *self, int idx, const char *name)
 {
 	NMDeviceAdslPrivate *priv = NM_DEVICE_ADSL_GET_PRIVATE (self);
+	gsize addrlen;
 
 	g_return_if_fail (name != NULL);
 
@@ -245,6 +237,13 @@ set_nas_iface (NMDeviceAdsl *self, int idx, const char *name)
 
 	g_warn_if_fail (priv->nas_ifname == NULL);
 	priv->nas_ifname = g_strdup (name);
+
+	/* Update NAS interface's MAC address */
+	addrlen = nm_device_read_hwaddr (NM_DEVICE (self),
+	                                 priv->nas_hw_addr,
+	                                 sizeof (priv->nas_hw_addr),
+	                                 NULL);
+	g_warn_if_fail (addrlen == sizeof (priv->nas_hw_addr));
 }
 
 static gboolean
@@ -591,10 +590,20 @@ deactivate (NMDevice *device)
 		priv->nas_ifindex = -1;
 	g_free (priv->nas_ifname);
 	priv->nas_ifname = NULL;
+	memset (priv->nas_hw_addr, 0, sizeof (priv->nas_hw_addr));
 }
 
 /**************************************************************/
 
+static const guint8 *
+get_hw_address (NMDevice *device, guint *out_len)
+{
+	NMDeviceAdslPrivate *priv = NM_DEVICE_ADSL_GET_PRIVATE (device);
+
+	*out_len = priv->nas_ifname ? sizeof (priv->nas_hw_addr) : 0;
+	return priv->nas_hw_addr;
+}
+
 static void
 set_carrier (NMDeviceAdsl *self, const gboolean carrier)
 {
@@ -818,6 +827,7 @@ nm_device_adsl_class_init (NMDeviceAdslClass *klass)
 	parent_class->get_best_auto_connection = get_best_auto_connection;
 	parent_class->complete_connection = complete_connection;
 
+	parent_class->get_hw_address = get_hw_address;
 	parent_class->act_stage2_config = act_stage2_config;
 	parent_class->act_stage3_ip4_config_start = act_stage3_ip4_config_start;
 	parent_class->deactivate = deactivate;
diff --git a/src/nm-device-bond.c b/src/nm-device-bond.c
index 30df94fa..7f47a3a6 100644
--- a/src/nm-device-bond.c
+++ b/src/nm-device-bond.c
@@ -46,8 +46,8 @@ G_DEFINE_TYPE (NMDeviceBond, nm_device_bond, NM_TYPE_DEVICE_WIRED)
 #define NM_BOND_ERROR (nm_bond_error_quark ())
 
 typedef struct {
-	gboolean ip4_waiting;
-	gboolean ip6_waiting;
+	guint8   hw_addr[NM_UTILS_HWADDR_LEN_MAX];
+	gsize    hw_addr_len;
 } NMDeviceBondPrivate;
 
 enum {
@@ -81,44 +81,42 @@ nm_bond_error_quark (void)
 /******************************************************************/
 
 static void
-device_state_changed (NMDevice *device,
-                      NMDeviceState new_state,
-                      NMDeviceState old_state,
-                      NMDeviceStateReason reason)
+carrier_action (NMDeviceWired *self, NMDeviceState state, gboolean carrier)
 {
-	NMDeviceBondPrivate *priv = NM_DEVICE_BOND_GET_PRIVATE (device);
-
-	if (new_state == NM_DEVICE_STATE_UNAVAILABLE) {
-		/* Use NM_DEVICE_STATE_REASON_CARRIER to make sure num retries is reset */
-		nm_device_queue_state (device, NM_DEVICE_STATE_DISCONNECTED, NM_DEVICE_STATE_REASON_CARRIER);
-	}
-
-	if (new_state <= NM_DEVICE_STATE_DISCONNECTED || new_state > NM_DEVICE_STATE_ACTIVATED) {
-		priv->ip4_waiting = FALSE;
-		priv->ip6_waiting = FALSE;
-	}
+	/* Carrier can't be used to signal availability of the bond master because
+	 * the bond's carrier follows the slaves' carriers.  So carrier gets
+	 * ignored when determining whether or not the device can be activated.
+	 *
+	 * Second, just because all slaves have been removed or have lost carrier
+	 * does not mean the master should be deactivated.  This could be due to
+	 * user addition/removal of slaves, and is also normal operation with some
+	 * failover modes.
+	 *
+	 * For these reasons, carrier changes are effectively ignored by overriding
+	 * the parent class' carrier handling and doing nothing.
+	 */
 }
 
 static void
 update_hw_address (NMDevice *dev)
 {
-	const guint8 *hw_addr;
-	guint8 old_addr[NM_UTILS_HWADDR_LEN_MAX];
-	int addrtype, addrlen;
-
-	addrtype = nm_device_wired_get_hwaddr_type (NM_DEVICE_WIRED (dev));
-	g_assert (addrtype >= 0);
-	addrlen = nm_utils_hwaddr_len (addrtype);
-	g_assert (addrlen > 0);
-
-	hw_addr = nm_device_wired_get_hwaddr (NM_DEVICE_WIRED (dev));
-	memcpy (old_addr, hw_addr, addrlen);
-
-	NM_DEVICE_CLASS (nm_device_bond_parent_class)->update_hw_address (dev);
+	NMDeviceBondPrivate *priv = NM_DEVICE_BOND_GET_PRIVATE (dev);
+	gsize addrlen;
+	gboolean changed = FALSE;
+
+	addrlen = nm_device_read_hwaddr (dev, priv->hw_addr, sizeof (priv->hw_addr), &changed);
+	if (addrlen) {
+		priv->hw_addr_len = addrlen;
+		if (changed)
+			g_object_notify (G_OBJECT (dev), NM_DEVICE_BOND_HW_ADDRESS);
+	}
+}
 
-	hw_addr = nm_device_wired_get_hwaddr (NM_DEVICE_WIRED (dev));
-	if (memcmp (old_addr, hw_addr, addrlen))
-		g_object_notify (G_OBJECT (dev), NM_DEVICE_BOND_HW_ADDRESS);
+static const guint8 *
+get_hw_address (NMDevice *device, guint *out_len)
+{
+	*out_len = NM_DEVICE_BOND_GET_PRIVATE (device)->hw_addr_len;
+	return NM_DEVICE_BOND_GET_PRIVATE (device)->hw_addr;
 }
 
 static guint32
@@ -128,6 +126,14 @@ get_generic_capabilities (NMDevice *dev)
 }
 
 static gboolean
+is_available (NMDevice *dev)
+{
+	if (NM_DEVICE_GET_CLASS (dev)->hw_is_up)
+		return NM_DEVICE_GET_CLASS (dev)->hw_is_up (dev);
+	return FALSE;
+}
+
+static gboolean
 match_bond_connection (NMDevice *device, NMConnection *connection, GError **error)
 {
 	const char *iface;
@@ -162,12 +168,8 @@ get_best_auto_connection (NMDevice *dev,
 
 	for (iter = connections; iter; iter = g_slist_next (iter)) {
 		NMConnection *connection = NM_CONNECTION (iter->data);
-		NMSettingConnection *s_con;
 
-		s_con = nm_connection_get_setting_connection (connection);
-		g_assert (s_con);
-		if (   nm_setting_connection_get_autoconnect (s_con)
-		    && match_bond_connection (dev, connection, NULL))
+		if (match_bond_connection (dev, connection, NULL))
 			return connection;
 	}
 	return NULL;
@@ -241,10 +243,11 @@ complete_connection (NMDevice *device,
 static gboolean
 spec_match_list (NMDevice *device, const GSList *specs)
 {
+	NMDeviceBondPrivate *priv = NM_DEVICE_BOND_GET_PRIVATE (device);
 	char *hwaddr;
 	gboolean matched;
 
-	hwaddr = nm_utils_hwaddr_ntoa (nm_device_wired_get_hwaddr (NM_DEVICE_WIRED (device)), ARPHRD_ETHER);
+	hwaddr = nm_utils_hwaddr_ntoa (priv->hw_addr, nm_utils_hwaddr_type (priv->hw_addr_len));
 	matched = nm_match_spec_hwaddr (specs, hwaddr);
 	g_free (hwaddr);
 
@@ -311,9 +314,6 @@ act_stage1_prepare (NMDevice *dev, NMDeviceStateReason *reason)
 
 	g_return_val_if_fail (reason != NULL, NM_ACT_STAGE_RETURN_FAILURE);
 
-	NM_DEVICE_BOND_GET_PRIVATE (dev)->ip4_waiting = FALSE;
-	NM_DEVICE_BOND_GET_PRIVATE (dev)->ip6_waiting = FALSE;
-
 	ret = NM_DEVICE_CLASS (nm_device_bond_parent_class)->act_stage1_prepare (dev, reason);
 	if (ret == NM_ACT_STAGE_RETURN_SUCCESS) {
 		connection = nm_device_get_connection (dev);
@@ -335,7 +335,6 @@ act_stage1_prepare (NMDevice *dev, NMDeviceStateReason *reason)
 static gboolean
 enslave_slave (NMDevice *device, NMDevice *slave, NMConnection *connection)
 {
-	NMDeviceBondPrivate *priv = NM_DEVICE_BOND_GET_PRIVATE (device);
 	gboolean success, no_firmware = FALSE;
 	const char *iface = nm_device_get_ip_iface (device);
 	const char *slave_iface = nm_device_get_ip_iface (slave);
@@ -352,19 +351,6 @@ enslave_slave (NMDevice *device, NMDevice *slave, NMConnection *connection)
 	if (success) {
 		nm_log_info (LOGD_BOND, "(%s): enslaved bond slave %s", iface, slave_iface);
 		g_object_notify (G_OBJECT (device), "slaves");
-
-		/* If waiting for a slave to continue with IP config, start now */
-		if (priv->ip4_waiting) {
-			nm_log_info (LOGD_BOND | LOGD_IP4, "(%s): retrying IPv4 config with first slave", iface);
-			priv->ip4_waiting = FALSE;
-			nm_device_activate_stage3_ip4_start (device);
-		}
-
-		if (priv->ip6_waiting) {
-			nm_log_info (LOGD_BOND | LOGD_IP6, "(%s): retrying IPv6 config with first slave", iface);
-			priv->ip6_waiting = FALSE;
-			nm_device_activate_stage3_ip6_start (device);
-		}
 	}
 
 	return success;
@@ -373,7 +359,7 @@ enslave_slave (NMDevice *device, NMDevice *slave, NMConnection *connection)
 static gboolean
 release_slave (NMDevice *device, NMDevice *slave)
 {
-	gboolean success;
+	gboolean success, no_firmware = FALSE;
 
 	success = nm_system_bond_release (nm_device_get_ip_ifindex (device),
 	                                  nm_device_get_ip_iface (device),
@@ -384,93 +370,17 @@ release_slave (NMDevice *device, NMDevice *slave)
 	             nm_device_get_ip_iface (slave),
 	             success);
 	g_object_notify (G_OBJECT (device), "slaves");
-	return success;
-}
-
-static NMActStageReturn
-act_stage3_ip4_config_start (NMDevice *device,
-                             NMIP4Config **out_config,
-                             NMDeviceStateReason *reason)
-{
-	NMDeviceBondPrivate *priv = NM_DEVICE_BOND_GET_PRIVATE (device);
-	NMActStageReturn ret = NM_ACT_STAGE_RETURN_SUCCESS;
-	NMConnection *connection;
-	NMSettingIP4Config *s_ip4;
-	const char *method = NULL;
-	GSList *slaves;
-
-	priv->ip4_waiting = FALSE;
-
-	slaves = nm_device_master_get_slaves (device);
-	if (slaves == NULL) {
-		connection = nm_device_get_connection (device);
-		g_assert (connection);
-
-		s_ip4 = nm_connection_get_setting_ip4_config (connection);
-		if (s_ip4)
-			method = nm_setting_ip4_config_get_method (s_ip4);
-
-		if (g_strcmp0 (method, NM_SETTING_IP4_CONFIG_METHOD_AUTO) == 0)
-			priv->ip4_waiting = TRUE;
-	}
-	g_slist_free (slaves);
-
-	if (priv->ip4_waiting) {
-		ret = NM_ACT_STAGE_RETURN_WAIT;
-		nm_log_info (LOGD_BOND | LOGD_IP4, "(%s): IPv4 config waiting until slaves are present",
-					 nm_device_get_ip_iface (device));
-	} else {
-		/* We have slaves; proceed with normal IPv4 configuration */
-		ret = NM_DEVICE_CLASS (nm_device_bond_parent_class)->act_stage3_ip4_config_start (device, out_config, reason);
-	}
-
-	return ret;
-}
 
-static NMActStageReturn
-act_stage3_ip6_config_start (NMDevice *device,
-                             NMIP6Config **out_config,
-                             NMDeviceStateReason *reason)
-{
-	NMDeviceBondPrivate *priv = NM_DEVICE_BOND_GET_PRIVATE (device);
-	NMActStageReturn ret = NM_ACT_STAGE_RETURN_SUCCESS;
-	NMConnection *connection;
-	NMSettingIP6Config *s_ip6;
-	const char *method = NULL;
-	GSList *slaves;
-
-	priv->ip6_waiting = FALSE;
-
-	slaves = nm_device_master_get_slaves (device);
-	if (slaves == NULL) {
-		connection = nm_device_get_connection (device);
-		g_assert (connection);
-
-		s_ip6 = nm_connection_get_setting_ip6_config (connection);
-		if (s_ip6)
-			method = nm_setting_ip6_config_get_method (s_ip6);
-
-		/* SLAAC, DHCP, and Link-Local depend on connectivity (and thus slaves)
-		 * to complete addressing.  SLAAC and DHCP obviously need a peer to
-		 * provide a prefix, while Link-Local must perform DAD on the local link.
-		 */
-		if (   !g_strcmp0 (method, NM_SETTING_IP6_CONFIG_METHOD_AUTO)
-		    || !g_strcmp0 (method, NM_SETTING_IP6_CONFIG_METHOD_DHCP)
-		    || !g_strcmp0 (method, NM_SETTING_IP6_CONFIG_METHOD_LINK_LOCAL))
-			priv->ip6_waiting = TRUE;
-	}
-	g_slist_free (slaves);
-
-	if (priv->ip6_waiting) {
-		ret = NM_ACT_STAGE_RETURN_WAIT;
-		nm_log_info (LOGD_BOND | LOGD_IP6, "(%s): IPv6 config waiting until slaves are present",
-					 nm_device_get_ip_iface (device));
-	} else {
-		/* We have slaves; proceed with normal IPv6 configuration */
-		ret = NM_DEVICE_CLASS (nm_device_bond_parent_class)->act_stage3_ip6_config_start (device, out_config, reason);
+	/* Kernel bonding code "closes" the slave when releasing it, (which clears
+	 * IFF_UP), so we must bring it back up here to ensure carrier changes and
+	 * other state is noticed by the now-released slave.
+	 */
+	if (!nm_device_hw_bring_up (slave, TRUE, &no_firmware)) {
+		nm_log_warn (LOGD_BOND, "(%s): released bond slave could not be brought up.",
+		             nm_device_get_iface (slave));
 	}
 
-	return ret;
+	return success;
 }
 
 /******************************************************************/
@@ -487,6 +397,7 @@ nm_device_bond_new (const char *udi, const char *iface)
 	                                  NM_DEVICE_DRIVER, "bonding",
 	                                  NM_DEVICE_TYPE_DESC, "Bond",
 	                                  NM_DEVICE_DEVICE_TYPE, NM_DEVICE_TYPE_BOND,
+	                                  NM_DEVICE_IS_MASTER, TRUE,
 	                                  NULL);
 }
 
@@ -509,14 +420,15 @@ static void
 get_property (GObject *object, guint prop_id,
               GValue *value, GParamSpec *pspec)
 {
-	const guint8 *current_addr;
+	NMDeviceBondPrivate *priv = NM_DEVICE_BOND_GET_PRIVATE (object);
 	GPtrArray *slaves;
 	GSList *list, *iter;
+	char *hwaddr;
 
 	switch (prop_id) {
 	case PROP_HW_ADDRESS:
-		current_addr = nm_device_wired_get_hwaddr (NM_DEVICE_WIRED (object));
-		g_value_take_string (value, nm_utils_hwaddr_ntoa (current_addr, ARPHRD_ETHER));
+		hwaddr = nm_utils_hwaddr_ntoa (priv->hw_addr, nm_utils_hwaddr_type (priv->hw_addr_len));
+		g_value_take_string (value, hwaddr);
 		break;
 	case PROP_CARRIER:
 		g_value_set_boolean (value, nm_device_wired_get_carrier (NM_DEVICE_WIRED (object)));
@@ -551,6 +463,7 @@ nm_device_bond_class_init (NMDeviceBondClass *klass)
 {
 	GObjectClass *object_class = G_OBJECT_CLASS (klass);
 	NMDeviceClass *parent_class = NM_DEVICE_CLASS (klass);
+	NMDeviceWiredClass *wired_class = NM_DEVICE_WIRED_CLASS (klass);
 
 	g_type_class_add_private (object_class, sizeof (NMDeviceBondPrivate));
 
@@ -561,6 +474,8 @@ nm_device_bond_class_init (NMDeviceBondClass *klass)
 
 	parent_class->get_generic_capabilities = get_generic_capabilities;
 	parent_class->update_hw_address = update_hw_address;
+	parent_class->get_hw_address = get_hw_address;
+	parent_class->is_available = is_available;
 	parent_class->get_best_auto_connection = get_best_auto_connection;
 	parent_class->check_connection_compatible = check_connection_compatible;
 	parent_class->complete_connection = complete_connection;
@@ -569,12 +484,10 @@ nm_device_bond_class_init (NMDeviceBondClass *klass)
 	parent_class->connection_match_config = connection_match_config;
 
 	parent_class->act_stage1_prepare = act_stage1_prepare;
-	parent_class->act_stage3_ip4_config_start = act_stage3_ip4_config_start;
-	parent_class->act_stage3_ip6_config_start = act_stage3_ip6_config_start;
 	parent_class->enslave_slave = enslave_slave;
 	parent_class->release_slave = release_slave;
 
-	parent_class->state_changed = device_state_changed;
+	wired_class->carrier_action = carrier_action;
 
 	/* properties */
 	g_object_class_install_property
diff --git a/src/nm-device-bridge.c b/src/nm-device-bridge.c
index 6f3d70e4..39275c8b 100644
--- a/src/nm-device-bridge.c
+++ b/src/nm-device-bridge.c
@@ -46,8 +46,8 @@ G_DEFINE_TYPE (NMDeviceBridge, nm_device_bridge, NM_TYPE_DEVICE_WIRED)
 #define NM_BRIDGE_ERROR (nm_bridge_error_quark ())
 
 typedef struct {
-	gboolean ip4_waiting;
-	gboolean ip6_waiting;
+	guint8   hw_addr[NM_UTILS_HWADDR_LEN_MAX];
+	gsize    hw_addr_len;
 } NMDeviceBridgePrivate;
 
 enum {
@@ -81,44 +81,39 @@ nm_bridge_error_quark (void)
 /******************************************************************/
 
 static void
-device_state_changed (NMDevice *device,
-                      NMDeviceState new_state,
-                      NMDeviceState old_state,
-                      NMDeviceStateReason reason)
+carrier_action (NMDeviceWired *self, NMDeviceState state, gboolean carrier)
 {
-	NMDeviceBridgePrivate *priv = NM_DEVICE_BRIDGE_GET_PRIVATE (device);
-
-	if (new_state == NM_DEVICE_STATE_UNAVAILABLE) {
-		/* Use NM_DEVICE_STATE_REASON_CARRIER to make sure num retries is reset */
-		nm_device_queue_state (device, NM_DEVICE_STATE_DISCONNECTED, NM_DEVICE_STATE_REASON_CARRIER);
-	}
-
-	if (new_state <= NM_DEVICE_STATE_DISCONNECTED || new_state > NM_DEVICE_STATE_ACTIVATED) {
-		priv->ip4_waiting = FALSE;
-		priv->ip6_waiting = FALSE;
-	}
+	/* Bridge carrier state follows IFF_UP with no ports, and port carrier
+	 * states when ports are added.  Thus carrier isn't useful when deciding
+	 * to auto-activate the bridge master.  Also, like bond masters, when the
+	 * carrier state changes due to slave changes, we shouldn't deactivate the
+	 * bridge since the user may be reconfiguring ports.
+	 *
+	 * For these reasons, carrier changes are effectively ignored by overriding
+	 * the parent class' carrier handling and doing nothing.
+	 */
 }
 
 static void
 update_hw_address (NMDevice *dev)
 {
-	const guint8 *hw_addr;
-	guint8 old_addr[NM_UTILS_HWADDR_LEN_MAX];
-	int addrtype, addrlen;
-
-	addrtype = nm_device_wired_get_hwaddr_type (NM_DEVICE_WIRED (dev));
-	g_assert (addrtype >= 0);
-	addrlen = nm_utils_hwaddr_len (addrtype);
-	g_assert (addrlen > 0);
-
-	hw_addr = nm_device_wired_get_hwaddr (NM_DEVICE_WIRED (dev));
-	memcpy (old_addr, hw_addr, addrlen);
-
-	NM_DEVICE_CLASS (nm_device_bridge_parent_class)->update_hw_address (dev);
+	NMDeviceBridgePrivate *priv = NM_DEVICE_BRIDGE_GET_PRIVATE (dev);
+	gsize addrlen;
+	gboolean changed = FALSE;
+
+	addrlen = nm_device_read_hwaddr (dev, priv->hw_addr, sizeof (priv->hw_addr), &changed);
+	if (addrlen) {
+		priv->hw_addr_len = addrlen;
+		if (changed)
+			g_object_notify (G_OBJECT (dev), NM_DEVICE_BRIDGE_HW_ADDRESS);
+	}
+}
 
-	hw_addr = nm_device_wired_get_hwaddr (NM_DEVICE_WIRED (dev));
-	if (memcmp (old_addr, hw_addr, addrlen))
-		g_object_notify (G_OBJECT (dev), NM_DEVICE_BRIDGE_HW_ADDRESS);
+static const guint8 *
+get_hw_address (NMDevice *device, guint *out_len)
+{
+	*out_len = NM_DEVICE_BRIDGE_GET_PRIVATE (device)->hw_addr_len;
+	return NM_DEVICE_BRIDGE_GET_PRIVATE (device)->hw_addr;
 }
 
 static guint32
@@ -247,10 +242,11 @@ complete_connection (NMDevice *device,
 static gboolean
 spec_match_list (NMDevice *device, const GSList *specs)
 {
+	NMDeviceBridgePrivate *priv = NM_DEVICE_BRIDGE_GET_PRIVATE (device);
 	char *hwaddr;
 	gboolean matched;
 
-	hwaddr = nm_utils_hwaddr_ntoa (nm_device_wired_get_hwaddr (NM_DEVICE_WIRED (device)), ARPHRD_ETHER);
+	hwaddr = nm_utils_hwaddr_ntoa (priv->hw_addr, nm_utils_hwaddr_type (priv->hw_addr_len));
 	matched = nm_match_spec_hwaddr (specs, hwaddr);
 	g_free (hwaddr);
 
@@ -311,6 +307,7 @@ static void
 set_sysfs_uint (const char *iface,
                 GObject *obj,
                 const char *obj_prop,
+                const char *dir,
                 const char *sysfs_prop,
                 gboolean default_if_zero,
                 gboolean user_hz_compensate)
@@ -353,7 +350,7 @@ set_sysfs_uint (const char *iface,
 	if (user_hz_compensate)
 		uval *= 100;
 
-	path = g_strdup_printf ("/sys/class/net/%s/bridge/%s", iface, sysfs_prop);
+	path = g_strdup_printf ("/sys/class/net/%s/%s/%s", iface, dir, sysfs_prop);
 	s = g_strdup_printf ("%u", uval);
 	/* FIXME: how should failure be handled? */
 	nm_utils_do_sysctl (path, s);
@@ -371,9 +368,6 @@ act_stage1_prepare (NMDevice *dev, NMDeviceStateReason *reason)
 
 	g_return_val_if_fail (reason != NULL, NM_ACT_STAGE_RETURN_FAILURE);
 
-	NM_DEVICE_BRIDGE_GET_PRIVATE (dev)->ip4_waiting = FALSE;
-	NM_DEVICE_BRIDGE_GET_PRIVATE (dev)->ip6_waiting = FALSE;
-
 	ret = NM_DEVICE_CLASS (nm_device_bridge_parent_class)->act_stage1_prepare (dev, reason);
 	if (ret == NM_ACT_STAGE_RETURN_SUCCESS) {
 		connection = nm_device_get_connection (dev);
@@ -385,12 +379,12 @@ act_stage1_prepare (NMDevice *dev, NMDeviceStateReason *reason)
 		iface = nm_device_get_ip_iface (dev);
 		g_assert (iface);
 
-		set_sysfs_uint (iface, G_OBJECT (s_bridge), NM_SETTING_BRIDGE_STP, "stp_state", FALSE, FALSE);
-		set_sysfs_uint (iface, G_OBJECT (s_bridge), NM_SETTING_BRIDGE_PRIORITY, "priority", TRUE, FALSE);
-		set_sysfs_uint (iface, G_OBJECT (s_bridge), NM_SETTING_BRIDGE_FORWARD_DELAY, "forward_delay", TRUE, TRUE);
-		set_sysfs_uint (iface, G_OBJECT (s_bridge), NM_SETTING_BRIDGE_HELLO_TIME, "hello_time", TRUE, TRUE);
-		set_sysfs_uint (iface, G_OBJECT (s_bridge), NM_SETTING_BRIDGE_MAX_AGE, "max_age", TRUE, TRUE);
-		set_sysfs_uint (iface, G_OBJECT (s_bridge), NM_SETTING_BRIDGE_AGEING_TIME, "ageing_time", TRUE, TRUE);
+		set_sysfs_uint (iface, G_OBJECT (s_bridge), NM_SETTING_BRIDGE_STP, "bridge", "stp_state", FALSE, FALSE);
+		set_sysfs_uint (iface, G_OBJECT (s_bridge), NM_SETTING_BRIDGE_PRIORITY, "bridge", "priority", TRUE, FALSE);
+		set_sysfs_uint (iface, G_OBJECT (s_bridge), NM_SETTING_BRIDGE_FORWARD_DELAY, "bridge", "forward_delay", TRUE, TRUE);
+		set_sysfs_uint (iface, G_OBJECT (s_bridge), NM_SETTING_BRIDGE_HELLO_TIME, "bridge", "hello_time", TRUE, TRUE);
+		set_sysfs_uint (iface, G_OBJECT (s_bridge), NM_SETTING_BRIDGE_MAX_AGE, "bridge", "max_age", TRUE, TRUE);
+		set_sysfs_uint (iface, G_OBJECT (s_bridge), NM_SETTING_BRIDGE_AGEING_TIME, "bridge", "ageing_time", TRUE, TRUE);
 	}
 	return ret;
 }
@@ -398,7 +392,6 @@ act_stage1_prepare (NMDevice *dev, NMDeviceStateReason *reason)
 static gboolean
 enslave_slave (NMDevice *device, NMDevice *slave, NMConnection *connection)
 {
-	NMDeviceBridgePrivate *priv = NM_DEVICE_BRIDGE_GET_PRIVATE (device);
 	gboolean success;
 	NMSettingBridgePort *s_port;
 	const char *iface = nm_device_get_ip_iface (device);
@@ -414,28 +407,15 @@ enslave_slave (NMDevice *device, NMDevice *slave, NMConnection *connection)
 	/* Set port properties */
 	s_port = nm_connection_get_setting_bridge_port (connection);
 	if (s_port) {
-		set_sysfs_uint (slave_iface, G_OBJECT (s_port), NM_SETTING_BRIDGE_PORT_PRIORITY, "priority", TRUE, FALSE);
-		set_sysfs_uint (slave_iface, G_OBJECT (s_port), NM_SETTING_BRIDGE_PORT_PATH_COST, "path_cost", TRUE, FALSE);
-		set_sysfs_uint (slave_iface, G_OBJECT (s_port), NM_SETTING_BRIDGE_PORT_HAIRPIN_MODE, "hairpin_mode", FALSE, FALSE);
+		set_sysfs_uint (slave_iface, G_OBJECT (s_port), NM_SETTING_BRIDGE_PORT_PRIORITY, "brport", "priority", TRUE, FALSE);
+		set_sysfs_uint (slave_iface, G_OBJECT (s_port), NM_SETTING_BRIDGE_PORT_PATH_COST, "brport", "path_cost", TRUE, FALSE);
+		set_sysfs_uint (slave_iface, G_OBJECT (s_port), NM_SETTING_BRIDGE_PORT_HAIRPIN_MODE, "brport", "hairpin_mode", FALSE, FALSE);
 	}
 
-	nm_log_info (LOGD_DEVICE, "(%s): attached bridge port %s", iface, slave_iface);
+	nm_log_info (LOGD_BRIDGE, "(%s): attached bridge port %s", iface, slave_iface);
 
 	g_object_notify (G_OBJECT (device), NM_DEVICE_BRIDGE_SLAVES);
 
-	/* If waiting for a slave to continue with IP config, start now */
-	if (priv->ip4_waiting) {
-		nm_log_info (LOGD_DEVICE | LOGD_IP4, "(%s): retrying IPv4 config with first slave", iface);
-		priv->ip4_waiting = FALSE;
-		nm_device_activate_stage3_ip4_start (device);
-	}
-
-	if (priv->ip6_waiting) {
-		nm_log_info (LOGD_DEVICE | LOGD_IP6, "(%s): retrying IPv6 config with first slave", iface);
-		priv->ip6_waiting = FALSE;
-		nm_device_activate_stage3_ip6_start (device);
-	}
-
 	return TRUE;
 }
 
@@ -448,7 +428,7 @@ release_slave (NMDevice *device, NMDevice *slave)
 	                                   nm_device_get_ip_iface (device),
 	                                   nm_device_get_ip_ifindex (slave),
 	                                   nm_device_get_ip_iface (slave));
-	nm_log_info (LOGD_DEVICE, "(%s): detached bridge port %s (success %d)",
+	nm_log_info (LOGD_BRIDGE, "(%s): detached bridge port %s (success %d)",
 	             nm_device_get_ip_iface (device),
 	             nm_device_get_ip_iface (slave),
 	             success);
@@ -456,92 +436,6 @@ release_slave (NMDevice *device, NMDevice *slave)
 	return success;
 }
 
-static NMActStageReturn
-act_stage3_ip4_config_start (NMDevice *device,
-                             NMIP4Config **out_config,
-                             NMDeviceStateReason *reason)
-{
-	NMDeviceBridgePrivate *priv = NM_DEVICE_BRIDGE_GET_PRIVATE (device);
-	NMActStageReturn ret = NM_ACT_STAGE_RETURN_SUCCESS;
-	NMConnection *connection;
-	NMSettingIP4Config *s_ip4;
-	const char *method = NULL;
-	GSList *slaves;
-
-	priv->ip4_waiting = FALSE;
-
-	slaves = nm_device_master_get_slaves (device);
-	if (slaves == NULL) {
-		connection = nm_device_get_connection (device);
-		g_assert (connection);
-
-		s_ip4 = nm_connection_get_setting_ip4_config (connection);
-		if (s_ip4)
-			method = nm_setting_ip4_config_get_method (s_ip4);
-
-		if (g_strcmp0 (method, NM_SETTING_IP4_CONFIG_METHOD_AUTO) == 0)
-			priv->ip4_waiting = TRUE;
-	}
-	g_slist_free (slaves);
-
-	if (priv->ip4_waiting) {
-		ret = NM_ACT_STAGE_RETURN_WAIT;
-		nm_log_info (LOGD_DEVICE | LOGD_IP4, "(%s): IPv4 config waiting until slaves are present",
-					 nm_device_get_ip_iface (device));
-	} else {
-		/* We have slaves; proceed with normal IPv4 configuration */
-		ret = NM_DEVICE_CLASS (nm_device_bridge_parent_class)->act_stage3_ip4_config_start (device, out_config, reason);
-	}
-
-	return ret;
-}
-
-static NMActStageReturn
-act_stage3_ip6_config_start (NMDevice *device,
-                             NMIP6Config **out_config,
-                             NMDeviceStateReason *reason)
-{
-	NMDeviceBridgePrivate *priv = NM_DEVICE_BRIDGE_GET_PRIVATE (device);
-	NMActStageReturn ret = NM_ACT_STAGE_RETURN_SUCCESS;
-	NMConnection *connection;
-	NMSettingIP6Config *s_ip6;
-	const char *method = NULL;
-	GSList *slaves;
-
-	priv->ip6_waiting = FALSE;
-
-	slaves = nm_device_master_get_slaves (device);
-	if (slaves == NULL) {
-		connection = nm_device_get_connection (device);
-		g_assert (connection);
-
-		s_ip6 = nm_connection_get_setting_ip6_config (connection);
-		if (s_ip6)
-			method = nm_setting_ip6_config_get_method (s_ip6);
-
-		/* SLAAC, DHCP, and Link-Local depend on connectivity (and thus slaves)
-		 * to complete addressing.  SLAAC and DHCP obviously need a peer to
-		 * provide a prefix, while Link-Local must perform DAD on the local link.
-		 */
-		if (   !g_strcmp0 (method, NM_SETTING_IP6_CONFIG_METHOD_AUTO)
-		    || !g_strcmp0 (method, NM_SETTING_IP6_CONFIG_METHOD_DHCP)
-		    || !g_strcmp0 (method, NM_SETTING_IP6_CONFIG_METHOD_LINK_LOCAL))
-			priv->ip6_waiting = TRUE;
-	}
-	g_slist_free (slaves);
-
-	if (priv->ip6_waiting) {
-		ret = NM_ACT_STAGE_RETURN_WAIT;
-		nm_log_info (LOGD_DEVICE | LOGD_IP6, "(%s): IPv6 config waiting until slaves are present",
-					 nm_device_get_ip_iface (device));
-	} else {
-		/* We have slaves; proceed with normal IPv6 configuration */
-		ret = NM_DEVICE_CLASS (nm_device_bridge_parent_class)->act_stage3_ip6_config_start (device, out_config, reason);
-	}
-
-	return ret;
-}
-
 /******************************************************************/
 
 NMDevice *
@@ -556,6 +450,7 @@ nm_device_bridge_new (const char *udi, const char *iface)
 	                                  NM_DEVICE_DRIVER, "bridge",
 	                                  NM_DEVICE_TYPE_DESC, "Bridge",
 	                                  NM_DEVICE_DEVICE_TYPE, NM_DEVICE_TYPE_BRIDGE,
+	                                  NM_DEVICE_IS_MASTER, TRUE,
 	                                  NULL);
 }
 
@@ -564,7 +459,7 @@ constructed (GObject *object)
 {
 	G_OBJECT_CLASS (nm_device_bridge_parent_class)->constructed (object);
 
-	nm_log_dbg (LOGD_HW | LOGD_DEVICE, "(%s): kernel ifindex %d",
+	nm_log_dbg (LOGD_HW | LOGD_BRIDGE, "(%s): kernel ifindex %d",
 	            nm_device_get_iface (NM_DEVICE (object)),
 	            nm_device_get_ifindex (NM_DEVICE (object)));
 }
@@ -578,14 +473,15 @@ static void
 get_property (GObject *object, guint prop_id,
               GValue *value, GParamSpec *pspec)
 {
-	const guint8 *current_addr;
+	NMDeviceBridgePrivate *priv = NM_DEVICE_BRIDGE_GET_PRIVATE (object);
 	GPtrArray *slaves;
 	GSList *list, *iter;
+	char *hwaddr;
 
 	switch (prop_id) {
 	case PROP_HW_ADDRESS:
-		current_addr = nm_device_wired_get_hwaddr (NM_DEVICE_WIRED (object));
-		g_value_take_string (value, nm_utils_hwaddr_ntoa (current_addr, ARPHRD_ETHER));
+		hwaddr = nm_utils_hwaddr_ntoa (priv->hw_addr, nm_utils_hwaddr_type (priv->hw_addr_len));
+		g_value_take_string (value, hwaddr);
 		break;
 	case PROP_CARRIER:
 		g_value_set_boolean (value, nm_device_wired_get_carrier (NM_DEVICE_WIRED (object)));
@@ -620,6 +516,7 @@ nm_device_bridge_class_init (NMDeviceBridgeClass *klass)
 {
 	GObjectClass *object_class = G_OBJECT_CLASS (klass);
 	NMDeviceClass *parent_class = NM_DEVICE_CLASS (klass);
+	NMDeviceWiredClass *wired_class = NM_DEVICE_WIRED_CLASS (klass);
 
 	g_type_class_add_private (object_class, sizeof (NMDeviceBridgePrivate));
 
@@ -630,6 +527,7 @@ nm_device_bridge_class_init (NMDeviceBridgeClass *klass)
 
 	parent_class->get_generic_capabilities = get_generic_capabilities;
 	parent_class->update_hw_address = update_hw_address;
+	parent_class->get_hw_address = get_hw_address;
 	parent_class->is_available = is_available;
 	parent_class->get_best_auto_connection = get_best_auto_connection;
 	parent_class->check_connection_compatible = check_connection_compatible;
@@ -639,12 +537,10 @@ nm_device_bridge_class_init (NMDeviceBridgeClass *klass)
 	parent_class->connection_match_config = connection_match_config;
 
 	parent_class->act_stage1_prepare = act_stage1_prepare;
-	parent_class->act_stage3_ip4_config_start = act_stage3_ip4_config_start;
-	parent_class->act_stage3_ip6_config_start = act_stage3_ip6_config_start;
 	parent_class->enslave_slave = enslave_slave;
 	parent_class->release_slave = release_slave;
 
-	parent_class->state_changed = device_state_changed;
+	wired_class->carrier_action = carrier_action;
 
 	/* properties */
 	g_object_class_install_property
diff --git a/src/nm-device-bt.c b/src/nm-device-bt.c
index cadedcf7..366e2683 100644
--- a/src/nm-device-bt.c
+++ b/src/nm-device-bt.c
@@ -63,6 +63,7 @@ typedef struct {
 	guint mm_watch_id;
 	gboolean mm_running;
 
+	guint8 hw_addr[ETH_ALEN];  /* binary representation of bdaddr */
 	char *bdaddr;
 	char *name;
 	guint32 capabilities;
@@ -117,14 +118,6 @@ guint32 nm_device_bt_get_capabilities (NMDeviceBt *self)
 	return NM_DEVICE_BT_GET_PRIVATE (self)->capabilities;
 }
 
-const char *nm_device_bt_get_hw_address (NMDeviceBt *self)
-{
-	g_return_val_if_fail (self != NULL, NULL);
-	g_return_val_if_fail (NM_IS_DEVICE_BT (self), NULL);
-
-	return NM_DEVICE_BT_GET_PRIVATE (self)->bdaddr;
-}
-
 static guint32
 get_connection_bt_type (NMConnection *connection)
 {
@@ -156,16 +149,9 @@ get_best_auto_connection (NMDevice *device,
 
 	for (iter = connections; iter; iter = g_slist_next (iter)) {
 		NMConnection *connection = NM_CONNECTION (iter->data);
-		NMSettingConnection *s_con;
 		guint32 bt_type;
 
-		s_con = nm_connection_get_setting_connection (connection);
-		g_assert (s_con);
-
-		if (!nm_setting_connection_get_autoconnect (s_con))
-			continue;
-
-		if (strcmp (nm_setting_connection_get_connection_type (s_con), NM_SETTING_BLUETOOTH_SETTING_NAME))
+		if (!nm_connection_is_type (connection, NM_SETTING_BLUETOOTH_SETTING_NAME))
 			continue;
 
 		bt_type = get_connection_bt_type (connection);
@@ -401,6 +387,15 @@ get_generic_capabilities (NMDevice *dev)
 	return NM_DEVICE_CAP_NM_SUPPORTED;
 }
 
+static const guint8 *
+get_hw_address (NMDevice *device, guint *out_len)
+{
+	NMDeviceBtPrivate *priv = NM_DEVICE_BT_GET_PRIVATE (device);
+
+	*out_len = sizeof (priv->hw_addr);
+	return priv->hw_addr;
+}
+
 static gboolean
 hwaddr_matches (NMDevice *device,
                 NMConnection *connection,
@@ -1231,6 +1226,8 @@ set_property (GObject *object, guint prop_id,
 	case PROP_HW_ADDRESS:
 		/* Construct only */
 		priv->bdaddr = g_ascii_strup (g_value_get_string (value), -1);
+		if (!nm_utils_hwaddr_aton (priv->bdaddr, ARPHRD_ETHER, &priv->hw_addr))
+			nm_log_err (LOGD_HW, "Failed to convert BT address '%s'", priv->bdaddr);
 		break;
 	case PROP_BT_NAME:
 		/* Construct only */
@@ -1326,6 +1323,7 @@ nm_device_bt_class_init (NMDeviceBtClass *klass)
 	device_class->check_connection_available = check_connection_available;
 	device_class->complete_connection = complete_connection;
 	device_class->hwaddr_matches = hwaddr_matches;
+	device_class->get_hw_address = get_hw_address;
 	device_class->is_available = is_available;
 
 	device_class->state_changed = device_state_changed;
diff --git a/src/nm-device-bt.h b/src/nm-device-bt.h
index 0d54d607..9382ee25 100644
--- a/src/nm-device-bt.h
+++ b/src/nm-device-bt.h
@@ -65,8 +65,6 @@ NMDevice *nm_device_bt_new (const char *udi,
 
 guint32 nm_device_bt_get_capabilities (NMDeviceBt *device);
 
-const char *nm_device_bt_get_hw_address (NMDeviceBt *device);
-
 gboolean nm_device_bt_modem_added (NMDeviceBt *device,
                                    NMModem *modem,
                                    const char *driver);
diff --git a/src/nm-device-ethernet.c b/src/nm-device-ethernet.c
index 4b8f9497..cf4541db 100644
--- a/src/nm-device-ethernet.c
+++ b/src/nm-device-ethernet.c
@@ -81,6 +81,7 @@ typedef struct Supplicant {
 } Supplicant;
 
 typedef struct {
+	guint8              hw_addr[ETH_ALEN];         /* Current MAC address */
 	guint8              perm_hw_addr[ETH_ALEN];    /* Permanent MAC address */
 	guint8              initial_hw_addr[ETH_ALEN]; /* Initial MAC address (as seen when NM starts) */
 
@@ -350,16 +351,17 @@ nm_device_ethernet_new (const char *udi,
 }
 
 static void
-_update_hw_addr (NMDeviceEthernet *self, const guint8 *addr)
+update_hw_address (NMDevice *dev)
 {
-	const guint8 *current_addr;
-
-	g_return_if_fail (addr != NULL);
-
-	current_addr = nm_device_wired_get_hwaddr (NM_DEVICE_WIRED (self));
-	if (memcmp (current_addr, addr, ETH_ALEN)) {
-		nm_device_wired_set_hwaddr (NM_DEVICE_WIRED (self), addr, ETH_ALEN);
-		g_object_notify (G_OBJECT (self), NM_DEVICE_ETHERNET_HW_ADDRESS);
+	NMDeviceEthernetPrivate *priv = NM_DEVICE_ETHERNET_GET_PRIVATE (dev);
+	gsize addrlen;
+	gboolean changed = FALSE;
+
+	addrlen = nm_device_read_hwaddr (dev, priv->hw_addr, sizeof (priv->hw_addr), &changed);
+	if (addrlen) {
+		g_return_if_fail (addrlen == ETH_ALEN);
+		if (changed)
+			g_object_notify (G_OBJECT (dev), NM_DEVICE_ETHERNET_HW_ADDRESS);
 	}
 }
 
@@ -367,7 +369,7 @@ static gboolean
 _set_hw_addr (NMDeviceEthernet *self, const guint8 *addr, const char *detail)
 {
 	NMDevice *dev = NM_DEVICE (self);
-	const guint8 *current_addr;
+	NMDeviceEthernetPrivate *priv = NM_DEVICE_ETHERNET_GET_PRIVATE (self);
 	const char *iface;
 	char *mac_str = NULL;
 	gboolean success = FALSE;
@@ -377,8 +379,7 @@ _set_hw_addr (NMDeviceEthernet *self, const guint8 *addr, const char *detail)
 	iface = nm_device_get_iface (dev);
 
 	/* Do nothing if current MAC is same */
-	current_addr = nm_device_wired_get_hwaddr (NM_DEVICE_WIRED (self));
-	if (!memcmp (current_addr, addr, ETH_ALEN)) {
+	if (!memcmp (priv->hw_addr, addr, ETH_ALEN)) {
 		nm_log_dbg (LOGD_DEVICE | LOGD_ETHER, "(%s): no MAC address change needed", iface);
 		return TRUE;
 	}
@@ -392,9 +393,15 @@ _set_hw_addr (NMDeviceEthernet *self, const guint8 *addr, const char *detail)
 	success = nm_system_iface_set_mac (nm_device_get_ip_ifindex (dev), (struct ether_addr *) addr);
 	if (success) {
 		/* MAC address succesfully changed; update the current MAC to match */
-		_update_hw_addr (self, addr);
-		nm_log_info (LOGD_DEVICE | LOGD_ETHER, "(%s): %s MAC address to %s",
-		             iface, detail, mac_str);
+		update_hw_address (dev);
+		if (memcmp (priv->hw_addr, addr, ETH_ALEN) == 0) {
+			nm_log_info (LOGD_DEVICE | LOGD_ETHER, "(%s): %s MAC address to %s",
+			             iface, detail, mac_str);
+		} else {
+			nm_log_warn (LOGD_DEVICE | LOGD_ETHER, "(%s): new MAC address %s "
+			             "not successfully set",
+			             iface, mac_str);
+		}
 	} else {
 		nm_log_warn (LOGD_DEVICE | LOGD_ETHER, "(%s): failed to %s MAC address to %s",
 		             iface, detail, mac_str);
@@ -406,22 +413,6 @@ _set_hw_addr (NMDeviceEthernet *self, const guint8 *addr, const char *detail)
 }
 
 static void
-update_hw_address (NMDevice *dev)
-{
-	const guint8 *hw_addr;
-	guint8 old_addr[ETH_ALEN];
-
-	hw_addr = nm_device_wired_get_hwaddr (NM_DEVICE_WIRED (dev));
-	memcpy (old_addr, hw_addr, ETH_ALEN);
-
-	NM_DEVICE_CLASS (nm_device_ethernet_parent_class)->update_hw_address (dev);
-
-	hw_addr = nm_device_wired_get_hwaddr (NM_DEVICE_WIRED (dev));
-	if (memcmp (old_addr, hw_addr, ETH_ALEN))
-		g_object_notify (G_OBJECT (dev), NM_DEVICE_ETHERNET_HW_ADDRESS);
-}
-
-static void
 update_permanent_hw_address (NMDevice *dev)
 {
 	NMDeviceEthernet *self = NM_DEVICE_ETHERNET (dev);
@@ -448,13 +439,10 @@ update_permanent_hw_address (NMDevice *dev)
 	errno = 0;
 	ret = ioctl (fd, SIOCETHTOOL, &req);
 	if ((ret < 0) || !nm_ethernet_address_is_valid ((struct ether_addr *) epaddr->data)) {
-		const guint8 *current_addr;
-
 		nm_log_err (LOGD_HW | LOGD_ETHER, "(%s): unable to read permanent MAC address (error %d)",
 		            nm_device_get_iface (dev), errno);
 		/* Fall back to current address */
-		current_addr = nm_device_wired_get_hwaddr (NM_DEVICE_WIRED (self));
-		memcpy (epaddr->data, current_addr, ETH_ALEN);
+		memcpy (epaddr->data, priv->hw_addr, ETH_ALEN);
 	}
 
 	if (memcmp (&priv->perm_hw_addr, epaddr->data, ETH_ALEN)) {
@@ -470,23 +458,26 @@ update_initial_hw_address (NMDevice *dev)
 {
 	NMDeviceEthernet *self = NM_DEVICE_ETHERNET (dev);
 	NMDeviceEthernetPrivate *priv = NM_DEVICE_ETHERNET_GET_PRIVATE (self);
-	const guint8 *current_addr;
+	gsize addrlen;
 	char *mac_str = NULL;
-	guint8 *addr = priv->initial_hw_addr;
-	guint8 zero[ETH_ALEN] = {0,0,0,0,0,0};
 
 	/* This sets initial MAC address from current MAC address. It should only
 	 * be called from NMDevice constructor() to really get the initial address.
 	 */
-	current_addr = nm_device_wired_get_hwaddr (NM_DEVICE_WIRED (self));
-	if (!memcmp (current_addr, &zero, ETH_ALEN))
-		update_hw_address (dev);
-
-	if (memcmp (&priv->initial_hw_addr, current_addr, ETH_ALEN))
-		memcpy (&priv->initial_hw_addr, current_addr, ETH_ALEN);
+	addrlen = nm_device_read_hwaddr (dev,
+	                                 priv->initial_hw_addr,
+	                                 sizeof (priv->initial_hw_addr),
+	                                 NULL);
+	if (addrlen)
+		g_return_if_fail (addrlen == ETH_ALEN);
 
 	mac_str = g_strdup_printf ("%02X:%02X:%02X:%02X:%02X:%02X",
-	                           addr[0], addr[1], addr[2], addr[3], addr[4], addr[5]);
+	                           priv->initial_hw_addr[0],
+	                           priv->initial_hw_addr[1],
+	                           priv->initial_hw_addr[2],
+	                           priv->initial_hw_addr[3],
+	                           priv->initial_hw_addr[4],
+	                           priv->initial_hw_addr[5]);
 
 	nm_log_dbg (LOGD_DEVICE | LOGD_ETHER, "(%s): read initial MAC address %s",
 	            nm_device_get_iface (dev), mac_str);
@@ -494,6 +485,13 @@ update_initial_hw_address (NMDevice *dev)
 	g_free (mac_str);
 }
 
+static const guint8 *
+get_hw_address (NMDevice *device, guint *out_len)
+{
+	*out_len = ETH_ALEN;
+	return NM_DEVICE_ETHERNET_GET_PRIVATE (device)->hw_addr;
+}
+
 static guint32
 get_generic_capabilities (NMDevice *dev)
 {
@@ -626,13 +624,8 @@ get_best_auto_connection (NMDevice *dev,
 
 	for (iter = connections; iter; iter = g_slist_next (iter)) {
 		NMConnection *connection = NM_CONNECTION (iter->data);
-		NMSettingConnection *s_con;
 
-		s_con = nm_connection_get_setting_connection (connection);
-		g_assert (s_con);
-
-		if (   nm_setting_connection_get_autoconnect (s_con)
-		    && match_ethernet_connection (dev, connection, TRUE, NULL))
+		if (match_ethernet_connection (dev, connection, TRUE, NULL))
 			return connection;
 	}
 
@@ -1418,14 +1411,9 @@ hwaddr_matches (NMDevice *device,
                 guint other_hwaddr_len,
                 gboolean fail_if_no_hwaddr)
 {
+	NMDeviceEthernetPrivate *priv = NM_DEVICE_ETHERNET_GET_PRIVATE (device);
 	NMSettingWired *s_wired;
-	const guint8 *devaddr;
 	const GByteArray *mac = NULL;
-	int devtype;
-
-	devtype = nm_device_wired_get_hwaddr_type (NM_DEVICE_WIRED (device));
-	devaddr = nm_device_wired_get_hwaddr (NM_DEVICE_WIRED (device));
-	g_return_val_if_fail (devaddr != NULL, FALSE);
 
 	s_wired = nm_connection_get_setting_wired (connection);
 	if (s_wired)
@@ -1437,7 +1425,7 @@ hwaddr_matches (NMDevice *device,
 			g_return_val_if_fail (other_hwaddr_len == ETH_ALEN, FALSE);
 			if (memcmp (mac->data, other_hwaddr, mac->len) == 0)
 				return TRUE;
-		} else if (memcmp (mac->data, devaddr, mac->len) == 0)
+		} else if (memcmp (mac->data, priv->hw_addr, mac->len) == 0)
 			return TRUE;
 	} else if (fail_if_no_hwaddr == FALSE)
 		return TRUE;
@@ -1465,12 +1453,10 @@ get_property (GObject *object, guint prop_id,
 {
 	NMDeviceEthernet *self = NM_DEVICE_ETHERNET (object);
 	NMDeviceEthernetPrivate *priv = NM_DEVICE_ETHERNET_GET_PRIVATE (self);
-	const guint8 *current_addr;
 
 	switch (prop_id) {
 	case PROP_HW_ADDRESS:
-		current_addr = nm_device_wired_get_hwaddr (NM_DEVICE_WIRED (self));
-		g_value_take_string (value, nm_utils_hwaddr_ntoa (current_addr, ARPHRD_ETHER));
+		g_value_take_string (value, nm_utils_hwaddr_ntoa (priv->hw_addr, ARPHRD_ETHER));
 		break;
 	case PROP_PERM_HW_ADDRESS:
 		g_value_take_string (value, nm_utils_hwaddr_ntoa (&priv->perm_hw_addr, ARPHRD_ETHER));
@@ -1517,6 +1503,7 @@ nm_device_ethernet_class_init (NMDeviceEthernetClass *klass)
 	parent_class->bring_up = bring_up;
 	parent_class->take_down = take_down;
 	parent_class->update_hw_address = update_hw_address;
+	parent_class->get_hw_address = get_hw_address;
 	parent_class->update_permanent_hw_address = update_permanent_hw_address;
 	parent_class->update_initial_hw_address = update_initial_hw_address;
 	parent_class->get_best_auto_connection = get_best_auto_connection;
diff --git a/src/nm-device-infiniband.c b/src/nm-device-infiniband.c
index b2915f9e..c7dcf19c 100644
--- a/src/nm-device-infiniband.c
+++ b/src/nm-device-infiniband.c
@@ -44,7 +44,7 @@ G_DEFINE_TYPE (NMDeviceInfiniband, nm_device_infiniband, NM_TYPE_DEVICE_WIRED)
 #define NM_INFINIBAND_ERROR (nm_infiniband_error_quark ())
 
 typedef struct {
-	int dummy;
+	guint8 hw_addr[INFINIBAND_ALEN];
 } NMDeviceInfinibandPrivate;
 
 enum {
@@ -120,21 +120,26 @@ nm_device_infiniband_new (const char *udi,
 	                                  NULL);
 }
 
-
 static void
 update_hw_address (NMDevice *dev)
 {
-	const guint8 *hw_addr;
-	guint8 old_addr[INFINIBAND_ALEN];
-
-	hw_addr = nm_device_wired_get_hwaddr (NM_DEVICE_WIRED (dev));
-	memcpy (old_addr, hw_addr, INFINIBAND_ALEN);
-
-	NM_DEVICE_CLASS (nm_device_infiniband_parent_class)->update_hw_address (dev);
+	NMDeviceInfinibandPrivate *priv = NM_DEVICE_INFINIBAND_GET_PRIVATE (dev);
+	gsize addrlen;
+	gboolean changed = FALSE;
+
+	addrlen = nm_device_read_hwaddr (dev, priv->hw_addr, sizeof (priv->hw_addr), &changed);
+	if (addrlen) {
+		g_return_if_fail (addrlen == INFINIBAND_ALEN);
+		if (changed)
+			g_object_notify (G_OBJECT (dev), NM_DEVICE_INFINIBAND_HW_ADDRESS);
+	}
+}
 
-	hw_addr = nm_device_wired_get_hwaddr (NM_DEVICE_WIRED (dev));
-	if (memcmp (old_addr, hw_addr, INFINIBAND_ALEN))
-		g_object_notify (G_OBJECT (dev), NM_DEVICE_INFINIBAND_HW_ADDRESS);
+static const guint8 *
+get_hw_address (NMDevice *device, guint *out_len)
+{
+	*out_len = INFINIBAND_ALEN;
+	return NM_DEVICE_INFINIBAND_GET_PRIVATE (device)->hw_addr;
 }
 
 static guint32
@@ -148,31 +153,25 @@ get_best_auto_connection (NMDevice *dev,
                           GSList *connections,
                           char **specific_object)
 {
+	NMDeviceInfinibandPrivate *priv = NM_DEVICE_INFINIBAND_GET_PRIVATE (dev);
 	GSList *iter;
 
 	for (iter = connections; iter; iter = g_slist_next (iter)) {
 		NMConnection *connection = NM_CONNECTION (iter->data);
-		NMSettingConnection *s_con;
 		NMSettingInfiniband *s_infiniband;
 
-		s_con = nm_connection_get_setting_connection (connection);
-		g_assert (s_con);
-
 		if (!nm_connection_is_type (connection, NM_SETTING_INFINIBAND_SETTING_NAME))
 			continue;
-		if (!nm_setting_connection_get_autoconnect (s_con))
-			continue;
 
 		s_infiniband = nm_connection_get_setting_infiniband (connection);
 		if (!s_infiniband)
 			continue;
 
 		if (s_infiniband) {
-			const guint8 *hwaddr = nm_device_wired_get_hwaddr (NM_DEVICE_WIRED (dev));
 			const GByteArray *mac;
 
 			mac = nm_setting_infiniband_get_mac_address (s_infiniband);
-			if (mac && memcmp (mac->data, hwaddr, INFINIBAND_ALEN))
+			if (mac && memcmp (mac->data, priv->hw_addr, INFINIBAND_ALEN))
 				continue;
 		}
 
@@ -249,6 +248,7 @@ check_connection_compatible (NMDevice *device,
                              NMConnection *connection,
                              GError **error)
 {
+	NMDeviceInfinibandPrivate *priv = NM_DEVICE_INFINIBAND_GET_PRIVATE (device);
 	NMSettingInfiniband *s_infiniband;
 	const GByteArray *mac;
 
@@ -269,10 +269,8 @@ check_connection_compatible (NMDevice *device,
 	}
 
 	if (s_infiniband) {
-		const guint8 *hwaddr = nm_device_wired_get_hwaddr (NM_DEVICE_WIRED (device));
-
 		mac = nm_setting_infiniband_get_mac_address (s_infiniband);
-		if (mac && memcmp (mac->data, hwaddr, INFINIBAND_ALEN)) {
+		if (mac && memcmp (mac->data, priv->hw_addr, INFINIBAND_ALEN)) {
 			g_set_error (error,
 			             NM_INFINIBAND_ERROR,
 			             NM_INFINIBAND_ERROR_CONNECTION_INCOMPATIBLE,
@@ -291,9 +289,9 @@ complete_connection (NMDevice *device,
                      const GSList *existing_connections,
                      GError **error)
 {
+	NMDeviceInfinibandPrivate *priv = NM_DEVICE_INFINIBAND_GET_PRIVATE (device);
 	NMSettingInfiniband *s_infiniband;
 	const GByteArray *setting_mac;
-	const guint8 *hwaddr;
 
 	nm_utils_complete_generic (connection,
 	                           NM_SETTING_INFINIBAND_SETTING_NAME,
@@ -308,11 +306,10 @@ complete_connection (NMDevice *device,
 		nm_connection_add_setting (connection, NM_SETTING (s_infiniband));
 	}
 
-	hwaddr = nm_device_wired_get_hwaddr (NM_DEVICE_WIRED (device));
 	setting_mac = nm_setting_infiniband_get_mac_address (s_infiniband);
 	if (setting_mac) {
 		/* Make sure the setting MAC (if any) matches the device's MAC */
-		if (memcmp (setting_mac->data, hwaddr, INFINIBAND_ALEN)) {
+		if (memcmp (setting_mac->data, priv->hw_addr, INFINIBAND_ALEN)) {
 			g_set_error_literal (error,
 			                     NM_SETTING_INFINIBAND_ERROR,
 			                     NM_SETTING_INFINIBAND_ERROR_INVALID_PROPERTY,
@@ -323,8 +320,8 @@ complete_connection (NMDevice *device,
 		GByteArray *mac;
 
 		/* Lock the connection to this device by default */
-		mac = g_byte_array_sized_new (INFINIBAND_ALEN);
-		g_byte_array_append (mac, hwaddr, INFINIBAND_ALEN);
+		mac = g_byte_array_sized_new (sizeof (priv->hw_addr));
+		g_byte_array_append (mac, priv->hw_addr, sizeof (priv->hw_addr));
 		g_object_set (G_OBJECT (s_infiniband), NM_SETTING_INFINIBAND_MAC_ADDRESS, mac, NULL);
 		g_byte_array_free (mac, TRUE);
 	}
@@ -338,10 +335,11 @@ complete_connection (NMDevice *device,
 static gboolean
 spec_match_list (NMDevice *device, const GSList *specs)
 {
+	NMDeviceInfinibandPrivate *priv = NM_DEVICE_INFINIBAND_GET_PRIVATE (device);
 	char *hwaddr;
 	gboolean matched;
 
-	hwaddr = nm_utils_hwaddr_ntoa (nm_device_wired_get_hwaddr (NM_DEVICE_WIRED (device)), ARPHRD_INFINIBAND);
+	hwaddr = nm_utils_hwaddr_ntoa (priv->hw_addr, ARPHRD_INFINIBAND);
 	matched = nm_match_spec_hwaddr (specs, hwaddr);
 	g_free (hwaddr);
 
@@ -351,6 +349,7 @@ spec_match_list (NMDevice *device, const GSList *specs)
 static gboolean
 infiniband_match_config (NMDevice *self, NMConnection *connection)
 {
+	NMDeviceInfinibandPrivate *priv = NM_DEVICE_INFINIBAND_GET_PRIVATE (self);
 	NMSettingInfiniband *s_infiniband;
 	const GByteArray *s_mac;
 
@@ -360,7 +359,7 @@ infiniband_match_config (NMDevice *self, NMConnection *connection)
 
 	/* MAC address check */
 	s_mac = nm_setting_infiniband_get_mac_address (s_infiniband);
-	if (s_mac && memcmp (s_mac->data, nm_device_wired_get_hwaddr (NM_DEVICE_WIRED (self)), INFINIBAND_ALEN))
+	if (s_mac && memcmp (s_mac->data, priv->hw_addr, INFINIBAND_ALEN))
 		return FALSE;
 
 	return TRUE;
@@ -403,14 +402,9 @@ hwaddr_matches (NMDevice *device,
                 guint other_hwaddr_len,
                 gboolean fail_if_no_hwaddr)
 {
+	NMDeviceInfinibandPrivate *priv = NM_DEVICE_INFINIBAND_GET_PRIVATE (device);
 	NMSettingInfiniband *s_ib;
-	const guint8 *devaddr;
 	const GByteArray *mac = NULL;
-	int devtype;
-
-	devtype = nm_device_wired_get_hwaddr_type (NM_DEVICE_WIRED (device));
-	devaddr = nm_device_wired_get_hwaddr (NM_DEVICE_WIRED (device));
-	g_return_val_if_fail (devaddr != NULL, FALSE);
 
 	s_ib = nm_connection_get_setting_infiniband (connection);
 	if (s_ib)
@@ -422,7 +416,7 @@ hwaddr_matches (NMDevice *device,
 			g_return_val_if_fail (other_hwaddr_len == INFINIBAND_ALEN, FALSE);
 			if (memcmp (mac->data, other_hwaddr, mac->len) == 0)
 				return TRUE;
-		} else if (memcmp (mac->data, devaddr, mac->len) == 0)
+		} else if (memcmp (mac->data, priv->hw_addr, mac->len) == 0)
 			return TRUE;
 	} else if (fail_if_no_hwaddr == FALSE)
 		return TRUE;
@@ -434,12 +428,11 @@ static void
 get_property (GObject *object, guint prop_id,
               GValue *value, GParamSpec *pspec)
 {
-	const guint8 *current_addr;
+	NMDeviceInfinibandPrivate *priv = NM_DEVICE_INFINIBAND_GET_PRIVATE (object);
 
 	switch (prop_id) {
 	case PROP_HW_ADDRESS:
-		current_addr = nm_device_wired_get_hwaddr (NM_DEVICE_WIRED (object));
-		g_value_take_string (value, nm_utils_hwaddr_ntoa (current_addr, ARPHRD_INFINIBAND));
+		g_value_take_string (value, nm_utils_hwaddr_ntoa (priv->hw_addr, ARPHRD_INFINIBAND));
 		break;
 	case PROP_CARRIER:
 		g_value_set_boolean (value, nm_device_wired_get_carrier (NM_DEVICE_WIRED (object)));
@@ -476,6 +469,7 @@ nm_device_infiniband_class_init (NMDeviceInfinibandClass *klass)
 
 	parent_class->get_generic_capabilities = get_generic_capabilities;
 	parent_class->update_hw_address = update_hw_address;
+	parent_class->get_hw_address = get_hw_address;
 	parent_class->get_best_auto_connection = get_best_auto_connection;
 	parent_class->check_connection_compatible = check_connection_compatible;
 	parent_class->complete_connection = complete_connection;
diff --git a/src/nm-device-modem.c b/src/nm-device-modem.c
index 57f0bf8e..24d9cefb 100644
--- a/src/nm-device-modem.c
+++ b/src/nm-device-modem.c
@@ -254,22 +254,6 @@ complete_connection (NMDevice *device,
 	return nm_modem_complete_connection (priv->modem, connection, existing_connections, error);
 }
 
-static gboolean
-hw_is_up (NMDevice *device)
-{
-	int ifindex = nm_device_get_ip_ifindex (device);
-
-	return ifindex > 0 ? nm_system_iface_is_up (ifindex) : TRUE;
-}
-
-static gboolean
-hw_bring_up (NMDevice *device, gboolean *no_firmware)
-{
-	int ifindex = nm_device_get_ip_ifindex (device);
-
-	return ifindex > 0 ? nm_system_iface_set_up (ifindex, TRUE, no_firmware) : TRUE;
-}
-
 static void
 deactivate (NMDevice *device)
 {
@@ -508,8 +492,6 @@ nm_device_modem_class_init (NMDeviceModemClass *mclass)
 	device_class->get_best_auto_connection = get_best_auto_connection;
 	device_class->check_connection_compatible = check_connection_compatible;
 	device_class->complete_connection = complete_connection;
-	device_class->hw_is_up = hw_is_up;
-	device_class->hw_bring_up = hw_bring_up;
 	device_class->deactivate = deactivate;
 	device_class->act_stage1_prepare = act_stage1_prepare;
 	device_class->act_stage2_config = act_stage2_config;
diff --git a/src/nm-device-olpc-mesh.c b/src/nm-device-olpc-mesh.c
index 289e5be3..1417736f 100644
--- a/src/nm-device-olpc-mesh.c
+++ b/src/nm-device-olpc-mesh.c
@@ -94,7 +94,7 @@ struct _NMDeviceOlpcMeshPrivate
 {
 	gboolean          dispose_has_run;
 
-	struct ether_addr hw_addr;
+	guint8            hw_addr[ETH_ALEN];
 
 	GByteArray *      ssid;
 
@@ -139,7 +139,7 @@ nm_device_olpc_mesh_init (NMDeviceOlpcMesh * self)
 	priv->companion = NULL;
 	priv->stage1_waiting = FALSE;
 
-	memset (&(priv->hw_addr), 0, sizeof (struct ether_addr));
+	memset (&priv->hw_addr, 0, sizeof (priv->hw_addr));
 }
 
 static GObject*
@@ -187,24 +187,6 @@ constructor (GType type,
 }
 
 static gboolean
-hw_is_up (NMDevice *device)
-{
-	return nm_system_iface_is_up (nm_device_get_ip_ifindex (device));
-}
-
-static gboolean
-hw_bring_up (NMDevice *dev, gboolean *no_firmware)
-{
-	return nm_system_iface_set_up (nm_device_get_ip_ifindex (dev), TRUE, no_firmware);
-}
-
-static void
-hw_take_down (NMDevice *dev)
-{
-	nm_system_iface_set_up (nm_device_get_ip_ifindex (dev), FALSE, NULL);
-}
-
-static gboolean
 is_up (NMDevice *device)
 {
 	NMDeviceOlpcMesh *self = NM_DEVICE_OLPC_MESH (device);
@@ -315,23 +297,6 @@ complete_connection (NMDevice *device,
 	return TRUE;
 }
 
-/*
- * nm_device_olpc_mesh_get_address
- *
- * Get a device's hardware address
- *
- */
-static void
-nm_device_olpc_mesh_get_address (NMDeviceOlpcMesh *self,
-                                       struct ether_addr *addr)
-{
-	NMDeviceOlpcMeshPrivate *priv = NM_DEVICE_OLPC_MESH_GET_PRIVATE (self);
-	g_return_if_fail (self != NULL);
-	g_return_if_fail (addr != NULL);
-
-	memcpy (addr, &(priv->hw_addr), sizeof (struct ether_addr));
-}
-
 /****************************************************************************/
 
 static void
@@ -339,34 +304,26 @@ update_hw_address (NMDevice *dev)
 {
 	NMDeviceOlpcMesh *self = NM_DEVICE_OLPC_MESH (dev);
 	NMDeviceOlpcMeshPrivate *priv = NM_DEVICE_OLPC_MESH_GET_PRIVATE (self);
-	struct ifreq req;
-	int ret, fd;
-
-	fd = socket (PF_INET, SOCK_DGRAM, 0);
-	if (fd < 0) {
-		nm_log_warn (LOGD_OLPC_MESH, "could not open control socket.");
-		return;
-	}
-
-	memset (&req, 0, sizeof (struct ifreq));
-	strncpy (req.ifr_name, nm_device_get_iface (dev), IFNAMSIZ);
-	ret = ioctl (fd, SIOCGIFHWADDR, &req);
-	if (ret) {
-		nm_log_warn (LOGD_OLPC_MESH, "(%s): error getting hardware address: %d",
-		             nm_device_get_iface (dev), errno);
-		goto out;
+	gsize addrlen;
+	gboolean changed = FALSE;
+
+	addrlen = nm_device_read_hwaddr (dev, priv->hw_addr, sizeof (priv->hw_addr), &changed);
+	if (addrlen) {
+		g_return_if_fail (addrlen == ETH_ALEN);
+		if (changed)
+			g_object_notify (G_OBJECT (dev), NM_DEVICE_OLPC_MESH_HW_ADDRESS);
 	}
+}
 
-	if (memcmp (&priv->hw_addr, &req.ifr_hwaddr.sa_data, sizeof (struct ether_addr))) {
-		memcpy (&priv->hw_addr, &req.ifr_hwaddr.sa_data, sizeof (struct ether_addr));
-		g_object_notify (G_OBJECT (dev), NM_DEVICE_OLPC_MESH_HW_ADDRESS);
-	}
+static const guint8 *
+get_hw_address (NMDevice *device, guint *out_len)
+{
+       NMDeviceOlpcMeshPrivate *priv = NM_DEVICE_OLPC_MESH_GET_PRIVATE (device);
 
-out:
-	close (fd);
+       *out_len = sizeof (priv->hw_addr);
+       return priv->hw_addr;
 }
 
-
 static NMActStageReturn
 act_stage1_prepare (NMDevice *dev, NMDeviceStateReason *reason)
 {
@@ -506,12 +463,10 @@ get_property (GObject *object, guint prop_id,
 {
 	NMDeviceOlpcMesh *device = NM_DEVICE_OLPC_MESH (object);
 	NMDeviceOlpcMeshPrivate *priv = NM_DEVICE_OLPC_MESH_GET_PRIVATE (device);
-	struct ether_addr hw_addr;
 
 	switch (prop_id) {
 	case PROP_HW_ADDRESS:
-		nm_device_olpc_mesh_get_address (device, &hw_addr);
-		g_value_take_string (value, nm_utils_hwaddr_ntoa (&hw_addr, ARPHRD_ETHER));
+		g_value_take_string (value, nm_utils_hwaddr_ntoa (priv->hw_addr, ARPHRD_ETHER));
 		break;
 	case PROP_COMPANION:
 		if (priv->companion)
@@ -554,13 +509,11 @@ nm_device_olpc_mesh_class_init (NMDeviceOlpcMeshClass *klass)
 
 	parent_class->get_type_capabilities = NULL;
 	parent_class->get_generic_capabilities = get_generic_capabilities;
-	parent_class->hw_is_up = hw_is_up;
-	parent_class->hw_bring_up = hw_bring_up;
-	parent_class->hw_take_down = hw_take_down;
 	parent_class->is_up = is_up;
 	parent_class->bring_up = bring_up;
 	parent_class->take_down = take_down;
 	parent_class->update_hw_address = update_hw_address;
+	parent_class->get_hw_address = get_hw_address;
 	parent_class->check_connection_compatible = check_connection_compatible;
 	parent_class->complete_connection = complete_connection;
 
@@ -672,18 +625,17 @@ static gboolean
 is_companion (NMDeviceOlpcMesh *self, NMDevice *other)
 {
 	NMDeviceOlpcMeshPrivate *priv = NM_DEVICE_OLPC_MESH_GET_PRIVATE (self);
-	struct ether_addr their_addr;
+	const guint8 *their_addr;
+	guint their_addr_len = 0;
 	NMManager *manager;
 
 	if (!NM_IS_DEVICE_WIFI (other))
 		return FALSE;
 
-	nm_device_wifi_get_address (NM_DEVICE_WIFI (other), &their_addr);
-
-	if (memcmp (priv->hw_addr.ether_addr_octet,
-		their_addr.ether_addr_octet, ETH_ALEN) != 0) {
+	their_addr = nm_device_get_hw_address (other, &their_addr_len);
+	if (   (their_addr_len != ETH_ALEN)
+	    || (memcmp (priv->hw_addr, their_addr, ETH_ALEN) != 0))
 		return FALSE;
-	}
 
 	priv->companion = other;
 
diff --git a/src/nm-device-private.h b/src/nm-device-private.h
index 57e16c0f..8edae660 100644
--- a/src/nm-device-private.h
+++ b/src/nm-device-private.h
@@ -46,6 +46,8 @@ gboolean nm_device_hw_bring_up (NMDevice *self, gboolean wait, gboolean *no_firm
 
 void nm_device_hw_take_down (NMDevice *self, gboolean block);
 
+gsize nm_device_read_hwaddr (NMDevice *dev, guint8 *out_buf, gsize buf_len, gboolean *out_changed);
+
 gboolean nm_device_ip_config_should_fail (NMDevice *self, gboolean ip6);
 
 void nm_device_set_firmware_missing (NMDevice *self, gboolean missing);
@@ -63,7 +65,10 @@ void nm_device_activate_schedule_ip6_config_result (NMDevice *device, NMIP6Confi
 void nm_device_activate_schedule_ip6_config_timeout (NMDevice *device);
 
 gboolean nm_device_activate_ip4_state_in_conf (NMDevice *device);
+gboolean nm_device_activate_ip4_state_in_wait (NMDevice *device);
+
 gboolean nm_device_activate_ip6_state_in_conf (NMDevice *device);
+gboolean nm_device_activate_ip6_state_in_wait (NMDevice *device);
 
 void nm_device_set_dhcp_timeout (NMDevice *device, guint32 timeout);
 void nm_device_set_dhcp_anycast_address (NMDevice *device, guint8 *addr);
@@ -80,4 +85,8 @@ void nm_device_queued_state_clear (NMDevice *device);
 
 NMDeviceState nm_device_queued_state_peek (NMDevice *device);
 
+gboolean nm_device_get_enslaved (NMDevice *device);
+
+NMDevice *nm_device_master_get_slave_by_ifindex (NMDevice *dev, int ifindex);
+
 #endif	/* NM_DEVICE_PRIVATE_H */
diff --git a/src/nm-device-vlan.c b/src/nm-device-vlan.c
index f22d47d8..d8e1f3c1 100644
--- a/src/nm-device-vlan.c
+++ b/src/nm-device-vlan.c
@@ -130,19 +130,13 @@ get_carrier_sync (NMDeviceVlan *self)
 }
 
 static gboolean
-hw_is_up (NMDevice *device)
-{
-	return nm_system_iface_is_up (nm_device_get_ip_ifindex (device));
-}
-
-static gboolean
 hw_bring_up (NMDevice *dev, gboolean *no_firmware)
 {
 	gboolean success = FALSE, carrier;
 	guint i = 20;
 
 	while (i-- > 0 && !success) {
-		success = nm_system_iface_set_up (nm_device_get_ip_ifindex (dev), TRUE, no_firmware);
+		success = NM_DEVICE_CLASS (nm_device_vlan_parent_class)->hw_bring_up (dev, no_firmware);
 		g_usleep (50);
 	}
 
@@ -163,49 +157,28 @@ hw_bring_up (NMDevice *dev, gboolean *no_firmware)
 }
 
 static void
-hw_take_down (NMDevice *dev)
-{
-	nm_system_iface_set_up (nm_device_get_ip_ifindex (dev), FALSE, NULL);
-}
-
-static void
 update_hw_address (NMDevice *dev)
 {
 	NMDeviceVlan *self = NM_DEVICE_VLAN (dev);
 	NMDeviceVlanPrivate *priv = NM_DEVICE_VLAN_GET_PRIVATE (self);
-	struct rtnl_link *rtnl;
-	struct nl_addr *addr;
-
-	rtnl = nm_netlink_index_to_rtnl_link (nm_device_get_ip_ifindex (dev));
-	if (!rtnl) {
-		nm_log_err (LOGD_HW | LOGD_VLAN,
-		            "(%s) failed to read hardware address (error %d)",
-		            nm_device_get_iface (dev), errno);
-		return;
-	}
-
-	addr = rtnl_link_get_addr (rtnl);
-	if (!addr) {
-		nm_log_err (LOGD_HW | LOGD_VLAN,
-		            "(%s) no hardware address?",
-		            nm_device_get_iface (dev));
-		goto out;
+	gsize addrlen;
+	gboolean changed = FALSE;
+
+	addrlen = nm_device_read_hwaddr (dev, priv->hw_addr, sizeof (priv->hw_addr), &changed);
+	if (addrlen) {
+		priv->hw_addr_len = addrlen;
+		if (changed)
+			g_object_notify (G_OBJECT (self), NM_DEVICE_VLAN_HW_ADDRESS);
 	}
+}
 
-	if (nl_addr_get_len (addr) > sizeof (priv->hw_addr)) {
-		nm_log_err (LOGD_HW | LOGD_VLAN,
-		            "(%s) hardware address is wrong length (got %d max %zd)",
-		            nm_device_get_iface (dev),
-		            nl_addr_get_len (addr),
-		            sizeof (priv->hw_addr));
-	} else {
-		priv->hw_addr_len = nl_addr_get_len (addr);
-		memcpy (&priv->hw_addr, nl_addr_get_binary_addr (addr), priv->hw_addr_len);
-		g_object_notify (G_OBJECT (self), NM_DEVICE_VLAN_HW_ADDRESS);
-	}
+static const guint8 *
+get_hw_address (NMDevice *device, guint *out_len)
+{
+	NMDeviceVlanPrivate *priv = NM_DEVICE_VLAN_GET_PRIVATE (device);
 
-out:
-	rtnl_link_put (rtnl);
+	*out_len = priv->hw_addr_len;
+	return priv->hw_addr;
 }
 
 static gboolean
@@ -327,12 +300,8 @@ get_best_auto_connection (NMDevice *dev,
 
 	for (iter = connections; iter; iter = g_slist_next (iter)) {
 		NMConnection *connection = NM_CONNECTION (iter->data);
-		NMSettingConnection *s_con;
 
-		s_con = nm_connection_get_setting_connection (connection);
-		g_assert (s_con);
-		if (   nm_setting_connection_get_autoconnect (s_con)
-		    && match_vlan_connection (NM_DEVICE_VLAN (dev), connection, NULL))
+		if (match_vlan_connection (NM_DEVICE_VLAN (dev), connection, NULL))
 			return connection;
 	}
 	return NULL;
@@ -760,9 +729,8 @@ nm_device_vlan_class_init (NMDeviceVlanClass *klass)
 
 	parent_class->get_generic_capabilities = get_generic_capabilities;
 	parent_class->update_hw_address = update_hw_address;
-	parent_class->hw_is_up = hw_is_up;
+	parent_class->get_hw_address = get_hw_address;
 	parent_class->hw_bring_up = hw_bring_up;
-	parent_class->hw_take_down = hw_take_down;
 	parent_class->can_interrupt_activation = can_interrupt_activation;
 	parent_class->is_available = is_available;
 
diff --git a/src/nm-device-wifi.c b/src/nm-device-wifi.c
index eb5ac1aa..67a10d43 100644
--- a/src/nm-device-wifi.c
+++ b/src/nm-device-wifi.c
@@ -203,6 +203,8 @@ static void schedule_scanlist_cull (NMDeviceWifi *self);
 
 static gboolean request_wireless_scan (gpointer user_data);
 
+static void update_hw_address (NMDevice *dev);
+
 /*****************************************************************/
 
 #define NM_WIFI_ERROR (nm_wifi_error_quark ())
@@ -804,24 +806,12 @@ periodic_update (gpointer user_data)
 }
 
 static gboolean
-hw_is_up (NMDevice *device)
-{
-	return nm_system_iface_is_up (nm_device_get_ip_ifindex (device));
-}
-
-static gboolean
 hw_bring_up (NMDevice *device, gboolean *no_firmware)
 {
 	if (!NM_DEVICE_WIFI_GET_PRIVATE (device)->enabled)
 		return FALSE;
 
-	return nm_system_iface_set_up (nm_device_get_ip_ifindex (device), TRUE, no_firmware);
-}
-
-static void
-hw_take_down (NMDevice *device)
-{
-	nm_system_iface_set_up (nm_device_get_ip_ifindex (device), FALSE, NULL);
+	return NM_DEVICE_CLASS (nm_device_wifi_parent_class)->hw_bring_up (device, no_firmware);
 }
 
 static gboolean
@@ -843,19 +833,6 @@ bring_up (NMDevice *dev)
 	return TRUE;
 }
 
-static void
-_update_hw_addr (NMDeviceWifi *self, const guint8 *addr)
-{
-	NMDeviceWifiPrivate *priv = NM_DEVICE_WIFI_GET_PRIVATE (self);
-
-	g_return_if_fail (addr != NULL);
-
-	if (memcmp (&priv->hw_addr, addr, ETH_ALEN)) {
-		memcpy (&priv->hw_addr, addr, ETH_ALEN);
-		g_object_notify (G_OBJECT (self), NM_DEVICE_WIFI_HW_ADDRESS);
-	}
-}
-
 static gboolean
 _set_hw_addr (NMDeviceWifi *self, const guint8 *addr, const char *detail)
 {
@@ -880,12 +857,12 @@ _set_hw_addr (NMDeviceWifi *self, const guint8 *addr, const char *detail)
 	}
 
 	/* Can't change MAC address while device is up */
-	hw_take_down (dev);
+	nm_device_hw_take_down (dev, FALSE);
 
 	success = nm_system_iface_set_mac (nm_device_get_ip_ifindex (dev), (struct ether_addr *) addr);
 	if (success) {
 		/* MAC address succesfully changed; update the current MAC to match */
-		_update_hw_addr (self, addr);
+		update_hw_address (dev);
 		nm_log_info (LOGD_DEVICE | LOGD_ETHER, "(%s): %s MAC address to %s",
 		             iface, detail, mac_str);
 	} else {
@@ -1409,7 +1386,6 @@ get_best_auto_connection (NMDevice *dev,
 
 	for (iter = connections; iter; iter = g_slist_next (iter)) {
 		NMConnection *connection = NM_CONNECTION (iter->data);
-		NMSettingConnection *s_con;
 		NMSettingWireless *s_wireless;
 		const GByteArray *mac;
 		const GSList *mac_blacklist, *mac_blacklist_iter;
@@ -1418,12 +1394,7 @@ get_best_auto_connection (NMDevice *dev,
 		const char *method = NULL;
 		guint64 timestamp = 0;
 
-		s_con = nm_connection_get_setting_connection (connection);
-		if (s_con == NULL)
-			continue;
-		if (strcmp (nm_setting_connection_get_connection_type (s_con), NM_SETTING_WIRELESS_SETTING_NAME))
-			continue;
-		if (!nm_setting_connection_get_autoconnect (s_con))
+		if (!nm_connection_is_type (connection, NM_SETTING_WIRELESS_SETTING_NAME))
 			continue;
 
 		/* Don't autoconnect to networks that have been tried at least once
@@ -1483,25 +1454,6 @@ get_best_auto_connection (NMDevice *dev,
 	return NULL;
 }
 
-/*
- * nm_device_wifi_get_address
- *
- * Get a device's hardware address
- *
- */
-void
-nm_device_wifi_get_address (NMDeviceWifi *self,
-                            struct ether_addr *addr)
-{
-	NMDeviceWifiPrivate *priv;
-
-	g_return_if_fail (self != NULL);
-	g_return_if_fail (addr != NULL);
-
-	priv = NM_DEVICE_WIFI_GET_PRIVATE (self);
-	memcpy (addr, &priv->hw_addr, sizeof (struct ether_addr));
-}
-
 static void
 ap_list_dump (NMDeviceWifi *self)
 {
@@ -2878,26 +2830,16 @@ error:
 static void
 update_hw_address (NMDevice *dev)
 {
-	NMDeviceWifi *self = NM_DEVICE_WIFI (dev);
-	struct ifreq req;
-	int fd;
+	NMDeviceWifiPrivate *priv = NM_DEVICE_WIFI_GET_PRIVATE (dev);
+	gsize addrlen;
+	gboolean changed = FALSE;
 
-	fd = socket (PF_INET, SOCK_DGRAM, 0);
-	if (fd < 0) {
-		nm_log_err (LOGD_HW, "could not open control socket.");
-		return;
+	addrlen = nm_device_read_hwaddr (dev, priv->hw_addr, sizeof (priv->hw_addr), &changed);
+	if (addrlen) {
+		g_return_if_fail (addrlen == ETH_ALEN);
+		if (changed)
+			g_object_notify (G_OBJECT (dev), NM_DEVICE_WIFI_HW_ADDRESS);
 	}
-
-	memset (&req, 0, sizeof (struct ifreq));
-	strncpy (req.ifr_name, nm_device_get_iface (dev), IFNAMSIZ);
-	errno = 0;
-	if (ioctl (fd, SIOCGIFHWADDR, &req) < 0) {
-		nm_log_err (LOGD_HW | LOGD_WIFI, "(%s): unable to read hardware address (error %d)",
-		            nm_device_get_iface (dev), errno);
-	} else
-		_update_hw_addr (self, (const guint8 *) &req.ifr_hwaddr.sa_data);
-
-	close (fd);
 }
 
 static void
@@ -2969,6 +2911,15 @@ update_initial_hw_address (NMDevice *dev)
 	g_free (mac_str);
 }
 
+static const guint8 *
+get_hw_address (NMDevice *device, guint *out_len)
+{
+	NMDeviceWifiPrivate *priv = NM_DEVICE_WIFI_GET_PRIVATE (device);
+
+	*out_len = ETH_ALEN;
+	return priv->hw_addr;
+}
+
 static NMActStageReturn
 act_stage1_prepare (NMDevice *dev, NMDeviceStateReason *reason)
 {
@@ -3789,13 +3740,12 @@ nm_device_wifi_class_init (NMDeviceWifiClass *klass)
 
 	parent_class->get_type_capabilities = get_type_capabilities;
 	parent_class->get_generic_capabilities = get_generic_capabilities;
-	parent_class->hw_is_up = hw_is_up;
 	parent_class->hw_bring_up = hw_bring_up;
-	parent_class->hw_take_down = hw_take_down;
 	parent_class->is_up = is_up;
 	parent_class->bring_up = bring_up;
 	parent_class->take_down = take_down;
 	parent_class->update_hw_address = update_hw_address;
+	parent_class->get_hw_address = get_hw_address;
 	parent_class->update_permanent_hw_address = update_permanent_hw_address;
 	parent_class->update_initial_hw_address = update_initial_hw_address;
 	parent_class->get_best_auto_connection = get_best_auto_connection;
diff --git a/src/nm-device-wifi.h b/src/nm-device-wifi.h
index 26d66ffc..425b8525 100644
--- a/src/nm-device-wifi.h
+++ b/src/nm-device-wifi.h
@@ -94,8 +94,6 @@ NMDevice *nm_device_wifi_new (const char *udi,
                               const char *iface,
                               const char *driver);
 
-void nm_device_wifi_get_address (NMDeviceWifi *dev, struct ether_addr *addr);
-
 NMAccessPoint * nm_device_wifi_get_activation_ap (NMDeviceWifi *self);
 
 RfKillState nm_device_wifi_get_ipw_rfkill_state (NMDeviceWifi *self);
diff --git a/src/nm-device-wired.c b/src/nm-device-wired.c
index 44510fc6..6d459630 100644
--- a/src/nm-device-wired.c
+++ b/src/nm-device-wired.c
@@ -49,9 +49,6 @@ G_DEFINE_TYPE (NMDeviceWired, nm_device_wired, NM_TYPE_DEVICE)
 #define NM_DEVICE_WIRED_LOG_LEVEL(dev) ((nm_device_get_device_type (dev) == NM_DEVICE_TYPE_INFINIBAND) ? LOGD_INFINIBAND : LOGD_ETHER)
 
 typedef struct {
-	guint8              hw_addr[NM_UTILS_HWADDR_LEN_MAX];         /* Currently set MAC address */
-	guint               hw_addr_type;
-	guint               hw_addr_len;
 	gboolean            carrier;
 	guint32             speed;
 
@@ -134,31 +131,37 @@ carrier_action_defer_clear (NMDeviceWired *self)
 	}
 }
 
-static gboolean
-carrier_action_defer_cb (gpointer user_data)
+static void
+carrier_action (NMDeviceWired *self, NMDeviceState state, gboolean carrier)
 {
-	NMDeviceWired *self = NM_DEVICE_WIRED (user_data);
-	NMDeviceWiredPrivate *priv = NM_DEVICE_WIRED_GET_PRIVATE (self);
-	NMDeviceState state;
+	NMDevice *device = NM_DEVICE (self);
 
-	priv->carrier_action_defer_id = 0;
-
-	state = nm_device_get_state (NM_DEVICE (self));
 	if (state == NM_DEVICE_STATE_UNAVAILABLE) {
-		if (priv->carrier)
-			nm_device_queue_state (NM_DEVICE (self), NM_DEVICE_STATE_DISCONNECTED, NM_DEVICE_STATE_REASON_CARRIER);
+		if (carrier)
+			nm_device_queue_state (device, NM_DEVICE_STATE_DISCONNECTED, NM_DEVICE_STATE_REASON_CARRIER);
 		else {
 			/* clear any queued state changes if they wouldn't be valid when the
 			 * carrier is off.
 			 */
-			if (nm_device_queued_state_peek (NM_DEVICE (self)) >= NM_DEVICE_STATE_DISCONNECTED)
-				nm_device_queued_state_clear (NM_DEVICE (self));
+			if (nm_device_queued_state_peek (device) >= NM_DEVICE_STATE_DISCONNECTED)
+				nm_device_queued_state_clear (device);
 		}
 	} else if (state >= NM_DEVICE_STATE_DISCONNECTED) {
-		if (!priv->carrier)
-			nm_device_queue_state (NM_DEVICE (self), NM_DEVICE_STATE_UNAVAILABLE, NM_DEVICE_STATE_REASON_CARRIER);
+		if (!carrier && !nm_device_get_enslaved (device))
+			nm_device_queue_state (device, NM_DEVICE_STATE_UNAVAILABLE, NM_DEVICE_STATE_REASON_CARRIER);
 	}
+}
 
+static gboolean
+carrier_action_defer_cb (gpointer user_data)
+{
+	NMDeviceWired *self = NM_DEVICE_WIRED (user_data);
+	NMDeviceWiredPrivate *priv = NM_DEVICE_WIRED_GET_PRIVATE (self);
+
+	priv->carrier_action_defer_id = 0;
+	NM_DEVICE_WIRED_GET_CLASS (self)->carrier_action (self,
+	                                                  nm_device_get_state (NM_DEVICE (self)),
+	                                                  priv->carrier);
 	return FALSE;
 }
 
@@ -167,13 +170,11 @@ set_carrier (NMDeviceWired *self,
              const gboolean carrier,
              const gboolean defer_action)
 {
-	NMDeviceWiredPrivate *priv;
+	NMDeviceWiredPrivate *priv = NM_DEVICE_WIRED_GET_PRIVATE (self);
+	NMDevice *device = NM_DEVICE (self);
 	NMDeviceState state;
 	guint32 caps;
 
-	g_return_if_fail (NM_IS_DEVICE (self));
-
-	priv = NM_DEVICE_WIRED_GET_PRIVATE (self);
 	if (priv->carrier == carrier)
 		return;
 
@@ -184,22 +185,32 @@ set_carrier (NMDeviceWired *self,
 	 * doesn't support carrier detect.  These devices assume
 	 * the carrier is always up.
 	 */
-	caps = nm_device_get_capabilities (NM_DEVICE (self));
+	caps = nm_device_get_capabilities (device);
 	g_return_if_fail (caps & NM_DEVICE_CAP_CARRIER_DETECT);
 
 	priv->carrier = carrier;
-	g_object_notify (G_OBJECT (self), "carrier");
 
-	state = nm_device_get_state (NM_DEVICE (self));
+	state = nm_device_get_state (device);
 	if (state >= NM_DEVICE_STATE_UNAVAILABLE) {
-		nm_log_info (LOGD_HW | NM_DEVICE_WIRED_LOG_LEVEL (NM_DEVICE (self)),
+		nm_log_info (LOGD_HW | NM_DEVICE_WIRED_LOG_LEVEL (device),
 		             "(%s): carrier now %s (device state %d%s)",
-		             nm_device_get_iface (NM_DEVICE (self)),
+		             nm_device_get_iface (device),
 		             carrier ? "ON" : "OFF",
 		             state,
 		             defer_action ? ", deferring action for 4 seconds" : "");
 	}
 
+	g_object_notify (G_OBJECT (self), "carrier");
+
+	/* Retry IP configuration for master devices now that the carrier is on */
+	if (nm_device_is_master (device) && priv->carrier) {
+		if (nm_device_activate_ip4_state_in_wait (device))
+			nm_device_activate_stage3_ip4_start (device);
+
+		if (nm_device_activate_ip6_state_in_wait (device))
+			nm_device_activate_stage3_ip6_start (device);
+	}
+
 	if (defer_action)
 		priv->carrier_action_defer_id = g_timeout_add_seconds (4, carrier_action_defer_cb, self);
 	else
@@ -301,22 +312,6 @@ constructor (GType type,
 	            nm_device_get_iface (NM_DEVICE (self)),
 	            nm_device_get_ifindex (NM_DEVICE (self)));
 
-	if (nm_device_get_device_type (self) == NM_DEVICE_TYPE_ETHERNET) {
-		priv->hw_addr_type = ARPHRD_ETHER;
-		priv->hw_addr_len = ETH_ALEN;
-	} else if (nm_device_get_device_type (self) == NM_DEVICE_TYPE_INFINIBAND) {
-		priv->hw_addr_type = ARPHRD_INFINIBAND;
-		priv->hw_addr_len = INFINIBAND_ALEN;
-	} else if (nm_device_get_device_type (self) == NM_DEVICE_TYPE_BOND) {
-		/* We may not know the hardware address type until a slave is added */
-		priv->hw_addr_type = ARPHRD_ETHER;
-		priv->hw_addr_len = ETH_ALEN;
-	} else if (nm_device_get_device_type (self) == NM_DEVICE_TYPE_BRIDGE) {
-		priv->hw_addr_type = ARPHRD_ETHER;
-		priv->hw_addr_len = ETH_ALEN;
-	} else
-		g_assert_not_reached ();
-
 	caps = nm_device_get_capabilities (self);
 	if (caps & NM_DEVICE_CAP_CARRIER_DETECT) {
 		/* Only listen to netlink for cards that support carrier detect */
@@ -357,70 +352,20 @@ nm_device_wired_init (NMDeviceWired * self)
 }
 
 static gboolean
-hw_is_up (NMDevice *device)
-{
-	return nm_system_iface_is_up (nm_device_get_ip_ifindex (device));
-}
-
-static gboolean
 hw_bring_up (NMDevice *dev, gboolean *no_firmware)
 {
-	gboolean success, carrier;
+	gboolean result, carrier;
 	guint32 caps;
 
-	success = nm_system_iface_set_up (nm_device_get_ip_ifindex (dev), TRUE, no_firmware);
-	if (success) {
+	result = NM_DEVICE_CLASS(nm_device_wired_parent_class)->hw_bring_up (dev, no_firmware);
+	if (result) {
 		caps = nm_device_get_capabilities (dev);
 		if (caps & NM_DEVICE_CAP_CARRIER_DETECT) {
 			carrier = get_carrier_sync (NM_DEVICE_WIRED (dev));
 			set_carrier (NM_DEVICE_WIRED (dev), carrier, carrier ? FALSE : TRUE);
 		}
 	}
-	return success;
-}
-
-static void
-hw_take_down (NMDevice *dev)
-{
-	nm_system_iface_set_up (nm_device_get_ip_ifindex (dev), FALSE, NULL);
-}
-
-static void
-update_hw_address (NMDevice *dev)
-{
-	NMDeviceWired *self = NM_DEVICE_WIRED (dev);
-	NMDeviceWiredPrivate *priv = NM_DEVICE_WIRED_GET_PRIVATE (self);
-	struct rtnl_link *rtnl;
-	struct nl_addr *addr;
-
-	rtnl = nm_netlink_index_to_rtnl_link (nm_device_get_ip_ifindex (dev));
-	if (!rtnl) {
-		nm_log_err (LOGD_HW | NM_DEVICE_WIRED_LOG_LEVEL (dev),
-		            "(%s) failed to read hardware address (error %d)",
-		            nm_device_get_iface (dev), errno);
-		return;
-	}
-
-	addr = rtnl_link_get_addr (rtnl);
-	if (!addr) {
-		nm_log_err (LOGD_HW | NM_DEVICE_WIRED_LOG_LEVEL (dev),
-		            "(%s) no hardware address?",
-		            nm_device_get_iface (dev));
-		rtnl_link_put (rtnl);
-		return;
-	}
-
-	if (nl_addr_get_len (addr) != priv->hw_addr_len) {
-		nm_log_err (LOGD_HW | NM_DEVICE_WIRED_LOG_LEVEL (dev),
-		            "(%s) hardware address is wrong length (expected %d got %d)",
-		            nm_device_get_iface (dev),
-		            priv->hw_addr_len, nl_addr_get_len (addr));
-	} else {
-		memcpy (&priv->hw_addr, nl_addr_get_binary_addr (addr),
-				priv->hw_addr_len);
-	}
-
-	rtnl_link_put (rtnl);
+	return result;
 }
 
 static gboolean
@@ -468,6 +413,36 @@ connection_match_config (NMDevice *self, const GSList *connections)
 	return NULL;
 }
 
+static NMActStageReturn
+act_stage3_ip4_config_start (NMDevice *device,
+                             NMIP4Config **out_config,
+                             NMDeviceStateReason *reason)
+{
+	if (nm_device_is_master (device) && !nm_device_wired_get_carrier (NM_DEVICE_WIRED (device))) {
+		nm_log_info (LOGD_IP4 | NM_DEVICE_WIRED_LOG_LEVEL (device),
+		             "(%s): IPv4 config waiting until carrier is on",
+		             nm_device_get_ip_iface (device));
+		return NM_ACT_STAGE_RETURN_WAIT;
+	}
+
+	return NM_DEVICE_CLASS (nm_device_wired_parent_class)->act_stage3_ip4_config_start (device, out_config, reason);
+}
+
+static NMActStageReturn
+act_stage3_ip6_config_start (NMDevice *device,
+                             NMIP6Config **out_config,
+                             NMDeviceStateReason *reason)
+{
+	if (nm_device_is_master (device) && !nm_device_wired_get_carrier (NM_DEVICE_WIRED (device))) {
+		nm_log_info (LOGD_IP6 | NM_DEVICE_WIRED_LOG_LEVEL (device),
+		             "(%s): IPv6 config waiting until carrier is on",
+		             nm_device_get_ip_iface (device));
+		return NM_ACT_STAGE_RETURN_WAIT;
+	}
+
+	return NM_DEVICE_CLASS (nm_device_wired_parent_class)->act_stage3_ip6_config_start (device, out_config, reason);
+}
+
 static void
 dispose (GObject *object)
 {
@@ -498,6 +473,7 @@ nm_device_wired_class_init (NMDeviceWiredClass *klass)
 {
 	GObjectClass *object_class = G_OBJECT_CLASS (klass);
 	NMDeviceClass *parent_class = NM_DEVICE_CLASS (klass);
+	NMDeviceWiredClass *wired_class = NM_DEVICE_WIRED_CLASS (klass);
 
 	g_type_class_add_private (object_class, sizeof (NMDeviceWiredPrivate));
 
@@ -505,75 +481,14 @@ nm_device_wired_class_init (NMDeviceWiredClass *klass)
 	object_class->constructor = constructor;
 	object_class->dispose = dispose;
 
-	parent_class->hw_is_up = hw_is_up;
 	parent_class->hw_bring_up = hw_bring_up;
-	parent_class->hw_take_down = hw_take_down;
 	parent_class->can_interrupt_activation = can_interrupt_activation;
-	parent_class->update_hw_address = update_hw_address;
 	parent_class->is_available = is_available;
 	parent_class->connection_match_config = connection_match_config;
-}
-
-/**
- * nm_device_wired_get_hwaddr:
- * @dev: an #NMDeviceWired
- *
- * Get a device's hardware address
- *
- * Returns: (transfer none): @dev's hardware address
- */
-const guint8 *
-nm_device_wired_get_hwaddr (NMDeviceWired *dev)
-{
-	NMDeviceWiredPrivate *priv;
-
-	g_return_val_if_fail (dev != NULL, NULL);
+	parent_class->act_stage3_ip4_config_start = act_stage3_ip4_config_start;
+	parent_class->act_stage3_ip6_config_start = act_stage3_ip6_config_start;
 
-	priv = NM_DEVICE_WIRED_GET_PRIVATE (dev);
-	return priv->hw_addr;
-}
-
-/**
- * nm_device_wired_set_hwaddr:
- * @dev: an #NMDeviceWired
- * @addr: the new hardware address, @addrlen bytes in length
- * @addrlen: the length in bytes of @addr
- *
- * Sets the device's hardware address.
- */
-void
-nm_device_wired_set_hwaddr (NMDeviceWired *dev,
-                            const guint8 *addr,
-                            guint addrlen)
-{
-	NMDeviceWiredPrivate *priv;
-
-	g_return_if_fail (dev != NULL);
-	g_return_if_fail (addr != NULL);
-
-	priv = NM_DEVICE_WIRED_GET_PRIVATE (dev);
-	g_return_if_fail (addrlen == priv->hw_addr_len);
-
-	memcpy (priv->hw_addr, addr, priv->hw_addr_len);
-}
-
-/**
- * nm_device_wired_get_hwaddr_type:
- * @dev: an #NMDeviceWired
- *
- * Get the type of a device's hardware address
- *
- * Returns: the type of @dev's hardware address
- */
-int
-nm_device_wired_get_hwaddr_type (NMDeviceWired *dev)
-{
-	NMDeviceWiredPrivate *priv;
-
-	g_return_val_if_fail (dev != NULL, -1);
-
-	priv = NM_DEVICE_WIRED_GET_PRIVATE (dev);
-	return priv->hw_addr_type;
+	wired_class->carrier_action = carrier_action;
 }
 
 /**
diff --git a/src/nm-device-wired.h b/src/nm-device-wired.h
index 3180ee45..a8084352 100644
--- a/src/nm-device-wired.h
+++ b/src/nm-device-wired.h
@@ -42,15 +42,13 @@ typedef struct {
 typedef struct {
 	NMDeviceClass parent;
 
+	void (*carrier_action) (NMDeviceWired *self,
+	                        NMDeviceState state,
+	                        gboolean carrier);
 } NMDeviceWiredClass;
 
 GType nm_device_wired_get_type (void);
 
-const guint8 *nm_device_wired_get_hwaddr      (NMDeviceWired *dev);
-void          nm_device_wired_set_hwaddr      (NMDeviceWired *dev,
-                                               const guint8 *addr,
-                                               guint addrlen);
-int           nm_device_wired_get_hwaddr_type (NMDeviceWired *dev);
 gboolean      nm_device_wired_get_carrier     (NMDeviceWired *dev);
 guint32       nm_device_wired_get_speed       (NMDeviceWired *dev);
 
diff --git a/src/nm-device.c b/src/nm-device.c
index c4cfbce0..b0810680 100644
--- a/src/nm-device.c
+++ b/src/nm-device.c
@@ -126,6 +126,7 @@ enum {
 	PROP_RFKILL_TYPE,
 	PROP_IFINDEX,
 	PROP_AVAILABLE_CONNECTIONS,
+	PROP_IS_MASTER,
 	LAST_PROP
 };
 
@@ -250,8 +251,9 @@ typedef struct {
 	NMDevice *      master;
 	gboolean        enslaved;
 
-	/* list of SlaveInfo for bond/bridge master */
-	GSList *        slaves;
+	/* slave management */
+	gboolean        is_master;
+	GSList *        slaves;    /* list of SlaveInfo */
 
 	NMConnectionProvider *con_provider;
 
@@ -498,6 +500,14 @@ nm_device_hw_is_up (NMDevice *self)
 	return TRUE;
 }
 
+static gboolean
+hw_is_up (NMDevice *device)
+{
+	int ifindex = nm_device_get_ip_ifindex (device);
+
+	return ifindex > 0 ? nm_system_iface_is_up (ifindex) : TRUE;
+}
+
 static guint32
 get_generic_capabilities (NMDevice *dev)
 {
@@ -603,6 +613,18 @@ nm_device_set_ip_iface (NMDevice *self, const char *iface)
 	g_free (old_ip_iface);
 }
 
+const guint8 *
+nm_device_get_hw_address (NMDevice *dev, guint *out_len)
+{
+	g_return_val_if_fail (dev != NULL, NULL);
+	g_return_val_if_fail (NM_IS_DEVICE (dev), NULL);
+	g_return_val_if_fail (out_len != NULL, NULL);
+	g_return_val_if_fail (*out_len == 0, NULL);
+
+	if (NM_DEVICE_GET_CLASS (dev)->get_hw_address)
+		return NM_DEVICE_GET_CLASS (dev)->get_hw_address (dev, out_len);
+	return NULL;
+}
 
 /*
  * Get/set functions for driver
@@ -830,6 +852,25 @@ nm_device_enslave_slave (NMDevice *dev, NMDevice *slave, NMConnection *connectio
 		info->enslaved = TRUE;
 		nm_device_slave_notify_enslaved (info->slave, TRUE, FALSE);
 	}
+
+	/* Ensure the device's hardware address is up-to-date; it often changes
+	 * when slaves change.
+	 */
+	if (NM_DEVICE_GET_CLASS (dev)->update_hw_address)
+		NM_DEVICE_GET_CLASS (dev)->update_hw_address (dev);
+
+	/* Restart IP configuration if we're waiting for slaves.  Do this
+	 * after updating the hardware address as IP config may need the
+	 * new address.
+	 */
+	if (success) {
+		if (NM_DEVICE_GET_PRIVATE (dev)->ip4_state == IP_WAIT)
+			nm_device_activate_stage3_ip4_start (dev);
+
+		if (NM_DEVICE_GET_PRIVATE (dev)->ip6_state == IP_WAIT)
+			nm_device_activate_stage3_ip6_start (dev);
+	}
+
 	return success;
 }
 
@@ -867,6 +908,13 @@ nm_device_release_one_slave (NMDevice *dev, NMDevice *slave, gboolean failed)
 
 	priv->slaves = g_slist_remove (priv->slaves, info);
 	free_slave_info (info);
+
+	/* Ensure the device's hardware address is up-to-date; it often changes
+	 * when slaves change.
+	 */
+	if (NM_DEVICE_GET_CLASS (dev)->update_hw_address)
+		NM_DEVICE_GET_CLASS (dev)->update_hw_address (dev);
+
 	return success;
 }
 
@@ -907,8 +955,10 @@ slave_state_changed (NMDevice *slave,
 
 	if (release) {
 		nm_device_release_one_slave (self, slave, FALSE);
-		if (priv->slaves == NULL) {
-			/* FIXME: all slaves gone; do something? */
+		/* Bridge/bond interfaces are left up until manually deactivated */
+		if (priv->slaves == NULL && priv->state == NM_DEVICE_STATE_ACTIVATED) {
+			nm_log_dbg (LOGD_DEVICE, "(%s): last slave removed; remaining activated",
+			            nm_device_get_iface (self));
 		}
 	}
 }
@@ -964,6 +1014,40 @@ nm_device_master_get_slaves (NMDevice *dev)
 	return slaves;
 }
 
+/**
+ * nm_device_master_get_slave_by_ifindex:
+ * @dev: the master device
+ * @ifindex: the slave's interface index
+ *
+ * Returns: the slave with the given @ifindex of which @device is the master,
+ *   or %NULL if no device with @ifinidex is a slave of @device.
+ */
+NMDevice *
+nm_device_master_get_slave_by_ifindex (NMDevice *dev, int ifindex)
+{
+	GSList *iter;
+
+	for (iter = NM_DEVICE_GET_PRIVATE (dev)->slaves; iter; iter = g_slist_next (iter)) {
+		SlaveInfo *info = iter->data;
+
+		if (nm_device_get_ip_ifindex (info->slave) == ifindex)
+			return info->slave;
+	}
+	return NULL;
+}
+
+/**
+ * nm_device_is_master:
+ * @dev: the device
+ *
+ * Returns: whether @dev can enslave other devices (eg, bridge or bond)
+ */
+gboolean
+nm_device_is_master (NMDevice *dev)
+{
+	return NM_DEVICE_GET_PRIVATE (dev)->is_master;
+}
+
 /* release all slaves */
 static void
 nm_device_master_release_slaves (NMDevice *self, gboolean failed)
@@ -997,9 +1081,8 @@ nm_device_slave_notify_enslaved (NMDevice *dev,
 	NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE (dev);
 	NMConnection *connection = nm_device_get_connection (dev);
 
-	g_assert (priv->master);
-
 	if (enslaved) {
+		g_assert (priv->master);
 		g_warn_if_fail (priv->enslaved == FALSE);
 		g_warn_if_fail (priv->state == NM_DEVICE_STATE_IP_CONFIG);
 
@@ -1019,25 +1102,41 @@ nm_device_slave_notify_enslaved (NMDevice *dev,
 		NMDeviceState new_state = NM_DEVICE_STATE_DISCONNECTED;
 		NMDeviceStateReason reason = NM_DEVICE_STATE_REASON_NONE;
 
-		if (master_failed) {
-			new_state = NM_DEVICE_STATE_FAILED;
-			reason = NM_DEVICE_STATE_REASON_DEPENDENCY_FAILED;
+		if (   priv->state > NM_DEVICE_STATE_DISCONNECTED
+		    && priv->state <= NM_DEVICE_STATE_ACTIVATED) {
+			if (master_failed) {
+				new_state = NM_DEVICE_STATE_FAILED;
+				reason = NM_DEVICE_STATE_REASON_DEPENDENCY_FAILED;
+
+				nm_log_warn (LOGD_DEVICE,
+				             "Activation (%s) connection '%s' master failed",
+				             nm_device_get_iface (dev),
+				             nm_connection_get_id (connection));
+			} else {
+				nm_log_dbg (LOGD_DEVICE,
+				            "Activation (%s) connection '%s' master deactivated",
+				            nm_device_get_iface (dev),
+				            nm_connection_get_id (connection));
+			}
 
-			nm_log_warn (LOGD_DEVICE,
-					     "Activation (%s) connection '%s' master failed",
-					     nm_device_get_iface (dev),
-					     nm_connection_get_id (connection));
-		} else {
-			nm_log_dbg (LOGD_DEVICE,
-					    "Activation (%s) connection '%s' master deactivated",
-					    nm_device_get_iface (dev),
-					    nm_connection_get_id (connection));
+			nm_device_queue_state (dev, new_state, reason);
 		}
-
-		nm_device_queue_state (dev, new_state, reason);
 	}
 }
 
+/**
+ * nm_device_get_enslaved:
+ * @device: the #NMDevice
+ *
+ * Returns: %TRUE if the device is enslaved to a master device (eg bridge or
+ * bond), %FALSE if not
+ */
+gboolean
+nm_device_get_enslaved (NMDevice *device)
+{
+	return NM_DEVICE_GET_PRIVATE (device)->enslaved;
+}
+
 /*
  * nm_device_get_act_request
  *
@@ -1141,6 +1240,8 @@ nm_device_get_best_auto_connection (NMDevice *dev,
                                     char **specific_object)
 {
 	guint32 caps;
+	GSList *iter, *available_conns;
+	NMConnection *best_connection;
 
 	g_return_val_if_fail (NM_IS_DEVICE (dev), NULL);
 	g_return_val_if_fail (specific_object != NULL, NULL);
@@ -1154,7 +1255,24 @@ nm_device_get_best_auto_connection (NMDevice *dev,
 	if (!NM_DEVICE_GET_CLASS (dev)->get_best_auto_connection)
 		return NULL;
 
-	return NM_DEVICE_GET_CLASS (dev)->get_best_auto_connection (dev, connections, specific_object);
+	available_conns = NULL;
+	for (iter = connections; iter; iter = iter->next) {
+		NMConnection *connection = NM_CONNECTION (iter->data);
+		NMSettingConnection *s_con;
+
+		s_con = nm_connection_get_setting_connection (connection);
+		g_assert (s_con);
+		if (nm_setting_connection_get_autoconnect (s_con))
+			available_conns = g_slist_prepend (available_conns, connection);
+	}
+
+	if (!available_conns)
+		return NULL;
+
+	best_connection = NM_DEVICE_GET_CLASS (dev)->get_best_auto_connection (dev, available_conns, specific_object);
+
+	g_slist_free (available_conns);
+	return best_connection;
 }
 
 gboolean
@@ -1903,6 +2021,9 @@ dhcp4_start (NMDevice *self,
 	NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE (self);
 	NMSettingIP4Config *s_ip4;
 	guint8 *anycast = NULL;
+	GByteArray *tmp = NULL;
+	guint hwaddr_len = 0;
+	const guint8 *hwaddr;
 
 	s_ip4 = nm_connection_get_setting_ip4_config (connection);
 
@@ -1914,14 +2035,25 @@ dhcp4_start (NMDevice *self,
 		g_object_unref (priv->dhcp4_config);
 	priv->dhcp4_config = nm_dhcp4_config_new ();
 
+	hwaddr = nm_device_get_hw_address (self, &hwaddr_len);
+	if (hwaddr) {
+		tmp = g_byte_array_sized_new (hwaddr_len);
+		g_byte_array_append (tmp, hwaddr, hwaddr_len);
+	}
+
 	/* Begin DHCP on the interface */
 	g_warn_if_fail (priv->dhcp4_client == NULL);
 	priv->dhcp4_client = nm_dhcp_manager_start_ip4 (priv->dhcp_manager,
 	                                                nm_device_get_ip_iface (self),
+	                                                tmp,
 	                                                nm_connection_get_uuid (connection),
 	                                                s_ip4,
 	                                                priv->dhcp_timeout,
 	                                                anycast);
+
+	if (tmp)
+		g_byte_array_free (tmp, TRUE);
+
 	if (!priv->dhcp4_client) {
 		*reason = NM_DEVICE_STATE_REASON_DHCP_START_FAILED;
 		return NM_ACT_STAGE_RETURN_FAILURE;
@@ -2026,6 +2158,35 @@ shared4_new_config (NMDevice *self, NMDeviceStateReason *reason)
 
 /*********************************************/
 
+static gboolean
+have_any_ready_slaves (NMDevice *device, const GSList *slaves)
+{
+	const GSList *iter;
+
+	/* Any enslaved slave is "ready" in the generic case as it's
+	 * at least >= NM_DEVCIE_STATE_IP_CONFIG and has had Layer 2
+	 * properties set up.
+	 */
+	for (iter = slaves; iter; iter = g_slist_next (iter)) {
+		if (nm_device_get_enslaved (iter->data))
+			return TRUE;
+	}
+	return FALSE;
+}
+
+static gboolean
+ip4_requires_slaves (NMConnection *connection)
+{
+	NMSettingIP4Config *s_ip4;
+	const char *method = NM_SETTING_IP4_CONFIG_METHOD_AUTO;
+
+	s_ip4 = nm_connection_get_setting_ip4_config (connection);
+	if (s_ip4)
+		method = nm_setting_ip4_config_get_method (s_ip4);
+
+	return g_strcmp0 (method, NM_SETTING_IP4_CONFIG_METHOD_AUTO) == 0;
+}
+
 static NMActStageReturn
 act_stage3_ip4_config_start (NMDevice *self,
                              NMIP4Config **out_config,
@@ -2036,12 +2197,30 @@ act_stage3_ip4_config_start (NMDevice *self,
 	NMSettingIP4Config *s_ip4;
 	NMActStageReturn ret = NM_ACT_STAGE_RETURN_FAILURE;
 	const char *method = NM_SETTING_IP4_CONFIG_METHOD_AUTO;
+	GSList *slaves;
+	gboolean ready_slaves;
 
 	g_return_val_if_fail (reason != NULL, NM_ACT_STAGE_RETURN_FAILURE);
 
 	connection = nm_device_get_connection (self);
 	g_assert (connection);
 
+	if (priv->is_master && ip4_requires_slaves (connection)) {
+		/* If the master has no ready slaves, and depends on slaves for
+		 * a successful IPv4 attempt, then postpone IPv4 addressing.
+		 */
+		slaves = nm_device_master_get_slaves (self);
+		ready_slaves = NM_DEVICE_GET_CLASS (self)->have_any_ready_slaves (self, slaves);
+		g_slist_free (slaves);
+
+		if (ready_slaves == FALSE) {
+			nm_log_info (LOGD_DEVICE | LOGD_IP4,
+			             "(%s): IPv4 config waiting until slaves are ready",
+			             nm_device_get_ip_iface (self));
+			return NM_ACT_STAGE_RETURN_WAIT;
+		}
+	}
+
 	/* If we did not receive IP4 configuration information, default to DHCP */
 	s_ip4 = nm_connection_get_setting_ip4_config (connection);
 	if (s_ip4)
@@ -2286,7 +2465,9 @@ dhcp6_start (NMDevice *self,
 	NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE (self);
 	NMActStageReturn ret = NM_ACT_STAGE_RETURN_FAILURE;
 	guint8 *anycast = NULL;
-	const char *ip_iface;
+	GByteArray *tmp = NULL;
+	guint hwaddr_len = 0;
+	const guint8 *hwaddr;
 
 	if (!connection) {
 		connection = nm_device_get_connection (self);
@@ -2309,14 +2490,23 @@ dhcp6_start (NMDevice *self,
 		priv->dhcp6_ip6_config = NULL;
 	}
 
-	ip_iface = nm_device_get_ip_iface (self);
+	hwaddr = nm_device_get_hw_address (self, &hwaddr_len);
+	if (hwaddr) {
+		tmp = g_byte_array_sized_new (hwaddr_len);
+		g_byte_array_append (tmp, hwaddr, hwaddr_len);
+	}
+
 	priv->dhcp6_client = nm_dhcp_manager_start_ip6 (priv->dhcp_manager,
-	                                                ip_iface,
+	                                                nm_device_get_ip_iface (self),
+	                                                tmp,
 	                                                nm_connection_get_uuid (connection),
 	                                                nm_connection_get_setting_ip6_config (connection),
 	                                                priv->dhcp_timeout,
 	                                                anycast,
 	                                                (dhcp_opt == IP6_DHCP_OPT_OTHERCONF) ? TRUE : FALSE);
+	if (tmp)
+		g_byte_array_free (tmp, TRUE);
+
 	if (priv->dhcp6_client) {
 		priv->dhcp6_state_sigid = g_signal_connect (priv->dhcp6_client,
 		                                            "state-changed",
@@ -2448,6 +2638,8 @@ addrconf6_start (NMDevice *self)
 	NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE (self);
 	NMConnection *connection;
 	gboolean success;
+	const guint8 *hwaddr;
+	guint hwaddr_len = 0;
 
 	connection = nm_device_get_connection (self);
 	g_assert (connection);
@@ -2470,8 +2662,12 @@ addrconf6_start (NMDevice *self)
 		                                                   self);
 	}
 
+	hwaddr = nm_device_get_hw_address (self, &hwaddr_len);
+	g_warn_if_fail (hwaddr != NULL);
 	success = nm_ip6_manager_prepare_interface (priv->ip6_manager,
 	                                            nm_device_get_ip_ifindex (self),
+	                                            hwaddr,
+	                                            hwaddr_len,
 	                                            nm_connection_get_setting_ip6_config (connection),
 	                                            priv->ip6_accept_ra_path);
 	if (success) {
@@ -2555,6 +2751,25 @@ done:
 	return ret;
 }
 
+static gboolean
+ip6_requires_slaves (NMConnection *connection)
+{
+	NMSettingIP6Config *s_ip6;
+	const char *method = NM_SETTING_IP6_CONFIG_METHOD_AUTO;
+
+	s_ip6 = nm_connection_get_setting_ip6_config (connection);
+	if (s_ip6)
+		method = nm_setting_ip6_config_get_method (s_ip6);
+
+	/* SLAAC, DHCP, and Link-Local depend on connectivity (and thus slaves)
+	 * to complete addressing.  SLAAC and DHCP obviously need a peer to
+	 * provide a prefix, while Link-Local must perform DAD on the local link.
+	 */
+	return    g_strcmp0 (method, NM_SETTING_IP6_CONFIG_METHOD_AUTO) == 0
+	       || g_strcmp0 (method, NM_SETTING_IP6_CONFIG_METHOD_DHCP) == 0
+	       || g_strcmp0 (method, NM_SETTING_IP6_CONFIG_METHOD_LINK_LOCAL) == 0;
+}
+
 static NMActStageReturn
 act_stage3_ip6_config_start (NMDevice *self,
                              NMIP6Config **out_config,
@@ -2568,6 +2783,8 @@ act_stage3_ip6_config_start (NMDevice *self,
 	int conf_use_tempaddr;
 	NMSettingIP6ConfigPrivacy ip6_privacy = NM_SETTING_IP6_CONFIG_PRIVACY_UNKNOWN;
 	const char *ip6_privacy_str = "0\n";
+	GSList *slaves;
+	gboolean ready_slaves;
 
 	g_return_val_if_fail (reason != NULL, NM_ACT_STAGE_RETURN_FAILURE);
 
@@ -2576,6 +2793,22 @@ act_stage3_ip6_config_start (NMDevice *self,
 
 	ip_iface = nm_device_get_ip_iface (self);
 
+	if (priv->is_master && ip6_requires_slaves (connection)) {
+		/* If the master has no ready slaves, and depends on slaves for
+		 * a successful IPv6 attempt, then postpone IPv6 addressing.
+		 */
+		slaves = nm_device_master_get_slaves (self);
+		ready_slaves = NM_DEVICE_GET_CLASS (self)->have_any_ready_slaves (self, slaves);
+		g_slist_free (slaves);
+
+		if (ready_slaves == FALSE) {
+			nm_log_info (LOGD_DEVICE | LOGD_IP6,
+			             "(%s): IPv6 config waiting until slaves are ready",
+			             ip_iface);
+			return NM_ACT_STAGE_RETURN_WAIT;
+		}
+	}
+
 	update_accept_ra_save (self);
 	update_ip6_privacy_save (self);
 
@@ -3247,6 +3480,13 @@ nm_device_activate_ip4_state_in_conf (NMDevice *self)
 	return NM_DEVICE_GET_PRIVATE (self)->ip4_state == IP_CONF;
 }
 
+gboolean
+nm_device_activate_ip4_state_in_wait (NMDevice *self)
+{
+	g_return_val_if_fail (self != NULL, FALSE);
+	return NM_DEVICE_GET_PRIVATE (self)->ip4_state == IP_WAIT;
+}
+
 static gboolean
 nm_device_activate_ip6_config_commit (gpointer user_data)
 {
@@ -3339,6 +3579,13 @@ nm_device_activate_ip6_state_in_conf (NMDevice *self)
 	return NM_DEVICE_GET_PRIVATE (self)->ip6_state == IP_CONF;
 }
 
+gboolean
+nm_device_activate_ip6_state_in_wait (NMDevice *self)
+{
+	g_return_val_if_fail (self != NULL, FALSE);
+	return NM_DEVICE_GET_PRIVATE (self)->ip6_state == IP_WAIT;
+}
+
 static void
 clear_act_request (NMDevice *self)
 {
@@ -3553,10 +3800,10 @@ nm_device_deactivate (NMDevice *self, NMDeviceStateReason reason)
 		NM_DEVICE_GET_CLASS (self)->deactivate (self);
 
 	/* master: release slaves */
-	g_clear_object (&priv->master);
 	nm_device_master_release_slaves (self, FALSE);
 
 	/* slave: mark no longer enslaved */
+	g_clear_object (&priv->master);
 	priv->enslaved = FALSE;
 
 	/* Tear down an existing activation request */
@@ -3919,6 +4166,14 @@ out:
 	return TRUE;
 }
 
+static gboolean
+hw_bring_up (NMDevice *device, gboolean *no_firmware)
+{
+	int ifindex = nm_device_get_ip_ifindex (device);
+
+	return ifindex > 0 ? nm_system_iface_set_up (ifindex, TRUE, no_firmware) : TRUE;
+}
+
 void
 nm_device_hw_take_down (NMDevice *self, gboolean block)
 {
@@ -3939,6 +4194,12 @@ nm_device_hw_take_down (NMDevice *self, gboolean block)
 		g_usleep (200);
 }
 
+static void
+hw_take_down (NMDevice *device)
+{
+	nm_system_iface_set_up (nm_device_get_ip_ifindex (device), FALSE, NULL);
+}
+
 static gboolean
 nm_device_bring_up (NMDevice *self, gboolean block, gboolean *no_firmware)
 {
@@ -4177,6 +4438,9 @@ set_property (GObject *object, guint prop_id,
 	case PROP_RFKILL_TYPE:
 		priv->rfkill_type = g_value_get_uint (value);
 		break;
+	case PROP_IS_MASTER:
+		priv->is_master = g_value_get_boolean (value);
+		break;
 	default:
 		G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
 		break;
@@ -4299,6 +4563,9 @@ get_property (GObject *object, guint prop_id,
 			g_ptr_array_add (array, g_strdup (nm_connection_get_path (connection)));
 		g_value_take_boxed (value, array);
 		break;
+	case PROP_IS_MASTER:
+		g_value_set_boolean (value, priv->is_master);
+		break;
 	default:
 		G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
 		break;
@@ -4329,7 +4596,12 @@ nm_device_class_init (NMDeviceClass *klass)
 	klass->act_stage3_ip6_config_start = act_stage3_ip6_config_start;
 	klass->act_stage4_ip4_config_timeout = act_stage4_ip4_config_timeout;
 	klass->act_stage4_ip6_config_timeout = act_stage4_ip6_config_timeout;
+	klass->have_any_ready_slaves = have_any_ready_slaves;
+
 	klass->check_connection_available = check_connection_available;
+	klass->hw_is_up = hw_is_up;
+	klass->hw_bring_up = hw_bring_up;
+	klass->hw_take_down = hw_take_down;
 
 	/* Properties */
 	g_object_class_install_property
@@ -4517,6 +4789,14 @@ nm_device_class_init (NMDeviceClass *klass)
 		                     DBUS_TYPE_G_ARRAY_OF_OBJECT_PATH,
 		                     G_PARAM_READABLE));
 
+	g_object_class_install_property
+		(object_class, PROP_IS_MASTER,
+		 g_param_spec_boolean (NM_DEVICE_IS_MASTER,
+		                       "IsMaster",
+		                       "IsMaster",
+		                       FALSE,
+		                       G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY));
+
 	/* Signals */
 	signals[STATE_CHANGED] =
 		g_signal_new ("state-changed",
@@ -5015,9 +5295,9 @@ nm_device_set_managed (NMDevice *device,
 		return;
 
 	priv->managed = managed;
-	nm_log_info (LOGD_DEVICE, "(%s): now %s",
-	             nm_device_get_iface (device),
-	             managed ? "managed" : "unmanaged");
+	nm_log_dbg (LOGD_DEVICE, "(%s): now %s",
+	            nm_device_get_iface (device),
+	            managed ? "managed" : "unmanaged");
 
 	g_object_notify (G_OBJECT (device), NM_DEVICE_MANAGED);
 
@@ -5333,3 +5613,71 @@ nm_device_supports_vlans (NMDevice *device)
 	/* At the moment, NM's VLAN code assumes all VLANs are over ethernet. */
 	return NM_IS_DEVICE_ETHERNET (device);
 }
+
+/**
+ * nm_device_read_hwaddr:
+ * @dev: the device
+ * @buf: an allocated buffer which on success holds the device's hardware
+ *   address
+ * @buf_len: the size of @buf
+ * @out_changed: on success, %TRUE if the contents of @buf are different from
+ *   the original contents of @buf when this function was called
+ *
+ * Reads the device's hardware address from the kernel and copies it into
+ * @buf, returning the size of the data copied into @buf.  On failure
+ * @buf is not modified.
+ *
+ * Returns: the size of the hardware address in bytes on success, 0 on failure
+ */
+gsize
+nm_device_read_hwaddr (NMDevice *dev,
+                       guint8 *buf,
+                       gsize buf_len,
+                       gboolean *out_changed)
+{
+	struct rtnl_link *rtnl;
+	struct nl_addr *addr;
+	int idx;
+	gsize addrlen = 0;
+	const guint8 *binaddr;
+
+	g_return_val_if_fail (dev != NULL, 0);
+	g_return_val_if_fail (buf != NULL, 0);
+	g_return_val_if_fail (buf_len > 0, 0);
+
+	idx = nm_device_get_ip_ifindex (dev);
+	g_return_val_if_fail (idx > 0, 0);
+
+	rtnl = nm_netlink_index_to_rtnl_link (idx);
+	if (!rtnl) {
+		nm_log_err (LOGD_HW | LOGD_DEVICE,
+		            "(%s): failed to read hardware address (error %d)",
+		            nm_device_get_iface (dev), errno);
+		return 0;
+	}
+
+	addr = rtnl_link_get_addr (rtnl);
+	if (!addr) {
+		nm_log_err (LOGD_HW | LOGD_DEVICE,
+		            "(%s): no hardware address?",
+		            nm_device_get_iface (dev));
+		goto out;
+	}
+
+	addrlen = nl_addr_get_len (addr);
+	if (addrlen > buf_len) {
+		nm_log_err (LOGD_HW | LOGD_DEVICE,
+		            "(%s): hardware address is wrong length (got %zd max %zd)",
+		            nm_device_get_iface (dev), addrlen, buf_len);
+		addrlen = 0;
+	} else {
+		binaddr = nl_addr_get_binary_addr (addr);
+		if (out_changed)
+			*out_changed = memcmp (buf, binaddr, addrlen) ? TRUE : FALSE;
+		memcpy (buf, binaddr, addrlen);
+	}
+
+out:
+	rtnl_link_put (rtnl);
+	return addrlen;
+}
diff --git a/src/nm-device.h b/src/nm-device.h
index 05b39622..87e428f5 100644
--- a/src/nm-device.h
+++ b/src/nm-device.h
@@ -60,6 +60,7 @@
 #define NM_DEVICE_TYPE_DESC        "type-desc"    /* Internal only */
 #define NM_DEVICE_RFKILL_TYPE      "rfkill-type"  /* Internal only */
 #define NM_DEVICE_IFINDEX          "ifindex"      /* Internal only */
+#define NM_DEVICE_IS_MASTER        "is-master"    /* Internal only */
 #define NM_DEVICE_AVAILABLE_CONNECTIONS "available-connections"
 
 /* Internal signals */
@@ -112,6 +113,7 @@ typedef struct {
 	void        (* update_hw_address) (NMDevice *self);
 	void        (* update_permanent_hw_address) (NMDevice *self);
 	void        (* update_initial_hw_address) (NMDevice *self);
+	const guint8 * (* get_hw_address) (NMDevice *self, guint *out_len);
 
 	guint32		(* get_type_capabilities)	(NMDevice *self);
 	guint32		(* get_generic_capabilities)	(NMDevice *self);
@@ -186,6 +188,9 @@ typedef struct {
 
 	gboolean        (* release_slave) (NMDevice *self,
 	                                   NMDevice *slave);
+
+	gboolean        (* have_any_ready_slaves) (NMDevice *self,
+	                                           const GSList *slaves);
 } NMDeviceClass;
 
 
@@ -212,6 +217,8 @@ NMDeviceType	nm_device_get_device_type	(NMDevice *dev);
 
 int			nm_device_get_priority (NMDevice *dev);
 
+const guint8 *  nm_device_get_hw_address (NMDevice *dev, guint *out_len);
+
 NMDHCP4Config * nm_device_get_dhcp4_config (NMDevice *dev);
 NMDHCP6Config * nm_device_get_dhcp6_config (NMDevice *dev);
 
@@ -221,6 +228,7 @@ NMIP6Config *	nm_device_get_ip6_config	(NMDevice *dev);
 /* Master */
 gboolean        nm_device_master_add_slave  (NMDevice *dev, NMDevice *slave);
 GSList *        nm_device_master_get_slaves (NMDevice *dev);
+gboolean        nm_device_is_master         (NMDevice *dev);
 
 /* Slave */
 void            nm_device_slave_notify_enslaved (NMDevice *dev,
diff --git a/src/nm-manager.c b/src/nm-manager.c
index fbc9d23d..3dc60d85 100644
--- a/src/nm-manager.c
+++ b/src/nm-manager.c
@@ -165,6 +165,8 @@ static GSList * remove_one_device (NMManager *manager,
                                    NMDevice *device,
                                    gboolean quitting);
 
+static void rfkill_change_wifi (const char *desc, gboolean enabled);
+
 #define SSD_POKE_INTERVAL 120
 #define ORIGDEV_TAG "originating-device"
 
@@ -244,6 +246,8 @@ typedef struct {
 
 	guint timestamp_update_id;
 
+	GHashTable *nm_bridges;
+
 	gboolean disposed;
 } NMManagerPrivate;
 
@@ -1130,6 +1134,92 @@ get_virtual_iface_placeholder_udi (void)
 	return g_strdup_printf ("/virtual/device/placeholder/%d", id++);
 }
 
+/***************************/
+
+/* FIXME: remove when we handle bridges non-destructively */
+
+#define NM_BRIDGE_FILE  NMRUNDIR "/nm-bridges"
+
+static void
+read_nm_created_bridges (NMManager *self)
+{
+	NMManagerPrivate *priv = NM_MANAGER_GET_PRIVATE (self);
+	char *contents;
+	char **lines, **iter;
+	GTimeVal tv;
+	glong ts;
+
+	if (!g_file_get_contents (NM_BRIDGE_FILE, &contents, NULL, NULL))
+		return;
+
+	g_get_current_time (&tv);
+
+	lines = g_strsplit_set (contents, "\n", 0);
+	g_free (contents);
+
+	for (iter = lines; iter && *iter; iter++) {
+		if (g_str_has_prefix (*iter, "ts=")) {
+			errno = 0;
+			ts = strtol (*iter + 3, NULL, 10);
+			/* allow 30 minutes time difference before we ignore the file */
+			if (errno || ABS (tv.tv_sec - ts) > 1800)
+				goto out;
+		} else if (g_str_has_prefix (*iter, "iface="))
+			g_hash_table_insert (priv->nm_bridges, g_strdup (*iter + 6), GUINT_TO_POINTER (1));
+	}
+
+out:
+	g_strfreev (lines);
+	unlink (NM_BRIDGE_FILE);
+}
+
+static void
+write_nm_created_bridges (NMManager *self)
+{
+	NMManagerPrivate *priv = NM_MANAGER_GET_PRIVATE (self);
+	GString *br_list;
+	GSList *iter;
+	GError *error = NULL;
+	GTimeVal tv;
+	gboolean found = FALSE;
+
+	/* write out nm-created bridges list */
+	br_list = g_string_sized_new (50);
+
+	/* Timestamp is first line */
+	g_get_current_time (&tv);
+	g_string_append_printf (br_list, "ts=%ld\n", tv.tv_sec);
+
+	for (iter = priv->devices; iter; iter = g_slist_next (iter)) {
+		NMDevice *device = iter->data;
+
+		if (nm_device_get_device_type (device) == NM_DEVICE_TYPE_BRIDGE) {
+			g_string_append_printf (br_list, "iface=%s\n", nm_device_get_iface (device));
+			found = TRUE;
+		}
+	}
+
+	if (found) {
+		if (!g_file_set_contents (NM_BRIDGE_FILE, br_list->str, -1, &error)) {
+			nm_log_warn (LOGD_BRIDGE, "Failed to write NetworkManager-created bridge list; "
+			             "on restart bridges may not be recognized. (%s)",
+			             error ? error->message : "unknown");
+			g_clear_error (&error);
+		}
+	}
+	g_string_free (br_list, TRUE);
+}
+
+static gboolean
+bridge_created_by_nm (NMManager *self, const char *iface)
+{
+	NMManagerPrivate *priv = NM_MANAGER_GET_PRIVATE (self);
+
+	return (priv->nm_bridges && g_hash_table_lookup (priv->nm_bridges, iface));
+}
+
+/***************************/
+
 /**
  * system_create_virtual_device:
  * @self: the #NMManager
@@ -1179,12 +1269,21 @@ system_create_virtual_device (NMManager *self, NMConnection *connection)
 		device = nm_device_bond_new (udi, iface);
 		g_free (udi);
 	} else if (nm_connection_is_type (connection, NM_SETTING_BRIDGE_SETTING_NAME)) {
-		if (!nm_system_create_bridge (iface)) {
+		gboolean exists = FALSE;
+
+		if (!nm_system_create_bridge (iface, &exists)) {
 			nm_log_warn (LOGD_DEVICE, "(%s): failed to add bridging interface for '%s'",
 			             iface, nm_connection_get_id (connection));
 			goto out;
 		}
 
+		/* FIXME: remove when we handle bridges non-destructively */
+		if (exists && !bridge_created_by_nm (self, iface)) {
+			nm_log_warn (LOGD_DEVICE, "(%s): cannot use existing bridge for '%s'",
+			             iface, nm_connection_get_id (connection));
+			goto out;
+		}
+
 		udi = get_virtual_iface_placeholder_udi ();
 		device = nm_device_bridge_new (udi, iface);
 		g_free (udi);
@@ -2175,9 +2274,14 @@ udev_device_added_cb (NMUdevManager *udev_mgr,
 			device = nm_device_infiniband_new (sysfs_path, iface, driver);
 		else if (is_bond (ifindex))
 			device = nm_device_bond_new (sysfs_path, iface);
-		else if (is_bridge (ifindex))
-			device = nm_device_bridge_new (sysfs_path, iface);
-		else if (is_vlan (ifindex)) {
+		else if (is_bridge (ifindex)) {
+
+			/* FIXME: always create device when we handle bridges non-destructively */
+			if (bridge_created_by_nm (self, iface))
+				device = nm_device_bridge_new (sysfs_path, iface);
+			else
+				nm_log_info (LOGD_BRIDGE, "(%s): ignoring bridge not created by NetworkManager", iface);
+		} else if (is_vlan (ifindex)) {
 			int parent_ifindex = -1;
 			NMDevice *parent;
 
@@ -2215,23 +2319,32 @@ udev_device_removed_cb (NMUdevManager *manager,
 	NMManagerPrivate *priv = NM_MANAGER_GET_PRIVATE (self);
 	NMDevice *device;
 	guint32 ifindex;
-	const char *iface = g_udev_device_get_name (udev_device);
-
-	/* Ignore PPP interfaces as they are the IP interface of a device,
-	 * but they come and go when the device gets activated or deactivated.
-	 * We don't want their transient nature to affect their master device.
-	 */
-	if (strncmp (iface, "ppp", 3) == 0)
-		return;
 
 	ifindex = g_udev_device_get_property_as_int (udev_device, "IFINDEX");
 	device = find_device_by_ifindex (self, ifindex);
 	if (!device) {
-		/* On removal we won't always be able to read properties anymore, as
-		 * they may have already been removed from sysfs.  Instead, we just
-		 * have to fall back to the device's interface name.
+		GSList *iter;
+		const char *iface = g_udev_device_get_name (udev_device);
+
+		/* On removal we aren't always be able to read properties like IFINDEX
+		 * anymore, as they may have already been removed from sysfs.  So we
+		 * have to fall back on device name (eg, interface name).
+		 *
+		 * Also, some devices (namely PPPoE (pppX), ADSL (nasX, pppX), and
+		 * mobile broadband (pppX, bnepX)) create a kernel netdevice for IP
+		 * communication (called the "IP interface" in NM) as part of the
+		 * connection process and thus the IP interface lifetime does not
+		 * correspond to the NMDevice lifetime.  For these devices we must
+		 * ignore removal events for the IP interface name otherwise the
+		 * NMDevice would be removed. Hence the usage here of
+		 * nm_device_get_iface() rather than nm_device_get_ip_iface().
 		 */
-		device = find_device_by_ip_iface (self, iface);
+		for (iter = priv->devices; iter; iter = g_slist_next (iter)) {
+			if (g_strcmp0 (nm_device_get_iface (NM_DEVICE (iter->data)), iface) == 0) {
+				device = iter->data;
+				break;
+			}
+		}
 	}
 
 	if (device)
@@ -2529,6 +2642,8 @@ ensure_master_active_connection (NMManager *self,
 					                                            nm_device_get_path (master_device),
 					                                            dbus_sender,
 					                                            error);
+					if (!master_ac)
+						g_prefix_error (error, "%s", "Master device activation failed: ");
 					g_slist_free (connections);
 					return master_ac;
 				}
@@ -2569,24 +2684,30 @@ ensure_master_active_connection (NMManager *self,
 			if (master_state != NM_DEVICE_STATE_DISCONNECTED)
 				continue;
 
-			return nm_manager_activate_connection (self,
-			                                       master_connection,
-			                                       NULL,
-			                                       nm_device_get_path (candidate),
-			                                       dbus_sender,
-			                                       error);
+			master_ac = nm_manager_activate_connection (self,
+			                                            master_connection,
+			                                            NULL,
+			                                            nm_device_get_path (candidate),
+			                                            dbus_sender,
+			                                            error);
+			if (!master_ac)
+				g_prefix_error (error, "%s", "Master device activation failed: ");
+			return master_ac;
 		}
 
 		/* Device described by master_connection may be a virtual one that's
 		 * not created yet.
 		 */
 		if (!found_device && connection_needs_virtual_device (master_connection)) {
-			return nm_manager_activate_connection (self,
-			                                       master_connection,
-			                                       NULL,
-			                                       NULL,
-			                                       dbus_sender,
-			                                       error);
+			master_ac = nm_manager_activate_connection (self,
+			                                            master_connection,
+			                                            NULL,
+			                                            NULL,
+			                                            dbus_sender,
+			                                            error);
+			if (!master_ac)
+				g_prefix_error (error, "%s", "Master device activation failed: ");
+			return master_ac;
 		}
 
 		g_set_error (error,
@@ -2774,6 +2895,16 @@ nm_manager_activate_connection (NMManager *manager,
 		return NULL;
 	}
 
+	/* If this is an autoconnect request, but the device isn't allowing autoconnect
+	 * right now, we reject it.
+	 */
+	if (!dbus_sender && !nm_device_autoconnect_allowed (device)) {
+		g_set_error (error, NM_MANAGER_ERROR, NM_MANAGER_ERROR_AUTOCONNECT_NOT_ALLOWED,
+		             "%s does not allow automatic connections at this time",
+		             nm_device_get_iface (device));
+		return NULL;
+	}
+
 	/* Try to find the master connection/device if the connection has a dependency */
 	if (!find_master (manager, connection, device, &master_connection, &master_device)) {
 		g_set_error_literal (error, NM_MANAGER_ERROR, NM_MANAGER_ERROR_UNKNOWN_DEVICE,
@@ -3621,6 +3752,13 @@ nm_manager_start (NMManager *self)
 	system_unmanaged_devices_changed_cb (priv->settings, NULL, self);
 	system_hostname_changed_cb (priv->settings, NULL, self);
 
+	/* FIXME: remove when we handle bridges non-destructively */
+	/* Read a list of bridges NM managed when it last quit, and only
+	 * manage those bridges to avoid conflicts with external tools.
+	 */
+	priv->nm_bridges = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, NULL);
+	read_nm_created_bridges (self);
+
 	nm_udev_manager_query_devices (priv->udev_mgr);
 	nm_bluez_manager_query_devices (priv->bluez_mgr);
 
@@ -3637,6 +3775,10 @@ nm_manager_start (NMManager *self)
 	 * connection-added signals thus devices have to be created manually.
 	 */
 	system_create_virtual_devices (self);
+
+	/* FIXME: remove when we handle bridges non-destructively */
+	g_hash_table_unref (priv->nm_bridges);
+	priv->nm_bridges = NULL;
 }
 
 static gboolean
@@ -4016,6 +4158,12 @@ nm_manager_new (NMSettings *settings,
 	                  G_CALLBACK (bluez_manager_bdaddr_removed_cb),
 	                  singleton);
 
+	/* Force kernel WiFi rfkill state to follow NM saved wifi state in case
+	 * the BIOS doesn't save rfkill state, and to be consistent with user
+	 * changes to the WirelessEnabled property which toggles kernel rfkill.
+	 */
+	rfkill_change_wifi (priv->radio_states[RFKILL_TYPE_WLAN].desc, initial_wifi_enabled);
+
 	return singleton;
 }
 
@@ -4046,6 +4194,10 @@ dispose (GObject *object)
 
 	nm_auth_changed_func_unregister (authority_changed_cb, manager);
 
+	/* FIXME: remove when we handle bridges non-destructively */
+	write_nm_created_bridges (manager);
+
+	/* Remove all devices */
 	while (g_slist_length (priv->devices)) {
 		priv->devices = remove_one_device (manager,
 		                                   priv->devices,
diff --git a/src/nm-manager.h b/src/nm-manager.h
index 66d06783..71084038 100644
--- a/src/nm-manager.h
+++ b/src/nm-manager.h
@@ -46,6 +46,7 @@ typedef enum {
 	NM_MANAGER_ERROR_ALREADY_ENABLED_OR_DISABLED, /*< nick=AlreadyEnabledOrDisabled >*/
 	NM_MANAGER_ERROR_UNSUPPORTED_CONNECTION_TYPE, /*< nick=UnsupportedConnectionType >*/
 	NM_MANAGER_ERROR_DEPENDENCY_FAILED,           /*< nick=DependencyFailed >*/
+	NM_MANAGER_ERROR_AUTOCONNECT_NOT_ALLOWED,     /*< nick=AutoconnectNotAllowed >*/
 } NMManagerError;
 
 #define NM_MANAGER_VERSION "version"
diff --git a/src/nm-netlink-compat.c b/src/nm-netlink-compat.c
index 68ee1215..9c90eabe 100644
--- a/src/nm-netlink-compat.c
+++ b/src/nm-netlink-compat.c
@@ -18,19 +18,11 @@
  * Copyright (C) 2011 Caixa Magica Software.
  */
 
-#include <config.h>
 #include <glib.h>
-#include <unistd.h>
-#include <sys/ioctl.h>
-#include <sys/socket.h>
-#include <linux/if_vlan.h>
-#include <linux/sockios.h>
 
-#include "nm-logging.h"
 #include "nm-netlink-compat.h"
 
-#if HAVE_LIBNL != 1
-struct rtnl_nexthop *
+static struct rtnl_nexthop *
 nm_netlink_get_nh (struct rtnl_route * route)
 {
 	int hops;
@@ -91,152 +83,3 @@ rtnl_route_get_dst_len(struct rtnl_route * rtnlroute)
 	dst = rtnl_route_get_dst(rtnlroute);
 	return nl_addr_get_prefixlen(dst);
 }
-#endif
-
-#if HAVE_LIBNL == 1
-int
-nl_compat_error (int err)
-{
-	err = abs (err);
-
-	if (err == EEXIST)
-		err = NLE_EXIST;
-	else if (err == ENOENT || err == ESRCH)
-		err = NLE_OBJ_NOTFOUND;
-	else if (err == ERANGE)
-		err = NLE_RANGE;
-
-	return -err;
-}
-
-int
-rtnl_link_vlan_get_id (struct rtnl_link *l)
-{
-	int fd;
-	struct vlan_ioctl_args if_request;
-	char *if_name = NULL;
-
-	memset (&if_request, 0, sizeof (struct vlan_ioctl_args));
-
-	if ((if_name = rtnl_link_get_name (l)) == NULL)
-		return -1;
-
-	g_strlcpy (if_request.device1, if_name, sizeof (if_request.device1));
-
-	if ((fd = socket (AF_INET, SOCK_STREAM, 0)) < 0) {
-		nm_log_err (LOGD_DEVICE, "couldn't open control socket.");
-		return -1;
-	}
-
-	if_request.cmd = GET_VLAN_VID_CMD;
-	if (ioctl (fd, SIOCSIFVLAN, &if_request) < 0) {
-		nm_log_err (LOGD_DEVICE, "couldn't get vlan id for %s.", if_name);
-		goto err_out;
-	}
-
-	close(fd);
-	return if_request.u.VID;
-err_out:
-	close(fd);
-	return -1;
-}
-
-int
-rtnl_link_vlan_set_flags (struct rtnl_link *l, unsigned int flags)
-{
-	int fd;
-	struct vlan_ioctl_args if_request;
-	char *if_name = NULL;
-
-
-	if ((if_name = rtnl_link_get_name (l)) == NULL)
-		return -1;
-
-	if ((fd = socket (AF_INET, SOCK_STREAM, 0)) < 0) {
-		nm_log_err (LOGD_DEVICE, "couldn't open control socket.");
-		return -1;
-	}
-
-	memset (&if_request, 0, sizeof (struct vlan_ioctl_args));
-	g_strlcpy (if_request.device1, if_name, sizeof (if_request.device1));
-	if_request.cmd = SET_VLAN_FLAG_CMD;
-	if_request.u.flag = flags;
-
-	if (ioctl (fd, SIOCSIFVLAN, &if_request) < 0) {
-		nm_log_err (LOGD_DEVICE, "couldn't set flag in device %s.", if_name);
-		goto err_out;
-	}
-
-	close(fd);
-	return 0;
-err_out:
-	close(fd);
-	return -1;
-}
-
-int
-rtnl_link_vlan_set_ingress_map (struct rtnl_link *l, int from, uint32_t to)
-{
-	int fd;
-	struct vlan_ioctl_args if_request;
-	char *if_name = NULL;
-
-	if ((if_name = rtnl_link_get_name (l)) == NULL)
-		return -1;
-
-	if ((fd = socket (AF_INET, SOCK_STREAM, 0)) < 0) {
-		nm_log_err (LOGD_DEVICE, "couldn't open control socket.");
-		return -1;
-	}
-
-	memset (&if_request, 0, sizeof (struct vlan_ioctl_args));
-	g_strlcpy (if_request.device1, if_name, sizeof (if_request.device1));
-	if_request.cmd = SET_VLAN_INGRESS_PRIORITY_CMD;
-	if_request.u.skb_priority = from;
-	if_request.vlan_qos = to;
-
-	if (ioctl (fd, SIOCSIFVLAN, &if_request) < 0) {
-		nm_log_err (LOGD_DEVICE, "couldn't set ingress map on device %s.", if_name);
-		goto err_out;
-	}
-
-	close(fd);
-	return 0;
-err_out:
-	close(fd);
-	return -1;
-}
-
-int
-rtnl_link_vlan_set_egress_map (struct rtnl_link *l, int from, uint32_t to)
-{
-	int fd;
-	struct vlan_ioctl_args if_request;
-	char *if_name = NULL;
-
-	if ((if_name = rtnl_link_get_name (l)) == NULL)
-		return -1;
-
-	if ((fd = socket (AF_INET, SOCK_STREAM, 0)) < 0) {
-		nm_log_err (LOGD_DEVICE, "couldn't open control socket.");
-		return -1;
-	}
-
-	memset (&if_request, 0, sizeof (struct vlan_ioctl_args));
-	g_strlcpy (if_request.device1, if_name, sizeof (if_request.device1));
-	if_request.cmd = SET_VLAN_EGRESS_PRIORITY_CMD;
-	if_request.u.skb_priority = from;
-	if_request.vlan_qos = to;
-
-	if (ioctl (fd, SIOCSIFVLAN, &if_request) < 0) {
-		nm_log_err (LOGD_DEVICE, "couldn't set egress map on device %s.", if_name);
-		goto err_out;
-	}
-
-	close(fd);
-	return 0;
-err_out:
-	close(fd);
-	return -1;
-}
-#endif
diff --git a/src/nm-netlink-compat.h b/src/nm-netlink-compat.h
index 80df0967..a844e9f2 100644
--- a/src/nm-netlink-compat.h
+++ b/src/nm-netlink-compat.h
@@ -22,260 +22,13 @@
 #ifndef NM_NETLINK_COMPAT_H
 #define NM_NETLINK_COMPAT_H
 
-#include <errno.h>
-
-#include <netlink/netlink.h>
-#include <netlink/route/rtnl.h>
-#include <netlink/route/link.h>
-#include <netlink/route/route.h>
-#include <netlink/route/addr.h>
-
-
-#include <netlink/netlink.h>
-#include <netlink/cache.h>
-#include <netlink/utils.h>
-#include <netlink/data.h>
-#include <netlink/route/rtnl.h>
 #include <netlink/route/route.h>
-#include <netlink/route/link.h>
-#include <netlink/route/nexthop.h>
-
-#include <config.h>
-
-/* libnl-1 API compatibility for libnl-2/3*/
-#if HAVE_LIBNL != 1
 
-struct rtnl_nexthop * nm_netlink_get_nh(struct rtnl_route *);
+/* libnl-1 API compatibility for libnl-3 */
 int rtnl_route_get_oif(struct rtnl_route *);
 int rtnl_route_set_oif(struct rtnl_route *, int);
 int rtnl_route_set_gateway(struct rtnl_route *, struct nl_addr *);
 int rtnl_route_get_dst_len(struct rtnl_route *);
 struct nl_addr * rtnl_route_get_gateway(struct rtnl_route *);
-#endif
-
-/* libnl-2 API compatibility for libnl-3 */
-#if HAVE_LIBNL == 3
-static inline int
-__rtnl_link_alloc_cache (struct nl_sock *h, struct nl_cache **cache)
-{
-       return rtnl_link_alloc_cache (h, AF_UNSPEC, cache);
-}
-#define rtnl_link_alloc_cache __rtnl_link_alloc_cache
-#endif
-
-
-/* libnl-2.0 compat functions */
-#if HAVE_LIBNL == 2
-
-/* functions with similar prototypes */
-#define nlmsg_datalen nlmsg_len
-#endif
-
-
-/* libnl-1.0 compat functions */
-#if HAVE_LIBNL == 1
-
-#define nl_sock nl_handle
-
-/* libnl-1.0 functions with similar prototypes */
-#define nl_socket_alloc nl_handle_alloc
-#define nl_socket_alloc_cb nl_handle_alloc_cb
-#define nl_socket_free nl_handle_destroy
-#define nl_socket_set_passcred nl_set_passcred
-#define nl_socket_disable_seq_check nl_disable_sequence_check
-#define rtnl_route_set_priority rtnl_route_set_prio
-#define nlmsg_datalen nlmsg_len
-
-/* auxiliary functions */
-int nl_compat_error (int);
-
-/* libnl-1.0 functions with modified prototypes in libnl-2/3*/
-static inline const char * 
-__nl_geterror (int err)
-{
-        /* err is set, can be parsed */
-        return nl_geterror ();
-}
-#define nl_geterror __nl_geterror
-
-static inline int
-__rtnl_addr_alloc_cache (struct nl_sock *h, struct nl_cache **cache)
-{
-	g_return_val_if_fail (cache != NULL, -EINVAL);
-
-	*cache = rtnl_addr_alloc_cache (h);
-	return *cache ? 0 : -ENOMEM;
-}
-#define rtnl_addr_alloc_cache __rtnl_addr_alloc_cache
-
-static inline int
-__rtnl_route_alloc_cache (struct nl_sock *h, int family, int flags, struct nl_cache **cache)
-{
-	g_return_val_if_fail (cache != NULL, -EINVAL);
-
-	*cache = rtnl_route_alloc_cache (h);
-	return *cache ? 0 : -ENOMEM;
-}
-#define rtnl_route_alloc_cache __rtnl_route_alloc_cache
-
-static inline int
-__rtnl_link_alloc_cache (struct nl_sock *h, struct nl_cache **cache)
-{
-	g_return_val_if_fail (cache != NULL, -EINVAL);
-
-	*cache = rtnl_link_alloc_cache (h);
-	return *cache ? 0 : -ENOMEM;
-}
-#define rtnl_link_alloc_cache __rtnl_link_alloc_cache
-
-static inline int
-__rtnl_route_get_metric (struct rtnl_route *route, int metric, unsigned int *value)
-{
-	g_return_val_if_fail (value != NULL, -EINVAL);
-
-	*value = rtnl_route_get_metric (route, metric);
-	return 0;
-}
-#define rtnl_route_get_metric __rtnl_route_get_metric
-
-static inline int
-__rtnl_addr_add (struct nl_sock *h, struct rtnl_addr *addr, int flags)
-{
-	return nl_compat_error (rtnl_addr_add (h, addr, flags));
-}
-#define rtnl_addr_add __rtnl_addr_add
-
-static inline int
-__rtnl_route_add (struct nl_sock *sk, struct rtnl_route *route, int flags)
-{
-	return nl_compat_error (rtnl_route_add (sk, route, flags));
-}
-#define rtnl_route_add __rtnl_route_add
-
-static inline int
-rtnl_route_delete (struct nl_sock *h, struct rtnl_route *route, int flags)
-{
-	return nl_compat_error (rtnl_route_del (h, route, flags));
-}
-#define rtnl_route_del rtnl_route_delete
-
-static inline int
-__rtnl_link_change (struct nl_sock *h, struct rtnl_link *old, struct rtnl_link *tmpl, int flags)
-{
-	return nl_compat_error (rtnl_link_change (h, old, tmpl,flags));
-}
-#define rtnl_link_change __rtnl_link_change
-
-static inline int
-__nl_cache_include (struct nl_cache *cache, struct nl_object *obj, change_func_t cb, void *data)
-{
-	return nl_cache_include (cache, obj, cb);
-}
-#define nl_cache_include __nl_cache_include
-
-#define NLE_SUCCESS             0
-#define NLE_FAILURE             1
-#define NLE_INTR                2
-#define NLE_BAD_SOCK            3
-#define NLE_AGAIN               4
-#define NLE_NOMEM               5
-#define NLE_EXIST               6
-#define NLE_INVAL               7
-#define NLE_RANGE               8
-#define NLE_MSGSIZE             9
-#define NLE_OPNOTSUPP           10
-#define NLE_AF_NOSUPPORT        11
-#define NLE_OBJ_NOTFOUND        12
-#define NLE_NOATTR              13
-#define NLE_MISSING_ATTR        14
-#define NLE_AF_MISMATCH         15
-#define NLE_SEQ_MISMATCH        16
-#define NLE_MSG_OVERFLOW        17
-#define NLE_MSG_TRUNC           18
-#define NLE_NOADDR              19
-#define NLE_SRCRT_NOSUPPORT     20
-#define NLE_MSG_TOOSHORT        21
-#define NLE_MSGTYPE_NOSUPPORT   22
-#define NLE_OBJ_MISMATCH        23
-#define NLE_NOCACHE             24
-#define NLE_BUSY                25
-#define NLE_PROTO_MISMATCH      26
-#define NLE_NOACCESS            27
-#define NLE_PERM                28
-#define NLE_PKTLOC_FILE         29
-
-#endif
-
-/* Stuff that only libnl3 has */
-#if HAVE_LIBNL == 1 || HAVE_LIBNL == 2
-
-static inline int
-rtnl_link_bond_add (struct nl_sock *h, const char *name, void *data)
-{
-	/* Bonding only in libnl3 */
-	return -NLE_OPNOTSUPP;
-}
-
-static inline int
-rtnl_link_get_kernel (struct nl_sock *h, int f, const char *name, struct rtnl_link **out_link)
-{
-	/* Bonding only in libnl3 */
-	return -NLE_OPNOTSUPP;
-}
-
-static inline char *
-rtnl_link_get_type (struct rtnl_link *rtnl_link)
-{
-	/* Bonding only in libnl3 */
-	return NULL;
-}
-
-static inline int
-rtnl_link_bond_enslave_ifindex (struct nl_sock *h, int master_ifidx, int slave_ifidx)
-{
-	/* Bonding only in libnl3 */
-	return -NLE_OPNOTSUPP;
-}
-
-static inline int
-rtnl_link_bond_release_ifindex (struct nl_sock *h, int slave_ifidx)
-{
-	/* Bonding only in libnl3 */
-	return -NLE_OPNOTSUPP;
-}
-
-static inline int
-rtnl_link_vlan_set_id (struct rtnl_link *l, int id)
-{
-	/* VLAN only in libnl3 */
-	return -NLE_OPNOTSUPP;
-}
-
-int rtnl_link_vlan_get_id (struct rtnl_link *l);
-int rtnl_link_vlan_set_flags (struct rtnl_link *l, unsigned int flags);
-int rtnl_link_vlan_set_ingress_map (struct rtnl_link *l, int from, uint32_t to);
-int rtnl_link_vlan_set_egress_map (struct rtnl_link *l, int from, uint32_t to);
-
-static inline int
-rtnl_link_set_type (struct rtnl_link *l, const char *type)
-{
-	/* Operation only in libnl3 */
-	return -NLE_OPNOTSUPP;
-}
-
-static inline int
-rtnl_link_add (struct nl_sock *sk, struct rtnl_link *l, int flags)
-{
-	/* Operation only in libnl3 */
-	return -NLE_OPNOTSUPP;
-}
-
-static inline int
-rtnl_link_delete(struct nl_sock *sk, const struct rtnl_link *l)
-{
-	/* Operation only in libnl3 */
-	return -NLE_OPNOTSUPP;
-}
-#endif
 
 #endif /* NM_NETLINK_COMPAT_H */
diff --git a/src/nm-netlink-monitor.c b/src/nm-netlink-monitor.c
index 29a21e3c..111dffaa 100644
--- a/src/nm-netlink-monitor.c
+++ b/src/nm-netlink-monitor.c
@@ -38,7 +38,11 @@
 #include <linux/if.h>
 #include <linux/unistd.h>
 #include <unistd.h>
+#include <netlink/version.h>
+#if LIBNL_VER_NUM == LIBNL_VER (3, 2) && LIBNL_VER_MIC < 20
 #include <netlink/object-api.h>
+#endif
+#include <netlink/object.h>
 #include <netlink/route/addr.h>
 #include <netlink/route/rtnl.h>
 
@@ -408,7 +412,7 @@ sync_connection_setup (NMNetlinkMonitor *self, GError **error)
 	nl_cache_free (addr_cache);
 #endif
 
-	err = rtnl_link_alloc_cache (priv->nlh_sync, &priv->link_cache);
+	err = rtnl_link_alloc_cache (priv->nlh_sync, AF_UNSPEC, &priv->link_cache);
 	if (err < 0) {
 		g_set_error (error, NM_NETLINK_MONITOR_ERROR,
 		             NM_NETLINK_MONITOR_ERROR_NETLINK_ALLOC_LINK_CACHE,
@@ -592,6 +596,24 @@ nm_netlink_monitor_request_ip6_info (NMNetlinkMonitor *self, GError **error)
 	return TRUE;
 }
 
+gboolean
+nm_netlink_monitor_request_bridge_info (NMNetlinkMonitor *self, GError **error)
+{
+	NMNetlinkMonitorPrivate *priv;
+
+	g_return_val_if_fail (self != NULL, FALSE);
+	g_return_val_if_fail (NM_IS_NETLINK_MONITOR (self), FALSE);
+
+	priv = NM_NETLINK_MONITOR_GET_PRIVATE (self);
+
+	/* FIXME: nl_rtgen_request() gets the return value screwed up with
+	 * libnl-1.1; revisit this and return a proper error when we port to
+	 * a later libnl.
+	 */
+	nl_rtgen_request (priv->nlh_event, RTM_GETLINK, AF_BRIDGE, NLM_F_DUMP);
+
+	return TRUE;
+}
 
 static gboolean
 deferred_emit_carrier_state (gpointer user_data)
diff --git a/src/nm-netlink-monitor.h b/src/nm-netlink-monitor.h
index 4e0787bd..b9468fdc 100644
--- a/src/nm-netlink-monitor.h
+++ b/src/nm-netlink-monitor.h
@@ -23,7 +23,6 @@
 #ifndef NM_NETLINK_MONITOR_H
 #define NM_NETLINK_MONITOR_H
 
-#include <glib.h>
 #include <glib-object.h>
 #include <netlink/netlink.h>
 #include <netlink/route/link.h>
@@ -82,6 +81,9 @@ void              nm_netlink_monitor_unsubscribe      (NMNetlinkMonitor *monitor
 gboolean          nm_netlink_monitor_request_ip6_info (NMNetlinkMonitor *monitor,
                                                        GError **error);
 
+gboolean          nm_netlink_monitor_request_bridge_info (NMNetlinkMonitor *monitor,
+                                                          GError **error);
+
 void              nm_netlink_monitor_request_status   (NMNetlinkMonitor *monitor);
 
 gboolean          nm_netlink_monitor_get_flags_sync   (NMNetlinkMonitor *monitor,
diff --git a/src/nm-netlink-utils.c b/src/nm-netlink-utils.c
index be8c17ed..100b4670 100644
--- a/src/nm-netlink-utils.c
+++ b/src/nm-netlink-utils.c
@@ -25,12 +25,8 @@
 
 #include <arpa/inet.h>
 #include <netinet/in.h>
-#include <netlink/netlink.h>
-#include <netlink/addr.h>
 #include <netlink/route/addr.h>
 
-#include <errno.h>
-
 typedef struct {
 	int ifindex;
 	int family;
diff --git a/src/nm-netlink-utils.h b/src/nm-netlink-utils.h
index 697faaf0..1f7c6796 100644
--- a/src/nm-netlink-utils.h
+++ b/src/nm-netlink-utils.h
@@ -21,10 +21,7 @@
 #ifndef NM_NETLINK_UTILS_H
 #define NM_NETLINK_UTILS_H
 
-#include <glib.h>
-#include <netlink/route/rtnl.h>
 #include <netlink/route/route.h>
-#include <netinet/in.h>
 
 gboolean nm_netlink_find_address (int ifindex,
                                   int family,
diff --git a/src/nm-policy.c b/src/nm-policy.c
index 420a9411..752cf44e 100644
--- a/src/nm-policy.c
+++ b/src/nm-policy.c
@@ -1396,7 +1396,7 @@ device_ip4_config_changed (NMDevice *device,
 
 	/* Old configs get removed immediately */
 	if (old_config)
-		nm_dns_manager_remove_ip4_config (dns_mgr, ip_iface, old_config);
+		nm_dns_manager_remove_ip4_config (dns_mgr, old_config);
 
 	/* Ignore IP config changes while the device is activating, because we'll
 	 * catch all the changes when the device moves to ACTIVATED state.
@@ -1433,7 +1433,7 @@ device_ip6_config_changed (NMDevice *device,
 
 	/* Old configs get removed immediately */
 	if (old_config)
-		nm_dns_manager_remove_ip6_config (dns_mgr, ip_iface, old_config);
+		nm_dns_manager_remove_ip6_config (dns_mgr, old_config);
 
 	/* Ignore IP config changes while the device is activating, because we'll
 	 * catch all the changes when the device moves to ACTIVATED state.
@@ -1608,7 +1608,7 @@ vpn_connection_deactivated (NMPolicy *policy, NMVPNConnection *vpn)
 	ip4_config = nm_vpn_connection_get_ip4_config (vpn);
 	if (ip4_config) {
 		/* Remove the VPN connection's IP4 config from DNS */
-		nm_dns_manager_remove_ip4_config (mgr, ip_iface, ip4_config);
+		nm_dns_manager_remove_ip4_config (mgr, ip4_config);
 
 		/* Re-apply routes and addresses of the VPN connection's parent interface,
 		 * which the VPN might have overridden.
@@ -1629,7 +1629,7 @@ vpn_connection_deactivated (NMPolicy *policy, NMVPNConnection *vpn)
 	ip6_config = nm_vpn_connection_get_ip6_config (vpn);
 	if (ip6_config) {
 		/* Remove the VPN connection's IP6 config from DNS */
-		nm_dns_manager_remove_ip6_config (mgr, ip_iface, ip6_config);
+		nm_dns_manager_remove_ip6_config (mgr, ip6_config);
 
 		/* Re-apply routes and addresses of the VPN connection's parent interface,
 		 * which the VPN might have overridden.
diff --git a/src/nm-system.c b/src/nm-system.c
index 5d1a4895..031daf8a 100644
--- a/src/nm-system.c
+++ b/src/nm-system.c
@@ -60,11 +60,8 @@
 #include <netlink/netlink.h>
 #include <netlink/utils.h>
 #include <netlink/route/link.h>
-
-#if HAVE_LIBNL == 3
 #include <netlink/route/link/bonding.h>
 #include <netlink/route/link/vlan.h>
-#endif
 
 #if !HAVE_VLAN_FLAG_LOOSE_BINDING
 /* Older kernels don't have this flag */
@@ -1689,9 +1686,29 @@ nm_system_bond_enslave (gint master_ifindex,
 	g_assert (!nm_system_iface_is_up (slave_ifindex));
 
 	if (nm_system_iface_get_flags (slave_ifindex) & IFF_SLAVE) {
-		nm_log_err (LOGD_DEVICE, "(%s): %s is already a slave",
-		            master_iface, slave_iface);
-		return FALSE;
+		struct rtnl_link *link;
+		int existing_master = -1;
+
+		/* Get the ifindex of the existing master device */
+		link = nm_netlink_index_to_rtnl_link (slave_ifindex);
+		g_warn_if_fail (link != NULL);
+		if (link) {
+			existing_master = rtnl_link_get_master (link);
+			rtnl_link_put (link);
+		}
+
+		if (existing_master > 0) {
+			/* Fail if the device is already a slave of a different master */
+			if (existing_master != master_ifindex) {
+				nm_log_err (LOGD_DEVICE, "(%s): already a slave of a different master",
+							slave_iface);
+				return FALSE;
+			}
+
+			nm_log_dbg (LOGD_DEVICE, "(%s): %s is already enslaved",
+			            master_iface, slave_iface);
+			return TRUE;
+		}
 	}
 
 	err = rtnl_link_bond_enslave_ifindex (sock, master_ifindex, slave_ifindex);
@@ -1783,7 +1800,7 @@ nm_system_bond_release (gint master_ifindex,
 }
 
 /**
- * nm_system_get_iface_type_compat:
+ * nm_system_compat_get_iface_type:
  * @ifindex: interface index
  * @name: name of interface
  *
@@ -1796,10 +1813,11 @@ static int
 nm_system_compat_get_iface_type (int ifindex, const char *name)
 {
 	int res = NM_IFACE_TYPE_UNSPEC;
-	char *ifname = NULL;
+	char *ifname = NULL, *path = NULL;
 	struct vlan_ioctl_args ifv;
 	struct ifreq ifr;
 	struct ifbond ifb;
+	struct stat st;
 	int fd;
 
 	g_return_val_if_fail (ifindex > 0 || name, NM_IFACE_TYPE_UNSPEC);
@@ -1833,7 +1851,15 @@ nm_system_compat_get_iface_type (int ifindex, const char *name)
 		goto out;
 	}
 
+	/* and bridge */
+	path = g_strdup_printf ("/sys/class/net/%s/bridge", ifname ? ifname : name);
+	if ((stat (path, &st) == 0) && S_ISDIR (st.st_mode)) {
+		res = NM_IFACE_TYPE_BRIDGE;
+		goto out;
+	}
+
 out:
+	g_free (path);
 	close (fd);
 	g_free (ifname);
 	return res;
@@ -1918,7 +1944,7 @@ nm_system_get_iface_vlan_info (int ifindex,
 	if (!nlh)
 		return FALSE;
 
-	ret = rtnl_link_alloc_cache (nlh, &cache);
+	ret = rtnl_link_alloc_cache (nlh, AF_UNSPEC, &cache);
 	g_return_val_if_fail (ret == 0, FALSE);
 	g_return_val_if_fail (cache != NULL, FALSE);
 
@@ -2295,7 +2321,7 @@ nm_system_del_vlan_iface (const char *iface)
 	nlh = nm_netlink_get_default_handle ();
 	g_return_val_if_fail (nlh != NULL, FALSE);
 
-	ret = rtnl_link_alloc_cache (nlh, &cache);
+	ret = rtnl_link_alloc_cache (nlh, AF_UNSPEC, &cache);
 	g_return_val_if_fail (ret == 0, FALSE);
 	g_return_val_if_fail (cache != NULL, FALSE);
 
@@ -2337,14 +2363,16 @@ _bridge_create_compat (const char *iface)
 /**
  * nm_system_create_bridge:
  * @iface: Name bridging device to create
+ * @out_exists: on return, %TRUE if the bridge already exists
  *
  * Creates a new bridging device in the kernel. If a bridging device with
- * the specified name already exists, it is being reused.
+ * the specified name already exists, it is reused and no error is returned,
+ * but @out_exists is set to %TRUE.
  *
  * Returns: %TRUE on success, %FALSE on error.
  */
 gboolean
-nm_system_create_bridge (const char *iface)
+nm_system_create_bridge (const char *iface, gboolean *out_exists)
 {
 	int err;
 
@@ -2355,6 +2383,8 @@ nm_system_create_bridge (const char *iface)
 		            iface, strerror (-err));
 		return FALSE;
 	}
+	if (out_exists && err == -EEXIST)
+		*out_exists = TRUE;
 	return TRUE;
 }
 
@@ -2490,9 +2520,14 @@ nm_system_bridge_attach (int master_ifindex,
 	                             mif ? mif : master_iface,
 	                             slave_ifindex,
 	                             sif ? sif : slave_iface);
-	if (err < 0 && err != -EBUSY) {
-		nm_log_err (LOGD_DEVICE, "(%s): failed to attach slave %s: %s",
-		            master_iface, slave_iface, strerror (-err));
+	if (err < 0) {
+		if (err == -EBUSY) {
+			/* Interface already attached to the given bridge */
+			err = 0;
+		} else {
+			nm_log_err (LOGD_DEVICE, "(%s): failed to attach slave %s: %s",
+			            master_iface, slave_iface, strerror (-err));
+		}
 	}
 
 out:
diff --git a/src/nm-system.h b/src/nm-system.h
index ca07d0f2..632786d3 100644
--- a/src/nm-system.h
+++ b/src/nm-system.h
@@ -128,7 +128,7 @@ gboolean        nm_system_add_vlan_iface (NMConnection *connection,
                                           int parent_ifindex);
 gboolean        nm_system_del_vlan_iface (const char *iface);
 
-gboolean        nm_system_create_bridge (const char *iface);
+gboolean        nm_system_create_bridge (const char *iface, gboolean *out_exists);
 gboolean        nm_system_del_bridge (const char *iface);
 
 gboolean        nm_system_bridge_attach (int master_ifindex,
diff --git a/src/posix-signals/Makefile.in b/src/posix-signals/Makefile.in
index db24efa6..14aeba6c 100644
--- a/src/posix-signals/Makefile.in
+++ b/src/posix-signals/Makefile.in
@@ -61,12 +61,11 @@ am__aclocal_m4_deps = $(top_srcdir)/m4/compiler_warnings.m4 \
 	$(top_srcdir)/m4/intlmacosx.m4 $(top_srcdir)/m4/intltool.m4 \
 	$(top_srcdir)/m4/introspection.m4 $(top_srcdir)/m4/lib-ld.m4 \
 	$(top_srcdir)/m4/lib-link.m4 $(top_srcdir)/m4/lib-prefix.m4 \
-	$(top_srcdir)/m4/libnl-check.m4 $(top_srcdir)/m4/libtool.m4 \
-	$(top_srcdir)/m4/ltoptions.m4 $(top_srcdir)/m4/ltsugar.m4 \
-	$(top_srcdir)/m4/ltversion.m4 $(top_srcdir)/m4/lt~obsolete.m4 \
-	$(top_srcdir)/m4/nls.m4 $(top_srcdir)/m4/po.m4 \
-	$(top_srcdir)/m4/progtest.m4 $(top_srcdir)/m4/vapigen.m4 \
-	$(top_srcdir)/configure.ac
+	$(top_srcdir)/m4/libtool.m4 $(top_srcdir)/m4/ltoptions.m4 \
+	$(top_srcdir)/m4/ltsugar.m4 $(top_srcdir)/m4/ltversion.m4 \
+	$(top_srcdir)/m4/lt~obsolete.m4 $(top_srcdir)/m4/nls.m4 \
+	$(top_srcdir)/m4/po.m4 $(top_srcdir)/m4/progtest.m4 \
+	$(top_srcdir)/m4/vapigen.m4 $(top_srcdir)/configure.ac
 am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \
 	$(ACLOCAL_M4)
 mkinstalldirs = $(install_sh) -d
@@ -216,12 +215,6 @@ LIBGCRYPT_LIBS = @LIBGCRYPT_LIBS@
 LIBICONV = @LIBICONV@
 LIBINTL = @LIBINTL@
 LIBM = @LIBM@
-LIBNL1_CFLAGS = @LIBNL1_CFLAGS@
-LIBNL1_LIBS = @LIBNL1_LIBS@
-LIBNL2_CFLAGS = @LIBNL2_CFLAGS@
-LIBNL2_LIBS = @LIBNL2_LIBS@
-LIBNL3_CFLAGS = @LIBNL3_CFLAGS@
-LIBNL3_LIBS = @LIBNL3_LIBS@
 LIBNL_CFLAGS = @LIBNL_CFLAGS@
 LIBNL_LIBS = @LIBNL_LIBS@
 LIBOBJS = @LIBOBJS@
diff --git a/src/ppp-manager/Makefile.in b/src/ppp-manager/Makefile.in
index f53e808b..026ce4b8 100644
--- a/src/ppp-manager/Makefile.in
+++ b/src/ppp-manager/Makefile.in
@@ -61,12 +61,11 @@ am__aclocal_m4_deps = $(top_srcdir)/m4/compiler_warnings.m4 \
 	$(top_srcdir)/m4/intlmacosx.m4 $(top_srcdir)/m4/intltool.m4 \
 	$(top_srcdir)/m4/introspection.m4 $(top_srcdir)/m4/lib-ld.m4 \
 	$(top_srcdir)/m4/lib-link.m4 $(top_srcdir)/m4/lib-prefix.m4 \
-	$(top_srcdir)/m4/libnl-check.m4 $(top_srcdir)/m4/libtool.m4 \
-	$(top_srcdir)/m4/ltoptions.m4 $(top_srcdir)/m4/ltsugar.m4 \
-	$(top_srcdir)/m4/ltversion.m4 $(top_srcdir)/m4/lt~obsolete.m4 \
-	$(top_srcdir)/m4/nls.m4 $(top_srcdir)/m4/po.m4 \
-	$(top_srcdir)/m4/progtest.m4 $(top_srcdir)/m4/vapigen.m4 \
-	$(top_srcdir)/configure.ac
+	$(top_srcdir)/m4/libtool.m4 $(top_srcdir)/m4/ltoptions.m4 \
+	$(top_srcdir)/m4/ltsugar.m4 $(top_srcdir)/m4/ltversion.m4 \
+	$(top_srcdir)/m4/lt~obsolete.m4 $(top_srcdir)/m4/nls.m4 \
+	$(top_srcdir)/m4/po.m4 $(top_srcdir)/m4/progtest.m4 \
+	$(top_srcdir)/m4/vapigen.m4 $(top_srcdir)/configure.ac
 am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \
 	$(ACLOCAL_M4)
 mkinstalldirs = $(install_sh) -d
@@ -261,12 +260,6 @@ LIBGCRYPT_LIBS = @LIBGCRYPT_LIBS@
 LIBICONV = @LIBICONV@
 LIBINTL = @LIBINTL@
 LIBM = @LIBM@
-LIBNL1_CFLAGS = @LIBNL1_CFLAGS@
-LIBNL1_LIBS = @LIBNL1_LIBS@
-LIBNL2_CFLAGS = @LIBNL2_CFLAGS@
-LIBNL2_LIBS = @LIBNL2_LIBS@
-LIBNL3_CFLAGS = @LIBNL3_CFLAGS@
-LIBNL3_LIBS = @LIBNL3_LIBS@
 LIBNL_CFLAGS = @LIBNL_CFLAGS@
 LIBNL_LIBS = @LIBNL_LIBS@
 LIBOBJS = @LIBOBJS@
diff --git a/src/settings/Makefile.in b/src/settings/Makefile.in
index 0c95d968..38fe0a5e 100644
--- a/src/settings/Makefile.in
+++ b/src/settings/Makefile.in
@@ -61,12 +61,11 @@ am__aclocal_m4_deps = $(top_srcdir)/m4/compiler_warnings.m4 \
 	$(top_srcdir)/m4/intlmacosx.m4 $(top_srcdir)/m4/intltool.m4 \
 	$(top_srcdir)/m4/introspection.m4 $(top_srcdir)/m4/lib-ld.m4 \
 	$(top_srcdir)/m4/lib-link.m4 $(top_srcdir)/m4/lib-prefix.m4 \
-	$(top_srcdir)/m4/libnl-check.m4 $(top_srcdir)/m4/libtool.m4 \
-	$(top_srcdir)/m4/ltoptions.m4 $(top_srcdir)/m4/ltsugar.m4 \
-	$(top_srcdir)/m4/ltversion.m4 $(top_srcdir)/m4/lt~obsolete.m4 \
-	$(top_srcdir)/m4/nls.m4 $(top_srcdir)/m4/po.m4 \
-	$(top_srcdir)/m4/progtest.m4 $(top_srcdir)/m4/vapigen.m4 \
-	$(top_srcdir)/configure.ac
+	$(top_srcdir)/m4/libtool.m4 $(top_srcdir)/m4/ltoptions.m4 \
+	$(top_srcdir)/m4/ltsugar.m4 $(top_srcdir)/m4/ltversion.m4 \
+	$(top_srcdir)/m4/lt~obsolete.m4 $(top_srcdir)/m4/nls.m4 \
+	$(top_srcdir)/m4/po.m4 $(top_srcdir)/m4/progtest.m4 \
+	$(top_srcdir)/m4/vapigen.m4 $(top_srcdir)/configure.ac
 am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \
 	$(ACLOCAL_M4)
 mkinstalldirs = $(install_sh) -d
@@ -280,12 +279,6 @@ LIBGCRYPT_LIBS = @LIBGCRYPT_LIBS@
 LIBICONV = @LIBICONV@
 LIBINTL = @LIBINTL@
 LIBM = @LIBM@
-LIBNL1_CFLAGS = @LIBNL1_CFLAGS@
-LIBNL1_LIBS = @LIBNL1_LIBS@
-LIBNL2_CFLAGS = @LIBNL2_CFLAGS@
-LIBNL2_LIBS = @LIBNL2_LIBS@
-LIBNL3_CFLAGS = @LIBNL3_CFLAGS@
-LIBNL3_LIBS = @LIBNL3_LIBS@
 LIBNL_CFLAGS = @LIBNL_CFLAGS@
 LIBNL_LIBS = @LIBNL_LIBS@
 LIBOBJS = @LIBOBJS@
diff --git a/src/settings/nm-settings.c b/src/settings/nm-settings.c
index 0c139174..fa474e09 100644
--- a/src/settings/nm-settings.c
+++ b/src/settings/nm-settings.c
@@ -1379,12 +1379,13 @@ have_connection_for_device (NMSettings *self, GByteArray *mac, NMDevice *device)
 
 /* Search through the list of blacklisted MAC addresses in the config file. */
 static gboolean
-is_mac_auto_wired_blacklisted (NMSettings *self, const GByteArray *mac, int hwaddr_type)
+is_mac_auto_wired_blacklisted (NMSettings *self, const GByteArray *mac)
 {
 	NMSettingsPrivate *priv = NM_SETTINGS_GET_PRIVATE (self);
 	GKeyFile *config;
 	char **list, **iter;
 	gboolean found = FALSE;
+	int hwaddr_type;
 
 	g_return_val_if_fail (mac != NULL, FALSE);
 
@@ -1401,6 +1402,8 @@ is_mac_auto_wired_blacklisted (NMSettings *self, const GByteArray *mac, int hwad
 	if (!g_key_file_load_from_file (config, priv->config_file, G_KEY_FILE_NONE, NULL))
 		goto out;
 
+	hwaddr_type = nm_utils_hwaddr_type (mac->len);
+
 	list = g_key_file_get_string_list (config, "main", CONFIG_KEY_NO_AUTO_DEFAULT, NULL, NULL);
 	for (iter = list; iter && *iter; iter++) {
 		guint8 *candidate, buffer[NM_UTILS_HWADDR_LEN_MAX];
@@ -1584,7 +1587,7 @@ nm_settings_device_added (NMSettings *self, NMDevice *device)
 	NMSettingsPrivate *priv = NM_SETTINGS_GET_PRIVATE (self);
 	GByteArray *mac = NULL;
 	const guint8 *hwaddr;
-	int hwaddr_type;
+	guint hwaddr_len = 0;
 	NMDefaultWiredConnection *wired;
 	gboolean read_only = TRUE;
 	const char *id;
@@ -1600,14 +1603,13 @@ nm_settings_device_added (NMSettings *self, NMDevice *device)
 	    || g_object_get_data (G_OBJECT (device), DEFAULT_WIRED_TAG))
 		return;
 
-	hwaddr = nm_device_wired_get_hwaddr (NM_DEVICE_WIRED (device));
-	hwaddr_type = nm_device_wired_get_hwaddr_type (NM_DEVICE_WIRED (device));
+	hwaddr = nm_device_get_hw_address (device, &hwaddr_len);
 
-	mac = g_byte_array_new ();
-	g_byte_array_append (mac, hwaddr, nm_utils_hwaddr_len (hwaddr_type));
+	mac = g_byte_array_sized_new (hwaddr_len);
+	g_byte_array_append (mac, hwaddr, hwaddr_len);
 
 	if (   have_connection_for_device (self, mac, device)
-		|| is_mac_auto_wired_blacklisted (self, mac, hwaddr_type))
+		|| is_mac_auto_wired_blacklisted (self, mac))
 		goto ignore;
 
 	if (get_plugin (self, NM_SYSTEM_CONFIG_INTERFACE_CAP_MODIFY_CONNECTIONS))
diff --git a/src/settings/plugins/Makefile.in b/src/settings/plugins/Makefile.in
index 5642eda7..a6d283f9 100644
--- a/src/settings/plugins/Makefile.in
+++ b/src/settings/plugins/Makefile.in
@@ -64,12 +64,11 @@ am__aclocal_m4_deps = $(top_srcdir)/m4/compiler_warnings.m4 \
 	$(top_srcdir)/m4/intlmacosx.m4 $(top_srcdir)/m4/intltool.m4 \
 	$(top_srcdir)/m4/introspection.m4 $(top_srcdir)/m4/lib-ld.m4 \
 	$(top_srcdir)/m4/lib-link.m4 $(top_srcdir)/m4/lib-prefix.m4 \
-	$(top_srcdir)/m4/libnl-check.m4 $(top_srcdir)/m4/libtool.m4 \
-	$(top_srcdir)/m4/ltoptions.m4 $(top_srcdir)/m4/ltsugar.m4 \
-	$(top_srcdir)/m4/ltversion.m4 $(top_srcdir)/m4/lt~obsolete.m4 \
-	$(top_srcdir)/m4/nls.m4 $(top_srcdir)/m4/po.m4 \
-	$(top_srcdir)/m4/progtest.m4 $(top_srcdir)/m4/vapigen.m4 \
-	$(top_srcdir)/configure.ac
+	$(top_srcdir)/m4/libtool.m4 $(top_srcdir)/m4/ltoptions.m4 \
+	$(top_srcdir)/m4/ltsugar.m4 $(top_srcdir)/m4/ltversion.m4 \
+	$(top_srcdir)/m4/lt~obsolete.m4 $(top_srcdir)/m4/nls.m4 \
+	$(top_srcdir)/m4/po.m4 $(top_srcdir)/m4/progtest.m4 \
+	$(top_srcdir)/m4/vapigen.m4 $(top_srcdir)/configure.ac
 am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \
 	$(ACLOCAL_M4)
 mkinstalldirs = $(install_sh) -d
@@ -228,12 +227,6 @@ LIBGCRYPT_LIBS = @LIBGCRYPT_LIBS@
 LIBICONV = @LIBICONV@
 LIBINTL = @LIBINTL@
 LIBM = @LIBM@
-LIBNL1_CFLAGS = @LIBNL1_CFLAGS@
-LIBNL1_LIBS = @LIBNL1_LIBS@
-LIBNL2_CFLAGS = @LIBNL2_CFLAGS@
-LIBNL2_LIBS = @LIBNL2_LIBS@
-LIBNL3_CFLAGS = @LIBNL3_CFLAGS@
-LIBNL3_LIBS = @LIBNL3_LIBS@
 LIBNL_CFLAGS = @LIBNL_CFLAGS@
 LIBNL_LIBS = @LIBNL_LIBS@
 LIBOBJS = @LIBOBJS@
diff --git a/src/settings/plugins/example/Makefile.in b/src/settings/plugins/example/Makefile.in
index fcdcd7b3..491c577a 100644
--- a/src/settings/plugins/example/Makefile.in
+++ b/src/settings/plugins/example/Makefile.in
@@ -61,12 +61,11 @@ am__aclocal_m4_deps = $(top_srcdir)/m4/compiler_warnings.m4 \
 	$(top_srcdir)/m4/intlmacosx.m4 $(top_srcdir)/m4/intltool.m4 \
 	$(top_srcdir)/m4/introspection.m4 $(top_srcdir)/m4/lib-ld.m4 \
 	$(top_srcdir)/m4/lib-link.m4 $(top_srcdir)/m4/lib-prefix.m4 \
-	$(top_srcdir)/m4/libnl-check.m4 $(top_srcdir)/m4/libtool.m4 \
-	$(top_srcdir)/m4/ltoptions.m4 $(top_srcdir)/m4/ltsugar.m4 \
-	$(top_srcdir)/m4/ltversion.m4 $(top_srcdir)/m4/lt~obsolete.m4 \
-	$(top_srcdir)/m4/nls.m4 $(top_srcdir)/m4/po.m4 \
-	$(top_srcdir)/m4/progtest.m4 $(top_srcdir)/m4/vapigen.m4 \
-	$(top_srcdir)/configure.ac
+	$(top_srcdir)/m4/libtool.m4 $(top_srcdir)/m4/ltoptions.m4 \
+	$(top_srcdir)/m4/ltsugar.m4 $(top_srcdir)/m4/ltversion.m4 \
+	$(top_srcdir)/m4/lt~obsolete.m4 $(top_srcdir)/m4/nls.m4 \
+	$(top_srcdir)/m4/po.m4 $(top_srcdir)/m4/progtest.m4 \
+	$(top_srcdir)/m4/vapigen.m4 $(top_srcdir)/configure.ac
 am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \
 	$(ACLOCAL_M4)
 mkinstalldirs = $(install_sh) -d
@@ -226,12 +225,6 @@ LIBGCRYPT_LIBS = @LIBGCRYPT_LIBS@
 LIBICONV = @LIBICONV@
 LIBINTL = @LIBINTL@
 LIBM = @LIBM@
-LIBNL1_CFLAGS = @LIBNL1_CFLAGS@
-LIBNL1_LIBS = @LIBNL1_LIBS@
-LIBNL2_CFLAGS = @LIBNL2_CFLAGS@
-LIBNL2_LIBS = @LIBNL2_LIBS@
-LIBNL3_CFLAGS = @LIBNL3_CFLAGS@
-LIBNL3_LIBS = @LIBNL3_LIBS@
 LIBNL_CFLAGS = @LIBNL_CFLAGS@
 LIBNL_LIBS = @LIBNL_LIBS@
 LIBOBJS = @LIBOBJS@
diff --git a/src/settings/plugins/ifcfg-rh/Makefile.in b/src/settings/plugins/ifcfg-rh/Makefile.in
index 53492e72..bdd6f233 100644
--- a/src/settings/plugins/ifcfg-rh/Makefile.in
+++ b/src/settings/plugins/ifcfg-rh/Makefile.in
@@ -62,12 +62,11 @@ am__aclocal_m4_deps = $(top_srcdir)/m4/compiler_warnings.m4 \
 	$(top_srcdir)/m4/intlmacosx.m4 $(top_srcdir)/m4/intltool.m4 \
 	$(top_srcdir)/m4/introspection.m4 $(top_srcdir)/m4/lib-ld.m4 \
 	$(top_srcdir)/m4/lib-link.m4 $(top_srcdir)/m4/lib-prefix.m4 \
-	$(top_srcdir)/m4/libnl-check.m4 $(top_srcdir)/m4/libtool.m4 \
-	$(top_srcdir)/m4/ltoptions.m4 $(top_srcdir)/m4/ltsugar.m4 \
-	$(top_srcdir)/m4/ltversion.m4 $(top_srcdir)/m4/lt~obsolete.m4 \
-	$(top_srcdir)/m4/nls.m4 $(top_srcdir)/m4/po.m4 \
-	$(top_srcdir)/m4/progtest.m4 $(top_srcdir)/m4/vapigen.m4 \
-	$(top_srcdir)/configure.ac
+	$(top_srcdir)/m4/libtool.m4 $(top_srcdir)/m4/ltoptions.m4 \
+	$(top_srcdir)/m4/ltsugar.m4 $(top_srcdir)/m4/ltversion.m4 \
+	$(top_srcdir)/m4/lt~obsolete.m4 $(top_srcdir)/m4/nls.m4 \
+	$(top_srcdir)/m4/po.m4 $(top_srcdir)/m4/progtest.m4 \
+	$(top_srcdir)/m4/vapigen.m4 $(top_srcdir)/configure.ac
 am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \
 	$(ACLOCAL_M4)
 mkinstalldirs = $(install_sh) -d
@@ -305,12 +304,6 @@ LIBGCRYPT_LIBS = @LIBGCRYPT_LIBS@
 LIBICONV = @LIBICONV@
 LIBINTL = @LIBINTL@
 LIBM = @LIBM@
-LIBNL1_CFLAGS = @LIBNL1_CFLAGS@
-LIBNL1_LIBS = @LIBNL1_LIBS@
-LIBNL2_CFLAGS = @LIBNL2_CFLAGS@
-LIBNL2_LIBS = @LIBNL2_LIBS@
-LIBNL3_CFLAGS = @LIBNL3_CFLAGS@
-LIBNL3_LIBS = @LIBNL3_LIBS@
 LIBNL_CFLAGS = @LIBNL_CFLAGS@
 LIBNL_LIBS = @LIBNL_LIBS@
 LIBOBJS = @LIBOBJS@
diff --git a/src/settings/plugins/ifcfg-rh/tests/Makefile.in b/src/settings/plugins/ifcfg-rh/tests/Makefile.in
index 155cb672..843d2f61 100644
--- a/src/settings/plugins/ifcfg-rh/tests/Makefile.in
+++ b/src/settings/plugins/ifcfg-rh/tests/Makefile.in
@@ -63,12 +63,11 @@ am__aclocal_m4_deps = $(top_srcdir)/m4/compiler_warnings.m4 \
 	$(top_srcdir)/m4/intlmacosx.m4 $(top_srcdir)/m4/intltool.m4 \
 	$(top_srcdir)/m4/introspection.m4 $(top_srcdir)/m4/lib-ld.m4 \
 	$(top_srcdir)/m4/lib-link.m4 $(top_srcdir)/m4/lib-prefix.m4 \
-	$(top_srcdir)/m4/libnl-check.m4 $(top_srcdir)/m4/libtool.m4 \
-	$(top_srcdir)/m4/ltoptions.m4 $(top_srcdir)/m4/ltsugar.m4 \
-	$(top_srcdir)/m4/ltversion.m4 $(top_srcdir)/m4/lt~obsolete.m4 \
-	$(top_srcdir)/m4/nls.m4 $(top_srcdir)/m4/po.m4 \
-	$(top_srcdir)/m4/progtest.m4 $(top_srcdir)/m4/vapigen.m4 \
-	$(top_srcdir)/configure.ac
+	$(top_srcdir)/m4/libtool.m4 $(top_srcdir)/m4/ltoptions.m4 \
+	$(top_srcdir)/m4/ltsugar.m4 $(top_srcdir)/m4/ltversion.m4 \
+	$(top_srcdir)/m4/lt~obsolete.m4 $(top_srcdir)/m4/nls.m4 \
+	$(top_srcdir)/m4/po.m4 $(top_srcdir)/m4/progtest.m4 \
+	$(top_srcdir)/m4/vapigen.m4 $(top_srcdir)/configure.ac
 am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \
 	$(ACLOCAL_M4)
 mkinstalldirs = $(install_sh) -d
@@ -268,12 +267,6 @@ LIBGCRYPT_LIBS = @LIBGCRYPT_LIBS@
 LIBICONV = @LIBICONV@
 LIBINTL = @LIBINTL@
 LIBM = @LIBM@
-LIBNL1_CFLAGS = @LIBNL1_CFLAGS@
-LIBNL1_LIBS = @LIBNL1_LIBS@
-LIBNL2_CFLAGS = @LIBNL2_CFLAGS@
-LIBNL2_LIBS = @LIBNL2_LIBS@
-LIBNL3_CFLAGS = @LIBNL3_CFLAGS@
-LIBNL3_LIBS = @LIBNL3_LIBS@
 LIBNL_CFLAGS = @LIBNL_CFLAGS@
 LIBNL_LIBS = @LIBNL_LIBS@
 LIBOBJS = @LIBOBJS@
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 43b0aadb..b19cd1d0 100644
--- a/src/settings/plugins/ifcfg-rh/tests/network-scripts/Makefile.in
+++ b/src/settings/plugins/ifcfg-rh/tests/network-scripts/Makefile.in
@@ -60,12 +60,11 @@ am__aclocal_m4_deps = $(top_srcdir)/m4/compiler_warnings.m4 \
 	$(top_srcdir)/m4/intlmacosx.m4 $(top_srcdir)/m4/intltool.m4 \
 	$(top_srcdir)/m4/introspection.m4 $(top_srcdir)/m4/lib-ld.m4 \
 	$(top_srcdir)/m4/lib-link.m4 $(top_srcdir)/m4/lib-prefix.m4 \
-	$(top_srcdir)/m4/libnl-check.m4 $(top_srcdir)/m4/libtool.m4 \
-	$(top_srcdir)/m4/ltoptions.m4 $(top_srcdir)/m4/ltsugar.m4 \
-	$(top_srcdir)/m4/ltversion.m4 $(top_srcdir)/m4/lt~obsolete.m4 \
-	$(top_srcdir)/m4/nls.m4 $(top_srcdir)/m4/po.m4 \
-	$(top_srcdir)/m4/progtest.m4 $(top_srcdir)/m4/vapigen.m4 \
-	$(top_srcdir)/configure.ac
+	$(top_srcdir)/m4/libtool.m4 $(top_srcdir)/m4/ltoptions.m4 \
+	$(top_srcdir)/m4/ltsugar.m4 $(top_srcdir)/m4/ltversion.m4 \
+	$(top_srcdir)/m4/lt~obsolete.m4 $(top_srcdir)/m4/nls.m4 \
+	$(top_srcdir)/m4/po.m4 $(top_srcdir)/m4/progtest.m4 \
+	$(top_srcdir)/m4/vapigen.m4 $(top_srcdir)/configure.ac
 am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \
 	$(ACLOCAL_M4)
 mkinstalldirs = $(install_sh) -d
@@ -184,12 +183,6 @@ LIBGCRYPT_LIBS = @LIBGCRYPT_LIBS@
 LIBICONV = @LIBICONV@
 LIBINTL = @LIBINTL@
 LIBM = @LIBM@
-LIBNL1_CFLAGS = @LIBNL1_CFLAGS@
-LIBNL1_LIBS = @LIBNL1_LIBS@
-LIBNL2_CFLAGS = @LIBNL2_CFLAGS@
-LIBNL2_LIBS = @LIBNL2_LIBS@
-LIBNL3_CFLAGS = @LIBNL3_CFLAGS@
-LIBNL3_LIBS = @LIBNL3_LIBS@
 LIBNL_CFLAGS = @LIBNL_CFLAGS@
 LIBNL_LIBS = @LIBNL_LIBS@
 LIBOBJS = @LIBOBJS@
diff --git a/src/settings/plugins/ifcfg-suse/Makefile.in b/src/settings/plugins/ifcfg-suse/Makefile.in
index 8832e679..e15fd3e5 100644
--- a/src/settings/plugins/ifcfg-suse/Makefile.in
+++ b/src/settings/plugins/ifcfg-suse/Makefile.in
@@ -61,12 +61,11 @@ am__aclocal_m4_deps = $(top_srcdir)/m4/compiler_warnings.m4 \
 	$(top_srcdir)/m4/intlmacosx.m4 $(top_srcdir)/m4/intltool.m4 \
 	$(top_srcdir)/m4/introspection.m4 $(top_srcdir)/m4/lib-ld.m4 \
 	$(top_srcdir)/m4/lib-link.m4 $(top_srcdir)/m4/lib-prefix.m4 \
-	$(top_srcdir)/m4/libnl-check.m4 $(top_srcdir)/m4/libtool.m4 \
-	$(top_srcdir)/m4/ltoptions.m4 $(top_srcdir)/m4/ltsugar.m4 \
-	$(top_srcdir)/m4/ltversion.m4 $(top_srcdir)/m4/lt~obsolete.m4 \
-	$(top_srcdir)/m4/nls.m4 $(top_srcdir)/m4/po.m4 \
-	$(top_srcdir)/m4/progtest.m4 $(top_srcdir)/m4/vapigen.m4 \
-	$(top_srcdir)/configure.ac
+	$(top_srcdir)/m4/libtool.m4 $(top_srcdir)/m4/ltoptions.m4 \
+	$(top_srcdir)/m4/ltsugar.m4 $(top_srcdir)/m4/ltversion.m4 \
+	$(top_srcdir)/m4/lt~obsolete.m4 $(top_srcdir)/m4/nls.m4 \
+	$(top_srcdir)/m4/po.m4 $(top_srcdir)/m4/progtest.m4 \
+	$(top_srcdir)/m4/vapigen.m4 $(top_srcdir)/configure.ac
 am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \
 	$(ACLOCAL_M4)
 mkinstalldirs = $(install_sh) -d
@@ -252,12 +251,6 @@ LIBGCRYPT_LIBS = @LIBGCRYPT_LIBS@
 LIBICONV = @LIBICONV@
 LIBINTL = @LIBINTL@
 LIBM = @LIBM@
-LIBNL1_CFLAGS = @LIBNL1_CFLAGS@
-LIBNL1_LIBS = @LIBNL1_LIBS@
-LIBNL2_CFLAGS = @LIBNL2_CFLAGS@
-LIBNL2_LIBS = @LIBNL2_LIBS@
-LIBNL3_CFLAGS = @LIBNL3_CFLAGS@
-LIBNL3_LIBS = @LIBNL3_LIBS@
 LIBNL_CFLAGS = @LIBNL_CFLAGS@
 LIBNL_LIBS = @LIBNL_LIBS@
 LIBOBJS = @LIBOBJS@
diff --git a/src/settings/plugins/ifnet/Makefile.in b/src/settings/plugins/ifnet/Makefile.in
index 6cdf335d..dc839622 100644
--- a/src/settings/plugins/ifnet/Makefile.in
+++ b/src/settings/plugins/ifnet/Makefile.in
@@ -61,12 +61,11 @@ am__aclocal_m4_deps = $(top_srcdir)/m4/compiler_warnings.m4 \
 	$(top_srcdir)/m4/intlmacosx.m4 $(top_srcdir)/m4/intltool.m4 \
 	$(top_srcdir)/m4/introspection.m4 $(top_srcdir)/m4/lib-ld.m4 \
 	$(top_srcdir)/m4/lib-link.m4 $(top_srcdir)/m4/lib-prefix.m4 \
-	$(top_srcdir)/m4/libnl-check.m4 $(top_srcdir)/m4/libtool.m4 \
-	$(top_srcdir)/m4/ltoptions.m4 $(top_srcdir)/m4/ltsugar.m4 \
-	$(top_srcdir)/m4/ltversion.m4 $(top_srcdir)/m4/lt~obsolete.m4 \
-	$(top_srcdir)/m4/nls.m4 $(top_srcdir)/m4/po.m4 \
-	$(top_srcdir)/m4/progtest.m4 $(top_srcdir)/m4/vapigen.m4 \
-	$(top_srcdir)/configure.ac
+	$(top_srcdir)/m4/libtool.m4 $(top_srcdir)/m4/ltoptions.m4 \
+	$(top_srcdir)/m4/ltsugar.m4 $(top_srcdir)/m4/ltversion.m4 \
+	$(top_srcdir)/m4/lt~obsolete.m4 $(top_srcdir)/m4/nls.m4 \
+	$(top_srcdir)/m4/po.m4 $(top_srcdir)/m4/progtest.m4 \
+	$(top_srcdir)/m4/vapigen.m4 $(top_srcdir)/configure.ac
 am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \
 	$(ACLOCAL_M4)
 mkinstalldirs = $(install_sh) -d
@@ -300,12 +299,6 @@ LIBGCRYPT_LIBS = @LIBGCRYPT_LIBS@
 LIBICONV = @LIBICONV@
 LIBINTL = @LIBINTL@
 LIBM = @LIBM@
-LIBNL1_CFLAGS = @LIBNL1_CFLAGS@
-LIBNL1_LIBS = @LIBNL1_LIBS@
-LIBNL2_CFLAGS = @LIBNL2_CFLAGS@
-LIBNL2_LIBS = @LIBNL2_LIBS@
-LIBNL3_CFLAGS = @LIBNL3_CFLAGS@
-LIBNL3_LIBS = @LIBNL3_LIBS@
 LIBNL_CFLAGS = @LIBNL_CFLAGS@
 LIBNL_LIBS = @LIBNL_LIBS@
 LIBOBJS = @LIBOBJS@
diff --git a/src/settings/plugins/ifnet/tests/Makefile.in b/src/settings/plugins/ifnet/tests/Makefile.in
index 0c2c1910..ee264631 100644
--- a/src/settings/plugins/ifnet/tests/Makefile.in
+++ b/src/settings/plugins/ifnet/tests/Makefile.in
@@ -62,12 +62,11 @@ am__aclocal_m4_deps = $(top_srcdir)/m4/compiler_warnings.m4 \
 	$(top_srcdir)/m4/intlmacosx.m4 $(top_srcdir)/m4/intltool.m4 \
 	$(top_srcdir)/m4/introspection.m4 $(top_srcdir)/m4/lib-ld.m4 \
 	$(top_srcdir)/m4/lib-link.m4 $(top_srcdir)/m4/lib-prefix.m4 \
-	$(top_srcdir)/m4/libnl-check.m4 $(top_srcdir)/m4/libtool.m4 \
-	$(top_srcdir)/m4/ltoptions.m4 $(top_srcdir)/m4/ltsugar.m4 \
-	$(top_srcdir)/m4/ltversion.m4 $(top_srcdir)/m4/lt~obsolete.m4 \
-	$(top_srcdir)/m4/nls.m4 $(top_srcdir)/m4/po.m4 \
-	$(top_srcdir)/m4/progtest.m4 $(top_srcdir)/m4/vapigen.m4 \
-	$(top_srcdir)/configure.ac
+	$(top_srcdir)/m4/libtool.m4 $(top_srcdir)/m4/ltoptions.m4 \
+	$(top_srcdir)/m4/ltsugar.m4 $(top_srcdir)/m4/ltversion.m4 \
+	$(top_srcdir)/m4/lt~obsolete.m4 $(top_srcdir)/m4/nls.m4 \
+	$(top_srcdir)/m4/po.m4 $(top_srcdir)/m4/progtest.m4 \
+	$(top_srcdir)/m4/vapigen.m4 $(top_srcdir)/configure.ac
 am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \
 	$(ACLOCAL_M4)
 mkinstalldirs = $(install_sh) -d
@@ -221,12 +220,6 @@ LIBGCRYPT_LIBS = @LIBGCRYPT_LIBS@
 LIBICONV = @LIBICONV@
 LIBINTL = @LIBINTL@
 LIBM = @LIBM@
-LIBNL1_CFLAGS = @LIBNL1_CFLAGS@
-LIBNL1_LIBS = @LIBNL1_LIBS@
-LIBNL2_CFLAGS = @LIBNL2_CFLAGS@
-LIBNL2_LIBS = @LIBNL2_LIBS@
-LIBNL3_CFLAGS = @LIBNL3_CFLAGS@
-LIBNL3_LIBS = @LIBNL3_LIBS@
 LIBNL_CFLAGS = @LIBNL_CFLAGS@
 LIBNL_LIBS = @LIBNL_LIBS@
 LIBOBJS = @LIBOBJS@
diff --git a/src/settings/plugins/ifupdown/Makefile.in b/src/settings/plugins/ifupdown/Makefile.in
index def93ad7..1d192555 100644
--- a/src/settings/plugins/ifupdown/Makefile.in
+++ b/src/settings/plugins/ifupdown/Makefile.in
@@ -61,12 +61,11 @@ am__aclocal_m4_deps = $(top_srcdir)/m4/compiler_warnings.m4 \
 	$(top_srcdir)/m4/intlmacosx.m4 $(top_srcdir)/m4/intltool.m4 \
 	$(top_srcdir)/m4/introspection.m4 $(top_srcdir)/m4/lib-ld.m4 \
 	$(top_srcdir)/m4/lib-link.m4 $(top_srcdir)/m4/lib-prefix.m4 \
-	$(top_srcdir)/m4/libnl-check.m4 $(top_srcdir)/m4/libtool.m4 \
-	$(top_srcdir)/m4/ltoptions.m4 $(top_srcdir)/m4/ltsugar.m4 \
-	$(top_srcdir)/m4/ltversion.m4 $(top_srcdir)/m4/lt~obsolete.m4 \
-	$(top_srcdir)/m4/nls.m4 $(top_srcdir)/m4/po.m4 \
-	$(top_srcdir)/m4/progtest.m4 $(top_srcdir)/m4/vapigen.m4 \
-	$(top_srcdir)/configure.ac
+	$(top_srcdir)/m4/libtool.m4 $(top_srcdir)/m4/ltoptions.m4 \
+	$(top_srcdir)/m4/ltsugar.m4 $(top_srcdir)/m4/ltversion.m4 \
+	$(top_srcdir)/m4/lt~obsolete.m4 $(top_srcdir)/m4/nls.m4 \
+	$(top_srcdir)/m4/po.m4 $(top_srcdir)/m4/progtest.m4 \
+	$(top_srcdir)/m4/vapigen.m4 $(top_srcdir)/configure.ac
 am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \
 	$(ACLOCAL_M4)
 mkinstalldirs = $(install_sh) -d
@@ -298,12 +297,6 @@ LIBGCRYPT_LIBS = @LIBGCRYPT_LIBS@
 LIBICONV = @LIBICONV@
 LIBINTL = @LIBINTL@
 LIBM = @LIBM@
-LIBNL1_CFLAGS = @LIBNL1_CFLAGS@
-LIBNL1_LIBS = @LIBNL1_LIBS@
-LIBNL2_CFLAGS = @LIBNL2_CFLAGS@
-LIBNL2_LIBS = @LIBNL2_LIBS@
-LIBNL3_CFLAGS = @LIBNL3_CFLAGS@
-LIBNL3_LIBS = @LIBNL3_LIBS@
 LIBNL_CFLAGS = @LIBNL_CFLAGS@
 LIBNL_LIBS = @LIBNL_LIBS@
 LIBOBJS = @LIBOBJS@
diff --git a/src/settings/plugins/ifupdown/tests/Makefile.in b/src/settings/plugins/ifupdown/tests/Makefile.in
index 2d4be7bf..42e76335 100644
--- a/src/settings/plugins/ifupdown/tests/Makefile.in
+++ b/src/settings/plugins/ifupdown/tests/Makefile.in
@@ -62,12 +62,11 @@ am__aclocal_m4_deps = $(top_srcdir)/m4/compiler_warnings.m4 \
 	$(top_srcdir)/m4/intlmacosx.m4 $(top_srcdir)/m4/intltool.m4 \
 	$(top_srcdir)/m4/introspection.m4 $(top_srcdir)/m4/lib-ld.m4 \
 	$(top_srcdir)/m4/lib-link.m4 $(top_srcdir)/m4/lib-prefix.m4 \
-	$(top_srcdir)/m4/libnl-check.m4 $(top_srcdir)/m4/libtool.m4 \
-	$(top_srcdir)/m4/ltoptions.m4 $(top_srcdir)/m4/ltsugar.m4 \
-	$(top_srcdir)/m4/ltversion.m4 $(top_srcdir)/m4/lt~obsolete.m4 \
-	$(top_srcdir)/m4/nls.m4 $(top_srcdir)/m4/po.m4 \
-	$(top_srcdir)/m4/progtest.m4 $(top_srcdir)/m4/vapigen.m4 \
-	$(top_srcdir)/configure.ac
+	$(top_srcdir)/m4/libtool.m4 $(top_srcdir)/m4/ltoptions.m4 \
+	$(top_srcdir)/m4/ltsugar.m4 $(top_srcdir)/m4/ltversion.m4 \
+	$(top_srcdir)/m4/lt~obsolete.m4 $(top_srcdir)/m4/nls.m4 \
+	$(top_srcdir)/m4/po.m4 $(top_srcdir)/m4/progtest.m4 \
+	$(top_srcdir)/m4/vapigen.m4 $(top_srcdir)/configure.ac
 am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \
 	$(ACLOCAL_M4)
 mkinstalldirs = $(install_sh) -d
@@ -222,12 +221,6 @@ LIBGCRYPT_LIBS = @LIBGCRYPT_LIBS@
 LIBICONV = @LIBICONV@
 LIBINTL = @LIBINTL@
 LIBM = @LIBM@
-LIBNL1_CFLAGS = @LIBNL1_CFLAGS@
-LIBNL1_LIBS = @LIBNL1_LIBS@
-LIBNL2_CFLAGS = @LIBNL2_CFLAGS@
-LIBNL2_LIBS = @LIBNL2_LIBS@
-LIBNL3_CFLAGS = @LIBNL3_CFLAGS@
-LIBNL3_LIBS = @LIBNL3_LIBS@
 LIBNL_CFLAGS = @LIBNL_CFLAGS@
 LIBNL_LIBS = @LIBNL_LIBS@
 LIBOBJS = @LIBOBJS@
diff --git a/src/settings/plugins/keyfile/Makefile.in b/src/settings/plugins/keyfile/Makefile.in
index 071838b1..4c1c7994 100644
--- a/src/settings/plugins/keyfile/Makefile.in
+++ b/src/settings/plugins/keyfile/Makefile.in
@@ -61,12 +61,11 @@ am__aclocal_m4_deps = $(top_srcdir)/m4/compiler_warnings.m4 \
 	$(top_srcdir)/m4/intlmacosx.m4 $(top_srcdir)/m4/intltool.m4 \
 	$(top_srcdir)/m4/introspection.m4 $(top_srcdir)/m4/lib-ld.m4 \
 	$(top_srcdir)/m4/lib-link.m4 $(top_srcdir)/m4/lib-prefix.m4 \
-	$(top_srcdir)/m4/libnl-check.m4 $(top_srcdir)/m4/libtool.m4 \
-	$(top_srcdir)/m4/ltoptions.m4 $(top_srcdir)/m4/ltsugar.m4 \
-	$(top_srcdir)/m4/ltversion.m4 $(top_srcdir)/m4/lt~obsolete.m4 \
-	$(top_srcdir)/m4/nls.m4 $(top_srcdir)/m4/po.m4 \
-	$(top_srcdir)/m4/progtest.m4 $(top_srcdir)/m4/vapigen.m4 \
-	$(top_srcdir)/configure.ac
+	$(top_srcdir)/m4/libtool.m4 $(top_srcdir)/m4/ltoptions.m4 \
+	$(top_srcdir)/m4/ltsugar.m4 $(top_srcdir)/m4/ltversion.m4 \
+	$(top_srcdir)/m4/lt~obsolete.m4 $(top_srcdir)/m4/nls.m4 \
+	$(top_srcdir)/m4/po.m4 $(top_srcdir)/m4/progtest.m4 \
+	$(top_srcdir)/m4/vapigen.m4 $(top_srcdir)/configure.ac
 am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \
 	$(ACLOCAL_M4)
 mkinstalldirs = $(install_sh) -d
@@ -269,12 +268,6 @@ LIBGCRYPT_LIBS = @LIBGCRYPT_LIBS@
 LIBICONV = @LIBICONV@
 LIBINTL = @LIBINTL@
 LIBM = @LIBM@
-LIBNL1_CFLAGS = @LIBNL1_CFLAGS@
-LIBNL1_LIBS = @LIBNL1_LIBS@
-LIBNL2_CFLAGS = @LIBNL2_CFLAGS@
-LIBNL2_LIBS = @LIBNL2_LIBS@
-LIBNL3_CFLAGS = @LIBNL3_CFLAGS@
-LIBNL3_LIBS = @LIBNL3_LIBS@
 LIBNL_CFLAGS = @LIBNL_CFLAGS@
 LIBNL_LIBS = @LIBNL_LIBS@
 LIBOBJS = @LIBOBJS@
diff --git a/src/settings/plugins/keyfile/tests/Makefile.in b/src/settings/plugins/keyfile/tests/Makefile.in
index ae5836f5..f9f0a9d3 100644
--- a/src/settings/plugins/keyfile/tests/Makefile.in
+++ b/src/settings/plugins/keyfile/tests/Makefile.in
@@ -62,12 +62,11 @@ am__aclocal_m4_deps = $(top_srcdir)/m4/compiler_warnings.m4 \
 	$(top_srcdir)/m4/intlmacosx.m4 $(top_srcdir)/m4/intltool.m4 \
 	$(top_srcdir)/m4/introspection.m4 $(top_srcdir)/m4/lib-ld.m4 \
 	$(top_srcdir)/m4/lib-link.m4 $(top_srcdir)/m4/lib-prefix.m4 \
-	$(top_srcdir)/m4/libnl-check.m4 $(top_srcdir)/m4/libtool.m4 \
-	$(top_srcdir)/m4/ltoptions.m4 $(top_srcdir)/m4/ltsugar.m4 \
-	$(top_srcdir)/m4/ltversion.m4 $(top_srcdir)/m4/lt~obsolete.m4 \
-	$(top_srcdir)/m4/nls.m4 $(top_srcdir)/m4/po.m4 \
-	$(top_srcdir)/m4/progtest.m4 $(top_srcdir)/m4/vapigen.m4 \
-	$(top_srcdir)/configure.ac
+	$(top_srcdir)/m4/libtool.m4 $(top_srcdir)/m4/ltoptions.m4 \
+	$(top_srcdir)/m4/ltsugar.m4 $(top_srcdir)/m4/ltversion.m4 \
+	$(top_srcdir)/m4/lt~obsolete.m4 $(top_srcdir)/m4/nls.m4 \
+	$(top_srcdir)/m4/po.m4 $(top_srcdir)/m4/progtest.m4 \
+	$(top_srcdir)/m4/vapigen.m4 $(top_srcdir)/configure.ac
 am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \
 	$(ACLOCAL_M4)
 mkinstalldirs = $(install_sh) -d
@@ -260,12 +259,6 @@ LIBGCRYPT_LIBS = @LIBGCRYPT_LIBS@
 LIBICONV = @LIBICONV@
 LIBINTL = @LIBINTL@
 LIBM = @LIBM@
-LIBNL1_CFLAGS = @LIBNL1_CFLAGS@
-LIBNL1_LIBS = @LIBNL1_LIBS@
-LIBNL2_CFLAGS = @LIBNL2_CFLAGS@
-LIBNL2_LIBS = @LIBNL2_LIBS@
-LIBNL3_CFLAGS = @LIBNL3_CFLAGS@
-LIBNL3_LIBS = @LIBNL3_LIBS@
 LIBNL_CFLAGS = @LIBNL_CFLAGS@
 LIBNL_LIBS = @LIBNL_LIBS@
 LIBOBJS = @LIBOBJS@
diff --git a/src/settings/plugins/keyfile/tests/keyfiles/Makefile.in b/src/settings/plugins/keyfile/tests/keyfiles/Makefile.in
index 0f0a0445..66d078ac 100644
--- a/src/settings/plugins/keyfile/tests/keyfiles/Makefile.in
+++ b/src/settings/plugins/keyfile/tests/keyfiles/Makefile.in
@@ -60,12 +60,11 @@ am__aclocal_m4_deps = $(top_srcdir)/m4/compiler_warnings.m4 \
 	$(top_srcdir)/m4/intlmacosx.m4 $(top_srcdir)/m4/intltool.m4 \
 	$(top_srcdir)/m4/introspection.m4 $(top_srcdir)/m4/lib-ld.m4 \
 	$(top_srcdir)/m4/lib-link.m4 $(top_srcdir)/m4/lib-prefix.m4 \
-	$(top_srcdir)/m4/libnl-check.m4 $(top_srcdir)/m4/libtool.m4 \
-	$(top_srcdir)/m4/ltoptions.m4 $(top_srcdir)/m4/ltsugar.m4 \
-	$(top_srcdir)/m4/ltversion.m4 $(top_srcdir)/m4/lt~obsolete.m4 \
-	$(top_srcdir)/m4/nls.m4 $(top_srcdir)/m4/po.m4 \
-	$(top_srcdir)/m4/progtest.m4 $(top_srcdir)/m4/vapigen.m4 \
-	$(top_srcdir)/configure.ac
+	$(top_srcdir)/m4/libtool.m4 $(top_srcdir)/m4/ltoptions.m4 \
+	$(top_srcdir)/m4/ltsugar.m4 $(top_srcdir)/m4/ltversion.m4 \
+	$(top_srcdir)/m4/lt~obsolete.m4 $(top_srcdir)/m4/nls.m4 \
+	$(top_srcdir)/m4/po.m4 $(top_srcdir)/m4/progtest.m4 \
+	$(top_srcdir)/m4/vapigen.m4 $(top_srcdir)/configure.ac
 am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \
 	$(ACLOCAL_M4)
 mkinstalldirs = $(install_sh) -d
@@ -184,12 +183,6 @@ LIBGCRYPT_LIBS = @LIBGCRYPT_LIBS@
 LIBICONV = @LIBICONV@
 LIBINTL = @LIBINTL@
 LIBM = @LIBM@
-LIBNL1_CFLAGS = @LIBNL1_CFLAGS@
-LIBNL1_LIBS = @LIBNL1_LIBS@
-LIBNL2_CFLAGS = @LIBNL2_CFLAGS@
-LIBNL2_LIBS = @LIBNL2_LIBS@
-LIBNL3_CFLAGS = @LIBNL3_CFLAGS@
-LIBNL3_LIBS = @LIBNL3_LIBS@
 LIBNL_CFLAGS = @LIBNL_CFLAGS@
 LIBNL_LIBS = @LIBNL_LIBS@
 LIBOBJS = @LIBOBJS@
diff --git a/src/settings/tests/Makefile.in b/src/settings/tests/Makefile.in
index 1b7450cf..51a0e9ce 100644
--- a/src/settings/tests/Makefile.in
+++ b/src/settings/tests/Makefile.in
@@ -62,12 +62,11 @@ am__aclocal_m4_deps = $(top_srcdir)/m4/compiler_warnings.m4 \
 	$(top_srcdir)/m4/intlmacosx.m4 $(top_srcdir)/m4/intltool.m4 \
 	$(top_srcdir)/m4/introspection.m4 $(top_srcdir)/m4/lib-ld.m4 \
 	$(top_srcdir)/m4/lib-link.m4 $(top_srcdir)/m4/lib-prefix.m4 \
-	$(top_srcdir)/m4/libnl-check.m4 $(top_srcdir)/m4/libtool.m4 \
-	$(top_srcdir)/m4/ltoptions.m4 $(top_srcdir)/m4/ltsugar.m4 \
-	$(top_srcdir)/m4/ltversion.m4 $(top_srcdir)/m4/lt~obsolete.m4 \
-	$(top_srcdir)/m4/nls.m4 $(top_srcdir)/m4/po.m4 \
-	$(top_srcdir)/m4/progtest.m4 $(top_srcdir)/m4/vapigen.m4 \
-	$(top_srcdir)/configure.ac
+	$(top_srcdir)/m4/libtool.m4 $(top_srcdir)/m4/ltoptions.m4 \
+	$(top_srcdir)/m4/ltsugar.m4 $(top_srcdir)/m4/ltversion.m4 \
+	$(top_srcdir)/m4/lt~obsolete.m4 $(top_srcdir)/m4/nls.m4 \
+	$(top_srcdir)/m4/po.m4 $(top_srcdir)/m4/progtest.m4 \
+	$(top_srcdir)/m4/vapigen.m4 $(top_srcdir)/configure.ac
 am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \
 	$(ACLOCAL_M4)
 mkinstalldirs = $(install_sh) -d
@@ -220,12 +219,6 @@ LIBGCRYPT_LIBS = @LIBGCRYPT_LIBS@
 LIBICONV = @LIBICONV@
 LIBINTL = @LIBINTL@
 LIBM = @LIBM@
-LIBNL1_CFLAGS = @LIBNL1_CFLAGS@
-LIBNL1_LIBS = @LIBNL1_LIBS@
-LIBNL2_CFLAGS = @LIBNL2_CFLAGS@
-LIBNL2_LIBS = @LIBNL2_LIBS@
-LIBNL3_CFLAGS = @LIBNL3_CFLAGS@
-LIBNL3_LIBS = @LIBNL3_LIBS@
 LIBNL_CFLAGS = @LIBNL_CFLAGS@
 LIBNL_LIBS = @LIBNL_LIBS@
 LIBOBJS = @LIBOBJS@
diff --git a/src/supplicant-manager/Makefile.in b/src/supplicant-manager/Makefile.in
index ae6768f8..bd972cb5 100644
--- a/src/supplicant-manager/Makefile.in
+++ b/src/supplicant-manager/Makefile.in
@@ -61,12 +61,11 @@ am__aclocal_m4_deps = $(top_srcdir)/m4/compiler_warnings.m4 \
 	$(top_srcdir)/m4/intlmacosx.m4 $(top_srcdir)/m4/intltool.m4 \
 	$(top_srcdir)/m4/introspection.m4 $(top_srcdir)/m4/lib-ld.m4 \
 	$(top_srcdir)/m4/lib-link.m4 $(top_srcdir)/m4/lib-prefix.m4 \
-	$(top_srcdir)/m4/libnl-check.m4 $(top_srcdir)/m4/libtool.m4 \
-	$(top_srcdir)/m4/ltoptions.m4 $(top_srcdir)/m4/ltsugar.m4 \
-	$(top_srcdir)/m4/ltversion.m4 $(top_srcdir)/m4/lt~obsolete.m4 \
-	$(top_srcdir)/m4/nls.m4 $(top_srcdir)/m4/po.m4 \
-	$(top_srcdir)/m4/progtest.m4 $(top_srcdir)/m4/vapigen.m4 \
-	$(top_srcdir)/configure.ac
+	$(top_srcdir)/m4/libtool.m4 $(top_srcdir)/m4/ltoptions.m4 \
+	$(top_srcdir)/m4/ltsugar.m4 $(top_srcdir)/m4/ltversion.m4 \
+	$(top_srcdir)/m4/lt~obsolete.m4 $(top_srcdir)/m4/nls.m4 \
+	$(top_srcdir)/m4/po.m4 $(top_srcdir)/m4/progtest.m4 \
+	$(top_srcdir)/m4/vapigen.m4 $(top_srcdir)/configure.ac
 am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \
 	$(ACLOCAL_M4)
 mkinstalldirs = $(install_sh) -d
@@ -260,12 +259,6 @@ LIBGCRYPT_LIBS = @LIBGCRYPT_LIBS@
 LIBICONV = @LIBICONV@
 LIBINTL = @LIBINTL@
 LIBM = @LIBM@
-LIBNL1_CFLAGS = @LIBNL1_CFLAGS@
-LIBNL1_LIBS = @LIBNL1_LIBS@
-LIBNL2_CFLAGS = @LIBNL2_CFLAGS@
-LIBNL2_LIBS = @LIBNL2_LIBS@
-LIBNL3_CFLAGS = @LIBNL3_CFLAGS@
-LIBNL3_LIBS = @LIBNL3_LIBS@
 LIBNL_CFLAGS = @LIBNL_CFLAGS@
 LIBNL_LIBS = @LIBNL_LIBS@
 LIBOBJS = @LIBOBJS@
diff --git a/src/supplicant-manager/nm-supplicant-manager.c b/src/supplicant-manager/nm-supplicant-manager.c
index 430a3852..ac57e8a3 100644
--- a/src/supplicant-manager/nm-supplicant-manager.c
+++ b/src/supplicant-manager/nm-supplicant-manager.c
@@ -179,7 +179,7 @@ get_capabilities_cb  (DBusGProxy *proxy, DBusGProxyCall *call_id, gpointer user_
 
 	nm_log_dbg (LOGD_SUPPLICANT, "AP mode is %ssupported",
 	            (priv->ap_support == AP_SUPPORT_YES) ? "" :
-	                (priv->ap_support == AP_SUPPORT_NO) ? "not " : " possibly");
+	                (priv->ap_support == AP_SUPPORT_NO) ? "not " : "possibly ");
 
 	/* EAP-FAST */
 	priv->fast_supported = FALSE;
diff --git a/src/supplicant-manager/tests/Makefile.in b/src/supplicant-manager/tests/Makefile.in
index cf4be05d..973411a1 100644
--- a/src/supplicant-manager/tests/Makefile.in
+++ b/src/supplicant-manager/tests/Makefile.in
@@ -62,12 +62,11 @@ am__aclocal_m4_deps = $(top_srcdir)/m4/compiler_warnings.m4 \
 	$(top_srcdir)/m4/intlmacosx.m4 $(top_srcdir)/m4/intltool.m4 \
 	$(top_srcdir)/m4/introspection.m4 $(top_srcdir)/m4/lib-ld.m4 \
 	$(top_srcdir)/m4/lib-link.m4 $(top_srcdir)/m4/lib-prefix.m4 \
-	$(top_srcdir)/m4/libnl-check.m4 $(top_srcdir)/m4/libtool.m4 \
-	$(top_srcdir)/m4/ltoptions.m4 $(top_srcdir)/m4/ltsugar.m4 \
-	$(top_srcdir)/m4/ltversion.m4 $(top_srcdir)/m4/lt~obsolete.m4 \
-	$(top_srcdir)/m4/nls.m4 $(top_srcdir)/m4/po.m4 \
-	$(top_srcdir)/m4/progtest.m4 $(top_srcdir)/m4/vapigen.m4 \
-	$(top_srcdir)/configure.ac
+	$(top_srcdir)/m4/libtool.m4 $(top_srcdir)/m4/ltoptions.m4 \
+	$(top_srcdir)/m4/ltsugar.m4 $(top_srcdir)/m4/ltversion.m4 \
+	$(top_srcdir)/m4/lt~obsolete.m4 $(top_srcdir)/m4/nls.m4 \
+	$(top_srcdir)/m4/po.m4 $(top_srcdir)/m4/progtest.m4 \
+	$(top_srcdir)/m4/vapigen.m4 $(top_srcdir)/configure.ac
 am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \
 	$(ACLOCAL_M4)
 mkinstalldirs = $(install_sh) -d
@@ -220,12 +219,6 @@ LIBGCRYPT_LIBS = @LIBGCRYPT_LIBS@
 LIBICONV = @LIBICONV@
 LIBINTL = @LIBINTL@
 LIBM = @LIBM@
-LIBNL1_CFLAGS = @LIBNL1_CFLAGS@
-LIBNL1_LIBS = @LIBNL1_LIBS@
-LIBNL2_CFLAGS = @LIBNL2_CFLAGS@
-LIBNL2_LIBS = @LIBNL2_LIBS@
-LIBNL3_CFLAGS = @LIBNL3_CFLAGS@
-LIBNL3_LIBS = @LIBNL3_LIBS@
 LIBNL_CFLAGS = @LIBNL_CFLAGS@
 LIBNL_LIBS = @LIBNL_LIBS@
 LIBOBJS = @LIBOBJS@
diff --git a/src/tests/Makefile.in b/src/tests/Makefile.in
index df19fc42..f2cb37d0 100644
--- a/src/tests/Makefile.in
+++ b/src/tests/Makefile.in
@@ -64,12 +64,11 @@ am__aclocal_m4_deps = $(top_srcdir)/m4/compiler_warnings.m4 \
 	$(top_srcdir)/m4/intlmacosx.m4 $(top_srcdir)/m4/intltool.m4 \
 	$(top_srcdir)/m4/introspection.m4 $(top_srcdir)/m4/lib-ld.m4 \
 	$(top_srcdir)/m4/lib-link.m4 $(top_srcdir)/m4/lib-prefix.m4 \
-	$(top_srcdir)/m4/libnl-check.m4 $(top_srcdir)/m4/libtool.m4 \
-	$(top_srcdir)/m4/ltoptions.m4 $(top_srcdir)/m4/ltsugar.m4 \
-	$(top_srcdir)/m4/ltversion.m4 $(top_srcdir)/m4/lt~obsolete.m4 \
-	$(top_srcdir)/m4/nls.m4 $(top_srcdir)/m4/po.m4 \
-	$(top_srcdir)/m4/progtest.m4 $(top_srcdir)/m4/vapigen.m4 \
-	$(top_srcdir)/configure.ac
+	$(top_srcdir)/m4/libtool.m4 $(top_srcdir)/m4/ltoptions.m4 \
+	$(top_srcdir)/m4/ltsugar.m4 $(top_srcdir)/m4/ltversion.m4 \
+	$(top_srcdir)/m4/lt~obsolete.m4 $(top_srcdir)/m4/nls.m4 \
+	$(top_srcdir)/m4/po.m4 $(top_srcdir)/m4/progtest.m4 \
+	$(top_srcdir)/m4/vapigen.m4 $(top_srcdir)/configure.ac
 am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \
 	$(ACLOCAL_M4)
 mkinstalldirs = $(install_sh) -d
@@ -238,12 +237,6 @@ LIBGCRYPT_LIBS = @LIBGCRYPT_LIBS@
 LIBICONV = @LIBICONV@
 LIBINTL = @LIBINTL@
 LIBM = @LIBM@
-LIBNL1_CFLAGS = @LIBNL1_CFLAGS@
-LIBNL1_LIBS = @LIBNL1_LIBS@
-LIBNL2_CFLAGS = @LIBNL2_CFLAGS@
-LIBNL2_LIBS = @LIBNL2_LIBS@
-LIBNL3_CFLAGS = @LIBNL3_CFLAGS@
-LIBNL3_LIBS = @LIBNL3_LIBS@
 LIBNL_CFLAGS = @LIBNL_CFLAGS@
 LIBNL_LIBS = @LIBNL_LIBS@
 LIBOBJS = @LIBOBJS@
diff --git a/src/vpn-manager/Makefile.in b/src/vpn-manager/Makefile.in
index bb8efd17..38dbb39d 100644
--- a/src/vpn-manager/Makefile.in
+++ b/src/vpn-manager/Makefile.in
@@ -61,12 +61,11 @@ am__aclocal_m4_deps = $(top_srcdir)/m4/compiler_warnings.m4 \
 	$(top_srcdir)/m4/intlmacosx.m4 $(top_srcdir)/m4/intltool.m4 \
 	$(top_srcdir)/m4/introspection.m4 $(top_srcdir)/m4/lib-ld.m4 \
 	$(top_srcdir)/m4/lib-link.m4 $(top_srcdir)/m4/lib-prefix.m4 \
-	$(top_srcdir)/m4/libnl-check.m4 $(top_srcdir)/m4/libtool.m4 \
-	$(top_srcdir)/m4/ltoptions.m4 $(top_srcdir)/m4/ltsugar.m4 \
-	$(top_srcdir)/m4/ltversion.m4 $(top_srcdir)/m4/lt~obsolete.m4 \
-	$(top_srcdir)/m4/nls.m4 $(top_srcdir)/m4/po.m4 \
-	$(top_srcdir)/m4/progtest.m4 $(top_srcdir)/m4/vapigen.m4 \
-	$(top_srcdir)/configure.ac
+	$(top_srcdir)/m4/libtool.m4 $(top_srcdir)/m4/ltoptions.m4 \
+	$(top_srcdir)/m4/ltsugar.m4 $(top_srcdir)/m4/ltversion.m4 \
+	$(top_srcdir)/m4/lt~obsolete.m4 $(top_srcdir)/m4/nls.m4 \
+	$(top_srcdir)/m4/po.m4 $(top_srcdir)/m4/progtest.m4 \
+	$(top_srcdir)/m4/vapigen.m4 $(top_srcdir)/configure.ac
 am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \
 	$(ACLOCAL_M4)
 mkinstalldirs = $(install_sh) -d
@@ -222,12 +221,6 @@ LIBGCRYPT_LIBS = @LIBGCRYPT_LIBS@
 LIBICONV = @LIBICONV@
 LIBINTL = @LIBINTL@
 LIBM = @LIBM@
-LIBNL1_CFLAGS = @LIBNL1_CFLAGS@
-LIBNL1_LIBS = @LIBNL1_LIBS@
-LIBNL2_CFLAGS = @LIBNL2_CFLAGS@
-LIBNL2_LIBS = @LIBNL2_LIBS@
-LIBNL3_CFLAGS = @LIBNL3_CFLAGS@
-LIBNL3_LIBS = @LIBNL3_LIBS@
 LIBNL_CFLAGS = @LIBNL_CFLAGS@
 LIBNL_LIBS = @LIBNL_LIBS@
 LIBOBJS = @LIBOBJS@
diff --git a/src/vpn-manager/nm-vpn-connection.c b/src/vpn-manager/nm-vpn-connection.c
index 639d66d0..f2e31a8d 100644
--- a/src/vpn-manager/nm-vpn-connection.c
+++ b/src/vpn-manager/nm-vpn-connection.c
@@ -166,8 +166,7 @@ vpn_cleanup (NMVPNConnection *connection)
 
 	if (priv->ip_ifindex) {
 		nm_system_iface_set_up (priv->ip_ifindex, FALSE, NULL);
-		/* FIXME: use AF_UNSPEC here when we have IPv6 support */
-		nm_system_iface_flush_routes (priv->ip_ifindex, AF_INET);
+		nm_system_iface_flush_routes (priv->ip_ifindex, AF_UNSPEC);
 		nm_system_iface_flush_addresses (priv->ip_ifindex, AF_UNSPEC);
 	}
 
diff --git a/src/wifi/Makefile.in b/src/wifi/Makefile.in
index 5019bbeb..ed80fdec 100644
--- a/src/wifi/Makefile.in
+++ b/src/wifi/Makefile.in
@@ -62,12 +62,11 @@ am__aclocal_m4_deps = $(top_srcdir)/m4/compiler_warnings.m4 \
 	$(top_srcdir)/m4/intlmacosx.m4 $(top_srcdir)/m4/intltool.m4 \
 	$(top_srcdir)/m4/introspection.m4 $(top_srcdir)/m4/lib-ld.m4 \
 	$(top_srcdir)/m4/lib-link.m4 $(top_srcdir)/m4/lib-prefix.m4 \
-	$(top_srcdir)/m4/libnl-check.m4 $(top_srcdir)/m4/libtool.m4 \
-	$(top_srcdir)/m4/ltoptions.m4 $(top_srcdir)/m4/ltsugar.m4 \
-	$(top_srcdir)/m4/ltversion.m4 $(top_srcdir)/m4/lt~obsolete.m4 \
-	$(top_srcdir)/m4/nls.m4 $(top_srcdir)/m4/po.m4 \
-	$(top_srcdir)/m4/progtest.m4 $(top_srcdir)/m4/vapigen.m4 \
-	$(top_srcdir)/configure.ac
+	$(top_srcdir)/m4/libtool.m4 $(top_srcdir)/m4/ltoptions.m4 \
+	$(top_srcdir)/m4/ltsugar.m4 $(top_srcdir)/m4/ltversion.m4 \
+	$(top_srcdir)/m4/lt~obsolete.m4 $(top_srcdir)/m4/nls.m4 \
+	$(top_srcdir)/m4/po.m4 $(top_srcdir)/m4/progtest.m4 \
+	$(top_srcdir)/m4/vapigen.m4 $(top_srcdir)/configure.ac
 am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \
 	$(ACLOCAL_M4)
 mkinstalldirs = $(install_sh) -d
@@ -224,12 +223,6 @@ LIBGCRYPT_LIBS = @LIBGCRYPT_LIBS@
 LIBICONV = @LIBICONV@
 LIBINTL = @LIBINTL@
 LIBM = @LIBM@
-LIBNL1_CFLAGS = @LIBNL1_CFLAGS@
-LIBNL1_LIBS = @LIBNL1_LIBS@
-LIBNL2_CFLAGS = @LIBNL2_CFLAGS@
-LIBNL2_LIBS = @LIBNL2_LIBS@
-LIBNL3_CFLAGS = @LIBNL3_CFLAGS@
-LIBNL3_LIBS = @LIBNL3_LIBS@
 LIBNL_CFLAGS = @LIBNL_CFLAGS@
 LIBNL_LIBS = @LIBNL_LIBS@
 LIBOBJS = @LIBOBJS@
diff --git a/src/wifi/wifi-utils-nl80211.c b/src/wifi/wifi-utils-nl80211.c
index 62ec6c2b..5a7103ee 100644
--- a/src/wifi/wifi-utils-nl80211.c
+++ b/src/wifi/wifi-utils-nl80211.c
@@ -33,6 +33,7 @@
 #include <netlink/genl/genl.h>
 #include <netlink/genl/family.h>
 #include <netlink/genl/ctrl.h>
+#include <netlink/route/link.h>
 
 #include <linux/nl80211.h>
 
@@ -40,7 +41,6 @@
 #include "wifi-utils-nl80211.h"
 #include "nm-logging.h"
 #include "nm-utils.h"
-#include "nm-netlink-compat.h"
 
 typedef struct {
 	WifiData parent;
@@ -813,7 +813,7 @@ iface_to_index (struct nl_sock *nl_sock, const char *iface)
 	int err, ifindex;
 
 	/* name to index */
-	err = rtnl_link_alloc_cache (nl_sock, &link_cache);
+	err = rtnl_link_alloc_cache (nl_sock, AF_UNSPEC, &link_cache);
 	if (err < 0) {
 		nm_log_warn (LOGD_HW, "failed to allocate link cache: (%d) %s",
 		             err, nl_geterror (err));
diff --git a/src/wimax/Makefile.in b/src/wimax/Makefile.in
index 8e235277..60f8ad66 100644
--- a/src/wimax/Makefile.in
+++ b/src/wimax/Makefile.in
@@ -61,12 +61,11 @@ am__aclocal_m4_deps = $(top_srcdir)/m4/compiler_warnings.m4 \
 	$(top_srcdir)/m4/intlmacosx.m4 $(top_srcdir)/m4/intltool.m4 \
 	$(top_srcdir)/m4/introspection.m4 $(top_srcdir)/m4/lib-ld.m4 \
 	$(top_srcdir)/m4/lib-link.m4 $(top_srcdir)/m4/lib-prefix.m4 \
-	$(top_srcdir)/m4/libnl-check.m4 $(top_srcdir)/m4/libtool.m4 \
-	$(top_srcdir)/m4/ltoptions.m4 $(top_srcdir)/m4/ltsugar.m4 \
-	$(top_srcdir)/m4/ltversion.m4 $(top_srcdir)/m4/lt~obsolete.m4 \
-	$(top_srcdir)/m4/nls.m4 $(top_srcdir)/m4/po.m4 \
-	$(top_srcdir)/m4/progtest.m4 $(top_srcdir)/m4/vapigen.m4 \
-	$(top_srcdir)/configure.ac
+	$(top_srcdir)/m4/libtool.m4 $(top_srcdir)/m4/ltoptions.m4 \
+	$(top_srcdir)/m4/ltsugar.m4 $(top_srcdir)/m4/ltversion.m4 \
+	$(top_srcdir)/m4/lt~obsolete.m4 $(top_srcdir)/m4/nls.m4 \
+	$(top_srcdir)/m4/po.m4 $(top_srcdir)/m4/progtest.m4 \
+	$(top_srcdir)/m4/vapigen.m4 $(top_srcdir)/configure.ac
 am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \
 	$(ACLOCAL_M4)
 mkinstalldirs = $(install_sh) -d
@@ -255,12 +254,6 @@ LIBGCRYPT_LIBS = @LIBGCRYPT_LIBS@
 LIBICONV = @LIBICONV@
 LIBINTL = @LIBINTL@
 LIBM = @LIBM@
-LIBNL1_CFLAGS = @LIBNL1_CFLAGS@
-LIBNL1_LIBS = @LIBNL1_LIBS@
-LIBNL2_CFLAGS = @LIBNL2_CFLAGS@
-LIBNL2_LIBS = @LIBNL2_LIBS@
-LIBNL3_CFLAGS = @LIBNL3_CFLAGS@
-LIBNL3_LIBS = @LIBNL3_LIBS@
 LIBNL_CFLAGS = @LIBNL_CFLAGS@
 LIBNL_LIBS = @LIBNL_LIBS@
 LIBOBJS = @LIBOBJS@
diff --git a/src/wimax/nm-device-wimax.c b/src/wimax/nm-device-wimax.c
index d549e67e..3e2e2833 100644
--- a/src/wimax/nm-device-wimax.c
+++ b/src/wimax/nm-device-wimax.c
@@ -87,7 +87,7 @@ typedef struct {
 
 	gboolean enabled;
 	gboolean wimaxd_enabled;
-	struct ether_addr hw_addr;
+	guint8 hw_addr[ETH_ALEN];
 	guint activation_timeout_id;
 
 	/* Track whether stage1 (Prepare) is completed yet or not */
@@ -124,18 +124,6 @@ nm_wimax_error_quark (void)
 
 /***********************************************************/
 
-void
-nm_device_wimax_get_hw_address (NMDeviceWimax *self, struct ether_addr *addr)
-{
-	NMDeviceWimaxPrivate *priv;
-
-	g_return_if_fail (NM_IS_DEVICE_WIMAX (self));
-	g_return_if_fail (addr != NULL);
-
-	priv = NM_DEVICE_WIMAX_GET_PRIVATE (self);
-	memcpy (addr, &(priv->hw_addr), sizeof (struct ether_addr));
-}
-
 guint32
 nm_device_wimax_get_center_frequency (NMDeviceWimax *self)
 {
@@ -356,12 +344,6 @@ take_down (NMDevice *device)
 }
 
 static gboolean
-hw_is_up (NMDevice *device)
-{
-	return nm_system_iface_is_up (nm_device_get_ip_ifindex (device));
-}
-
-static gboolean
 hw_bring_up (NMDevice *dev, gboolean *no_firmware)
 {
 	NMDeviceWimaxPrivate *priv = NM_DEVICE_WIMAX_GET_PRIVATE (dev);
@@ -369,13 +351,7 @@ hw_bring_up (NMDevice *dev, gboolean *no_firmware)
 	if (!priv->enabled || !priv->wimaxd_enabled)
 		return FALSE;
 
-	return nm_system_iface_set_up (nm_device_get_ip_ifindex (dev), TRUE, no_firmware);
-}
-
-static void
-hw_take_down (NMDevice *dev)
-{
-	nm_system_iface_set_up (nm_device_get_ip_ifindex (dev), FALSE, NULL);
+	return NM_DEVICE_GET_CLASS (dev)->hw_bring_up (dev, no_firmware);
 }
 
 static void
@@ -383,32 +359,24 @@ update_hw_address (NMDevice *dev)
 {
 	NMDeviceWimax *self = NM_DEVICE_WIMAX (dev);
 	NMDeviceWimaxPrivate *priv = NM_DEVICE_WIMAX_GET_PRIVATE (self);
-	struct ifreq req;
-	int fd;
-	const char *iface;
-
-	iface = nm_device_get_iface (dev);
-
-	fd = socket (PF_INET, SOCK_DGRAM, 0);
-	if (fd < 0) {
-		nm_log_warn (LOGD_HW, "(%s): couldn't open control socket.", iface);
-		return;
+	gboolean changed = FALSE;
+	gsize addrlen;
+
+	addrlen = nm_device_read_hwaddr (dev, priv->hw_addr, sizeof (priv->hw_addr), &changed);
+	if (addrlen) {
+		g_return_if_fail (addrlen == ETH_ALEN);
+		if (changed)
+			g_object_notify (G_OBJECT (self), NM_DEVICE_WIMAX_HW_ADDRESS);
 	}
+}
 
-	memset (&req, 0, sizeof (struct ifreq));
-	strncpy (req.ifr_name, nm_device_get_iface (dev), IFNAMSIZ);
-
-	errno = 0;
-	if (ioctl (fd, SIOCGIFHWADDR, &req) < 0) {
-		nm_log_err (LOGD_HW | LOGD_WIMAX,
-		            "(%s): failed to read hardware address (error %d)",
-		            iface, errno);
-	} else {
-		memcpy (&priv->hw_addr, &req.ifr_hwaddr.sa_data, ETH_ALEN);
-		g_object_notify (G_OBJECT (self), NM_DEVICE_WIMAX_HW_ADDRESS);
-	}
+static const guint8 *
+get_hw_address (NMDevice *device, guint *out_len)
+{
+	NMDeviceWimaxPrivate *priv = NM_DEVICE_WIMAX_GET_PRIVATE (device);
 
-	close (fd);
+	*out_len = sizeof (priv->hw_addr);
+	return priv->hw_addr;
 }
 
 static gboolean
@@ -432,7 +400,7 @@ hwaddr_matches (NMDevice *device,
 			g_return_val_if_fail (other_hwaddr_len == ETH_ALEN, FALSE);
 			if (memcmp (mac->data, other_hwaddr, mac->len) == 0)
 				return TRUE;
-		} else if (memcmp (mac->data, priv->hw_addr.ether_addr_octet, mac->len) == 0)
+		} else if (memcmp (mac->data, priv->hw_addr, mac->len) == 0)
 			return TRUE;
 	} else if (fail_if_no_hwaddr == FALSE)
 		return TRUE;
@@ -471,7 +439,7 @@ check_connection_compatible (NMDevice *device,
 	}
 
 	mac = nm_setting_wimax_get_mac_address (s_wimax);
-	if (mac && memcmp (mac->data, &(priv->hw_addr.ether_addr_octet), ETH_ALEN)) {
+	if (mac && memcmp (mac->data, &priv->hw_addr, ETH_ALEN)) {
 		g_set_error (error,
 					 NM_WIMAX_ERROR, NM_WIMAX_ERROR_CONNECTION_INCOMPATIBLE,
 					 "The connection's MAC address did not match this device.");
@@ -585,7 +553,7 @@ complete_connection (NMDevice *device,
 	setting_mac = nm_setting_wimax_get_mac_address (s_wimax);
 	if (setting_mac) {
 		/* Make sure the setting MAC (if any) matches the device's permanent MAC */
-		if (memcmp (setting_mac->data, &priv->hw_addr.ether_addr_octet, ETH_ALEN)) {
+		if (memcmp (setting_mac->data, &priv->hw_addr, ETH_ALEN)) {
 			g_set_error (error,
 				         NM_SETTING_WIMAX_ERROR,
 				         NM_SETTING_WIMAX_ERROR_INVALID_PROPERTY,
@@ -597,9 +565,9 @@ complete_connection (NMDevice *device,
 		const guint8 null_mac[ETH_ALEN] = { 0, 0, 0, 0, 0, 0 };
 
 		/* Lock the connection to this device by default */
-		if (memcmp (&priv->hw_addr.ether_addr_octet, null_mac, ETH_ALEN)) {
+		if (memcmp (&priv->hw_addr, null_mac, ETH_ALEN)) {
 			mac = g_byte_array_sized_new (ETH_ALEN);
-			g_byte_array_append (mac, priv->hw_addr.ether_addr_octet, ETH_ALEN);
+			g_byte_array_append (mac, priv->hw_addr, ETH_ALEN);
 			g_object_set (G_OBJECT (s_wimax), NM_SETTING_WIMAX_MAC_ADDRESS, mac, NULL);
 			g_byte_array_free (mac, TRUE);
 		}
@@ -638,7 +606,7 @@ get_best_auto_connection (NMDevice *device,
 			continue;
 
 		mac = nm_setting_wimax_get_mac_address (s_wimax);
-		if (mac && memcmp (mac->data, priv->hw_addr.ether_addr_octet, ETH_ALEN))
+		if (mac && memcmp (mac->data, priv->hw_addr, ETH_ALEN))
 			continue;
 
 		for (iter = priv->nsp_list; iter; iter = iter->next) {
@@ -1433,12 +1401,10 @@ get_property (GObject *object, guint prop_id,
 {
 	NMDeviceWimax *self = NM_DEVICE_WIMAX (object);
 	NMDeviceWimaxPrivate *priv = NM_DEVICE_WIMAX_GET_PRIVATE (self);
-	struct ether_addr hw_addr;
 
 	switch (prop_id) {
 	case PROP_HW_ADDRESS:
-		nm_device_wimax_get_hw_address (self, &hw_addr);
-		g_value_take_string (value, nm_utils_hwaddr_ntoa (&hw_addr, ARPHRD_ETHER));
+		g_value_take_string (value, nm_utils_hwaddr_ntoa (priv->hw_addr, ARPHRD_ETHER));
 		break;
 	case PROP_ACTIVE_NSP:
 		if (priv->current_nsp)
@@ -1518,10 +1484,9 @@ nm_device_wimax_class_init (NMDeviceWimaxClass *klass)
 	object_class->dispose = dispose;
 
 	device_class->take_down = take_down;
-	device_class->hw_is_up = hw_is_up;
 	device_class->hw_bring_up = hw_bring_up;
-	device_class->hw_take_down = hw_take_down;
 	device_class->update_hw_address = update_hw_address;
+	device_class->get_hw_address = get_hw_address;
 	device_class->check_connection_compatible = check_connection_compatible;
 	device_class->check_connection_available = check_connection_available;
 	device_class->complete_connection = complete_connection;
diff --git a/src/wimax/nm-device-wimax.h b/src/wimax/nm-device-wimax.h
index a67ff17d..c43c5dd2 100644
--- a/src/wimax/nm-device-wimax.h
+++ b/src/wimax/nm-device-wimax.h
@@ -70,9 +70,6 @@ NMDevice   *nm_device_wimax_new            (const char *udi,
 											const char *iface,
 											const char *driver);
 
-void        nm_device_wimax_get_hw_address (NMDeviceWimax *self,
-											struct ether_addr *addr);
-
 NMWimaxNsp *nm_device_wimax_get_active_nsp (NMDeviceWimax *self);
 
 guint       nm_device_wimax_get_center_frequency (NMDeviceWimax *self);