summary refs log tree commit diff
path: root/src
diff options
context:
space:
mode:
authorMichael Biebl <biebl@debian.org>2012-06-29 20:12:44 +0200
committerMichael Biebl <biebl@debian.org>2012-06-29 20:12:44 +0200
commit867254ea7c2b193fecf8cd36cc6e5dc53c290d92 (patch)
tree7c698b403882736ab70c3efd524c3460f08c391c /src
parentde06e5715e780baade318f3490ac7a4c9ce84e32 (diff)
Imported Upstream version 0.9.5.95 upstream/0.9.5.95
Diffstat (limited to 'src')
-rw-r--r--src/Makefile.am13
-rw-r--r--src/Makefile.in125
-rw-r--r--src/NetworkManagerUtils.c5
-rw-r--r--src/backends/Makefile.in11
-rw-r--r--src/backends/NetworkManagerRedHat.c6
-rw-r--r--src/bluez-manager/Makefile.in11
-rw-r--r--src/bluez-manager/nm-bluez-adapter.c80
-rw-r--r--src/bluez-manager/nm-bluez-adapter.h6
-rw-r--r--src/bluez-manager/nm-bluez-device.c223
-rw-r--r--src/bluez-manager/nm-bluez-device.h7
-rw-r--r--src/bluez-manager/nm-bluez-manager.c64
-rw-r--r--src/bluez-manager/nm-bluez-manager.h11
-rw-r--r--src/dhcp-manager/Makefile.am3
-rw-r--r--src/dhcp-manager/Makefile.in16
-rw-r--r--src/dhcp-manager/nm-dhcp-client.c58
-rw-r--r--src/dhcp-manager/nm-dhcp-dhclient.c10
-rw-r--r--src/dhcp-manager/nm-dhcp-dhcpcd.c7
-rw-r--r--src/dhcp-manager/tests/Makefile.in11
-rw-r--r--src/dns-manager/Makefile.am2
-rw-r--r--src/dns-manager/Makefile.in14
-rw-r--r--src/dns-manager/nm-dns-manager.c161
-rw-r--r--src/dns-manager/nm-dns-manager.h4
-rw-r--r--src/dns-manager/nm-dns-plugin.c9
-rw-r--r--src/dnsmasq-manager/Makefile.am2
-rw-r--r--src/dnsmasq-manager/Makefile.in14
-rw-r--r--src/dnsmasq-manager/nm-dnsmasq-manager.c9
-rw-r--r--src/firewall-manager/Makefile.in11
-rw-r--r--src/generated/Makefile.in11
-rw-r--r--src/generated/nm-enum-types.c133
-rw-r--r--src/generated/nm-enum-types.h18
-rw-r--r--src/generated/nm-marshal.c142
-rw-r--r--src/generated/nm-marshal.h58
-rw-r--r--src/ip6-manager/Makefile.in11
-rw-r--r--src/ip6-manager/nm-ip6-manager.c592
-rw-r--r--src/logging/Makefile.in11
-rw-r--r--src/logging/nm-logging.c3
-rw-r--r--src/logging/nm-logging.h1
-rw-r--r--src/main.c193
-rw-r--r--src/modem-manager/Makefile.in11
-rw-r--r--src/modem-manager/nm-modem.c12
-rw-r--r--src/nm-activation-request.c6
-rw-r--r--src/nm-connection-provider.c112
-rw-r--r--src/nm-connection-provider.h106
-rw-r--r--src/nm-device-adsl.c841
-rw-r--r--src/nm-device-adsl.h66
-rw-r--r--src/nm-device-bt.c16
-rw-r--r--src/nm-device-ethernet.c5
-rw-r--r--src/nm-device-modem.c9
-rw-r--r--src/nm-device-olpc-mesh.c16
-rw-r--r--src/nm-device-private.h2
-rw-r--r--src/nm-device-vlan.c4
-rw-r--r--src/nm-device-wifi.c234
-rw-r--r--src/nm-device-wifi.h1
-rw-r--r--src/nm-device-wired.c38
-rw-r--r--src/nm-device.c427
-rw-r--r--src/nm-device.h25
-rw-r--r--src/nm-ip4-config.c82
-rw-r--r--src/nm-ip4-config.h2
-rw-r--r--src/nm-ip6-config.c106
-rw-r--r--src/nm-ip6-config.h5
-rw-r--r--src/nm-manager.c427
-rw-r--r--src/nm-netlink-compat.c8
-rw-r--r--src/nm-netlink-utils.c4
-rw-r--r--src/nm-policy.c725
-rw-r--r--src/nm-system.c268
-rw-r--r--src/nm-system.h11
-rw-r--r--src/nm-udev-manager.c156
-rw-r--r--src/nm-wifi-ap.c19
-rw-r--r--src/org.freedesktop.NetworkManager.conf7
-rw-r--r--src/posix-signals/Makefile.am15
-rw-r--r--src/posix-signals/Makefile.in640
-rw-r--r--src/posix-signals/nm-posix-signals.c62
-rw-r--r--src/posix-signals/nm-posix-signals.h36
-rw-r--r--src/ppp-manager/Makefile.am4
-rw-r--r--src/ppp-manager/Makefile.in16
-rw-r--r--src/ppp-manager/nm-ppp-manager.c63
-rw-r--r--src/settings/Makefile.in11
-rw-r--r--src/settings/nm-settings-connection.c2
-rw-r--r--src/settings/nm-settings.c116
-rw-r--r--src/settings/plugins/Makefile.am2
-rw-r--r--src/settings/plugins/Makefile.in17
-rw-r--r--src/settings/plugins/example/Makefile.am40
-rw-r--r--src/settings/plugins/example/Makefile.in712
-rw-r--r--src/settings/plugins/example/README35
-rw-r--r--src/settings/plugins/example/common.h56
-rw-r--r--src/settings/plugins/example/errors.c40
-rw-r--r--src/settings/plugins/example/nm-example-connection.c191
-rw-r--r--src/settings/plugins/example/nm-example-connection.h55
-rw-r--r--src/settings/plugins/example/plugin.c868
-rw-r--r--src/settings/plugins/example/plugin.h55
-rw-r--r--src/settings/plugins/example/reader.c46
-rw-r--r--src/settings/plugins/example/writer.c55
-rw-r--r--src/settings/plugins/ifcfg-rh/Makefile.am2
-rw-r--r--src/settings/plugins/ifcfg-rh/Makefile.in14
-rw-r--r--src/settings/plugins/ifcfg-rh/reader.c28
-rw-r--r--src/settings/plugins/ifcfg-rh/tests/Makefile.in11
-rw-r--r--src/settings/plugins/ifcfg-rh/tests/network-scripts/Makefile.in11
-rw-r--r--src/settings/plugins/ifcfg-rh/tests/network-scripts/keys-test-wifi-wpa-psk-22
-rw-r--r--src/settings/plugins/ifcfg-rh/tests/test-ifcfg-rh.c4
-rw-r--r--src/settings/plugins/ifcfg-rh/utils.c2
-rw-r--r--src/settings/plugins/ifcfg-rh/writer.c1
-rw-r--r--src/settings/plugins/ifcfg-suse/Makefile.in11
-rw-r--r--src/settings/plugins/ifnet/Makefile.am2
-rw-r--r--src/settings/plugins/ifnet/Makefile.in14
-rw-r--r--src/settings/plugins/ifnet/net_parser.c46
-rw-r--r--src/settings/plugins/ifnet/net_utils.c10
-rw-r--r--src/settings/plugins/ifnet/tests/Makefile.am3
-rw-r--r--src/settings/plugins/ifnet/tests/Makefile.in17
-rw-r--r--src/settings/plugins/ifnet/tests/net2
-rw-r--r--src/settings/plugins/ifnet/tests/test_all.c3
-rw-r--r--src/settings/plugins/ifupdown/Makefile.in11
-rw-r--r--src/settings/plugins/ifupdown/tests/Makefile.am3
-rw-r--r--src/settings/plugins/ifupdown/tests/Makefile.in14
-rw-r--r--src/settings/plugins/ifupdown/tests/test18-wired-static-verify-ip66
-rw-r--r--src/settings/plugins/keyfile/Makefile.in11
-rw-r--r--src/settings/plugins/keyfile/reader.c3
-rw-r--r--src/settings/plugins/keyfile/tests/Makefile.in11
-rw-r--r--src/settings/plugins/keyfile/tests/keyfiles/Makefile.in11
-rw-r--r--src/settings/tests/Makefile.in11
-rw-r--r--src/supplicant-manager/Makefile.in11
-rw-r--r--src/supplicant-manager/nm-supplicant-interface.c158
-rw-r--r--src/supplicant-manager/nm-supplicant-interface.h7
-rw-r--r--src/supplicant-manager/tests/Makefile.in11
-rw-r--r--src/tests/Makefile.in11
-rw-r--r--src/vpn-manager/Makefile.am2
-rw-r--r--src/vpn-manager/Makefile.in14
-rw-r--r--src/vpn-manager/nm-vpn-connection.c851
-rw-r--r--src/vpn-manager/nm-vpn-connection.h10
-rw-r--r--src/vpn-manager/nm-vpn-manager.c17
-rw-r--r--src/vpn-manager/nm-vpn-manager.h6
-rw-r--r--src/vpn-manager/nm-vpn-service.c20
-rw-r--r--src/wifi/Makefile.in11
-rw-r--r--src/wifi/wifi-utils-nl80211.c42
-rw-r--r--src/wimax/Makefile.in11
134 files changed, 8640 insertions, 1760 deletions
diff --git a/src/Makefile.am b/src/Makefile.am
index f46fbab3..7930c286 100644
--- a/src/Makefile.am
+++ b/src/Makefile.am
@@ -1,6 +1,7 @@
 SUBDIRS= \
 	generated \
 	logging \
+	posix-signals \
 	dns-manager \
 	vpn-manager \
 	dhcp-manager \
@@ -27,6 +28,7 @@ INCLUDES = -I${top_srcdir} \
            -I${top_srcdir}/src/generated \
            -I${top_builddir}/src/generated \
            -I${top_srcdir}/src/logging \
+           -I${top_srcdir}/src/posix-signals \
            -I${top_srcdir}/src/dns-manager \
            -I${top_srcdir}/src/vpn-manager \
            -I${top_srcdir}/src/dhcp-manager \
@@ -120,6 +122,8 @@ NetworkManager_SOURCES = \
 		nm-device-private.h \
 		nm-device-ethernet.c \
 		nm-device-ethernet.h \
+		nm-device-adsl.c \
+		nm-device-adsl.h \
 		nm-device-wifi.c \
 		nm-device-wifi.h \
 		nm-device-wired.c \
@@ -187,7 +191,9 @@ NetworkManager_SOURCES = \
 		nm-rfkill.h \
 		nm-session-monitor.h \
 		nm-session-utils.c \
-		nm-session-utils.h
+		nm-session-utils.h \
+		nm-connection-provider.h \
+		nm-connection-provider.c
 
 if WITH_CONCHECK
 NetworkManager_SOURCES += nm-connectivity.c nm-connectivity.h
@@ -218,6 +224,9 @@ nm-device-ethernet-glue.h: $(top_srcdir)/introspection/nm-device-ethernet.xml
 nm-device-infiniband-glue.h: $(top_srcdir)/introspection/nm-device-infiniband.xml
 	$(AM_V_GEN) dbus-binding-tool --prefix=nm_device_infiniband --mode=glib-server --output=$@ $<
 
+nm-device-adsl-glue.h: $(top_srcdir)/introspection/nm-device-adsl.xml
+	$(AM_V_GEN) dbus-binding-tool --prefix=nm_device_adsl --mode=glib-server --output=$@ $<
+
 nm-device-wifi-glue.h: $(top_srcdir)/introspection/nm-device-wifi.xml
 	$(AM_V_GEN) dbus-binding-tool --prefix=nm_device_wifi --mode=glib-server --output=$@ $<
 
@@ -259,6 +268,7 @@ BUILT_SOURCES = \
 	nm-device-infiniband-glue.h \
 	nm-device-bond-glue.h \
 	nm-device-vlan-glue.h \
+	nm-device-adsl-glue.h \
 	nm-device-wifi-glue.h \
 	nm-device-olpc-mesh-glue.h \
 	nm-device-bt-glue.h \
@@ -296,6 +306,7 @@ endif
 NetworkManager_LDADD = \
 	./generated/libnm-generated.la \
 	./logging/libnm-logging.la \
+	./posix-signals/libnm-posix-signals.la \
 	./dns-manager/libdns-manager.la \
 	./vpn-manager/libvpn-manager.la \
 	./dhcp-manager/libdhcp-manager.la \
diff --git a/src/Makefile.in b/src/Makefile.in
index 715658e8..e1c0fff4 100644
--- a/src/Makefile.in
+++ b/src/Makefile.in
@@ -58,7 +58,7 @@ am__aclocal_m4_deps = $(top_srcdir)/m4/compiler_warnings.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)/configure.ac
+	$(top_srcdir)/m4/vapigen.m4 $(top_srcdir)/configure.ac
 am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \
 	$(ACLOCAL_M4)
 mkinstalldirs = $(install_sh) -d
@@ -97,20 +97,21 @@ am__installdirs = "$(DESTDIR)$(libexecdir)" "$(DESTDIR)$(sbindir)" \
 PROGRAMS = $(libexec_PROGRAMS) $(sbin_PROGRAMS)
 am__NetworkManager_SOURCES_DIST = 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-wifi.c \
-	nm-device-wifi.h nm-device-wired.c nm-device-wired.h \
-	nm-device-olpc-mesh.c nm-device-olpc-mesh.h nm-device-bt.c \
-	nm-device-bt.h nm-device-modem.h nm-device-modem.c \
-	nm-device-infiniband.c nm-device-infiniband.h nm-device-bond.c \
-	nm-device-bond.h nm-device-vlan.c nm-device-vlan.h \
-	nm-wifi-ap.c nm-wifi-ap.h nm-wifi-ap-utils.c \
-	nm-wifi-ap-utils.h nm-dbus-manager.h nm-dbus-manager.c \
-	nm-udev-manager.c nm-udev-manager.h nm-device-factory.h \
-	nm-hostname-provider.c nm-hostname-provider.h nm-ip4-config.c \
-	nm-ip4-config.h nm-ip6-config.c nm-ip6-config.h \
-	nm-active-connection.h nm-active-connection.c nm-config.h \
-	nm-config.c main.c nm-policy.c nm-policy.h nm-policy-hosts.c \
-	nm-policy-hosts.h nm-policy-hostname.c nm-policy-hostname.h \
+	nm-device-ethernet.c nm-device-ethernet.h nm-device-adsl.c \
+	nm-device-adsl.h nm-device-wifi.c nm-device-wifi.h \
+	nm-device-wired.c nm-device-wired.h nm-device-olpc-mesh.c \
+	nm-device-olpc-mesh.h nm-device-bt.c nm-device-bt.h \
+	nm-device-modem.h nm-device-modem.c nm-device-infiniband.c \
+	nm-device-infiniband.h nm-device-bond.c nm-device-bond.h \
+	nm-device-vlan.c nm-device-vlan.h nm-wifi-ap.c nm-wifi-ap.h \
+	nm-wifi-ap-utils.c nm-wifi-ap-utils.h nm-dbus-manager.h \
+	nm-dbus-manager.c nm-udev-manager.c nm-udev-manager.h \
+	nm-device-factory.h nm-hostname-provider.c \
+	nm-hostname-provider.h nm-ip4-config.c nm-ip4-config.h \
+	nm-ip6-config.c nm-ip6-config.h nm-active-connection.h \
+	nm-active-connection.c nm-config.h nm-config.c main.c \
+	nm-policy.c nm-policy.h nm-policy-hosts.c nm-policy-hosts.h \
+	nm-policy-hostname.c nm-policy-hostname.h \
 	NetworkManagerUtils.c NetworkManagerUtils.h nm-system.c \
 	nm-system.h nm-manager.c nm-manager.h nm-manager-auth.c \
 	nm-manager-auth.h nm-netlink-monitor.c nm-netlink-monitor.h \
@@ -120,7 +121,8 @@ am__NetworkManager_SOURCES_DIST = nm-call-store.c nm-call-store.h \
 	nm-properties-changed-signal.h nm-dhcp4-config.c \
 	nm-dhcp4-config.h nm-dhcp6-config.c nm-dhcp6-config.h \
 	nm-rfkill.h nm-session-monitor.h nm-session-utils.c \
-	nm-session-utils.h nm-connectivity.c nm-connectivity.h \
+	nm-session-utils.h nm-connection-provider.h \
+	nm-connection-provider.c nm-connectivity.c nm-connectivity.h \
 	nm-session-monitor-systemd.c nm-session-monitor-ck.c \
 	nm-session-monitor-null.c
 @WITH_CONCHECK_TRUE@am__objects_1 =  \
@@ -131,6 +133,7 @@ am__NetworkManager_SOURCES_DIST = nm-call-store.c nm-call-store.h \
 am_NetworkManager_OBJECTS = NetworkManager-nm-call-store.$(OBJEXT) \
 	NetworkManager-nm-device.$(OBJEXT) \
 	NetworkManager-nm-device-ethernet.$(OBJEXT) \
+	NetworkManager-nm-device-adsl.$(OBJEXT) \
 	NetworkManager-nm-device-wifi.$(OBJEXT) \
 	NetworkManager-nm-device-wired.$(OBJEXT) \
 	NetworkManager-nm-device-olpc-mesh.$(OBJEXT) \
@@ -163,12 +166,16 @@ am_NetworkManager_OBJECTS = NetworkManager-nm-call-store.$(OBJEXT) \
 	NetworkManager-nm-properties-changed-signal.$(OBJEXT) \
 	NetworkManager-nm-dhcp4-config.$(OBJEXT) \
 	NetworkManager-nm-dhcp6-config.$(OBJEXT) \
-	NetworkManager-nm-session-utils.$(OBJEXT) $(am__objects_1) \
-	$(am__objects_2) $(am__objects_3) $(am__objects_4)
+	NetworkManager-nm-session-utils.$(OBJEXT) \
+	NetworkManager-nm-connection-provider.$(OBJEXT) \
+	$(am__objects_1) $(am__objects_2) $(am__objects_3) \
+	$(am__objects_4)
 NetworkManager_OBJECTS = $(am_NetworkManager_OBJECTS)
 @WITH_CONCHECK_TRUE@am__DEPENDENCIES_2 = $(am__DEPENDENCIES_1)
 NetworkManager_DEPENDENCIES = ./generated/libnm-generated.la \
-	./logging/libnm-logging.la ./dns-manager/libdns-manager.la \
+	./logging/libnm-logging.la \
+	./posix-signals/libnm-posix-signals.la \
+	./dns-manager/libdns-manager.la \
 	./vpn-manager/libvpn-manager.la \
 	./dhcp-manager/libdhcp-manager.la \
 	./ip6-manager/libip6-manager.la \
@@ -263,10 +270,10 @@ AM_RECURSIVE_TARGETS = $(RECURSIVE_TARGETS:-recursive=) \
 	distdir
 ETAGS = etags
 CTAGS = ctags
-DIST_SUBDIRS = generated logging dns-manager vpn-manager dhcp-manager \
-	ip6-manager supplicant-manager ppp-manager backends \
-	dnsmasq-manager modem-manager bluez-manager firewall-manager \
-	wifi settings wimax . tests
+DIST_SUBDIRS = generated logging posix-signals dns-manager vpn-manager \
+	dhcp-manager ip6-manager supplicant-manager ppp-manager \
+	backends dnsmasq-manager modem-manager bluez-manager \
+	firewall-manager wifi settings wimax . tests
 DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST)
 am__relativize = \
   dir0=`pwd`; \
@@ -365,6 +372,10 @@ INTLTOOL_EXTRACT = @INTLTOOL_EXTRACT@
 INTLTOOL_MERGE = @INTLTOOL_MERGE@
 INTLTOOL_PERL = @INTLTOOL_PERL@
 INTLTOOL_UPDATE = @INTLTOOL_UPDATE@
+INTLTOOL_V_MERGE = @INTLTOOL_V_MERGE@
+INTLTOOL_V_MERGE_OPTIONS = @INTLTOOL_V_MERGE_OPTIONS@
+INTLTOOL__v_MERGE_ = @INTLTOOL__v_MERGE_@
+INTLTOOL__v_MERGE_0 = @INTLTOOL__v_MERGE_0@
 INTL_MACOSX_LIBS = @INTL_MACOSX_LIBS@
 INTROSPECTION_CFLAGS = @INTROSPECTION_CFLAGS@
 INTROSPECTION_COMPILER = @INTROSPECTION_COMPILER@
@@ -460,6 +471,9 @@ UDEV_BASE_DIR = @UDEV_BASE_DIR@
 USE_NLS = @USE_NLS@
 UUID_CFLAGS = @UUID_CFLAGS@
 UUID_LIBS = @UUID_LIBS@
+VAPIGEN = @VAPIGEN@
+VAPIGEN_MAKEFILE = @VAPIGEN_MAKEFILE@
+VAPIGEN_VAPIDIR = @VAPIGEN_VAPIDIR@
 VERSION = @VERSION@
 XGETTEXT = @XGETTEXT@
 XGETTEXT_015 = @XGETTEXT_015@
@@ -498,6 +512,8 @@ htmldir = @htmldir@
 includedir = @includedir@
 infodir = @infodir@
 install_sh = @install_sh@
+intltool__v_merge_options_ = @intltool__v_merge_options_@
+intltool__v_merge_options_0 = @intltool__v_merge_options_0@
 libdir = @libdir@
 libexecdir = @libexecdir@
 localedir = @localedir@
@@ -518,16 +534,17 @@ target_alias = @target_alias@
 top_build_prefix = @top_build_prefix@
 top_builddir = @top_builddir@
 top_srcdir = @top_srcdir@
-SUBDIRS = generated logging dns-manager vpn-manager dhcp-manager \
-	ip6-manager supplicant-manager ppp-manager backends \
-	dnsmasq-manager modem-manager bluez-manager firewall-manager \
-	wifi settings $(am__append_1) . tests
+SUBDIRS = generated logging posix-signals dns-manager vpn-manager \
+	dhcp-manager ip6-manager supplicant-manager ppp-manager \
+	backends dnsmasq-manager modem-manager bluez-manager \
+	firewall-manager wifi settings $(am__append_1) . tests
 INCLUDES = -I${top_srcdir} \
            -I${top_srcdir}/include \
            -I${top_builddir}/include \
            -I${top_srcdir}/src/generated \
            -I${top_builddir}/src/generated \
            -I${top_srcdir}/src/logging \
+           -I${top_srcdir}/src/posix-signals \
            -I${top_srcdir}/src/dns-manager \
            -I${top_srcdir}/src/vpn-manager \
            -I${top_srcdir}/src/dhcp-manager \
@@ -607,10 +624,11 @@ libtest_wifi_ap_utils_la_LIBADD = \
 
 NetworkManager_SOURCES = 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-wifi.c nm-device-wifi.h \
-	nm-device-wired.c nm-device-wired.h nm-device-olpc-mesh.c \
-	nm-device-olpc-mesh.h nm-device-bt.c nm-device-bt.h \
-	nm-device-modem.h nm-device-modem.c nm-device-infiniband.c \
+	nm-device-ethernet.h nm-device-adsl.c nm-device-adsl.h \
+	nm-device-wifi.c nm-device-wifi.h nm-device-wired.c \
+	nm-device-wired.h nm-device-olpc-mesh.c nm-device-olpc-mesh.h \
+	nm-device-bt.c nm-device-bt.h nm-device-modem.h \
+	nm-device-modem.c nm-device-infiniband.c \
 	nm-device-infiniband.h nm-device-bond.c nm-device-bond.h \
 	nm-device-vlan.c nm-device-vlan.h nm-wifi-ap.c nm-wifi-ap.h \
 	nm-wifi-ap-utils.c nm-wifi-ap-utils.h nm-dbus-manager.h \
@@ -630,7 +648,8 @@ NetworkManager_SOURCES = nm-call-store.c nm-call-store.h nm-device.c \
 	nm-properties-changed-signal.h nm-dhcp4-config.c \
 	nm-dhcp4-config.h nm-dhcp6-config.c nm-dhcp6-config.h \
 	nm-rfkill.h nm-session-monitor.h nm-session-utils.c \
-	nm-session-utils.h $(am__append_2) $(am__append_3) \
+	nm-session-utils.h nm-connection-provider.h \
+	nm-connection-provider.c $(am__append_2) $(am__append_3) \
 	$(am__append_4) $(am__append_5)
 BUILT_SOURCES = \
 	nm-access-point-glue.h \
@@ -640,6 +659,7 @@ BUILT_SOURCES = \
 	nm-device-infiniband-glue.h \
 	nm-device-bond-glue.h \
 	nm-device-vlan-glue.h \
+	nm-device-adsl-glue.h \
 	nm-device-wifi-glue.h \
 	nm-device-olpc-mesh-glue.h \
 	nm-device-bt-glue.h \
@@ -660,7 +680,9 @@ NetworkManager_CPPFLAGS = $(DBUS_CFLAGS) $(GLIB_CFLAGS) \
 	-DNM_RUN_DIR=\"$(rundir)\" -DNMLOCALEDIR=\"$(datadir)/locale\" \
 	-DNMPLUGINDIR=\"$(pkglibdir)\" $(am__append_6)
 NetworkManager_LDADD = ./generated/libnm-generated.la \
-	./logging/libnm-logging.la ./dns-manager/libdns-manager.la \
+	./logging/libnm-logging.la \
+	./posix-signals/libnm-posix-signals.la \
+	./dns-manager/libdns-manager.la \
 	./vpn-manager/libvpn-manager.la \
 	./dhcp-manager/libdhcp-manager.la \
 	./ip6-manager/libip6-manager.la \
@@ -853,8 +875,10 @@ distclean-compile:
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/NetworkManager-nm-active-connection.Po@am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/NetworkManager-nm-call-store.Po@am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/NetworkManager-nm-config.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/NetworkManager-nm-connection-provider.Po@am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/NetworkManager-nm-connectivity.Po@am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/NetworkManager-nm-dbus-manager.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/NetworkManager-nm-device-adsl.Po@am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/NetworkManager-nm-device-bond.Po@am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/NetworkManager-nm-device-bt.Po@am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/NetworkManager-nm-device-ethernet.Po@am__quote@
@@ -1018,6 +1042,22 @@ NetworkManager-nm-device-ethernet.obj: nm-device-ethernet.c
 @AMDEP_TRUE@@am__fastdepCC_FALSE@	DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
 @am__fastdepCC_FALSE@	$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(NetworkManager_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o NetworkManager-nm-device-ethernet.obj `if test -f 'nm-device-ethernet.c'; then $(CYGPATH_W) 'nm-device-ethernet.c'; else $(CYGPATH_W) '$(srcdir)/nm-device-ethernet.c'; fi`
 
+NetworkManager-nm-device-adsl.o: nm-device-adsl.c
+@am__fastdepCC_TRUE@	$(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(NetworkManager_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT NetworkManager-nm-device-adsl.o -MD -MP -MF $(DEPDIR)/NetworkManager-nm-device-adsl.Tpo -c -o NetworkManager-nm-device-adsl.o `test -f 'nm-device-adsl.c' || echo '$(srcdir)/'`nm-device-adsl.c
+@am__fastdepCC_TRUE@	$(AM_V_at)$(am__mv) $(DEPDIR)/NetworkManager-nm-device-adsl.Tpo $(DEPDIR)/NetworkManager-nm-device-adsl.Po
+@am__fastdepCC_FALSE@	$(AM_V_CC) @AM_BACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@	source='nm-device-adsl.c' object='NetworkManager-nm-device-adsl.o' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@	DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@	$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(NetworkManager_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o NetworkManager-nm-device-adsl.o `test -f 'nm-device-adsl.c' || echo '$(srcdir)/'`nm-device-adsl.c
+
+NetworkManager-nm-device-adsl.obj: nm-device-adsl.c
+@am__fastdepCC_TRUE@	$(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(NetworkManager_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT NetworkManager-nm-device-adsl.obj -MD -MP -MF $(DEPDIR)/NetworkManager-nm-device-adsl.Tpo -c -o NetworkManager-nm-device-adsl.obj `if test -f 'nm-device-adsl.c'; then $(CYGPATH_W) 'nm-device-adsl.c'; else $(CYGPATH_W) '$(srcdir)/nm-device-adsl.c'; fi`
+@am__fastdepCC_TRUE@	$(AM_V_at)$(am__mv) $(DEPDIR)/NetworkManager-nm-device-adsl.Tpo $(DEPDIR)/NetworkManager-nm-device-adsl.Po
+@am__fastdepCC_FALSE@	$(AM_V_CC) @AM_BACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@	source='nm-device-adsl.c' object='NetworkManager-nm-device-adsl.obj' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@	DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@	$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(NetworkManager_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o NetworkManager-nm-device-adsl.obj `if test -f 'nm-device-adsl.c'; then $(CYGPATH_W) 'nm-device-adsl.c'; else $(CYGPATH_W) '$(srcdir)/nm-device-adsl.c'; fi`
+
 NetworkManager-nm-device-wifi.o: nm-device-wifi.c
 @am__fastdepCC_TRUE@	$(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(NetworkManager_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT NetworkManager-nm-device-wifi.o -MD -MP -MF $(DEPDIR)/NetworkManager-nm-device-wifi.Tpo -c -o NetworkManager-nm-device-wifi.o `test -f 'nm-device-wifi.c' || echo '$(srcdir)/'`nm-device-wifi.c
 @am__fastdepCC_TRUE@	$(AM_V_at)$(am__mv) $(DEPDIR)/NetworkManager-nm-device-wifi.Tpo $(DEPDIR)/NetworkManager-nm-device-wifi.Po
@@ -1546,6 +1586,22 @@ NetworkManager-nm-session-utils.obj: nm-session-utils.c
 @AMDEP_TRUE@@am__fastdepCC_FALSE@	DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
 @am__fastdepCC_FALSE@	$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(NetworkManager_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o NetworkManager-nm-session-utils.obj `if test -f 'nm-session-utils.c'; then $(CYGPATH_W) 'nm-session-utils.c'; else $(CYGPATH_W) '$(srcdir)/nm-session-utils.c'; fi`
 
+NetworkManager-nm-connection-provider.o: nm-connection-provider.c
+@am__fastdepCC_TRUE@	$(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(NetworkManager_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT NetworkManager-nm-connection-provider.o -MD -MP -MF $(DEPDIR)/NetworkManager-nm-connection-provider.Tpo -c -o NetworkManager-nm-connection-provider.o `test -f 'nm-connection-provider.c' || echo '$(srcdir)/'`nm-connection-provider.c
+@am__fastdepCC_TRUE@	$(AM_V_at)$(am__mv) $(DEPDIR)/NetworkManager-nm-connection-provider.Tpo $(DEPDIR)/NetworkManager-nm-connection-provider.Po
+@am__fastdepCC_FALSE@	$(AM_V_CC) @AM_BACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@	source='nm-connection-provider.c' object='NetworkManager-nm-connection-provider.o' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@	DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@	$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(NetworkManager_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o NetworkManager-nm-connection-provider.o `test -f 'nm-connection-provider.c' || echo '$(srcdir)/'`nm-connection-provider.c
+
+NetworkManager-nm-connection-provider.obj: nm-connection-provider.c
+@am__fastdepCC_TRUE@	$(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(NetworkManager_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT NetworkManager-nm-connection-provider.obj -MD -MP -MF $(DEPDIR)/NetworkManager-nm-connection-provider.Tpo -c -o NetworkManager-nm-connection-provider.obj `if test -f 'nm-connection-provider.c'; then $(CYGPATH_W) 'nm-connection-provider.c'; else $(CYGPATH_W) '$(srcdir)/nm-connection-provider.c'; fi`
+@am__fastdepCC_TRUE@	$(AM_V_at)$(am__mv) $(DEPDIR)/NetworkManager-nm-connection-provider.Tpo $(DEPDIR)/NetworkManager-nm-connection-provider.Po
+@am__fastdepCC_FALSE@	$(AM_V_CC) @AM_BACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@	source='nm-connection-provider.c' object='NetworkManager-nm-connection-provider.obj' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@	DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@	$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(NetworkManager_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o NetworkManager-nm-connection-provider.obj `if test -f 'nm-connection-provider.c'; then $(CYGPATH_W) 'nm-connection-provider.c'; else $(CYGPATH_W) '$(srcdir)/nm-connection-provider.c'; fi`
+
 NetworkManager-nm-connectivity.o: nm-connectivity.c
 @am__fastdepCC_TRUE@	$(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(NetworkManager_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT NetworkManager-nm-connectivity.o -MD -MP -MF $(DEPDIR)/NetworkManager-nm-connectivity.Tpo -c -o NetworkManager-nm-connectivity.o `test -f 'nm-connectivity.c' || echo '$(srcdir)/'`nm-connectivity.c
 @am__fastdepCC_TRUE@	$(AM_V_at)$(am__mv) $(DEPDIR)/NetworkManager-nm-connectivity.Tpo $(DEPDIR)/NetworkManager-nm-connectivity.Po
@@ -2015,6 +2071,9 @@ nm-device-ethernet-glue.h: $(top_srcdir)/introspection/nm-device-ethernet.xml
 nm-device-infiniband-glue.h: $(top_srcdir)/introspection/nm-device-infiniband.xml
 	$(AM_V_GEN) dbus-binding-tool --prefix=nm_device_infiniband --mode=glib-server --output=$@ $<
 
+nm-device-adsl-glue.h: $(top_srcdir)/introspection/nm-device-adsl.xml
+	$(AM_V_GEN) dbus-binding-tool --prefix=nm_device_adsl --mode=glib-server --output=$@ $<
+
 nm-device-wifi-glue.h: $(top_srcdir)/introspection/nm-device-wifi.xml
 	$(AM_V_GEN) dbus-binding-tool --prefix=nm_device_wifi --mode=glib-server --output=$@ $<
 
diff --git a/src/NetworkManagerUtils.c b/src/NetworkManagerUtils.c
index 6c2c0446..952b4e5d 100644
--- a/src/NetworkManagerUtils.c
+++ b/src/NetworkManagerUtils.c
@@ -15,7 +15,7 @@
  * with this program; if not, write to the Free Software Foundation, Inc.,
  * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
  *
- * Copyright (C) 2004 - 2011 Red Hat, Inc.
+ * Copyright (C) 2004 - 2012 Red Hat, Inc.
  * Copyright (C) 2005 - 2008 Novell, Inc.
  */
 
@@ -41,6 +41,7 @@
 #include "nm-setting-wireless.h"
 #include "nm-setting-wireless-security.h"
 #include "nm-manager-auth.h"
+#include "nm-posix-signals.h"
 
 /*
  * nm_ethernet_address_is_valid
@@ -94,7 +95,7 @@ nm_spawn_process (const char *args)
 		return -1;
 	}
 
-	if (!g_spawn_sync ("/", argv, NULL, 0, NULL, NULL, NULL, NULL, &status, &error)) {
+	if (!g_spawn_sync ("/", argv, NULL, 0, nm_unblock_posix_signals, NULL, NULL, NULL, &status, &error)) {
 		nm_log_warn (LOGD_CORE, "could not spawn process '%s': %s", args, error->message);
 		g_error_free (error);
 	}
diff --git a/src/backends/Makefile.in b/src/backends/Makefile.in
index 9c6f7d0c..48895fd3 100644
--- a/src/backends/Makefile.in
+++ b/src/backends/Makefile.in
@@ -60,7 +60,7 @@ am__aclocal_m4_deps = $(top_srcdir)/m4/compiler_warnings.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)/configure.ac
+	$(top_srcdir)/m4/vapigen.m4 $(top_srcdir)/configure.ac
 am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \
 	$(ACLOCAL_M4)
 mkinstalldirs = $(install_sh) -d
@@ -214,6 +214,10 @@ INTLTOOL_EXTRACT = @INTLTOOL_EXTRACT@
 INTLTOOL_MERGE = @INTLTOOL_MERGE@
 INTLTOOL_PERL = @INTLTOOL_PERL@
 INTLTOOL_UPDATE = @INTLTOOL_UPDATE@
+INTLTOOL_V_MERGE = @INTLTOOL_V_MERGE@
+INTLTOOL_V_MERGE_OPTIONS = @INTLTOOL_V_MERGE_OPTIONS@
+INTLTOOL__v_MERGE_ = @INTLTOOL__v_MERGE_@
+INTLTOOL__v_MERGE_0 = @INTLTOOL__v_MERGE_0@
 INTL_MACOSX_LIBS = @INTL_MACOSX_LIBS@
 INTROSPECTION_CFLAGS = @INTROSPECTION_CFLAGS@
 INTROSPECTION_COMPILER = @INTROSPECTION_COMPILER@
@@ -309,6 +313,9 @@ UDEV_BASE_DIR = @UDEV_BASE_DIR@
 USE_NLS = @USE_NLS@
 UUID_CFLAGS = @UUID_CFLAGS@
 UUID_LIBS = @UUID_LIBS@
+VAPIGEN = @VAPIGEN@
+VAPIGEN_MAKEFILE = @VAPIGEN_MAKEFILE@
+VAPIGEN_VAPIDIR = @VAPIGEN_VAPIDIR@
 VERSION = @VERSION@
 XGETTEXT = @XGETTEXT@
 XGETTEXT_015 = @XGETTEXT_015@
@@ -347,6 +354,8 @@ htmldir = @htmldir@
 includedir = @includedir@
 infodir = @infodir@
 install_sh = @install_sh@
+intltool__v_merge_options_ = @intltool__v_merge_options_@
+intltool__v_merge_options_0 = @intltool__v_merge_options_0@
 libdir = @libdir@
 libexecdir = @libexecdir@
 localedir = @localedir@
diff --git a/src/backends/NetworkManagerRedHat.c b/src/backends/NetworkManagerRedHat.c
index c14eb837..843b03b2 100644
--- a/src/backends/NetworkManagerRedHat.c
+++ b/src/backends/NetworkManagerRedHat.c
@@ -35,7 +35,11 @@ void nm_backend_update_dns (void)
 {
 	/* Invalidate the nscd host cache since we changed resolv.conf */
 	if (g_file_test ("/usr/sbin/nscd", G_FILE_TEST_EXISTS | G_FILE_TEST_IS_EXECUTABLE | G_FILE_TEST_IS_REGULAR)) {
-		nm_spawn_process ("/etc/init.d/nscd condrestart");
+		if (g_file_test ("/etc/init.d/nscd", G_FILE_TEST_EXISTS))
+			nm_spawn_process ("/etc/init.d/nscd condrestart");
+		else if (g_file_test ("/bin/systemctl", G_FILE_TEST_IS_EXECUTABLE))
+			nm_spawn_process ("/bin/systemctl condrestart nscd.service");
+
 		nm_spawn_process ("/usr/sbin/nscd -i hosts");
 	}
 }
diff --git a/src/bluez-manager/Makefile.in b/src/bluez-manager/Makefile.in
index efb5ab4e..eb9b464b 100644
--- a/src/bluez-manager/Makefile.in
+++ b/src/bluez-manager/Makefile.in
@@ -47,7 +47,7 @@ am__aclocal_m4_deps = $(top_srcdir)/m4/compiler_warnings.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)/configure.ac
+	$(top_srcdir)/m4/vapigen.m4 $(top_srcdir)/configure.ac
 am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \
 	$(ACLOCAL_M4)
 mkinstalldirs = $(install_sh) -d
@@ -171,6 +171,10 @@ INTLTOOL_EXTRACT = @INTLTOOL_EXTRACT@
 INTLTOOL_MERGE = @INTLTOOL_MERGE@
 INTLTOOL_PERL = @INTLTOOL_PERL@
 INTLTOOL_UPDATE = @INTLTOOL_UPDATE@
+INTLTOOL_V_MERGE = @INTLTOOL_V_MERGE@
+INTLTOOL_V_MERGE_OPTIONS = @INTLTOOL_V_MERGE_OPTIONS@
+INTLTOOL__v_MERGE_ = @INTLTOOL__v_MERGE_@
+INTLTOOL__v_MERGE_0 = @INTLTOOL__v_MERGE_0@
 INTL_MACOSX_LIBS = @INTL_MACOSX_LIBS@
 INTROSPECTION_CFLAGS = @INTROSPECTION_CFLAGS@
 INTROSPECTION_COMPILER = @INTROSPECTION_COMPILER@
@@ -266,6 +270,9 @@ UDEV_BASE_DIR = @UDEV_BASE_DIR@
 USE_NLS = @USE_NLS@
 UUID_CFLAGS = @UUID_CFLAGS@
 UUID_LIBS = @UUID_LIBS@
+VAPIGEN = @VAPIGEN@
+VAPIGEN_MAKEFILE = @VAPIGEN_MAKEFILE@
+VAPIGEN_VAPIDIR = @VAPIGEN_VAPIDIR@
 VERSION = @VERSION@
 XGETTEXT = @XGETTEXT@
 XGETTEXT_015 = @XGETTEXT_015@
@@ -304,6 +311,8 @@ htmldir = @htmldir@
 includedir = @includedir@
 infodir = @infodir@
 install_sh = @install_sh@
+intltool__v_merge_options_ = @intltool__v_merge_options_@
+intltool__v_merge_options_0 = @intltool__v_merge_options_0@
 libdir = @libdir@
 libexecdir = @libexecdir@
 localedir = @localedir@
diff --git a/src/bluez-manager/nm-bluez-adapter.c b/src/bluez-manager/nm-bluez-adapter.c
index 27a85e78..4c36f3de 100644
--- a/src/bluez-manager/nm-bluez-adapter.c
+++ b/src/bluez-manager/nm-bluez-adapter.c
@@ -15,7 +15,7 @@
  * with this program; if not, write to the Free Software Foundation, Inc.,
  * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
  *
- * Copyright (C) 2009 - 2010 Red Hat, Inc.
+ * Copyright (C) 2009 - 2012 Red Hat, Inc.
  */
 
 #include <glib.h>
@@ -41,6 +41,9 @@ typedef struct {
 
 	char *address;
 	GHashTable *devices;
+
+	/* Cached for devices */
+	NMConnectionProvider *provider;
 } NMBluezAdapterPrivate;
 
 
@@ -85,23 +88,18 @@ nm_bluez_adapter_get_initialized (NMBluezAdapter *self)
 	return NM_BLUEZ_ADAPTER_GET_PRIVATE (self)->initialized;
 }
 
-static void
-devices_to_list (gpointer key, gpointer data, gpointer user_data)
-{
-	NMBluezDevice *device = NM_BLUEZ_DEVICE (data);
-	GSList **list = user_data;
-
-	if (nm_bluez_device_get_usable (device))
-		*list = g_slist_append (*list, data);
-}
-
 GSList *
 nm_bluez_adapter_get_devices (NMBluezAdapter *self)
 {
-	NMBluezAdapterPrivate *priv = NM_BLUEZ_ADAPTER_GET_PRIVATE (self);
 	GSList *devices = NULL;
+	GHashTableIter iter;
+	NMBluezDevice *device;
 
-	g_hash_table_foreach (priv->devices, devices_to_list, &devices);
+	g_hash_table_iter_init (&iter, NM_BLUEZ_ADAPTER_GET_PRIVATE (self)->devices);
+	while (g_hash_table_iter_next (&iter, NULL, (gpointer) &device)) {
+		if (nm_bluez_device_get_usable (device))
+			devices = g_slist_append (devices, device);
+	}
 	return devices;
 }
 
@@ -109,16 +107,19 @@ static void
 device_usable (NMBluezDevice *device, GParamSpec *pspec, gpointer user_data)
 {
 	NMBluezAdapter *self = NM_BLUEZ_ADAPTER (user_data);
-	NMBluezAdapterPrivate *priv = NM_BLUEZ_ADAPTER_GET_PRIVATE (self);
+	gboolean usable = nm_bluez_device_get_usable (device);
 
-	if (nm_bluez_device_get_usable (device))
+	nm_log_dbg (LOGD_BT, "(%s): bluez device now %s",
+	            nm_bluez_device_get_path (device),
+	            usable ? "usable" : "unusable");
+
+	if (usable) {
+		nm_log_dbg (LOGD_BT, "(%s): bluez device address %s",
+				    nm_bluez_device_get_path (device),
+				    nm_bluez_device_get_address (device));
 		g_signal_emit (self, signals[DEVICE_ADDED], 0, device);
-	else {
-		g_object_ref (device);
-		g_hash_table_remove (priv->devices, nm_bluez_device_get_path (device));
+	} else
 		g_signal_emit (self, signals[DEVICE_REMOVED], 0, device);
-		g_object_unref (device);
-	}
 }
 
 static void
@@ -127,6 +128,9 @@ device_initialized (NMBluezDevice *device, gboolean success, gpointer user_data)
 	NMBluezAdapter *self = NM_BLUEZ_ADAPTER (user_data);
 	NMBluezAdapterPrivate *priv = NM_BLUEZ_ADAPTER_GET_PRIVATE (self);
 
+	nm_log_dbg (LOGD_BT, "(%s): bluez device %s",
+	            nm_bluez_device_get_path (device),
+	            success ? "initialized" : "failed to initialize");
 	if (!success)
 		g_hash_table_remove (priv->devices, nm_bluez_device_get_path (device));
 }
@@ -138,10 +142,12 @@ device_created (DBusGProxy *proxy, const char *path, gpointer user_data)
 	NMBluezAdapterPrivate *priv = NM_BLUEZ_ADAPTER_GET_PRIVATE (self);
 	NMBluezDevice *device;
 
-	device = nm_bluez_device_new (path);
+	device = nm_bluez_device_new (path, priv->provider);
 	g_signal_connect (device, "initialized", G_CALLBACK (device_initialized), self);
 	g_signal_connect (device, "notify::usable", G_CALLBACK (device_usable), self);
-	g_hash_table_insert (priv->devices, g_strdup (path), device);
+	g_hash_table_insert (priv->devices, (gpointer) nm_bluez_device_get_path (device), device);
+
+	nm_log_dbg (LOGD_BT, "(%s): new bluez device found", path);
 }
 
 static void
@@ -151,10 +157,12 @@ device_removed (DBusGProxy *proxy, const char *path, gpointer user_data)
 	NMBluezAdapterPrivate *priv = NM_BLUEZ_ADAPTER_GET_PRIVATE (self);
 	NMBluezDevice *device;
 
+	nm_log_dbg (LOGD_BT, "(%s): bluez device removed", path);
+
 	device = g_hash_table_lookup (priv->devices, path);
 	if (device) {
 		g_object_ref (device);
-		g_hash_table_remove (priv->devices, path);
+		g_hash_table_remove (priv->devices, nm_bluez_device_get_path (device));
 		g_signal_emit (self, signals[DEVICE_REMOVED], 0, device);
 		g_object_unref (device);
 	}
@@ -214,8 +222,10 @@ query_properties (NMBluezAdapter *self)
 	}
 }
 
+/***********************************************************/
+
 NMBluezAdapter *
-nm_bluez_adapter_new (const char *path)
+nm_bluez_adapter_new (const char *path, NMConnectionProvider *provider)
 {
 	NMBluezAdapter *self;
 	NMBluezAdapterPrivate *priv;
@@ -229,6 +239,9 @@ nm_bluez_adapter_new (const char *path)
 		return NULL;
 
 	priv = NM_BLUEZ_ADAPTER_GET_PRIVATE (self);
+
+	priv->provider = provider;
+
 	dbus_mgr = nm_dbus_manager_get ();
 	connection = nm_dbus_manager_get_connection (dbus_mgr);
 
@@ -258,7 +271,23 @@ nm_bluez_adapter_init (NMBluezAdapter *self)
 	NMBluezAdapterPrivate *priv = NM_BLUEZ_ADAPTER_GET_PRIVATE (self);
 
 	priv->devices = g_hash_table_new_full (g_str_hash, g_str_equal,
-	                                       g_free, g_object_unref);
+	                                       NULL, g_object_unref);
+}
+
+static void
+dispose (GObject *object)
+{
+	NMBluezAdapter *self = NM_BLUEZ_ADAPTER (object);
+	NMBluezAdapterPrivate *priv = NM_BLUEZ_ADAPTER_GET_PRIVATE (self);
+	GHashTableIter iter;
+	NMBluezDevice *device;
+
+	g_hash_table_iter_init (&iter, priv->devices);
+	while (g_hash_table_iter_next (&iter, NULL, (gpointer) &device))
+		g_signal_emit (self, signals[DEVICE_REMOVED], 0, device);
+	g_hash_table_remove_all (priv->devices);
+
+	G_OBJECT_CLASS (nm_bluez_adapter_parent_class)->dispose (object);
 }
 
 static void
@@ -320,6 +349,7 @@ nm_bluez_adapter_class_init (NMBluezAdapterClass *config_class)
 	/* virtual methods */
 	object_class->get_property = get_property;
 	object_class->set_property = set_property;
+	object_class->dispose = dispose;
 	object_class->finalize = finalize;
 
 	/* Properties */
diff --git a/src/bluez-manager/nm-bluez-adapter.h b/src/bluez-manager/nm-bluez-adapter.h
index c552e989..36aa55df 100644
--- a/src/bluez-manager/nm-bluez-adapter.h
+++ b/src/bluez-manager/nm-bluez-adapter.h
@@ -15,7 +15,7 @@
  * with this program; if not, write to the Free Software Foundation, Inc.,
  * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
  *
- * Copyright (C) 2009 Red Hat, Inc.
+ * Copyright (C) 2009 - 2012 Red Hat, Inc.
  */
 
 #ifndef NM_BLUEZ_ADAPTER_H
@@ -25,6 +25,7 @@
 #include <glib-object.h>
 
 #include "nm-bluez-device.h"
+#include "nm-connection-provider.h"
 
 #define NM_TYPE_BLUEZ_ADAPTER            (nm_bluez_adapter_get_type ())
 #define NM_BLUEZ_ADAPTER(obj)            (G_TYPE_CHECK_INSTANCE_CAST ((obj), NM_TYPE_BLUEZ_ADAPTER, NMBluezAdapter))
@@ -53,7 +54,8 @@ typedef struct {
 
 GType nm_bluez_adapter_get_type (void);
 
-NMBluezAdapter *nm_bluez_adapter_new (const char *path);
+NMBluezAdapter *nm_bluez_adapter_new (const char *path,
+                                      NMConnectionProvider *provider);
 
 const char *nm_bluez_adapter_get_path (NMBluezAdapter *self);
 
diff --git a/src/bluez-manager/nm-bluez-device.c b/src/bluez-manager/nm-bluez-device.c
index ecb6ce51..b12a8619 100644
--- a/src/bluez-manager/nm-bluez-device.c
+++ b/src/bluez-manager/nm-bluez-device.c
@@ -15,13 +15,17 @@
  * with this program; if not, write to the Free Software Foundation, Inc.,
  * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
  *
- * Copyright (C) 2009 - 2010 Red Hat, Inc.
+ * Copyright (C) 2009 - 2012 Red Hat, Inc.
  */
 
 #include <glib.h>
 #include <string.h>
+#include <net/ethernet.h>
+#include <netinet/ether.h>
 
 #include "NetworkManager.h"
+#include "nm-setting-bluetooth.h"
+
 #include "nm-dbus-manager.h"
 #include "nm-bluez-device.h"
 #include "nm-bluez-common.h"
@@ -41,9 +45,13 @@ typedef struct {
 	gboolean usable;
 
 	char *address;
+	guint8 bin_address[ETH_ALEN];
 	char *name;
 	guint32 capabilities;
 	gint rssi;
+
+	NMConnectionProvider *provider;
+	GSList *connections;
 } NMBluezDevicePrivate;
 
 
@@ -66,6 +74,8 @@ enum {
 };
 static guint signals[LAST_SIGNAL] = { 0 };
 
+/***********************************************************/
+
 const char *
 nm_bluez_device_get_path (NMBluezDevice *self)
 {
@@ -122,59 +132,137 @@ nm_bluez_device_get_rssi (NMBluezDevice *self)
 	return NM_BLUEZ_DEVICE_GET_PRIVATE (self)->rssi;
 }
 
-static guint32
-convert_uuids_to_capabilities (const char **strings)
+static void
+check_emit_usable (NMBluezDevice *self)
 {
-	const char **iter;
-	guint32 capabilities = 0;
+	NMBluezDevicePrivate *priv = NM_BLUEZ_DEVICE_GET_PRIVATE (self);
+	gboolean new_usable;
 
-	for (iter = strings; iter && *iter; iter++) {
-		char **parts;
-		guint uuid16;
+	new_usable = (priv->initialized && priv->capabilities && priv->name && priv->address && priv->connections);
+	if (new_usable != priv->usable) {
+		priv->usable = new_usable;
+		g_object_notify (G_OBJECT (self), NM_BLUEZ_DEVICE_USABLE);
+	}
+}
 
-		parts = g_strsplit (*iter, "-", -1);
-		if (parts == NULL || parts[0] == NULL) {
-			g_strfreev (parts);
-			continue;
-		}
+/********************************************************************/
 
-		uuid16 = g_ascii_strtoull (parts[0], NULL, 16);
-		g_strfreev (parts);
+static gboolean
+connection_compatible (NMBluezDevice *self, NMConnection *connection)
+{
+	NMBluezDevicePrivate *priv = NM_BLUEZ_DEVICE_GET_PRIVATE (self);
+	NMSettingBluetooth *s_bt;
+	const char *bt_type;
+	const GByteArray *bdaddr;
 
-		switch (uuid16) {
-		case 0x1103:
-			capabilities |= NM_BT_CAPABILITY_DUN;
-			break;
-		case 0x1116:
-			capabilities |= NM_BT_CAPABILITY_NAP;
-			break;
-		default:
-			break;
-		}
+	if (!nm_connection_is_type (connection, NM_SETTING_BLUETOOTH_SETTING_NAME))
+		return FALSE;
+
+	s_bt = nm_connection_get_setting_bluetooth (connection);
+	if (!s_bt)
+		return FALSE;
+
+	bdaddr = nm_setting_bluetooth_get_bdaddr (s_bt);
+	if (!bdaddr || bdaddr->len != ETH_ALEN)
+		return FALSE;
+	if (memcmp (bdaddr->data, priv->bin_address, ETH_ALEN) != 0)
+		return FALSE;
+
+	bt_type = nm_setting_bluetooth_get_connection_type (s_bt);
+	if (   g_str_equal (bt_type, NM_SETTING_BLUETOOTH_TYPE_DUN)
+	    && !(priv->capabilities & NM_BT_CAPABILITY_DUN))
+	    	return FALSE;
+
+	if (   g_str_equal (bt_type, NM_SETTING_BLUETOOTH_TYPE_PANU)
+	    && !(priv->capabilities & NM_BT_CAPABILITY_NAP))
+	    	return FALSE;
+
+	return TRUE;
+}
+
+static void
+_internal_add_connection (NMBluezDevice *self, NMConnection *connection)
+{
+	NMBluezDevicePrivate *priv = NM_BLUEZ_DEVICE_GET_PRIVATE (self);
+
+	if (!g_slist_find (priv->connections, connection)) {
+		priv->connections = g_slist_prepend (priv->connections, g_object_ref (connection));
+		check_emit_usable (self);
 	}
+}
 
-	return capabilities;
+static void
+cp_connection_added (NMConnectionProvider *provider,
+                     NMConnection *connection,
+                     NMBluezDevice *self)
+{
+	if (connection_compatible (self, connection))
+		_internal_add_connection (self, connection);
 }
 
 static void
-check_emit_usable (NMBluezDevice *self)
+cp_connection_removed (NMConnectionProvider *provider,
+                       NMConnection *connection,
+                       NMBluezDevice *self)
 {
 	NMBluezDevicePrivate *priv = NM_BLUEZ_DEVICE_GET_PRIVATE (self);
 
-	if (   priv->initialized
-	    && priv->capabilities
-	    && priv->name
-	    && priv->address) {
-		if (!priv->usable) {
-			priv->usable = TRUE;
-			g_object_notify (G_OBJECT (self), NM_BLUEZ_DEVICE_USABLE);
-		}
-	} else {
-		if (priv->usable) {
-			priv->usable = FALSE;
-			g_object_notify (G_OBJECT (self), NM_BLUEZ_DEVICE_USABLE);
+	if (g_slist_find (priv->connections, connection)) {
+		priv->connections = g_slist_remove (priv->connections, connection);
+		g_object_unref (connection);
+		check_emit_usable (self);
+	}
+}
+
+static void
+cp_connection_updated (NMConnectionProvider *provider,
+                       NMConnection *connection,
+                       NMBluezDevice *self)
+{
+	if (connection_compatible (self, connection))
+		_internal_add_connection (self, connection);
+	else
+		cp_connection_removed (provider, connection, self);
+}
+
+static void
+cp_connections_loaded (NMConnectionProvider *provider, NMBluezDevice *self)
+{
+	const GSList *connections, *iter;
+
+	connections = nm_connection_provider_get_connections (provider);
+	for (iter = connections; iter; iter = g_slist_next (iter))
+		cp_connection_added (provider, NM_CONNECTION (iter->data), self);
+}
+
+/***********************************************************/
+
+static guint32
+convert_uuids_to_capabilities (const char **strings)
+{
+	const char **iter;
+	guint32 capabilities = 0;
+
+	for (iter = strings; iter && *iter; iter++) {
+		char **parts;
+
+		parts = g_strsplit (*iter, "-", -1);
+		if (parts && parts[0]) {
+			switch (g_ascii_strtoull (parts[0], NULL, 16)) {
+			case 0x1103:
+				capabilities |= NM_BT_CAPABILITY_DUN;
+				break;
+			case 0x1116:
+				capabilities |= NM_BT_CAPABILITY_NAP;
+				break;
+			default:
+				break;
+			}
 		}
+		g_strfreev (parts);
 	}
+
+	return capabilities;
 }
 
 static void
@@ -224,6 +312,7 @@ get_properties_cb (DBusGProxy *proxy, DBusGProxyCall *call, gpointer user_data)
 	GError *err = NULL;
 	GValue *value;
 	const char **uuids;
+	struct ether_addr *tmp;
 
 	if (!dbus_g_proxy_end_call (proxy, call, &err,
 	                            DBUS_TYPE_G_MAP_OF_VARIANT, &properties,
@@ -237,6 +326,11 @@ get_properties_cb (DBusGProxy *proxy, DBusGProxyCall *call, gpointer user_data)
 
 	value = g_hash_table_lookup (properties, "Address");
 	priv->address = value ? g_value_dup_string (value) : NULL;
+	if (priv->address) {
+		tmp = ether_aton (priv->address);
+		g_assert (tmp);
+		memcpy (priv->bin_address, tmp->ether_addr_octet, ETH_ALEN);
+	}
 
 	value = g_hash_table_lookup (properties, "Name");
 	priv->name = value ? g_value_dup_string (value) : NULL;
@@ -253,6 +347,9 @@ get_properties_cb (DBusGProxy *proxy, DBusGProxyCall *call, gpointer user_data)
 
 	g_hash_table_unref (properties);
 
+	/* Check if any connections match this device */
+	cp_connections_loaded (priv->provider, self);
+
 	priv->initialized = TRUE;
 	g_signal_emit (self, signals[INITIALIZED], 0, TRUE);
 
@@ -275,14 +372,18 @@ query_properties (NMBluezDevice *self)
 	}
 }
 
+/********************************************************************/
+
 NMBluezDevice *
-nm_bluez_device_new (const char *path)
+nm_bluez_device_new (const char *path, NMConnectionProvider *provider)
 {
 	NMBluezDevice *self;
 	NMBluezDevicePrivate *priv;
 	NMDBusManager *dbus_mgr;
 	DBusGConnection *connection;
 
+	g_return_val_if_fail (path != NULL, NULL);
+	g_return_val_if_fail (provider != NULL, NULL);
 
 	self = (NMBluezDevice *) g_object_new (NM_TYPE_BLUEZ_DEVICE,
 	                                       NM_BLUEZ_DEVICE_PATH, path,
@@ -291,6 +392,29 @@ nm_bluez_device_new (const char *path)
 		return NULL;
 
 	priv = NM_BLUEZ_DEVICE_GET_PRIVATE (self);
+
+	priv->provider = provider;
+
+	g_signal_connect (priv->provider,
+	                  NM_CP_SIGNAL_CONNECTION_ADDED,
+	                  G_CALLBACK (cp_connection_added),
+	                  self);
+
+	g_signal_connect (priv->provider,
+	                  NM_CP_SIGNAL_CONNECTION_REMOVED,
+	                  G_CALLBACK (cp_connection_removed),
+	                  self);
+
+	g_signal_connect (priv->provider,
+	                  NM_CP_SIGNAL_CONNECTION_UPDATED,
+	                  G_CALLBACK (cp_connection_updated),
+	                  self);
+
+	g_signal_connect (priv->provider,
+	                  NM_CP_SIGNAL_CONNECTIONS_LOADED,
+	                  G_CALLBACK (cp_connections_loaded),
+	                  self);
+
 	dbus_mgr = nm_dbus_manager_get ();
 	connection = nm_dbus_manager_get_connection (dbus_mgr);
 
@@ -319,6 +443,24 @@ nm_bluez_device_init (NMBluezDevice *self)
 }
 
 static void
+dispose (GObject *object)
+{
+	NMBluezDevice *self = NM_BLUEZ_DEVICE (object);
+	NMBluezDevicePrivate *priv = NM_BLUEZ_DEVICE_GET_PRIVATE (self);
+
+	g_slist_foreach (priv->connections, (GFunc) g_object_unref, NULL);
+	g_slist_free (priv->connections);
+	priv->connections = NULL;
+
+	g_signal_handlers_disconnect_by_func (priv->provider, cp_connection_added, self);
+	g_signal_handlers_disconnect_by_func (priv->provider, cp_connection_removed, self);
+	g_signal_handlers_disconnect_by_func (priv->provider, cp_connection_updated, self);
+	g_signal_handlers_disconnect_by_func (priv->provider, cp_connections_loaded, self);
+
+	G_OBJECT_CLASS (nm_bluez_device_parent_class)->dispose (object);
+}
+
+static void
 finalize (GObject *object)
 {
 	NMBluezDevicePrivate *priv = NM_BLUEZ_DEVICE_GET_PRIVATE (object);
@@ -389,6 +531,7 @@ nm_bluez_device_class_init (NMBluezDeviceClass *config_class)
 	/* virtual methods */
 	object_class->get_property = get_property;
 	object_class->set_property = set_property;
+	object_class->dispose = dispose;
 	object_class->finalize = finalize;
 
 	/* Properties */
diff --git a/src/bluez-manager/nm-bluez-device.h b/src/bluez-manager/nm-bluez-device.h
index 8a6b3597..f5fdbf5f 100644
--- a/src/bluez-manager/nm-bluez-device.h
+++ b/src/bluez-manager/nm-bluez-device.h
@@ -15,7 +15,7 @@
  * with this program; if not, write to the Free Software Foundation, Inc.,
  * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
  *
- * Copyright (C) 2009 Red Hat, Inc.
+ * Copyright (C) 2009 - 2012 Red Hat, Inc.
  */
 
 #ifndef NM_BLUEZ_DEVICE_H
@@ -24,6 +24,9 @@
 #include <glib.h>
 #include <glib-object.h>
 
+#include "nm-connection.h"
+#include "nm-connection-provider.h"
+
 #define NM_TYPE_BLUEZ_DEVICE            (nm_bluez_device_get_type ())
 #define NM_BLUEZ_DEVICE(obj)            (G_TYPE_CHECK_INSTANCE_CAST ((obj), NM_TYPE_BLUEZ_DEVICE, NMBluezDevice))
 #define NM_BLUEZ_DEVICE_CLASS(klass)    (G_TYPE_CHECK_CLASS_CAST ((klass), NM_TYPE_BLUEZ_DEVICE, NMBluezDeviceClass))
@@ -53,7 +56,7 @@ typedef struct {
 
 GType nm_bluez_device_get_type (void);
 
-NMBluezDevice *nm_bluez_device_new (const char *path);
+NMBluezDevice *nm_bluez_device_new (const char *path, NMConnectionProvider *provider);
 
 const char *nm_bluez_device_get_path (NMBluezDevice *self);
 
diff --git a/src/bluez-manager/nm-bluez-manager.c b/src/bluez-manager/nm-bluez-manager.c
index 942d0f34..e485ffe4 100644
--- a/src/bluez-manager/nm-bluez-manager.c
+++ b/src/bluez-manager/nm-bluez-manager.c
@@ -16,7 +16,7 @@
  * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
  *
  * Copyright (C) 2007 - 2008 Novell, Inc.
- * Copyright (C) 2007 - 2010 Red Hat, Inc.
+ * Copyright (C) 2007 - 2012 Red Hat, Inc.
  */
 
 #include <signal.h>
@@ -37,6 +37,8 @@ typedef struct {
 	NMDBusManager *dbus_mgr;
 	gulong name_owner_changed_id;
 
+	NMConnectionProvider *provider;
+
 	DBusGProxy *proxy;
 
 	NMBluezAdapter *adapter;
@@ -165,7 +167,7 @@ default_adapter_changed (DBusGProxy *proxy, const char *path, NMBluezManager *se
 
 	/* Add the new default adapter */
 	if (path) {
-		priv->adapter = nm_bluez_adapter_new (path);
+		priv->adapter = nm_bluez_adapter_new (path, priv->provider);
 		g_signal_connect (priv->adapter, "initialized", G_CALLBACK (adapter_initialized), self);
 	}
 }
@@ -238,12 +240,6 @@ bluez_connect (NMBluezManager *self)
 }
 
 static void
-remove_all_devices (NMBluezManager *self, gboolean do_signal)
-{
-	/* FIXME: do something */
-}
-
-static void
 name_owner_changed_cb (NMDBusManager *dbus_mgr,
                        const char *name,
                        const char *old_owner,
@@ -251,6 +247,7 @@ name_owner_changed_cb (NMDBusManager *dbus_mgr,
                        gpointer user_data)
 {
 	NMBluezManager *self = NM_BLUEZ_MANAGER (user_data);
+	NMBluezManagerPrivate *priv = NM_BLUEZ_MANAGER_GET_PRIVATE (self);
 	gboolean old_owner_good = (old_owner && strlen (old_owner));
 	gboolean new_owner_good = (new_owner && strlen (new_owner));
 
@@ -260,8 +257,13 @@ name_owner_changed_cb (NMDBusManager *dbus_mgr,
 
 	if (!old_owner_good && new_owner_good)
 		query_default_adapter (self);
-	else if (old_owner_good && !new_owner_good)
-		remove_all_devices (self, TRUE);
+	else if (old_owner_good && !new_owner_good) {
+		/* Throwing away the adapter removes all devices too */
+		if (priv->adapter) {
+			g_object_unref (priv->adapter);
+			priv->adapter = NULL;
+		}
+	}
 }
 
 static void
@@ -274,7 +276,10 @@ bluez_cleanup (NMBluezManager *self, gboolean do_signal)
 		priv->proxy = NULL;
 	}
 
-	remove_all_devices (self, do_signal);
+	if (priv->adapter) {
+		g_object_unref (priv->adapter);
+		priv->adapter = NULL;
+	}
 }
 
 static void
@@ -290,24 +295,22 @@ dbus_connection_changed_cb (NMDBusManager *dbus_mgr,
 		bluez_connect (self);
 }
 
+/****************************************************************/
 
 NMBluezManager *
-nm_bluez_manager_new (void)
-{
-	return NM_BLUEZ_MANAGER (g_object_new (NM_TYPE_BLUEZ_MANAGER, NULL));
-}
-
-NMBluezManager *
-nm_bluez_manager_get (void)
+nm_bluez_manager_get (NMConnectionProvider *provider)
 {
 	static NMBluezManager *singleton = NULL;
 
-	if (!singleton)
-		singleton = nm_bluez_manager_new ();
-	else
-		g_object_ref (singleton);
+	if (singleton)
+		return g_object_ref (singleton);
 
+	singleton = (NMBluezManager *) g_object_new (NM_TYPE_BLUEZ_MANAGER, NULL);
 	g_assert (singleton);
+
+	/* Cache the connection provider for NMBluezAdapter objects */
+	NM_BLUEZ_MANAGER_GET_PRIVATE (singleton)->provider = provider;
+
 	return singleton;
 }
 
@@ -333,13 +336,20 @@ nm_bluez_manager_init (NMBluezManager *self)
 }
 
 static void
-finalize (GObject *object)
+dispose (GObject *object)
 {
 	NMBluezManager *self = NM_BLUEZ_MANAGER (object);
+	NMBluezManagerPrivate *priv = NM_BLUEZ_MANAGER_GET_PRIVATE (self);
 
 	bluez_cleanup (self, FALSE);
 
-	G_OBJECT_CLASS (nm_bluez_manager_parent_class)->finalize (object);
+	if (priv->dbus_mgr) {
+		g_signal_handlers_disconnect_by_func (priv->dbus_mgr, name_owner_changed_cb, self);
+		g_signal_handlers_disconnect_by_func (priv->dbus_mgr, dbus_connection_changed_cb, self);
+		g_object_unref (priv->dbus_mgr);
+	}
+
+	G_OBJECT_CLASS (nm_bluez_manager_parent_class)->dispose (object);
 }
 
 static void
@@ -350,11 +360,11 @@ nm_bluez_manager_class_init (NMBluezManagerClass *klass)
 	g_type_class_add_private (klass, sizeof (NMBluezManagerPrivate));
 
 	/* virtual methods */
-	object_class->finalize = finalize;
+	object_class->dispose = dispose;
 
 	/* Signals */
 	signals[BDADDR_ADDED] =
-		g_signal_new ("bdaddr-added",
+		g_signal_new (NM_BLUEZ_MANAGER_BDADDR_ADDED,
 		              G_OBJECT_CLASS_TYPE (object_class),
 		              G_SIGNAL_RUN_FIRST,
 		              G_STRUCT_OFFSET (NMBluezManagerClass, bdaddr_added),
@@ -363,7 +373,7 @@ nm_bluez_manager_class_init (NMBluezManagerClass *klass)
 		              G_TYPE_NONE, 4, G_TYPE_STRING, G_TYPE_STRING, G_TYPE_STRING, G_TYPE_UINT);
 
 	signals[BDADDR_REMOVED] =
-		g_signal_new ("bdaddr-removed",
+		g_signal_new (NM_BLUEZ_MANAGER_BDADDR_REMOVED,
 		              G_OBJECT_CLASS_TYPE (object_class),
 		              G_SIGNAL_RUN_FIRST,
 		              G_STRUCT_OFFSET (NMBluezManagerClass, bdaddr_removed),
diff --git a/src/bluez-manager/nm-bluez-manager.h b/src/bluez-manager/nm-bluez-manager.h
index 9cfab1b7..1549e699 100644
--- a/src/bluez-manager/nm-bluez-manager.h
+++ b/src/bluez-manager/nm-bluez-manager.h
@@ -16,7 +16,7 @@
  * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
  *
  * Copyright (C) 2007 - 2008 Novell, Inc.
- * Copyright (C) 2007 - 2009 Red Hat, Inc.
+ * Copyright (C) 2007 - 2012 Red Hat, Inc.
  */
 
 #ifndef NM_BLUEZ_MANAGER_H
@@ -25,6 +25,8 @@
 #include <glib.h>
 #include <glib-object.h>
 
+#include  "nm-connection-provider.h"
+
 G_BEGIN_DECLS
 
 #define NM_TYPE_BLUEZ_MANAGER            (nm_bluez_manager_get_type ())
@@ -34,6 +36,9 @@ G_BEGIN_DECLS
 #define NM_IS_BLUEZ_MANAGER_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((obj), NM_TYPE_BLUEZ_MANAGER))
 #define NM_BLUEZ_MANAGER_GET_CLASS(obj)  (G_TYPE_INSTANCE_GET_CLASS ((obj), NM_TYPE_BLUEZ_MANAGER, NMBluezManagerClass))
 
+#define NM_BLUEZ_MANAGER_BDADDR_ADDED   "bdaddr-added"
+#define NM_BLUEZ_MANAGER_BDADDR_REMOVED "bdaddr-removed"
+
 typedef struct {
 	GObject parent;
 } NMBluezManager;
@@ -55,8 +60,8 @@ typedef struct {
 
 GType nm_bluez_manager_get_type (void);
 
-NMBluezManager *nm_bluez_manager_new (void);
-NMBluezManager *nm_bluez_manager_get (void);
+NMBluezManager *nm_bluez_manager_get (NMConnectionProvider *provider);
+
 void nm_bluez_manager_query_devices (NMBluezManager *manager);
 
 #endif /* NM_BLUEZ_MANAGER_H */
diff --git a/src/dhcp-manager/Makefile.am b/src/dhcp-manager/Makefile.am
index ce34c416..11560fde 100644
--- a/src/dhcp-manager/Makefile.am
+++ b/src/dhcp-manager/Makefile.am
@@ -7,6 +7,7 @@ INCLUDES = \
 	-I${top_srcdir}/src/generated \
 	-I${top_builddir}/src/generated \
 	-I${top_srcdir}/src/logging \
+	-I${top_srcdir}/src/posix-signals \
 	-I${top_srcdir}/libnm-util \
 	-I${top_builddir}/libnm-util \
 	-I${top_srcdir}/src
@@ -33,6 +34,7 @@ libdhcp_dhclient_la_CPPFLAGS = \
 
 libdhcp_dhclient_la_LIBADD = \
 	$(top_builddir)/src/logging/libnm-logging.la \
+	$(top_builddir)/src/posix-signals/libnm-posix-signals.la \
 	$(top_builddir)/libnm-util/libnm-util.la \
 	$(DBUS_LIBS) \
 	$(GLIB_LIBS)
@@ -58,6 +60,7 @@ libdhcp_manager_la_CPPFLAGS = \
 
 libdhcp_manager_la_LIBADD = \
 	$(top_builddir)/src/logging/libnm-logging.la \
+	$(top_builddir)/src/posix-signals/libnm-posix-signals.la \
 	$(builddir)/libdhcp-dhclient.la \
 	$(DBUS_LIBS) \
 	$(GLIB_LIBS)
diff --git a/src/dhcp-manager/Makefile.in b/src/dhcp-manager/Makefile.in
index 4c389562..3d71a405 100644
--- a/src/dhcp-manager/Makefile.in
+++ b/src/dhcp-manager/Makefile.in
@@ -47,7 +47,7 @@ am__aclocal_m4_deps = $(top_srcdir)/m4/compiler_warnings.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)/configure.ac
+	$(top_srcdir)/m4/vapigen.m4 $(top_srcdir)/configure.ac
 am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \
 	$(ACLOCAL_M4)
 mkinstalldirs = $(install_sh) -d
@@ -58,6 +58,7 @@ LTLIBRARIES = $(noinst_LTLIBRARIES)
 am__DEPENDENCIES_1 =
 libdhcp_dhclient_la_DEPENDENCIES =  \
 	$(top_builddir)/src/logging/libnm-logging.la \
+	$(top_builddir)/src/posix-signals/libnm-posix-signals.la \
 	$(top_builddir)/libnm-util/libnm-util.la $(am__DEPENDENCIES_1) \
 	$(am__DEPENDENCIES_1)
 am_libdhcp_dhclient_la_OBJECTS =  \
@@ -69,6 +70,7 @@ am__v_lt_ = $(am__v_lt_$(AM_DEFAULT_VERBOSITY))
 am__v_lt_0 = --silent
 libdhcp_manager_la_DEPENDENCIES =  \
 	$(top_builddir)/src/logging/libnm-logging.la \
+	$(top_builddir)/src/posix-signals/libnm-posix-signals.la \
 	$(builddir)/libdhcp-dhclient.la $(am__DEPENDENCIES_1) \
 	$(am__DEPENDENCIES_1)
 am_libdhcp_manager_la_OBJECTS = libdhcp_manager_la-nm-dhcp-client.lo \
@@ -217,6 +219,10 @@ INTLTOOL_EXTRACT = @INTLTOOL_EXTRACT@
 INTLTOOL_MERGE = @INTLTOOL_MERGE@
 INTLTOOL_PERL = @INTLTOOL_PERL@
 INTLTOOL_UPDATE = @INTLTOOL_UPDATE@
+INTLTOOL_V_MERGE = @INTLTOOL_V_MERGE@
+INTLTOOL_V_MERGE_OPTIONS = @INTLTOOL_V_MERGE_OPTIONS@
+INTLTOOL__v_MERGE_ = @INTLTOOL__v_MERGE_@
+INTLTOOL__v_MERGE_0 = @INTLTOOL__v_MERGE_0@
 INTL_MACOSX_LIBS = @INTL_MACOSX_LIBS@
 INTROSPECTION_CFLAGS = @INTROSPECTION_CFLAGS@
 INTROSPECTION_COMPILER = @INTROSPECTION_COMPILER@
@@ -312,6 +318,9 @@ UDEV_BASE_DIR = @UDEV_BASE_DIR@
 USE_NLS = @USE_NLS@
 UUID_CFLAGS = @UUID_CFLAGS@
 UUID_LIBS = @UUID_LIBS@
+VAPIGEN = @VAPIGEN@
+VAPIGEN_MAKEFILE = @VAPIGEN_MAKEFILE@
+VAPIGEN_VAPIDIR = @VAPIGEN_VAPIDIR@
 VERSION = @VERSION@
 XGETTEXT = @XGETTEXT@
 XGETTEXT_015 = @XGETTEXT_015@
@@ -350,6 +359,8 @@ htmldir = @htmldir@
 includedir = @includedir@
 infodir = @infodir@
 install_sh = @install_sh@
+intltool__v_merge_options_ = @intltool__v_merge_options_@
+intltool__v_merge_options_0 = @intltool__v_merge_options_0@
 libdir = @libdir@
 libexecdir = @libexecdir@
 localedir = @localedir@
@@ -378,6 +389,7 @@ INCLUDES = \
 	-I${top_srcdir}/src/generated \
 	-I${top_builddir}/src/generated \
 	-I${top_srcdir}/src/logging \
+	-I${top_srcdir}/src/posix-signals \
 	-I${top_srcdir}/libnm-util \
 	-I${top_builddir}/libnm-util \
 	-I${top_srcdir}/src
@@ -403,6 +415,7 @@ libdhcp_dhclient_la_CPPFLAGS = \
 
 libdhcp_dhclient_la_LIBADD = \
 	$(top_builddir)/src/logging/libnm-logging.la \
+	$(top_builddir)/src/posix-signals/libnm-posix-signals.la \
 	$(top_builddir)/libnm-util/libnm-util.la \
 	$(DBUS_LIBS) \
 	$(GLIB_LIBS)
@@ -428,6 +441,7 @@ libdhcp_manager_la_CPPFLAGS = \
 
 libdhcp_manager_la_LIBADD = \
 	$(top_builddir)/src/logging/libnm-logging.la \
+	$(top_builddir)/src/posix-signals/libnm-posix-signals.la \
 	$(builddir)/libdhcp-dhclient.la \
 	$(DBUS_LIBS) \
 	$(GLIB_LIBS)
diff --git a/src/dhcp-manager/nm-dhcp-client.c b/src/dhcp-manager/nm-dhcp-client.c
index 16c6dd77..ea4084ac 100644
--- a/src/dhcp-manager/nm-dhcp-client.c
+++ b/src/dhcp-manager/nm-dhcp-client.c
@@ -570,8 +570,20 @@ nm_dhcp_client_new_options (NMDHCPClient *self,
 	g_hash_table_remove_all (priv->options);
 	g_hash_table_foreach (options, copy_option, priv->options);
 
-	if (old_state == new_state)
-		return;
+	if (old_state == new_state) {
+		/* dhclient will stay in the same state (or, really, provide the same
+		 * reason) for operations like RENEW and REBIND.  We need to ensure
+		 * that triggers various DHCP lease change code, so we need to pass
+		 * along same-state transitions for these states.
+		 */
+		if (   new_state != DHC_BOUND4
+		    && new_state != DHC_RENEW4
+		    && new_state != DHC_REBIND4
+		    && new_state != DHC_BOUND6
+		    && new_state != DHC_RENEW6
+		    && new_state != DHC_REBIND6)
+			return;
+	}
 
 	/* Handle changed device state */
 	if (state_is_bound (new_state)) {
@@ -1217,12 +1229,6 @@ ip6_options_to_config (NMDHCPClient *self)
 		return NULL;
 	}
 
-	addr = nm_ip6_address_new ();
-	if (!addr) {
-		nm_log_warn (LOGD_DHCP6, "(%s): couldn't allocate memory for an IP6 Address!", priv->iface);
-		goto error;
-	}
-
 	str = g_hash_table_lookup (priv->options, "new_ip6_address");
 	if (str) {
 		if (!inet_pton (AF_INET6, str, &tmp_addr)) {
@@ -1231,35 +1237,17 @@ ip6_options_to_config (NMDHCPClient *self)
 			goto error;
 		}
 
+		addr = nm_ip6_address_new ();
+		g_assert (addr);
 		nm_ip6_address_set_address (addr, &tmp_addr);
-		nm_log_info (LOGD_DHCP6, "  address %s", str);
-	} else {
-		/* No address in managed mode is a hard error */
-		if (priv->info_only == FALSE)
-			goto error;
-
-		/* But "info-only" setups don't necessarily need an address */
-		nm_ip6_address_unref (addr);
-		addr = NULL;
-	}
-
-	/* Only care about prefix if we got an address */
-	if (addr) {
-		str = g_hash_table_lookup (priv->options, "new_ip6_prefixlen");
-		if (str) {
-			long unsigned int prefix;
-
-			errno = 0;
-			prefix = strtoul (str, NULL, 10);
-			if (errno != 0 || prefix > 128)
-				goto error;
-
-			nm_ip6_address_set_prefix (addr, (guint32) prefix);
-			nm_log_info (LOGD_DHCP6, "  prefix %lu", prefix);
-		}
+		/* DHCPv6 IA_NA assignments are single address only */
+		nm_ip6_address_set_prefix (addr, 128);
+		nm_log_info (LOGD_DHCP6, "  address %s/128", str);
 
 		nm_ip6_config_take_address (ip6_config, addr);
-		addr = NULL;
+	} else if (priv->info_only == FALSE) {
+		/* No address in Managed mode is a hard error */
+		goto error;
 	}
 
 	str = g_hash_table_lookup (priv->options, "new_host_name");
@@ -1288,8 +1276,6 @@ ip6_options_to_config (NMDHCPClient *self)
 	return ip6_config;
 
 error:
-	if (addr)
-		nm_ip6_address_unref (addr);
 	g_object_unref (ip6_config);
 	return NULL;
 }
diff --git a/src/dhcp-manager/nm-dhcp-dhclient.c b/src/dhcp-manager/nm-dhcp-dhclient.c
index 09321396..043cd63d 100644
--- a/src/dhcp-manager/nm-dhcp-dhclient.c
+++ b/src/dhcp-manager/nm-dhcp-dhclient.c
@@ -15,7 +15,7 @@
  * with this program; if not, write to the Free Software Foundation, Inc.,
  * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
  *
- * Copyright (C) 2005 - 2010 Red Hat, Inc.
+ * Copyright (C) 2005 - 2012 Red Hat, Inc.
  */
 
 #define _XOPEN_SOURCE
@@ -40,6 +40,7 @@
 #include "nm-utils.h"
 #include "nm-logging.h"
 #include "nm-dhcp-dhclient-utils.h"
+#include "nm-posix-signals.h"
 
 G_DEFINE_TYPE (NMDHCPDhclient, nm_dhcp_dhclient, NM_TYPE_DHCP_CLIENT)
 
@@ -333,6 +334,7 @@ merge_dhclient_config (const char *iface,
 	g_assert (new);
 	success = g_file_set_contents (conf_file, new, -1, error);
 	g_free (new);
+	g_free (orig);
 
 	return success;
 }
@@ -407,6 +409,12 @@ dhclient_child_setup (gpointer user_data G_GNUC_UNUSED)
 	/* We are in the child process at this point */
 	pid_t pid = getpid ();
 	setpgid (pid, pid);
+
+	/*
+	 * We blocked signals in main(). We need to restore original signal
+	 * mask for dhclient here so that it can receive signals.
+	 */
+	nm_unblock_posix_signals (NULL);
 }
 
 static GPid
diff --git a/src/dhcp-manager/nm-dhcp-dhcpcd.c b/src/dhcp-manager/nm-dhcp-dhcpcd.c
index 237661fe..dc9bee13 100644
--- a/src/dhcp-manager/nm-dhcp-dhcpcd.c
+++ b/src/dhcp-manager/nm-dhcp-dhcpcd.c
@@ -35,6 +35,7 @@
 #include "nm-dhcp-dhcpcd.h"
 #include "nm-utils.h"
 #include "nm-logging.h"
+#include "nm-posix-signals.h"
 
 G_DEFINE_TYPE (NMDHCPDhcpcd, nm_dhcp_dhcpcd, NM_TYPE_DHCP_CLIENT)
 
@@ -83,6 +84,12 @@ dhcpcd_child_setup (gpointer user_data G_GNUC_UNUSED)
 	/* We are in the child process at this point */
 	pid_t pid = getpid ();
 	setpgid (pid, pid);
+
+	/*
+	 * We blocked signals in main(). We need to restore original signal
+	 * mask for dhcpcd here so that it can receive signals.
+	 */
+	nm_unblock_posix_signals (NULL);
 }
 
 static GPid
diff --git a/src/dhcp-manager/tests/Makefile.in b/src/dhcp-manager/tests/Makefile.in
index 20422cdb..d325dd9e 100644
--- a/src/dhcp-manager/tests/Makefile.in
+++ b/src/dhcp-manager/tests/Makefile.in
@@ -48,7 +48,7 @@ am__aclocal_m4_deps = $(top_srcdir)/m4/compiler_warnings.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)/configure.ac
+	$(top_srcdir)/m4/vapigen.m4 $(top_srcdir)/configure.ac
 am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \
 	$(ACLOCAL_M4)
 mkinstalldirs = $(install_sh) -d
@@ -169,6 +169,10 @@ INTLTOOL_EXTRACT = @INTLTOOL_EXTRACT@
 INTLTOOL_MERGE = @INTLTOOL_MERGE@
 INTLTOOL_PERL = @INTLTOOL_PERL@
 INTLTOOL_UPDATE = @INTLTOOL_UPDATE@
+INTLTOOL_V_MERGE = @INTLTOOL_V_MERGE@
+INTLTOOL_V_MERGE_OPTIONS = @INTLTOOL_V_MERGE_OPTIONS@
+INTLTOOL__v_MERGE_ = @INTLTOOL__v_MERGE_@
+INTLTOOL__v_MERGE_0 = @INTLTOOL__v_MERGE_0@
 INTL_MACOSX_LIBS = @INTL_MACOSX_LIBS@
 INTROSPECTION_CFLAGS = @INTROSPECTION_CFLAGS@
 INTROSPECTION_COMPILER = @INTROSPECTION_COMPILER@
@@ -264,6 +268,9 @@ UDEV_BASE_DIR = @UDEV_BASE_DIR@
 USE_NLS = @USE_NLS@
 UUID_CFLAGS = @UUID_CFLAGS@
 UUID_LIBS = @UUID_LIBS@
+VAPIGEN = @VAPIGEN@
+VAPIGEN_MAKEFILE = @VAPIGEN_MAKEFILE@
+VAPIGEN_VAPIDIR = @VAPIGEN_VAPIDIR@
 VERSION = @VERSION@
 XGETTEXT = @XGETTEXT@
 XGETTEXT_015 = @XGETTEXT_015@
@@ -302,6 +309,8 @@ htmldir = @htmldir@
 includedir = @includedir@
 infodir = @infodir@
 install_sh = @install_sh@
+intltool__v_merge_options_ = @intltool__v_merge_options_@
+intltool__v_merge_options_0 = @intltool__v_merge_options_0@
 libdir = @libdir@
 libexecdir = @libexecdir@
 localedir = @localedir@
diff --git a/src/dns-manager/Makefile.am b/src/dns-manager/Makefile.am
index 331f85c4..fd31b140 100644
--- a/src/dns-manager/Makefile.am
+++ b/src/dns-manager/Makefile.am
@@ -1,5 +1,6 @@
 INCLUDES = \
 	-I${top_srcdir}/src/logging \
+	-I${top_srcdir}/src/posix-signals \
 	-I${top_srcdir}/libnm-util \
 	-I${top_builddir}/libnm-util \
 	-I${top_srcdir}/src \
@@ -28,6 +29,7 @@ libdns_manager_la_CPPFLAGS = \
 
 libdns_manager_la_LIBADD = \
 	$(top_builddir)/src/logging/libnm-logging.la \
+	$(top_builddir)/src/posix-signals/libnm-posix-signals.la \
 	$(LIBNL_LIBS) \
 	$(DBUS_LIBS) \
 	$(GLIB_LIBS)
diff --git a/src/dns-manager/Makefile.in b/src/dns-manager/Makefile.in
index c9b8b0b3..ddcce666 100644
--- a/src/dns-manager/Makefile.in
+++ b/src/dns-manager/Makefile.in
@@ -47,7 +47,7 @@ am__aclocal_m4_deps = $(top_srcdir)/m4/compiler_warnings.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)/configure.ac
+	$(top_srcdir)/m4/vapigen.m4 $(top_srcdir)/configure.ac
 am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \
 	$(ACLOCAL_M4)
 mkinstalldirs = $(install_sh) -d
@@ -58,6 +58,7 @@ LTLIBRARIES = $(noinst_LTLIBRARIES)
 am__DEPENDENCIES_1 =
 libdns_manager_la_DEPENDENCIES =  \
 	$(top_builddir)/src/logging/libnm-logging.la \
+	$(top_builddir)/src/posix-signals/libnm-posix-signals.la \
 	$(am__DEPENDENCIES_1) $(am__DEPENDENCIES_1) \
 	$(am__DEPENDENCIES_1)
 am_libdns_manager_la_OBJECTS = libdns_manager_la-nm-dns-manager.lo \
@@ -172,6 +173,10 @@ INTLTOOL_EXTRACT = @INTLTOOL_EXTRACT@
 INTLTOOL_MERGE = @INTLTOOL_MERGE@
 INTLTOOL_PERL = @INTLTOOL_PERL@
 INTLTOOL_UPDATE = @INTLTOOL_UPDATE@
+INTLTOOL_V_MERGE = @INTLTOOL_V_MERGE@
+INTLTOOL_V_MERGE_OPTIONS = @INTLTOOL_V_MERGE_OPTIONS@
+INTLTOOL__v_MERGE_ = @INTLTOOL__v_MERGE_@
+INTLTOOL__v_MERGE_0 = @INTLTOOL__v_MERGE_0@
 INTL_MACOSX_LIBS = @INTL_MACOSX_LIBS@
 INTROSPECTION_CFLAGS = @INTROSPECTION_CFLAGS@
 INTROSPECTION_COMPILER = @INTROSPECTION_COMPILER@
@@ -267,6 +272,9 @@ UDEV_BASE_DIR = @UDEV_BASE_DIR@
 USE_NLS = @USE_NLS@
 UUID_CFLAGS = @UUID_CFLAGS@
 UUID_LIBS = @UUID_LIBS@
+VAPIGEN = @VAPIGEN@
+VAPIGEN_MAKEFILE = @VAPIGEN_MAKEFILE@
+VAPIGEN_VAPIDIR = @VAPIGEN_VAPIDIR@
 VERSION = @VERSION@
 XGETTEXT = @XGETTEXT@
 XGETTEXT_015 = @XGETTEXT_015@
@@ -305,6 +313,8 @@ htmldir = @htmldir@
 includedir = @includedir@
 infodir = @infodir@
 install_sh = @install_sh@
+intltool__v_merge_options_ = @intltool__v_merge_options_@
+intltool__v_merge_options_0 = @intltool__v_merge_options_0@
 libdir = @libdir@
 libexecdir = @libexecdir@
 localedir = @localedir@
@@ -327,6 +337,7 @@ top_builddir = @top_builddir@
 top_srcdir = @top_srcdir@
 INCLUDES = \
 	-I${top_srcdir}/src/logging \
+	-I${top_srcdir}/src/posix-signals \
 	-I${top_srcdir}/libnm-util \
 	-I${top_builddir}/libnm-util \
 	-I${top_srcdir}/src \
@@ -354,6 +365,7 @@ libdns_manager_la_CPPFLAGS = \
 
 libdns_manager_la_LIBADD = \
 	$(top_builddir)/src/logging/libnm-logging.la \
+	$(top_builddir)/src/posix-signals/libnm-posix-signals.la \
 	$(LIBNL_LIBS) \
 	$(DBUS_LIBS) \
 	$(GLIB_LIBS)
diff --git a/src/dns-manager/nm-dns-manager.c b/src/dns-manager/nm-dns-manager.c
index 6272e374..38ef08ea 100644
--- a/src/dns-manager/nm-dns-manager.c
+++ b/src/dns-manager/nm-dns-manager.c
@@ -16,7 +16,7 @@
  * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
  *
  * Copyright (C) 2004 - 2005 Colin Walters <walters@redhat.com>
- * Copyright (C) 2004 - 2011 Red Hat, Inc.
+ * Copyright (C) 2004 - 2012 Red Hat, Inc.
  * Copyright (C) 2005 - 2008 Novell, Inc.
  *   and others
  */
@@ -42,6 +42,7 @@
 #include "nm-logging.h"
 #include "backends/nm-backend.h"
 #include "NetworkManagerUtils.h"
+#include "nm-posix-signals.h"
 
 #include "nm-dns-plugin.h"
 #include "nm-dns-dnsmasq.h"
@@ -61,6 +62,8 @@ G_DEFINE_TYPE(NMDnsManager, nm_dns_manager, G_TYPE_OBJECT)
                                        NM_TYPE_DNS_MANAGER, \
                                        NMDnsManagerPrivate))
 
+#define HASH_LEN 20
+
 typedef struct {
 	gboolean disposed;
 
@@ -70,14 +73,10 @@ typedef struct {
 	NMIP6Config *ip6_device_config;
 	GSList *configs;
 	char *hostname;
+	guint updates_queue;
 
-	/* poor man's hash; we assume that the IP4 config object won't change
-	 * after it's given to us, which is (at this time) a fair assumption. So
-	 * we track the order of the currently applied IP configs and if they
-	 * haven't changed we don't need to rewrite resolv.conf.
-	 */
-	#define HLEN 6
-	gpointer hash[HLEN];
+	guint8 hash[HASH_LEN];  /* SHA1 hash of current DNS config */
+	guint8 prev_hash[HASH_LEN];  /* Hash when begin_updates() was called */
 
 	GSList *plugins;
 
@@ -218,6 +217,12 @@ netconfig_child_setup (gpointer user_data G_GNUC_UNUSED)
 {
 	pid_t pid = getpid ();
 	setpgid (pid, pid);
+
+	/*
+	 * We blocked signals in main(). We need to restore original signal
+	 * mask for netconfig here so that it can receive signals.
+	 */
+	nm_unblock_posix_signals (NULL);
 }
 
 static GPid
@@ -529,34 +534,43 @@ out:
 }
 
 static void
-compute_hash (NMDnsManager *self, gpointer *hash)
+compute_hash (NMDnsManager *self, guint8 buffer[HASH_LEN])
 {
 	NMDnsManagerPrivate *priv = NM_DNS_MANAGER_GET_PRIVATE (self);
-	gpointer check[HLEN];
+	GChecksum *sum;
 	GSList *iter;
-	int i = 0;
+	gsize len = HASH_LEN;
 
-	memset (check, 0, sizeof (check));
+	sum = g_checksum_new (G_CHECKSUM_SHA1);
+	g_assert (len == g_checksum_type_get_length (G_CHECKSUM_SHA1));
 
 	if (priv->ip4_vpn_config)
-		check[i++] = priv->ip4_vpn_config;
+		nm_ip4_config_hash (priv->ip4_vpn_config, sum, TRUE);
 	if (priv->ip4_device_config)
-		check[i++] = priv->ip4_device_config;
+		nm_ip4_config_hash (priv->ip4_device_config, sum, TRUE);
 
 	if (priv->ip6_vpn_config)
-		check[i++] = priv->ip6_vpn_config;
+		nm_ip6_config_hash (priv->ip6_vpn_config, sum, TRUE);
 	if (priv->ip6_device_config)
-		check[i++] = priv->ip6_device_config;
+		nm_ip6_config_hash (priv->ip6_device_config, sum, TRUE);
 
-	/* Add two more "other" configs if any exist */
-	for (iter = priv->configs; iter && i < HLEN; iter = g_slist_next (iter)) {
-		if (   (iter->data != priv->ip4_vpn_config)
-		    && (iter->data != priv->ip4_device_config)
-		    && (iter->data != priv->ip6_vpn_config)
-		    && (iter->data != priv->ip6_device_config))
-			check[i++] = iter->data;
+	/* add any other configs we know about */
+	for (iter = priv->configs; iter; iter = g_slist_next (iter)) {
+		if (   (iter->data == priv->ip4_vpn_config)
+		    && (iter->data == priv->ip4_device_config)
+		    && (iter->data == priv->ip6_vpn_config)
+		    && (iter->data == priv->ip6_device_config))
+			continue;
+
+		if (NM_IS_IP4_CONFIG (iter->data))
+			nm_ip4_config_hash (NM_IP4_CONFIG (iter->data), sum, TRUE);
+		else if (NM_IS_IP6_CONFIG (iter->data))
+			nm_ip6_config_hash (NM_IP6_CONFIG (iter->data), sum, TRUE);
 	}
-	memcpy (hash, check, sizeof (check));
+
+	memset (buffer, 0, sizeof (buffer));
+	g_checksum_get_digest (sum, buffer, &len);
+	g_checksum_free (sum);
 }
 
 static gboolean
@@ -581,6 +595,8 @@ update_dns (NMDnsManager *self,
 
 	priv = NM_DNS_MANAGER_GET_PRIVATE (self);
 
+	nm_log_dbg (LOGD_DNS, "updating resolv.conf");
+
 	if (iface && (iface != priv->last_iface)) {
 		g_free (priv->last_iface);
 		priv->last_iface = g_strdup (iface);
@@ -784,23 +800,6 @@ plugin_failed (NMDnsPlugin *plugin, gpointer user_data)
 	}
 }
 
-static gboolean
-config_changed (NMDnsManager *self)
-{
-	NMDnsManagerPrivate *priv = NM_DNS_MANAGER_GET_PRIVATE (self);
-	gpointer check[HLEN];
-
-	/* We only store HLEN configs; so if there are actually more than that,
-	 * we have to assume that the config has changed.
-	 */
-	if (g_slist_length (priv->configs) > HLEN)
-		return TRUE;
-
-	/* Otherwise return TRUE if the configuration has changed */
-	compute_hash (self, check);
-	return memcmp (check, priv->hash, sizeof (check)) ? TRUE : FALSE;
-}
-
 gboolean
 nm_dns_manager_add_ip4_config (NMDnsManager *mgr,
                                const char *iface,
@@ -831,10 +830,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 (!config_changed (mgr))
-		return TRUE;
-
-	if (!update_dns (mgr, iface, FALSE, &error)) {
+	if (!priv->updates_queue && !update_dns (mgr, iface, FALSE, &error)) {
 		nm_log_warn (LOGD_DNS, "could not commit DNS changes: (%d) %s",
 		             error ? error->code : -1,
 		             error && error->message ? error->message : "(unknown)");
@@ -871,10 +867,7 @@ nm_dns_manager_remove_ip4_config (NMDnsManager *mgr,
 
 	g_object_unref (config);
 
-	if (!config_changed (mgr))
-		return TRUE;
-
-	if (!update_dns (mgr, iface, FALSE, &error)) {
+	if (!priv->updates_queue && !update_dns (mgr, iface, FALSE, &error)) {
 		nm_log_warn (LOGD_DNS, "could not commit DNS changes: (%d) %s",
 		             error ? error->code : -1,
 		             error && error->message ? error->message : "(unknown)");
@@ -901,8 +894,6 @@ nm_dns_manager_add_ip6_config (NMDnsManager *mgr,
 
 	switch (cfg_type) {
 	case NM_DNS_IP_CONFIG_TYPE_VPN:
-		/* FIXME: not quite yet... */
-		g_return_val_if_fail (cfg_type != NM_DNS_IP_CONFIG_TYPE_VPN, FALSE);
 		priv->ip6_vpn_config = config;
 		break;
 	case NM_DNS_IP_CONFIG_TYPE_BEST_DEVICE:
@@ -916,10 +907,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 (!config_changed (mgr))
-		return TRUE;
-
-	if (!update_dns (mgr, iface, FALSE, &error)) {
+	if (!priv->updates_queue && !update_dns (mgr, iface, FALSE, &error)) {
 		nm_log_warn (LOGD_DNS, "could not commit DNS changes: (%d) %s",
 		             error ? error->code : -1,
 		             error && error->message ? error->message : "(unknown)");
@@ -956,10 +944,7 @@ nm_dns_manager_remove_ip6_config (NMDnsManager *mgr,
 
 	g_object_unref (config);	
 
-	if (!config_changed (mgr))
-		return TRUE;
-
-	if (!update_dns (mgr, iface, FALSE, &error)) {
+	if (!priv->updates_queue && !update_dns (mgr, iface, FALSE, &error)) {
 		nm_log_warn (LOGD_DNS, "could not commit DNS changes: (%d) %s",
 		             error ? error->code : -1,
 		             error && error->message ? error->message : "(unknown)");
@@ -997,7 +982,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 (!update_dns (mgr, priv->last_iface, FALSE, &error)) {
+	if (!priv->updates_queue && !update_dns (mgr, priv->last_iface, FALSE, &error)) {
 		nm_log_warn (LOGD_DNS, "could not commit DNS changes: (%d) %s",
 		             error ? error->code : -1,
 		             error && error->message ? error->message : "(unknown)");
@@ -1005,6 +990,58 @@ nm_dns_manager_set_hostname (NMDnsManager *mgr,
 	}
 }
 
+void
+nm_dns_manager_begin_updates (NMDnsManager *mgr, const char *func)
+{
+	NMDnsManagerPrivate *priv;
+
+	g_return_if_fail (mgr != NULL);
+	priv = NM_DNS_MANAGER_GET_PRIVATE (mgr);
+
+	/* Save current hash when starting a new batch */
+	if (priv->updates_queue == 0)
+		memcpy (priv->prev_hash, priv->hash, sizeof (priv->hash));
+
+	priv->updates_queue++;
+
+	nm_log_dbg (LOGD_DNS, "(%s): queueing DNS updates (%d)", func, priv->updates_queue);
+}
+
+void
+nm_dns_manager_end_updates (NMDnsManager *mgr, const char *func)
+{
+	NMDnsManagerPrivate *priv;
+	GError *error = NULL;
+	gboolean changed;
+	guint8 new[HASH_LEN];
+
+	g_return_if_fail (mgr != NULL);
+
+	priv = NM_DNS_MANAGER_GET_PRIVATE (mgr);
+	g_return_if_fail (priv->updates_queue > 0);
+
+	compute_hash (mgr, new);
+	changed = (memcmp (new, priv->prev_hash, sizeof (new)) != 0) ? TRUE : FALSE;
+	nm_log_dbg (LOGD_DNS, "(%s): DNS configuration %s", __func__, changed ? "changed" : "did not change");
+
+	priv->updates_queue--;
+	if ((priv->updates_queue > 0) || (changed == FALSE)) {
+		nm_log_dbg (LOGD_DNS, "(%s): no DNS changes to commit (%d)", func, priv->updates_queue);
+		return;
+	}
+
+	/* 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)) {
+		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);
+	}
+
+	memset (priv->prev_hash, 0, sizeof (priv->prev_hash));
+}
+
 static void
 load_plugins (NMDnsManager *self, const char **plugins)
 {
@@ -1079,8 +1116,10 @@ nm_dns_manager_error_quark (void)
 }
 
 static void
-nm_dns_manager_init (NMDnsManager *mgr)
+nm_dns_manager_init (NMDnsManager *self)
 {
+	/* Set the initial hash */
+	compute_hash (self, NM_DNS_MANAGER_GET_PRIVATE (self)->hash);
 }
 
 static void
diff --git a/src/dns-manager/nm-dns-manager.h b/src/dns-manager/nm-dns-manager.h
index 25d2a981..f559865b 100644
--- a/src/dns-manager/nm-dns-manager.h
+++ b/src/dns-manager/nm-dns-manager.h
@@ -66,6 +66,10 @@ GType nm_dns_manager_get_type (void);
 
 NMDnsManager * nm_dns_manager_get (const char **plugins);
 
+/* Allow changes to be batched together */
+void nm_dns_manager_begin_updates (NMDnsManager *mgr, const char *func);
+void nm_dns_manager_end_updates (NMDnsManager *mgr, const char *func);
+
 gboolean nm_dns_manager_add_ip4_config (NMDnsManager *mgr,
                                         const char *iface,
                                         NMIP4Config *config,
diff --git a/src/dns-manager/nm-dns-plugin.c b/src/dns-manager/nm-dns-plugin.c
index e997948e..b26f2b94 100644
--- a/src/dns-manager/nm-dns-plugin.c
+++ b/src/dns-manager/nm-dns-plugin.c
@@ -13,7 +13,7 @@
  * with this program; if not, write to the Free Software Foundation, Inc.,
  * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
  *
- * Copyright (C) 2010 Red Hat, Inc.
+ * Copyright (C) 2010 - 2012 Red Hat, Inc.
  *
  */
 
@@ -27,6 +27,7 @@
 
 #include "nm-dns-plugin.h"
 #include "nm-logging.h"
+#include "nm-posix-signals.h"
 
 typedef struct {
 	gboolean disposed;
@@ -141,6 +142,12 @@ child_setup (gpointer user_data G_GNUC_UNUSED)
 	/* We are in the child process at this point */
 	pid_t pid = getpid ();
 	setpgid (pid, pid);
+
+	/*
+	 * We blocked signals in main(). We need to restore original signal
+	 * mask for DNS plugin here so that it can receive signals.
+	 */
+	nm_unblock_posix_signals (NULL);
 }
 
 GPid
diff --git a/src/dnsmasq-manager/Makefile.am b/src/dnsmasq-manager/Makefile.am
index 66bbdd83..8b7dd683 100644
--- a/src/dnsmasq-manager/Makefile.am
+++ b/src/dnsmasq-manager/Makefile.am
@@ -1,6 +1,7 @@
 INCLUDES = \
 	-I${top_srcdir}/libnm-util \
 	-I${top_srcdir}/src/logging \
+	-I${top_srcdir}/src/posix-signals \
 	-I${top_srcdir}/src \
 	-I${top_srcdir}/include
 
@@ -16,4 +17,5 @@ libdnsmasq_manager_la_CPPFLAGS = \
 
 libdnsmasq_manager_la_LIBADD = \
 	$(top_builddir)/src/logging/libnm-logging.la \
+	$(top_builddir)/src/posix-signals/libnm-posix-signals.la \
 	$(GLIB_LIBS)
diff --git a/src/dnsmasq-manager/Makefile.in b/src/dnsmasq-manager/Makefile.in
index bb1e56c0..6da083c4 100644
--- a/src/dnsmasq-manager/Makefile.in
+++ b/src/dnsmasq-manager/Makefile.in
@@ -47,7 +47,7 @@ am__aclocal_m4_deps = $(top_srcdir)/m4/compiler_warnings.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)/configure.ac
+	$(top_srcdir)/m4/vapigen.m4 $(top_srcdir)/configure.ac
 am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \
 	$(ACLOCAL_M4)
 mkinstalldirs = $(install_sh) -d
@@ -58,6 +58,7 @@ LTLIBRARIES = $(noinst_LTLIBRARIES)
 am__DEPENDENCIES_1 =
 libdnsmasq_manager_la_DEPENDENCIES =  \
 	$(top_builddir)/src/logging/libnm-logging.la \
+	$(top_builddir)/src/posix-signals/libnm-posix-signals.la \
 	$(am__DEPENDENCIES_1)
 am_libdnsmasq_manager_la_OBJECTS =  \
 	libdnsmasq_manager_la-nm-dnsmasq-manager.lo
@@ -168,6 +169,10 @@ INTLTOOL_EXTRACT = @INTLTOOL_EXTRACT@
 INTLTOOL_MERGE = @INTLTOOL_MERGE@
 INTLTOOL_PERL = @INTLTOOL_PERL@
 INTLTOOL_UPDATE = @INTLTOOL_UPDATE@
+INTLTOOL_V_MERGE = @INTLTOOL_V_MERGE@
+INTLTOOL_V_MERGE_OPTIONS = @INTLTOOL_V_MERGE_OPTIONS@
+INTLTOOL__v_MERGE_ = @INTLTOOL__v_MERGE_@
+INTLTOOL__v_MERGE_0 = @INTLTOOL__v_MERGE_0@
 INTL_MACOSX_LIBS = @INTL_MACOSX_LIBS@
 INTROSPECTION_CFLAGS = @INTROSPECTION_CFLAGS@
 INTROSPECTION_COMPILER = @INTROSPECTION_COMPILER@
@@ -263,6 +268,9 @@ UDEV_BASE_DIR = @UDEV_BASE_DIR@
 USE_NLS = @USE_NLS@
 UUID_CFLAGS = @UUID_CFLAGS@
 UUID_LIBS = @UUID_LIBS@
+VAPIGEN = @VAPIGEN@
+VAPIGEN_MAKEFILE = @VAPIGEN_MAKEFILE@
+VAPIGEN_VAPIDIR = @VAPIGEN_VAPIDIR@
 VERSION = @VERSION@
 XGETTEXT = @XGETTEXT@
 XGETTEXT_015 = @XGETTEXT_015@
@@ -301,6 +309,8 @@ htmldir = @htmldir@
 includedir = @includedir@
 infodir = @infodir@
 install_sh = @install_sh@
+intltool__v_merge_options_ = @intltool__v_merge_options_@
+intltool__v_merge_options_0 = @intltool__v_merge_options_0@
 libdir = @libdir@
 libexecdir = @libexecdir@
 localedir = @localedir@
@@ -324,6 +334,7 @@ top_srcdir = @top_srcdir@
 INCLUDES = \
 	-I${top_srcdir}/libnm-util \
 	-I${top_srcdir}/src/logging \
+	-I${top_srcdir}/src/posix-signals \
 	-I${top_srcdir}/src \
 	-I${top_srcdir}/include
 
@@ -338,6 +349,7 @@ libdnsmasq_manager_la_CPPFLAGS = \
 
 libdnsmasq_manager_la_LIBADD = \
 	$(top_builddir)/src/logging/libnm-logging.la \
+	$(top_builddir)/src/posix-signals/libnm-posix-signals.la \
 	$(GLIB_LIBS)
 
 all: all-am
diff --git a/src/dnsmasq-manager/nm-dnsmasq-manager.c b/src/dnsmasq-manager/nm-dnsmasq-manager.c
index ca2f9dc4..0b3b629f 100644
--- a/src/dnsmasq-manager/nm-dnsmasq-manager.c
+++ b/src/dnsmasq-manager/nm-dnsmasq-manager.c
@@ -15,7 +15,7 @@
  * with this program; if not, write to the Free Software Foundation, Inc.,
  * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
  *
- * Copyright (C) 2008 - 2010 Red Hat, Inc.
+ * Copyright (C) 2008 - 2012 Red Hat, Inc.
  */
 
 #include <config.h>
@@ -30,6 +30,7 @@
 #include "nm-dnsmasq-manager.h"
 #include "nm-logging.h"
 #include "nm-glib-compat.h"
+#include "nm-posix-signals.h"
 
 typedef struct {
 	char *iface;
@@ -356,6 +357,12 @@ dm_child_setup (gpointer user_data G_GNUC_UNUSED)
 	/* We are in the child process at this point */
 	pid_t pid = getpid ();
 	setpgid (pid, pid);
+
+	/*
+	 * We blocked signals in main(). We need to restore original signal
+	 * mask for dnsmasq here so that it can receive signals.
+	 */
+	nm_unblock_posix_signals (NULL);
 }
 
 static void
diff --git a/src/firewall-manager/Makefile.in b/src/firewall-manager/Makefile.in
index 821fa838..59ade87c 100644
--- a/src/firewall-manager/Makefile.in
+++ b/src/firewall-manager/Makefile.in
@@ -47,7 +47,7 @@ am__aclocal_m4_deps = $(top_srcdir)/m4/compiler_warnings.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)/configure.ac
+	$(top_srcdir)/m4/vapigen.m4 $(top_srcdir)/configure.ac
 am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \
 	$(ACLOCAL_M4)
 mkinstalldirs = $(install_sh) -d
@@ -168,6 +168,10 @@ INTLTOOL_EXTRACT = @INTLTOOL_EXTRACT@
 INTLTOOL_MERGE = @INTLTOOL_MERGE@
 INTLTOOL_PERL = @INTLTOOL_PERL@
 INTLTOOL_UPDATE = @INTLTOOL_UPDATE@
+INTLTOOL_V_MERGE = @INTLTOOL_V_MERGE@
+INTLTOOL_V_MERGE_OPTIONS = @INTLTOOL_V_MERGE_OPTIONS@
+INTLTOOL__v_MERGE_ = @INTLTOOL__v_MERGE_@
+INTLTOOL__v_MERGE_0 = @INTLTOOL__v_MERGE_0@
 INTL_MACOSX_LIBS = @INTL_MACOSX_LIBS@
 INTROSPECTION_CFLAGS = @INTROSPECTION_CFLAGS@
 INTROSPECTION_COMPILER = @INTROSPECTION_COMPILER@
@@ -263,6 +267,9 @@ UDEV_BASE_DIR = @UDEV_BASE_DIR@
 USE_NLS = @USE_NLS@
 UUID_CFLAGS = @UUID_CFLAGS@
 UUID_LIBS = @UUID_LIBS@
+VAPIGEN = @VAPIGEN@
+VAPIGEN_MAKEFILE = @VAPIGEN_MAKEFILE@
+VAPIGEN_VAPIDIR = @VAPIGEN_VAPIDIR@
 VERSION = @VERSION@
 XGETTEXT = @XGETTEXT@
 XGETTEXT_015 = @XGETTEXT_015@
@@ -301,6 +308,8 @@ htmldir = @htmldir@
 includedir = @includedir@
 infodir = @infodir@
 install_sh = @install_sh@
+intltool__v_merge_options_ = @intltool__v_merge_options_@
+intltool__v_merge_options_0 = @intltool__v_merge_options_0@
 libdir = @libdir@
 libexecdir = @libexecdir@
 localedir = @localedir@
diff --git a/src/generated/Makefile.in b/src/generated/Makefile.in
index 85a346be..966a9638 100644
--- a/src/generated/Makefile.in
+++ b/src/generated/Makefile.in
@@ -48,7 +48,7 @@ am__aclocal_m4_deps = $(top_srcdir)/m4/compiler_warnings.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)/configure.ac
+	$(top_srcdir)/m4/vapigen.m4 $(top_srcdir)/configure.ac
 am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \
 	$(ACLOCAL_M4)
 mkinstalldirs = $(install_sh) -d
@@ -167,6 +167,10 @@ INTLTOOL_EXTRACT = @INTLTOOL_EXTRACT@
 INTLTOOL_MERGE = @INTLTOOL_MERGE@
 INTLTOOL_PERL = @INTLTOOL_PERL@
 INTLTOOL_UPDATE = @INTLTOOL_UPDATE@
+INTLTOOL_V_MERGE = @INTLTOOL_V_MERGE@
+INTLTOOL_V_MERGE_OPTIONS = @INTLTOOL_V_MERGE_OPTIONS@
+INTLTOOL__v_MERGE_ = @INTLTOOL__v_MERGE_@
+INTLTOOL__v_MERGE_0 = @INTLTOOL__v_MERGE_0@
 INTL_MACOSX_LIBS = @INTL_MACOSX_LIBS@
 INTROSPECTION_CFLAGS = @INTROSPECTION_CFLAGS@
 INTROSPECTION_COMPILER = @INTROSPECTION_COMPILER@
@@ -262,6 +266,9 @@ UDEV_BASE_DIR = @UDEV_BASE_DIR@
 USE_NLS = @USE_NLS@
 UUID_CFLAGS = @UUID_CFLAGS@
 UUID_LIBS = @UUID_LIBS@
+VAPIGEN = @VAPIGEN@
+VAPIGEN_MAKEFILE = @VAPIGEN_MAKEFILE@
+VAPIGEN_VAPIDIR = @VAPIGEN_VAPIDIR@
 VERSION = @VERSION@
 XGETTEXT = @XGETTEXT@
 XGETTEXT_015 = @XGETTEXT_015@
@@ -300,6 +307,8 @@ htmldir = @htmldir@
 includedir = @includedir@
 infodir = @infodir@
 install_sh = @install_sh@
+intltool__v_merge_options_ = @intltool__v_merge_options_@
+intltool__v_merge_options_0 = @intltool__v_merge_options_0@
 libdir = @libdir@
 libexecdir = @libexecdir@
 localedir = @localedir@
diff --git a/src/generated/nm-enum-types.c b/src/generated/nm-enum-types.c
index a9973b4d..aa73b52e 100644
--- a/src/generated/nm-enum-types.c
+++ b/src/generated/nm-enum-types.c
@@ -5,29 +5,30 @@
 
 #include "nm-enum-types.h"
 
-#include "nm-device-vlan.h" 
+#include "nm-ip4-config.h" 
 #include "nm-device-olpc-mesh.h" 
 #include "nm-hostname-provider.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" 
 #include "nm-wifi-ap.h" 
-#include "nm-device-ethernet.h" 
 #include "nm-device-bt.h" 
+#include "nm-device-private.h" 
 #include "nm-device-wifi.h" 
 #include "nm-dbus-manager.h" 
 #include "nm-dhcp4-config.h" 
 #include "nm-dhcp6-config.h" 
 #include "nm-netlink-compat.h" 
 #include "nm-session-monitor.h" 
-#include "nm-ip4-config.h" 
 #include "nm-device-bond.h" 
 #include "nm-wifi-ap-utils.h" 
-#include "nm-call-store.h" 
+#include "nm-device-adsl.h" 
 #include "nm-policy-hosts.h" 
 #include "nm-udev-manager.h" 
+#include "nm-connection-provider.h" 
 #include "nm-manager.h" 
 #include "nm-device-modem.h" 
 #include "nm-device-wired.h" 
@@ -37,7 +38,7 @@
 #include "nm-device-infiniband.h" 
 #include "nm-properties-changed-signal.h" 
 #include "nm-ip6-config.h" 
-#include "nm-device-private.h" 
+#include "nm-call-store.h" 
 #include "nm-policy.h" 
 #include "nm-manager-auth.h" 
 #include "nm-config.h" 
@@ -45,6 +46,7 @@
 #include "nm-netlink-monitor.h" 
 #include "nm-system.h" 
 #include "nm-connectivity.h" 
+#include "nm-device-ethernet.h" 
 #include "nm-logging.h" 
 #include "nm-dns-utils.h" 
 #include "nm-dns-plugin.h" 
@@ -56,9 +58,9 @@
 #include "nm-vpn-connection.h" 
 #include "nm-dhcp-dhcpcd.h" 
 #include "nm-dhcp-dhclient.h" 
+#include "nm-dhcp-manager.h" 
 #include "nm-dhcp-client.h" 
 #include "nm-dhcp-dhclient-utils.h" 
-#include "nm-dhcp-manager.h" 
 #include "nm-ip6-manager.h" 
 #include "nm-supplicant-types.h" 
 #include "nm-supplicant-config.h" 
@@ -97,20 +99,30 @@
 #include "nm-wimax-nsp.h"
 
 GType
-nm_vlan_error_get_type (void)
+nm_ip4_config_compare_flags_get_type (void)
 {
   static volatile gsize g_define_type_id__volatile = 0;
 
   if (g_once_init_enter (&g_define_type_id__volatile))
     {
       static const GEnumValue values[] = {
-        { NM_VLAN_ERROR_CONNECTION_NOT_VLAN, "NM_VLAN_ERROR_CONNECTION_NOT_VLAN", "ConnectionNotVlan" },
-        { NM_VLAN_ERROR_CONNECTION_INVALID, "NM_VLAN_ERROR_CONNECTION_INVALID", "ConnectionInvalid" },
-        { NM_VLAN_ERROR_CONNECTION_INCOMPATIBLE, "NM_VLAN_ERROR_CONNECTION_INCOMPATIBLE", "ConnectionIncompatible" },
+        { NM_IP4_COMPARE_FLAG_NONE, "NM_IP4_COMPARE_FLAG_NONE", "none" },
+        { NM_IP4_COMPARE_FLAG_ADDRESSES, "NM_IP4_COMPARE_FLAG_ADDRESSES", "addresses" },
+        { NM_IP4_COMPARE_FLAG_PTP_ADDRESS, "NM_IP4_COMPARE_FLAG_PTP_ADDRESS", "ptp-address" },
+        { NM_IP4_COMPARE_FLAG_NAMESERVERS, "NM_IP4_COMPARE_FLAG_NAMESERVERS", "nameservers" },
+        { NM_IP4_COMPARE_FLAG_ROUTES, "NM_IP4_COMPARE_FLAG_ROUTES", "routes" },
+        { NM_IP4_COMPARE_FLAG_DOMAINS, "NM_IP4_COMPARE_FLAG_DOMAINS", "domains" },
+        { NM_IP4_COMPARE_FLAG_SEARCHES, "NM_IP4_COMPARE_FLAG_SEARCHES", "searches" },
+        { NM_IP4_COMPARE_FLAG_MTU, "NM_IP4_COMPARE_FLAG_MTU", "mtu" },
+        { NM_IP4_COMPARE_FLAG_MSS, "NM_IP4_COMPARE_FLAG_MSS", "mss" },
+        { NM_IP4_COMPARE_FLAG_WINS_SERVERS, "NM_IP4_COMPARE_FLAG_WINS_SERVERS", "wins-servers" },
+        { NM_IP4_COMPARE_FLAG_NIS_SERVERS, "NM_IP4_COMPARE_FLAG_NIS_SERVERS", "nis-servers" },
+        { NM_IP4_COMPARE_FLAG_NIS_DOMAIN, "NM_IP4_COMPARE_FLAG_NIS_DOMAIN", "nis-domain" },
+        { NM_IP4_COMPARE_FLAG_ALL, "NM_IP4_COMPARE_FLAG_ALL", "all" },
         { 0, NULL, NULL }
       };
       GType g_define_type_id =
-        g_enum_register_static (g_intern_static_string ("NMVlanError"), values);
+        g_enum_register_static (g_intern_static_string ("NMIP4ConfigCompareFlags"), values);
       g_once_init_leave (&g_define_type_id__volatile, g_define_type_id);
     }
 
@@ -199,20 +211,20 @@ nm_rf_kill_type_get_type (void)
   return g_define_type_id__volatile;
 }
 GType
-nm_ethernet_error_get_type (void)
+nm_vlan_error_get_type (void)
 {
   static volatile gsize g_define_type_id__volatile = 0;
 
   if (g_once_init_enter (&g_define_type_id__volatile))
     {
       static const GEnumValue values[] = {
-        { NM_ETHERNET_ERROR_CONNECTION_NOT_WIRED, "NM_ETHERNET_ERROR_CONNECTION_NOT_WIRED", "ConnectionNotWired" },
-        { NM_ETHERNET_ERROR_CONNECTION_INVALID, "NM_ETHERNET_ERROR_CONNECTION_INVALID", "ConnectionInvalid" },
-        { NM_ETHERNET_ERROR_CONNECTION_INCOMPATIBLE, "NM_ETHERNET_ERROR_CONNECTION_INCOMPATIBLE", "ConnectionIncompatible" },
+        { NM_VLAN_ERROR_CONNECTION_NOT_VLAN, "NM_VLAN_ERROR_CONNECTION_NOT_VLAN", "ConnectionNotVlan" },
+        { NM_VLAN_ERROR_CONNECTION_INVALID, "NM_VLAN_ERROR_CONNECTION_INVALID", "ConnectionInvalid" },
+        { NM_VLAN_ERROR_CONNECTION_INCOMPATIBLE, "NM_VLAN_ERROR_CONNECTION_INCOMPATIBLE", "ConnectionIncompatible" },
         { 0, NULL, NULL }
       };
       GType g_define_type_id =
-        g_enum_register_static (g_intern_static_string ("NMEthernetError"), values);
+        g_enum_register_static (g_intern_static_string ("NMVlanError"), values);
       g_once_init_leave (&g_define_type_id__volatile, g_define_type_id);
     }
 
@@ -250,6 +262,7 @@ nm_wifi_error_get_type (void)
         { NM_WIFI_ERROR_CONNECTION_INVALID, "NM_WIFI_ERROR_CONNECTION_INVALID", "ConnectionInvalid" },
         { NM_WIFI_ERROR_CONNECTION_INCOMPATIBLE, "NM_WIFI_ERROR_CONNECTION_INCOMPATIBLE", "ConnectionIncompatible" },
         { NM_WIFI_ERROR_ACCESS_POINT_NOT_FOUND, "NM_WIFI_ERROR_ACCESS_POINT_NOT_FOUND", "AccessPointNotFound" },
+        { NM_WIFI_ERROR_SCAN_NOT_ALLOWED, "NM_WIFI_ERROR_SCAN_NOT_ALLOWED", "ScanNotAllowed" },
         { 0, NULL, NULL }
       };
       GType g_define_type_id =
@@ -260,50 +273,40 @@ nm_wifi_error_get_type (void)
   return g_define_type_id__volatile;
 }
 GType
-nm_ip4_config_compare_flags_get_type (void)
+nm_bond_error_get_type (void)
 {
   static volatile gsize g_define_type_id__volatile = 0;
 
   if (g_once_init_enter (&g_define_type_id__volatile))
     {
       static const GEnumValue values[] = {
-        { NM_IP4_COMPARE_FLAG_NONE, "NM_IP4_COMPARE_FLAG_NONE", "none" },
-        { NM_IP4_COMPARE_FLAG_ADDRESSES, "NM_IP4_COMPARE_FLAG_ADDRESSES", "addresses" },
-        { NM_IP4_COMPARE_FLAG_PTP_ADDRESS, "NM_IP4_COMPARE_FLAG_PTP_ADDRESS", "ptp-address" },
-        { NM_IP4_COMPARE_FLAG_NAMESERVERS, "NM_IP4_COMPARE_FLAG_NAMESERVERS", "nameservers" },
-        { NM_IP4_COMPARE_FLAG_ROUTES, "NM_IP4_COMPARE_FLAG_ROUTES", "routes" },
-        { NM_IP4_COMPARE_FLAG_DOMAINS, "NM_IP4_COMPARE_FLAG_DOMAINS", "domains" },
-        { NM_IP4_COMPARE_FLAG_SEARCHES, "NM_IP4_COMPARE_FLAG_SEARCHES", "searches" },
-        { NM_IP4_COMPARE_FLAG_MTU, "NM_IP4_COMPARE_FLAG_MTU", "mtu" },
-        { NM_IP4_COMPARE_FLAG_MSS, "NM_IP4_COMPARE_FLAG_MSS", "mss" },
-        { NM_IP4_COMPARE_FLAG_WINS_SERVERS, "NM_IP4_COMPARE_FLAG_WINS_SERVERS", "wins-servers" },
-        { NM_IP4_COMPARE_FLAG_NIS_SERVERS, "NM_IP4_COMPARE_FLAG_NIS_SERVERS", "nis-servers" },
-        { NM_IP4_COMPARE_FLAG_NIS_DOMAIN, "NM_IP4_COMPARE_FLAG_NIS_DOMAIN", "nis-domain" },
-        { NM_IP4_COMPARE_FLAG_ALL, "NM_IP4_COMPARE_FLAG_ALL", "all" },
+        { NM_BOND_ERROR_CONNECTION_NOT_BOND, "NM_BOND_ERROR_CONNECTION_NOT_BOND", "ConnectionNotBond" },
+        { NM_BOND_ERROR_CONNECTION_INVALID, "NM_BOND_ERROR_CONNECTION_INVALID", "ConnectionInvalid" },
+        { NM_BOND_ERROR_CONNECTION_INCOMPATIBLE, "NM_BOND_ERROR_CONNECTION_INCOMPATIBLE", "ConnectionIncompatible" },
         { 0, NULL, NULL }
       };
       GType g_define_type_id =
-        g_enum_register_static (g_intern_static_string ("NMIP4ConfigCompareFlags"), values);
+        g_enum_register_static (g_intern_static_string ("NMBondError"), values);
       g_once_init_leave (&g_define_type_id__volatile, g_define_type_id);
     }
 
   return g_define_type_id__volatile;
 }
 GType
-nm_bond_error_get_type (void)
+nm_adsl_error_get_type (void)
 {
   static volatile gsize g_define_type_id__volatile = 0;
 
   if (g_once_init_enter (&g_define_type_id__volatile))
     {
       static const GEnumValue values[] = {
-        { NM_BOND_ERROR_CONNECTION_NOT_BOND, "NM_BOND_ERROR_CONNECTION_NOT_BOND", "ConnectionNotBond" },
-        { NM_BOND_ERROR_CONNECTION_INVALID, "NM_BOND_ERROR_CONNECTION_INVALID", "ConnectionInvalid" },
-        { NM_BOND_ERROR_CONNECTION_INCOMPATIBLE, "NM_BOND_ERROR_CONNECTION_INCOMPATIBLE", "ConnectionIncompatible" },
+        { NM_ADSL_ERROR_CONNECTION_NOT_ADSL, "NM_ADSL_ERROR_CONNECTION_NOT_ADSL", "not-adsl" },
+        { NM_ADSL_ERROR_CONNECTION_INVALID, "NM_ADSL_ERROR_CONNECTION_INVALID", "invalid" },
+        { NM_ADSL_ERROR_CONNECTION_INCOMPATIBLE, "NM_ADSL_ERROR_CONNECTION_INCOMPATIBLE", "incompatible" },
         { 0, NULL, NULL }
       };
       GType g_define_type_id =
-        g_enum_register_static (g_intern_static_string ("NMBondError"), values);
+        g_enum_register_static (g_intern_static_string ("NMAdslError"), values);
       g_once_init_leave (&g_define_type_id__volatile, g_define_type_id);
     }
 
@@ -512,6 +515,26 @@ nm_netlink_monitor_error_get_type (void)
   return g_define_type_id__volatile;
 }
 GType
+nm_ethernet_error_get_type (void)
+{
+  static volatile gsize g_define_type_id__volatile = 0;
+
+  if (g_once_init_enter (&g_define_type_id__volatile))
+    {
+      static const GEnumValue values[] = {
+        { NM_ETHERNET_ERROR_CONNECTION_NOT_WIRED, "NM_ETHERNET_ERROR_CONNECTION_NOT_WIRED", "ConnectionNotWired" },
+        { NM_ETHERNET_ERROR_CONNECTION_INVALID, "NM_ETHERNET_ERROR_CONNECTION_INVALID", "ConnectionInvalid" },
+        { NM_ETHERNET_ERROR_CONNECTION_INCOMPATIBLE, "NM_ETHERNET_ERROR_CONNECTION_INCOMPATIBLE", "ConnectionIncompatible" },
+        { 0, NULL, NULL }
+      };
+      GType g_define_type_id =
+        g_enum_register_static (g_intern_static_string ("NMEthernetError"), values);
+      g_once_init_leave (&g_define_type_id__volatile, g_define_type_id);
+    }
+
+  return g_define_type_id__volatile;
+}
+GType
 nm_logging_error_get_type (void)
 {
   static volatile gsize g_define_type_id__volatile = 0;
@@ -593,6 +616,25 @@ nm_vpn_manager_error_get_type (void)
   return g_define_type_id__volatile;
 }
 GType
+nm_dhcp_manager_error_get_type (void)
+{
+  static volatile gsize g_define_type_id__volatile = 0;
+
+  if (g_once_init_enter (&g_define_type_id__volatile))
+    {
+      static const GEnumValue values[] = {
+        { NM_DHCP_MANAGER_ERROR_BAD_CLIENT, "NM_DHCP_MANAGER_ERROR_BAD_CLIENT", "BadClient" },
+        { NM_DHCP_MANAGER_ERROR_INTERNAL, "NM_DHCP_MANAGER_ERROR_INTERNAL", "InternalError" },
+        { 0, NULL, NULL }
+      };
+      GType g_define_type_id =
+        g_enum_register_static (g_intern_static_string ("NMDHCPManagerError"), values);
+      g_once_init_leave (&g_define_type_id__volatile, g_define_type_id);
+    }
+
+  return g_define_type_id__volatile;
+}
+GType
 nm_dhcp_state_get_type (void)
 {
   static volatile gsize g_define_type_id__volatile = 0;
@@ -635,25 +677,6 @@ nm_dhcp_state_get_type (void)
   return g_define_type_id__volatile;
 }
 GType
-nm_dhcp_manager_error_get_type (void)
-{
-  static volatile gsize g_define_type_id__volatile = 0;
-
-  if (g_once_init_enter (&g_define_type_id__volatile))
-    {
-      static const GEnumValue values[] = {
-        { NM_DHCP_MANAGER_ERROR_BAD_CLIENT, "NM_DHCP_MANAGER_ERROR_BAD_CLIENT", "BadClient" },
-        { NM_DHCP_MANAGER_ERROR_INTERNAL, "NM_DHCP_MANAGER_ERROR_INTERNAL", "InternalError" },
-        { 0, NULL, NULL }
-      };
-      GType g_define_type_id =
-        g_enum_register_static (g_intern_static_string ("NMDHCPManagerError"), values);
-      g_once_init_leave (&g_define_type_id__volatile, g_define_type_id);
-    }
-
-  return g_define_type_id__volatile;
-}
-GType
 nm_opt_type_get_type (void)
 {
   static volatile gsize g_define_type_id__volatile = 0;
diff --git a/src/generated/nm-enum-types.h b/src/generated/nm-enum-types.h
index 324dbf6a..608eaad6 100644
--- a/src/generated/nm-enum-types.h
+++ b/src/generated/nm-enum-types.h
@@ -9,8 +9,8 @@
 #include <glib-object.h>
 
 G_BEGIN_DECLS
-GType nm_vlan_error_get_type (void) G_GNUC_CONST;
-#define NM_TYPE_VLAN_ERROR (nm_vlan_error_get_type ())
+GType nm_ip4_config_compare_flags_get_type (void) G_GNUC_CONST;
+#define NM_TYPE_IP4_CONFIG_COMPARE_FLAGS (nm_ip4_config_compare_flags_get_type ())
 GType nm_olpc_mesh_error_get_type (void) G_GNUC_CONST;
 #define NM_TYPE_OLPC_MESH_ERROR (nm_olpc_mesh_error_get_type ())
 GType nm_device_error_get_type (void) G_GNUC_CONST;
@@ -19,16 +19,16 @@ GType nm_rf_kill_state_get_type (void) G_GNUC_CONST;
 #define NM_TYPE_RF_KILL_STATE (nm_rf_kill_state_get_type ())
 GType nm_rf_kill_type_get_type (void) G_GNUC_CONST;
 #define NM_TYPE_RF_KILL_TYPE (nm_rf_kill_type_get_type ())
-GType nm_ethernet_error_get_type (void) G_GNUC_CONST;
-#define NM_TYPE_ETHERNET_ERROR (nm_ethernet_error_get_type ())
+GType nm_vlan_error_get_type (void) G_GNUC_CONST;
+#define NM_TYPE_VLAN_ERROR (nm_vlan_error_get_type ())
 GType nm_bt_error_get_type (void) G_GNUC_CONST;
 #define NM_TYPE_BT_ERROR (nm_bt_error_get_type ())
 GType nm_wifi_error_get_type (void) G_GNUC_CONST;
 #define NM_TYPE_WIFI_ERROR (nm_wifi_error_get_type ())
-GType nm_ip4_config_compare_flags_get_type (void) G_GNUC_CONST;
-#define NM_TYPE_IP4_CONFIG_COMPARE_FLAGS (nm_ip4_config_compare_flags_get_type ())
 GType nm_bond_error_get_type (void) G_GNUC_CONST;
 #define NM_TYPE_BOND_ERROR (nm_bond_error_get_type ())
+GType nm_adsl_error_get_type (void) G_GNUC_CONST;
+#define NM_TYPE_ADSL_ERROR (nm_adsl_error_get_type ())
 GType nm_manager_error_get_type (void) G_GNUC_CONST;
 #define NM_TYPE_MANAGER_ERROR (nm_manager_error_get_type ())
 GType nm_act_request_dependency_result_get_type (void) G_GNUC_CONST;
@@ -47,6 +47,8 @@ GType nm_nm_nl_prop_get_type (void) G_GNUC_CONST;
 #define NM_TYPE_NM_NL_PROP (nm_nm_nl_prop_get_type ())
 GType nm_netlink_monitor_error_get_type (void) G_GNUC_CONST;
 #define NM_TYPE_NETLINK_MONITOR_ERROR (nm_netlink_monitor_error_get_type ())
+GType nm_ethernet_error_get_type (void) G_GNUC_CONST;
+#define NM_TYPE_ETHERNET_ERROR (nm_ethernet_error_get_type ())
 GType nm_logging_error_get_type (void) G_GNUC_CONST;
 #define NM_TYPE_LOGGING_ERROR (nm_logging_error_get_type ())
 GType nm_dns_manager_error_get_type (void) G_GNUC_CONST;
@@ -55,10 +57,10 @@ GType nm_dns_ip_config_type_get_type (void) G_GNUC_CONST;
 #define NM_TYPE_DNS_IP_CONFIG_TYPE (nm_dns_ip_config_type_get_type ())
 GType nm_vpn_manager_error_get_type (void) G_GNUC_CONST;
 #define NM_TYPE_VPN_MANAGER_ERROR (nm_vpn_manager_error_get_type ())
-GType nm_dhcp_state_get_type (void) G_GNUC_CONST;
-#define NM_TYPE_DHCP_STATE (nm_dhcp_state_get_type ())
 GType nm_dhcp_manager_error_get_type (void) G_GNUC_CONST;
 #define NM_TYPE_DHCP_MANAGER_ERROR (nm_dhcp_manager_error_get_type ())
+GType nm_dhcp_state_get_type (void) G_GNUC_CONST;
+#define NM_TYPE_DHCP_STATE (nm_dhcp_state_get_type ())
 GType nm_opt_type_get_type (void) G_GNUC_CONST;
 #define NM_TYPE_OPT_TYPE (nm_opt_type_get_type ())
 GType nm_ppp_status_get_type (void) G_GNUC_CONST;
diff --git a/src/generated/nm-marshal.c b/src/generated/nm-marshal.c
index 4ba973af..e3d39724 100644
--- a/src/generated/nm-marshal.c
+++ b/src/generated/nm-marshal.c
@@ -5,7 +5,7 @@
 
 #ifdef G_ENABLE_DEBUG
 #define g_marshal_value_peek_boolean(v)  g_value_get_boolean (v)
-#define g_marshal_value_peek_char(v)     g_value_get_char (v)
+#define g_marshal_value_peek_char(v)     g_value_get_schar (v)
 #define g_marshal_value_peek_uchar(v)    g_value_get_uchar (v)
 #define g_marshal_value_peek_int(v)      g_value_get_int (v)
 #define g_marshal_value_peek_uint(v)     g_value_get_uint (v)
@@ -163,7 +163,44 @@ _nm_marshal_VOID__INT_UINT_BOOLEAN (GClosure     *closure,
             data2);
 }
 
-/* VOID:OBJECT,STRING (nm-marshal.list:4) */
+/* VOID:OBJECT,OBJECT (nm-marshal.list:4) */
+void
+_nm_marshal_VOID__OBJECT_OBJECT (GClosure     *closure,
+                                 GValue       *return_value G_GNUC_UNUSED,
+                                 guint         n_param_values,
+                                 const GValue *param_values,
+                                 gpointer      invocation_hint G_GNUC_UNUSED,
+                                 gpointer      marshal_data)
+{
+  typedef void (*GMarshalFunc_VOID__OBJECT_OBJECT) (gpointer     data1,
+                                                    gpointer     arg_1,
+                                                    gpointer     arg_2,
+                                                    gpointer     data2);
+  register GMarshalFunc_VOID__OBJECT_OBJECT callback;
+  register GCClosure *cc = (GCClosure*) closure;
+  register gpointer data1, data2;
+
+  g_return_if_fail (n_param_values == 3);
+
+  if (G_CCLOSURE_SWAP_DATA (closure))
+    {
+      data1 = closure->data;
+      data2 = g_value_peek_pointer (param_values + 0);
+    }
+  else
+    {
+      data1 = g_value_peek_pointer (param_values + 0);
+      data2 = closure->data;
+    }
+  callback = (GMarshalFunc_VOID__OBJECT_OBJECT) (marshal_data ? marshal_data : cc->callback);
+
+  callback (data1,
+            g_marshal_value_peek_object (param_values + 1),
+            g_marshal_value_peek_object (param_values + 2),
+            data2);
+}
+
+/* VOID:OBJECT,STRING (nm-marshal.list:5) */
 void
 _nm_marshal_VOID__OBJECT_STRING (GClosure     *closure,
                                  GValue       *return_value G_GNUC_UNUSED,
@@ -200,25 +237,26 @@ _nm_marshal_VOID__OBJECT_STRING (GClosure     *closure,
             data2);
 }
 
-/* VOID:OBJECT,UINT,UINT (nm-marshal.list:5) */
+/* VOID:OBJECT,UINT,UINT,UINT (nm-marshal.list:6) */
 void
-_nm_marshal_VOID__OBJECT_UINT_UINT (GClosure     *closure,
-                                    GValue       *return_value G_GNUC_UNUSED,
-                                    guint         n_param_values,
-                                    const GValue *param_values,
-                                    gpointer      invocation_hint G_GNUC_UNUSED,
-                                    gpointer      marshal_data)
+_nm_marshal_VOID__OBJECT_UINT_UINT_UINT (GClosure     *closure,
+                                         GValue       *return_value G_GNUC_UNUSED,
+                                         guint         n_param_values,
+                                         const GValue *param_values,
+                                         gpointer      invocation_hint G_GNUC_UNUSED,
+                                         gpointer      marshal_data)
 {
-  typedef void (*GMarshalFunc_VOID__OBJECT_UINT_UINT) (gpointer     data1,
-                                                       gpointer     arg_1,
-                                                       guint        arg_2,
-                                                       guint        arg_3,
-                                                       gpointer     data2);
-  register GMarshalFunc_VOID__OBJECT_UINT_UINT callback;
+  typedef void (*GMarshalFunc_VOID__OBJECT_UINT_UINT_UINT) (gpointer     data1,
+                                                            gpointer     arg_1,
+                                                            guint        arg_2,
+                                                            guint        arg_3,
+                                                            guint        arg_4,
+                                                            gpointer     data2);
+  register GMarshalFunc_VOID__OBJECT_UINT_UINT_UINT callback;
   register GCClosure *cc = (GCClosure*) closure;
   register gpointer data1, data2;
 
-  g_return_if_fail (n_param_values == 4);
+  g_return_if_fail (n_param_values == 5);
 
   if (G_CCLOSURE_SWAP_DATA (closure))
     {
@@ -230,18 +268,19 @@ _nm_marshal_VOID__OBJECT_UINT_UINT (GClosure     *closure,
       data1 = g_value_peek_pointer (param_values + 0);
       data2 = closure->data;
     }
-  callback = (GMarshalFunc_VOID__OBJECT_UINT_UINT) (marshal_data ? marshal_data : cc->callback);
+  callback = (GMarshalFunc_VOID__OBJECT_UINT_UINT_UINT) (marshal_data ? marshal_data : cc->callback);
 
   callback (data1,
             g_marshal_value_peek_object (param_values + 1),
             g_marshal_value_peek_uint (param_values + 2),
             g_marshal_value_peek_uint (param_values + 3),
+            g_marshal_value_peek_uint (param_values + 4),
             data2);
 }
 
-/* VOID:POINTER (nm-marshal.list:6) */
+/* VOID:POINTER (nm-marshal.list:7) */
 
-/* VOID:POINTER,POINTER,POINTER,POINTER,INT (nm-marshal.list:7) */
+/* VOID:POINTER,POINTER,POINTER,POINTER,INT (nm-marshal.list:8) */
 void
 _nm_marshal_VOID__POINTER_POINTER_POINTER_POINTER_INT (GClosure     *closure,
                                                        GValue       *return_value G_GNUC_UNUSED,
@@ -284,7 +323,7 @@ _nm_marshal_VOID__POINTER_POINTER_POINTER_POINTER_INT (GClosure     *closure,
             data2);
 }
 
-/* VOID:POINTER,STRING (nm-marshal.list:8) */
+/* VOID:POINTER,STRING (nm-marshal.list:9) */
 void
 _nm_marshal_VOID__POINTER_STRING (GClosure     *closure,
                                   GValue       *return_value G_GNUC_UNUSED,
@@ -321,7 +360,50 @@ _nm_marshal_VOID__POINTER_STRING (GClosure     *closure,
             data2);
 }
 
-/* VOID:STRING,BOXED (nm-marshal.list:9) */
+/* VOID:POINTER,STRING,BOOLEAN,POINTER,POINTER (nm-marshal.list:10) */
+void
+_nm_marshal_VOID__POINTER_STRING_BOOLEAN_POINTER_POINTER (GClosure     *closure,
+                                                          GValue       *return_value G_GNUC_UNUSED,
+                                                          guint         n_param_values,
+                                                          const GValue *param_values,
+                                                          gpointer      invocation_hint G_GNUC_UNUSED,
+                                                          gpointer      marshal_data)
+{
+  typedef void (*GMarshalFunc_VOID__POINTER_STRING_BOOLEAN_POINTER_POINTER) (gpointer     data1,
+                                                                             gpointer     arg_1,
+                                                                             gpointer     arg_2,
+                                                                             gboolean     arg_3,
+                                                                             gpointer     arg_4,
+                                                                             gpointer     arg_5,
+                                                                             gpointer     data2);
+  register GMarshalFunc_VOID__POINTER_STRING_BOOLEAN_POINTER_POINTER callback;
+  register GCClosure *cc = (GCClosure*) closure;
+  register gpointer data1, data2;
+
+  g_return_if_fail (n_param_values == 6);
+
+  if (G_CCLOSURE_SWAP_DATA (closure))
+    {
+      data1 = closure->data;
+      data2 = g_value_peek_pointer (param_values + 0);
+    }
+  else
+    {
+      data1 = g_value_peek_pointer (param_values + 0);
+      data2 = closure->data;
+    }
+  callback = (GMarshalFunc_VOID__POINTER_STRING_BOOLEAN_POINTER_POINTER) (marshal_data ? marshal_data : cc->callback);
+
+  callback (data1,
+            g_marshal_value_peek_pointer (param_values + 1),
+            g_marshal_value_peek_string (param_values + 2),
+            g_marshal_value_peek_boolean (param_values + 3),
+            g_marshal_value_peek_pointer (param_values + 4),
+            g_marshal_value_peek_pointer (param_values + 5),
+            data2);
+}
+
+/* VOID:STRING,BOXED (nm-marshal.list:11) */
 void
 _nm_marshal_VOID__STRING_BOXED (GClosure     *closure,
                                 GValue       *return_value G_GNUC_UNUSED,
@@ -358,7 +440,7 @@ _nm_marshal_VOID__STRING_BOXED (GClosure     *closure,
             data2);
 }
 
-/* VOID:STRING,BOXED,BOXED (nm-marshal.list:10) */
+/* VOID:STRING,BOXED,BOXED (nm-marshal.list:12) */
 void
 _nm_marshal_VOID__STRING_BOXED_BOXED (GClosure     *closure,
                                       GValue       *return_value G_GNUC_UNUSED,
@@ -397,7 +479,7 @@ _nm_marshal_VOID__STRING_BOXED_BOXED (GClosure     *closure,
             data2);
 }
 
-/* VOID:STRING,OBJECT (nm-marshal.list:11) */
+/* VOID:STRING,OBJECT (nm-marshal.list:13) */
 void
 _nm_marshal_VOID__STRING_OBJECT (GClosure     *closure,
                                  GValue       *return_value G_GNUC_UNUSED,
@@ -434,7 +516,7 @@ _nm_marshal_VOID__STRING_OBJECT (GClosure     *closure,
             data2);
 }
 
-/* VOID:STRING,OBJECT,POINTER (nm-marshal.list:12) */
+/* VOID:STRING,OBJECT,POINTER (nm-marshal.list:14) */
 void
 _nm_marshal_VOID__STRING_OBJECT_POINTER (GClosure     *closure,
                                          GValue       *return_value G_GNUC_UNUSED,
@@ -473,7 +555,7 @@ _nm_marshal_VOID__STRING_OBJECT_POINTER (GClosure     *closure,
             data2);
 }
 
-/* VOID:STRING,POINTER (nm-marshal.list:13) */
+/* VOID:STRING,POINTER (nm-marshal.list:15) */
 void
 _nm_marshal_VOID__STRING_POINTER (GClosure     *closure,
                                   GValue       *return_value G_GNUC_UNUSED,
@@ -510,7 +592,7 @@ _nm_marshal_VOID__STRING_POINTER (GClosure     *closure,
             data2);
 }
 
-/* VOID:STRING,STRING (nm-marshal.list:14) */
+/* VOID:STRING,STRING (nm-marshal.list:16) */
 void
 _nm_marshal_VOID__STRING_STRING (GClosure     *closure,
                                  GValue       *return_value G_GNUC_UNUSED,
@@ -547,7 +629,7 @@ _nm_marshal_VOID__STRING_STRING (GClosure     *closure,
             data2);
 }
 
-/* VOID:STRING,STRING,STRING (nm-marshal.list:15) */
+/* VOID:STRING,STRING,STRING (nm-marshal.list:17) */
 void
 _nm_marshal_VOID__STRING_STRING_STRING (GClosure     *closure,
                                         GValue       *return_value G_GNUC_UNUSED,
@@ -586,7 +668,7 @@ _nm_marshal_VOID__STRING_STRING_STRING (GClosure     *closure,
             data2);
 }
 
-/* VOID:STRING,STRING,STRING,UINT (nm-marshal.list:16) */
+/* VOID:STRING,STRING,STRING,UINT (nm-marshal.list:18) */
 void
 _nm_marshal_VOID__STRING_STRING_STRING_UINT (GClosure     *closure,
                                              GValue       *return_value G_GNUC_UNUSED,
@@ -627,7 +709,7 @@ _nm_marshal_VOID__STRING_STRING_STRING_UINT (GClosure     *closure,
             data2);
 }
 
-/* VOID:UINT,UINT (nm-marshal.list:17) */
+/* VOID:UINT,UINT (nm-marshal.list:19) */
 void
 _nm_marshal_VOID__UINT_UINT (GClosure     *closure,
                              GValue       *return_value G_GNUC_UNUSED,
@@ -664,7 +746,7 @@ _nm_marshal_VOID__UINT_UINT (GClosure     *closure,
             data2);
 }
 
-/* VOID:UINT,UINT,UINT (nm-marshal.list:18) */
+/* VOID:UINT,UINT,UINT (nm-marshal.list:20) */
 void
 _nm_marshal_VOID__UINT_UINT_UINT (GClosure     *closure,
                                   GValue       *return_value G_GNUC_UNUSED,
diff --git a/src/generated/nm-marshal.h b/src/generated/nm-marshal.h
index 9f9ea6ad..61ef6479 100644
--- a/src/generated/nm-marshal.h
+++ b/src/generated/nm-marshal.h
@@ -30,7 +30,15 @@ extern void _nm_marshal_VOID__INT_UINT_BOOLEAN (GClosure     *closure,
                                                 gpointer      invocation_hint,
                                                 gpointer      marshal_data);
 
-/* VOID:OBJECT,STRING (nm-marshal.list:4) */
+/* VOID:OBJECT,OBJECT (nm-marshal.list:4) */
+extern void _nm_marshal_VOID__OBJECT_OBJECT (GClosure     *closure,
+                                             GValue       *return_value,
+                                             guint         n_param_values,
+                                             const GValue *param_values,
+                                             gpointer      invocation_hint,
+                                             gpointer      marshal_data);
+
+/* VOID:OBJECT,STRING (nm-marshal.list:5) */
 extern void _nm_marshal_VOID__OBJECT_STRING (GClosure     *closure,
                                              GValue       *return_value,
                                              guint         n_param_values,
@@ -38,18 +46,18 @@ extern void _nm_marshal_VOID__OBJECT_STRING (GClosure     *closure,
                                              gpointer      invocation_hint,
                                              gpointer      marshal_data);
 
-/* VOID:OBJECT,UINT,UINT (nm-marshal.list:5) */
-extern void _nm_marshal_VOID__OBJECT_UINT_UINT (GClosure     *closure,
-                                                GValue       *return_value,
-                                                guint         n_param_values,
-                                                const GValue *param_values,
-                                                gpointer      invocation_hint,
-                                                gpointer      marshal_data);
+/* VOID:OBJECT,UINT,UINT,UINT (nm-marshal.list:6) */
+extern void _nm_marshal_VOID__OBJECT_UINT_UINT_UINT (GClosure     *closure,
+                                                     GValue       *return_value,
+                                                     guint         n_param_values,
+                                                     const GValue *param_values,
+                                                     gpointer      invocation_hint,
+                                                     gpointer      marshal_data);
 
-/* VOID:POINTER (nm-marshal.list:6) */
+/* VOID:POINTER (nm-marshal.list:7) */
 #define _nm_marshal_VOID__POINTER	g_cclosure_marshal_VOID__POINTER
 
-/* VOID:POINTER,POINTER,POINTER,POINTER,INT (nm-marshal.list:7) */
+/* VOID:POINTER,POINTER,POINTER,POINTER,INT (nm-marshal.list:8) */
 extern void _nm_marshal_VOID__POINTER_POINTER_POINTER_POINTER_INT (GClosure     *closure,
                                                                    GValue       *return_value,
                                                                    guint         n_param_values,
@@ -57,7 +65,7 @@ extern void _nm_marshal_VOID__POINTER_POINTER_POINTER_POINTER_INT (GClosure
                                                                    gpointer      invocation_hint,
                                                                    gpointer      marshal_data);
 
-/* VOID:POINTER,STRING (nm-marshal.list:8) */
+/* VOID:POINTER,STRING (nm-marshal.list:9) */
 extern void _nm_marshal_VOID__POINTER_STRING (GClosure     *closure,
                                               GValue       *return_value,
                                               guint         n_param_values,
@@ -65,7 +73,15 @@ extern void _nm_marshal_VOID__POINTER_STRING (GClosure     *closure,
                                               gpointer      invocation_hint,
                                               gpointer      marshal_data);
 
-/* VOID:STRING,BOXED (nm-marshal.list:9) */
+/* VOID:POINTER,STRING,BOOLEAN,POINTER,POINTER (nm-marshal.list:10) */
+extern void _nm_marshal_VOID__POINTER_STRING_BOOLEAN_POINTER_POINTER (GClosure     *closure,
+                                                                      GValue       *return_value,
+                                                                      guint         n_param_values,
+                                                                      const GValue *param_values,
+                                                                      gpointer      invocation_hint,
+                                                                      gpointer      marshal_data);
+
+/* VOID:STRING,BOXED (nm-marshal.list:11) */
 extern void _nm_marshal_VOID__STRING_BOXED (GClosure     *closure,
                                             GValue       *return_value,
                                             guint         n_param_values,
@@ -73,7 +89,7 @@ extern void _nm_marshal_VOID__STRING_BOXED (GClosure     *closure,
                                             gpointer      invocation_hint,
                                             gpointer      marshal_data);
 
-/* VOID:STRING,BOXED,BOXED (nm-marshal.list:10) */
+/* VOID:STRING,BOXED,BOXED (nm-marshal.list:12) */
 extern void _nm_marshal_VOID__STRING_BOXED_BOXED (GClosure     *closure,
                                                   GValue       *return_value,
                                                   guint         n_param_values,
@@ -81,7 +97,7 @@ extern void _nm_marshal_VOID__STRING_BOXED_BOXED (GClosure     *closure,
                                                   gpointer      invocation_hint,
                                                   gpointer      marshal_data);
 
-/* VOID:STRING,OBJECT (nm-marshal.list:11) */
+/* VOID:STRING,OBJECT (nm-marshal.list:13) */
 extern void _nm_marshal_VOID__STRING_OBJECT (GClosure     *closure,
                                              GValue       *return_value,
                                              guint         n_param_values,
@@ -89,7 +105,7 @@ extern void _nm_marshal_VOID__STRING_OBJECT (GClosure     *closure,
                                              gpointer      invocation_hint,
                                              gpointer      marshal_data);
 
-/* VOID:STRING,OBJECT,POINTER (nm-marshal.list:12) */
+/* VOID:STRING,OBJECT,POINTER (nm-marshal.list:14) */
 extern void _nm_marshal_VOID__STRING_OBJECT_POINTER (GClosure     *closure,
                                                      GValue       *return_value,
                                                      guint         n_param_values,
@@ -97,7 +113,7 @@ extern void _nm_marshal_VOID__STRING_OBJECT_POINTER (GClosure     *closure,
                                                      gpointer      invocation_hint,
                                                      gpointer      marshal_data);
 
-/* VOID:STRING,POINTER (nm-marshal.list:13) */
+/* VOID:STRING,POINTER (nm-marshal.list:15) */
 extern void _nm_marshal_VOID__STRING_POINTER (GClosure     *closure,
                                               GValue       *return_value,
                                               guint         n_param_values,
@@ -105,7 +121,7 @@ extern void _nm_marshal_VOID__STRING_POINTER (GClosure     *closure,
                                               gpointer      invocation_hint,
                                               gpointer      marshal_data);
 
-/* VOID:STRING,STRING (nm-marshal.list:14) */
+/* VOID:STRING,STRING (nm-marshal.list:16) */
 extern void _nm_marshal_VOID__STRING_STRING (GClosure     *closure,
                                              GValue       *return_value,
                                              guint         n_param_values,
@@ -113,7 +129,7 @@ extern void _nm_marshal_VOID__STRING_STRING (GClosure     *closure,
                                              gpointer      invocation_hint,
                                              gpointer      marshal_data);
 
-/* VOID:STRING,STRING,STRING (nm-marshal.list:15) */
+/* VOID:STRING,STRING,STRING (nm-marshal.list:17) */
 extern void _nm_marshal_VOID__STRING_STRING_STRING (GClosure     *closure,
                                                     GValue       *return_value,
                                                     guint         n_param_values,
@@ -121,7 +137,7 @@ extern void _nm_marshal_VOID__STRING_STRING_STRING (GClosure     *closure,
                                                     gpointer      invocation_hint,
                                                     gpointer      marshal_data);
 
-/* VOID:STRING,STRING,STRING,UINT (nm-marshal.list:16) */
+/* VOID:STRING,STRING,STRING,UINT (nm-marshal.list:18) */
 extern void _nm_marshal_VOID__STRING_STRING_STRING_UINT (GClosure     *closure,
                                                          GValue       *return_value,
                                                          guint         n_param_values,
@@ -129,7 +145,7 @@ extern void _nm_marshal_VOID__STRING_STRING_STRING_UINT (GClosure     *closure,
                                                          gpointer      invocation_hint,
                                                          gpointer      marshal_data);
 
-/* VOID:UINT,UINT (nm-marshal.list:17) */
+/* VOID:UINT,UINT (nm-marshal.list:19) */
 extern void _nm_marshal_VOID__UINT_UINT (GClosure     *closure,
                                          GValue       *return_value,
                                          guint         n_param_values,
@@ -137,7 +153,7 @@ extern void _nm_marshal_VOID__UINT_UINT (GClosure     *closure,
                                          gpointer      invocation_hint,
                                          gpointer      marshal_data);
 
-/* VOID:UINT,UINT,UINT (nm-marshal.list:18) */
+/* VOID:UINT,UINT,UINT (nm-marshal.list:20) */
 extern void _nm_marshal_VOID__UINT_UINT_UINT (GClosure     *closure,
                                               GValue       *return_value,
                                               guint         n_param_values,
diff --git a/src/ip6-manager/Makefile.in b/src/ip6-manager/Makefile.in
index 59c2e7b4..d0d3129b 100644
--- a/src/ip6-manager/Makefile.in
+++ b/src/ip6-manager/Makefile.in
@@ -47,7 +47,7 @@ am__aclocal_m4_deps = $(top_srcdir)/m4/compiler_warnings.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)/configure.ac
+	$(top_srcdir)/m4/vapigen.m4 $(top_srcdir)/configure.ac
 am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \
 	$(ACLOCAL_M4)
 mkinstalldirs = $(install_sh) -d
@@ -169,6 +169,10 @@ INTLTOOL_EXTRACT = @INTLTOOL_EXTRACT@
 INTLTOOL_MERGE = @INTLTOOL_MERGE@
 INTLTOOL_PERL = @INTLTOOL_PERL@
 INTLTOOL_UPDATE = @INTLTOOL_UPDATE@
+INTLTOOL_V_MERGE = @INTLTOOL_V_MERGE@
+INTLTOOL_V_MERGE_OPTIONS = @INTLTOOL_V_MERGE_OPTIONS@
+INTLTOOL__v_MERGE_ = @INTLTOOL__v_MERGE_@
+INTLTOOL__v_MERGE_0 = @INTLTOOL__v_MERGE_0@
 INTL_MACOSX_LIBS = @INTL_MACOSX_LIBS@
 INTROSPECTION_CFLAGS = @INTROSPECTION_CFLAGS@
 INTROSPECTION_COMPILER = @INTROSPECTION_COMPILER@
@@ -264,6 +268,9 @@ UDEV_BASE_DIR = @UDEV_BASE_DIR@
 USE_NLS = @USE_NLS@
 UUID_CFLAGS = @UUID_CFLAGS@
 UUID_LIBS = @UUID_LIBS@
+VAPIGEN = @VAPIGEN@
+VAPIGEN_MAKEFILE = @VAPIGEN_MAKEFILE@
+VAPIGEN_VAPIDIR = @VAPIGEN_VAPIDIR@
 VERSION = @VERSION@
 XGETTEXT = @XGETTEXT@
 XGETTEXT_015 = @XGETTEXT_015@
@@ -302,6 +309,8 @@ htmldir = @htmldir@
 includedir = @includedir@
 infodir = @infodir@
 install_sh = @install_sh@
+intltool__v_merge_options_ = @intltool__v_merge_options_@
+intltool__v_merge_options_0 = @intltool__v_merge_options_0@
 libdir = @libdir@
 libexecdir = @libexecdir@
 localedir = @localedir@
diff --git a/src/ip6-manager/nm-ip6-manager.c b/src/ip6-manager/nm-ip6-manager.c
index 99f85ede..e452c18e 100644
--- a/src/ip6-manager/nm-ip6-manager.c
+++ b/src/ip6-manager/nm-ip6-manager.c
@@ -18,8 +18,12 @@
  * Copyright (C) 2009 - 2010 Red Hat, Inc.
  */
 
+#define _GNU_SOURCE /* for struct in6_pktinfo */
+
 #include <errno.h>
+#include <unistd.h>
 #include <netinet/icmp6.h>
+#include <netinet/in.h>
 
 #include <netlink/route/addr.h>
 #include <netlink/route/rtnl.h>
@@ -32,6 +36,7 @@
 #include "NetworkManagerUtils.h"
 #include "nm-marshal.h"
 #include "nm-logging.h"
+#include "nm-utils.h"
 
 /* Pre-DHCP addrconf timeout, in seconds */
 #define NM_IP6_TIMEOUT 20
@@ -89,6 +94,10 @@ typedef struct {
 	char *iface;
 	int ifindex;
 
+	gboolean has_linklocal;
+	gboolean has_nonlinklocal;
+	guint dhcp_opts;
+
 	char *disable_ip6_path;
 	gboolean disable_ip6_save_valid;
 	gint32 disable_ip6_save;
@@ -102,9 +111,13 @@ typedef struct {
 
 	GArray *rdnss_servers;
 	guint rdnss_timeout_id;
+	guint32 rdnss_timeout;
 
 	GArray *dnssl_domains;
 	guint dnssl_timeout_id;
+	guint32 dnssl_timeout;
+
+	time_t last_solicitation;
 
 	guint ip6flags_poll_id;
 
@@ -209,11 +222,221 @@ 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)
+{
+	int sock, hops;
+	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 };
+	struct msghdr mhdr;
+	struct iovec iov[3];
+	struct cmsghdr *cmsg;
+	struct in6_pktinfo *ipi;
+	guint8 cmsgbuf[128];
+	int cmsglen = 0;
+	time_t now;
+
+	now = time (NULL);
+	if (device->last_solicitation > now - 5)
+		return;
+	device->last_solicitation = now;
+
+	nm_log_dbg (LOGD_IP6, "(%s): %s: sending router solicitation",
+	            device->iface, why);
+
+	sock = socket (AF_INET6, SOCK_RAW, IPPROTO_ICMPV6);
+	if (sock < 0) {
+		nm_log_dbg (LOGD_IP6, "(%s): could not create ICMPv6 socket: %s",
+		            device->iface, g_strerror (errno));
+		return;
+	}
+
+	hops = 255;
+	if (   setsockopt (sock, IPPROTO_IPV6, IPV6_MULTICAST_HOPS, &hops, sizeof (hops)) == -1
+	    || setsockopt (sock, IPPROTO_IPV6, IPV6_UNICAST_HOPS, &hops, sizeof (hops)) == -1) {
+		nm_log_dbg (LOGD_IP6, "(%s): could not set hop limit on ICMPv6 socket: %s",
+		            device->iface, g_strerror (errno));
+		close (sock);
+		return;
+	}
+
+	/* Use the "all link-local routers" multicast address */
+	memset (&sin6, 0, sizeof (sin6));
+	memcpy (&sin6.sin6_addr, local_routers_addr, sizeof (sin6.sin6_addr));
+	mhdr.msg_name = &sin6;
+	mhdr.msg_namelen = sizeof (sin6);
+
+	/* Build the router solicitation */
+	mhdr.msg_iov = iov;
+	memset (&rs, 0, sizeof (rs));
+	rs.nd_rs_type = ND_ROUTER_SOLICIT;
+	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) {
+		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;
+		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;
+
+		mhdr.msg_iovlen = 3;
+	} else
+		mhdr.msg_iovlen = 1;
+
+	/* Force this to go on the right device */
+	memset (cmsgbuf, 0, sizeof (cmsgbuf));
+	cmsg = (struct cmsghdr *) cmsgbuf;
+	cmsglen = CMSG_SPACE (sizeof (*ipi));
+	cmsg->cmsg_len = CMSG_LEN (sizeof (*ipi));
+	cmsg->cmsg_level = SOL_IPV6;
+	cmsg->cmsg_type = IPV6_PKTINFO;
+	ipi = (struct in6_pktinfo *) CMSG_DATA (cmsg);
+	ipi->ipi6_ifindex = device->ifindex;
+
+	mhdr.msg_control = cmsg;
+	mhdr.msg_controllen = cmsglen;
+
+	if (sendmsg (sock, &mhdr, 0) == -1) {
+		nm_log_dbg (LOGD_IP6, "(%s): could not send router solicitation: %s",
+		            device->iface, g_strerror (errno));
+	}
+
+	close (sock);
+}
+
+static char *
+device_get_iface (NMIP6Device *device)
+{
+	return device ? device->iface : "unknown";
+}
+
+static const char *
+state_to_string (NMIP6DeviceState state)
+{
+	switch (state) {
+	case NM_IP6_DEVICE_UNCONFIGURED:
+		return "unconfigured";
+	case NM_IP6_DEVICE_GOT_LINK_LOCAL:
+		return "got-link-local";
+	case NM_IP6_DEVICE_GOT_ROUTER_ADVERTISEMENT:
+		return "got-ra";
+	case NM_IP6_DEVICE_GOT_ADDRESS:
+		return "got-address";
+	case NM_IP6_DEVICE_TIMED_OUT:
+		return "timed-out";
+	default:
+		return "unknown";
+	}
+}
+
+static gboolean
+device_set_state (NMIP6Device *device, NMIP6DeviceState state)
+{
+	NMIP6DeviceState old_state;
+
+	g_return_val_if_fail (device != NULL, FALSE);
+
+	if (state == device->state)
+		return FALSE;
+
+	old_state = device->state;
+	device->state = state;
+	nm_log_dbg (LOGD_IP6, "(%s) IP6 device state: %s -> %s",
+	            device_get_iface (device),
+	            state_to_string (old_state),
+	            state_to_string (state));
+	return TRUE;
+}
+
+static char *
+ra_flags_to_string (guint32 ra_flags)
+{
+	GString *s = g_string_sized_new (20);
+
+	g_string_append (s, " (");
+	if (ra_flags & IF_RS_SENT)
+		g_string_append_c (s, 'S');
+
+	if (ra_flags & IF_RA_RCVD)
+		g_string_append_c (s, 'R');
+
+	if (ra_flags & IF_RA_MANAGED)
+		g_string_append_c (s, 'M');
+
+	if (ra_flags & IF_RA_OTHERCONF)
+		g_string_append_c (s, 'O');
+
+	g_string_append_c (s, ')');
+	return g_string_free (s, FALSE);
+}
+
+static gboolean
+device_set_ra_flags (NMIP6Device *device, guint ra_flags)
+{
+	guint old_ra_flags;
+	gchar *ra_flags_str, *old_ra_flags_str;
+
+	g_return_val_if_fail (device != NULL, FALSE);
+
+	if (ra_flags == device->ra_flags)
+		return FALSE;
+
+	old_ra_flags = device->ra_flags;
+	device->ra_flags = ra_flags;
+
+	if (nm_logging_level_enabled (LOGL_DEBUG)) {
+		ra_flags_str = ra_flags_to_string (ra_flags);
+		old_ra_flags_str = ra_flags_to_string (old_ra_flags);
+		nm_log_dbg (LOGD_IP6, "(%s) IP6 device ra_flags: 0x%08x %s -> 0x%08x %s",
+		            device_get_iface (device),
+		            old_ra_flags, old_ra_flags_str,
+		            ra_flags, ra_flags_str);
+		g_free (ra_flags_str);
+		g_free (old_ra_flags_str);
+	}
+
+	return TRUE;
+}
+
 /******************************************************************/
 
 typedef struct {
 	NMIP6Device *device;
-	guint dhcp_opts;
 	gboolean success;
 } CallbackInfo;
 
@@ -238,14 +461,14 @@ finish_addrconf (gpointer user_data)
 	/* And tell listeners that addrconf is complete */
 	if (info->success) {
 		g_signal_emit (manager, signals[ADDRCONF_COMPLETE], 0,
-		               ifindex, info->dhcp_opts, TRUE);
+		               ifindex, device->dhcp_opts, TRUE);
 	} else {
 		nm_log_info (LOGD_IP6, "(%s): IP6 addrconf timed out or failed.",
 		             device->iface);
 
 		nm_ip6_manager_cancel_addrconf (manager, ifindex);
 		g_signal_emit (manager, signals[ADDRCONF_COMPLETE], 0,
-		               ifindex, info->dhcp_opts, FALSE);
+		               ifindex, device->dhcp_opts, FALSE);
 	}
 
 	return FALSE;
@@ -261,7 +484,7 @@ emit_config_changed (gpointer user_data)
 	device->config_changed_id = 0;
 	g_signal_emit (manager, signals[CONFIG_CHANGED], 0,
 	               device->ifindex,
-	               info->dhcp_opts,
+	               device->dhcp_opts,
 	               info->success);
 	return FALSE;
 }
@@ -272,7 +495,7 @@ static gboolean
 rdnss_expired (gpointer user_data)
 {
 	NMIP6Device *device = user_data;
-	CallbackInfo info = { device, IP6_DHCP_OPT_NONE, FALSE };
+	CallbackInfo info = { device, FALSE };
 
 	nm_log_dbg (LOGD_IP6, "(%s): IPv6 RDNSS information expired", device->iface);
 
@@ -282,6 +505,22 @@ rdnss_expired (gpointer user_data)
 	return FALSE;
 }
 
+static gboolean
+rdnss_needs_refresh (gpointer user_data)
+{
+	NMIP6Device *device = user_data;
+	gchar *msg;
+
+	msg = g_strdup_printf ("IPv6 RDNSS due to expire in %d seconds",
+	                       device->rdnss_timeout);
+	device_send_router_solicitation (device, msg);
+	g_free (msg);
+
+	set_rdnss_timeout (device);
+
+	return FALSE;
+}
+
 static void
 set_rdnss_timeout (NMIP6Device *device)
 {
@@ -320,9 +559,23 @@ set_rdnss_timeout (NMIP6Device *device)
 	}
 
 	if (expires) {
-		device->rdnss_timeout_id = g_timeout_add_seconds (MIN (expires - now, G_MAXUINT32 - 1),
-		                                                  rdnss_expired,
-		                                                  device);
+		gchar *msg;
+
+		device->rdnss_timeout = MIN (expires - now, G_MAXUINT32 - 1);
+
+		if (device->rdnss_timeout <= 5) {
+			msg = g_strdup_printf ("IPv6 RDNSS about to expire in %d seconds",
+			                       device->rdnss_timeout);
+			device_send_router_solicitation (device, msg);
+			g_free (msg);
+			device->rdnss_timeout_id = g_timeout_add_seconds (device->rdnss_timeout,
+			                                                  rdnss_expired,
+			                                                  device);
+		} else {
+			device->rdnss_timeout_id = g_timeout_add_seconds (device->rdnss_timeout / 2,
+			                                                  rdnss_needs_refresh,
+			                                                  device);
+		}
 	}
 }
 
@@ -332,7 +585,7 @@ static gboolean
 dnssl_expired (gpointer user_data)
 {
 	NMIP6Device *device = user_data;
-	CallbackInfo info = { device, IP6_DHCP_OPT_NONE, FALSE };
+	CallbackInfo info = { device, FALSE };
 
 	nm_log_dbg (LOGD_IP6, "(%s): IPv6 DNSSL information expired", device->iface);
 
@@ -342,6 +595,22 @@ dnssl_expired (gpointer user_data)
 	return FALSE;
 }
 
+static gboolean
+dnssl_needs_refresh (gpointer user_data)
+{
+	NMIP6Device *device = user_data;
+	gchar *msg;
+
+	msg = g_strdup_printf ("IPv6 DNSSL due to expire in %d seconds",
+	                       device->dnssl_timeout);
+	device_send_router_solicitation (device, msg);
+	g_free (msg);
+
+	set_dnssl_timeout (device);
+
+	return FALSE;
+}
+
 static void
 set_dnssl_timeout (NMIP6Device *device)
 {
@@ -376,59 +645,49 @@ set_dnssl_timeout (NMIP6Device *device)
 	}
 
 	if (expires) {
-		device->dnssl_timeout_id = g_timeout_add_seconds (MIN (expires - now, G_MAXUINT32 - 1),
-		                                                  dnssl_expired,
-		                                                  device);
+		gchar *msg;
+
+		device->dnssl_timeout = MIN (expires - now, G_MAXUINT32 - 1);
+
+		if (device->dnssl_timeout <= 5) {
+			msg = g_strdup_printf ("IPv6 DNSSL about to expire in %d seconds",
+			                       device->dnssl_timeout);
+			device_send_router_solicitation (device, msg);
+			g_free (msg);
+			device->dnssl_timeout_id = g_timeout_add_seconds (device->dnssl_timeout,
+			                                                  dnssl_expired,
+			                                                  device);
+		} else {
+			device->dnssl_timeout_id = g_timeout_add_seconds (device->dnssl_timeout / 2,
+			                                                  dnssl_needs_refresh,
+			                                                  device);
+		}
 	}
 }
 
 static CallbackInfo *
-callback_info_new (NMIP6Device *device, guint dhcp_opts, gboolean success)
+callback_info_new (NMIP6Device *device, gboolean success)
 {
 	CallbackInfo *info;
 
 	info = g_malloc0 (sizeof (CallbackInfo));
 	info->device = device;
-	info->dhcp_opts = dhcp_opts;
 	info->success = success;
 	return info;
 }
 
-static const char *
-state_to_string (NMIP6DeviceState state)
-{
-	switch (state) {
-	case NM_IP6_DEVICE_UNCONFIGURED:
-		return "unconfigured";
-	case NM_IP6_DEVICE_GOT_LINK_LOCAL:
-		return "got-link-local";
-	case NM_IP6_DEVICE_GOT_ROUTER_ADVERTISEMENT:
-		return "got-ra";
-	case NM_IP6_DEVICE_GOT_ADDRESS:
-		return "got-address";
-	case NM_IP6_DEVICE_TIMED_OUT:
-		return "timed-out";
-	default:
-		return "unknown";
-	}
-}
-
 static void
-nm_ip6_device_sync_from_netlink (NMIP6Device *device, gboolean config_changed)
+check_addresses (NMIP6Device *device)
 {
 	NMIP6Manager *manager = device->manager;
 	NMIP6ManagerPrivate *priv = NM_IP6_MANAGER_GET_PRIVATE (manager);
 	struct rtnl_addr *rtnladdr;
 	struct nl_addr *nladdr;
 	struct in6_addr *addr;
-	CallbackInfo *info;
-	guint dhcp_opts = IP6_DHCP_OPT_NONE;
-	gboolean found_linklocal = FALSE, found_other = FALSE;
 
-	nm_log_dbg (LOGD_IP6, "(%s): syncing with netlink (ra_flags 0x%X) (state/target '%s'/'%s')",
-	            device->iface, device->ra_flags,
-	            state_to_string (device->state),
-	            state_to_string (device->target_state));
+	/* Reset address information */
+	device->has_linklocal = FALSE;
+	device->has_nonlinklocal = FALSE;
 
 	/* Look for any IPv6 addresses the kernel may have set for the device */
 	for (rtnladdr = (struct rtnl_addr *) nl_cache_get_first (priv->addr_cache);
@@ -453,12 +712,12 @@ nm_ip6_device_sync_from_netlink (NMIP6Device *device, gboolean config_changed)
 
 		if (IN6_IS_ADDR_LINKLOCAL (addr)) {
 			if (device->state == NM_IP6_DEVICE_UNCONFIGURED)
-				device->state = NM_IP6_DEVICE_GOT_LINK_LOCAL;
-			found_linklocal = TRUE;
+				device_set_state (device, NM_IP6_DEVICE_GOT_LINK_LOCAL);
+			device->has_linklocal = TRUE;
 		} else {
 			if (device->state < NM_IP6_DEVICE_GOT_ADDRESS)
-				device->state = NM_IP6_DEVICE_GOT_ADDRESS;
-			found_other = TRUE;
+				device_set_state (device, NM_IP6_DEVICE_GOT_ADDRESS);
+			device->has_nonlinklocal = TRUE;
 		}
 	}
 
@@ -466,27 +725,41 @@ nm_ip6_device_sync_from_netlink (NMIP6Device *device, gboolean config_changed)
 	 * before in the initial run, but if it goes away later, make sure we
 	 * regress from GOT_LINK_LOCAL back to UNCONFIGURED.
 	 */
-	if ((device->state == NM_IP6_DEVICE_GOT_LINK_LOCAL) && !found_linklocal)
-		device->state = NM_IP6_DEVICE_UNCONFIGURED;
+	if ((device->state == NM_IP6_DEVICE_GOT_LINK_LOCAL) && !device->has_linklocal)
+		device_set_state (device, NM_IP6_DEVICE_UNCONFIGURED);
 
-	nm_log_dbg (LOGD_IP6, "(%s): addresses synced (state %s)",
-	            device->iface, state_to_string (device->state));
+	nm_log_dbg (LOGD_IP6, "(%s): addresses checked (state %s)",
+		    device->iface, state_to_string (device->state));
+}
+
+static void
+check_ra_flags (NMIP6Device *device)
+{
+	device->dhcp_opts = IP6_DHCP_OPT_NONE;
 
 	/* We only care about router advertisements if we want a real IPv6 address */
 	if (   (device->target_state == NM_IP6_DEVICE_GOT_ADDRESS)
 	    && (device->ra_flags & IF_RA_RCVD)) {
 
 		if (device->state < NM_IP6_DEVICE_GOT_ROUTER_ADVERTISEMENT)
-			device->state = NM_IP6_DEVICE_GOT_ROUTER_ADVERTISEMENT;
+			device_set_state (device, NM_IP6_DEVICE_GOT_ROUTER_ADVERTISEMENT);
 
 		if (device->ra_flags & IF_RA_MANAGED) {
-			dhcp_opts = IP6_DHCP_OPT_MANAGED;
+			device->dhcp_opts = IP6_DHCP_OPT_MANAGED;
 			nm_log_dbg (LOGD_IP6, "router advertisement deferred to DHCPv6");
 		} else if (device->ra_flags & IF_RA_OTHERCONF) {
-			dhcp_opts = IP6_DHCP_OPT_OTHERCONF;
+			device->dhcp_opts = IP6_DHCP_OPT_OTHERCONF;
 			nm_log_dbg (LOGD_IP6, "router advertisement requests parallel DHCPv6");
 		}
 	}
+	nm_log_dbg (LOGD_IP6, "(%s): router advertisement checked (state %s)",
+		    device->iface, state_to_string (device->state));
+}
+
+static void
+check_addrconf_complete (NMIP6Device *device)
+{
+	CallbackInfo *info;
 
 	if (!device->addrconf_complete) {
 		/* Managed mode (ie DHCP only) short-circuits automatic addrconf, so
@@ -494,7 +767,7 @@ nm_ip6_device_sync_from_netlink (NMIP6Device *device, gboolean config_changed)
 		 * when the RA requests managed mode.
 		 */
 		if (   (device->state >= device->target_state)
-		    || (dhcp_opts == IP6_DHCP_OPT_MANAGED)) {
+		    || (device->dhcp_opts == IP6_DHCP_OPT_MANAGED)) {
 			/* device->finish_addrconf_id may currently be a timeout
 			 * rather than an idle, so we remove the existing source.
 			 */
@@ -503,15 +776,15 @@ nm_ip6_device_sync_from_netlink (NMIP6Device *device, gboolean config_changed)
 
 			nm_log_dbg (LOGD_IP6, "(%s): reached target state or Managed-mode requested (state '%s') (dhcp opts 0x%X)",
 			            device->iface, state_to_string (device->state),
-			            dhcp_opts);
+			            device->dhcp_opts);
 
-			info = callback_info_new (device, dhcp_opts, TRUE);
+			info = callback_info_new (device, TRUE);
 			device->finish_addrconf_id = g_idle_add_full (G_PRIORITY_DEFAULT_IDLE,
 			                                              finish_addrconf,
 			                                              info,
 			                                              (GDestroyNotify) g_free);
 		}
-	} else if (config_changed) {
+	} else {
 		if (!device->config_changed_id) {
 			gboolean success = TRUE;
 
@@ -520,19 +793,35 @@ nm_ip6_device_sync_from_netlink (NMIP6Device *device, gboolean config_changed)
 			 */
 			if (   (device->state == NM_IP6_DEVICE_GOT_ADDRESS)
 			    && (device->target_state == NM_IP6_DEVICE_GOT_ADDRESS)
-			    && !found_other) {
-				nm_log_dbg (LOGD_IP6, "(%s): RA-provided address no longer valid",
+			    && !device->has_nonlinklocal) {
+				nm_log_dbg (LOGD_IP6, "(%s): RA-provided address no longer found",
 				            device->iface);
 				success = FALSE;
 			}
 
-			info = callback_info_new (device, dhcp_opts, success);
+			info = callback_info_new (device, success);
 			device->config_changed_id = g_idle_add_full (G_PRIORITY_DEFAULT_IDLE,
 			                                             emit_config_changed,
 			                                             info,
 			                                             (GDestroyNotify) g_free);
 		}
 	}
+
+	nm_log_dbg (LOGD_IP6, "(%s): dhcp_opts checked (state %s)",
+		    device->iface, state_to_string (device->state));
+}
+
+static void
+nm_ip6_device_sync_from_netlink (NMIP6Device *device)
+{
+	nm_log_dbg (LOGD_IP6, "(%s): syncing with netlink (ra_flags 0x%X) (state/target '%s'/'%s')",
+	            device->iface, device->ra_flags,
+	            state_to_string (device->state),
+	            state_to_string (device->target_state));
+
+	check_addresses (device);
+	check_ra_flags (device);
+	check_addrconf_complete (device);
 }
 
 static void
@@ -544,16 +833,51 @@ ref_object (struct nl_object *obj, void *data)
 	*out = obj;
 }
 
+static void
+dump_address_change (NMIP6Device *device, struct nlmsghdr *hdr, struct rtnl_addr *rtnladdr)
+{
+	char *event;
+	struct nl_addr *addr;
+	char addr_str[40] = "none";
+
+	event = hdr->nlmsg_type == RTM_NEWADDR ? "new" : "lost";
+	addr = rtnl_addr_get_local (rtnladdr);
+	if (addr)
+		nl_addr2str (addr, addr_str, 40);
+
+	nm_log_dbg (LOGD_IP6, "(%s) %s address: %s", device_get_iface (device), event, addr_str);
+}
+
+static void
+dump_route_change (NMIP6Device *device, struct nlmsghdr *hdr, struct rtnl_route *rtnlroute)
+{
+	char *event;
+	struct nl_addr *dst;
+	char dst_str[40] = "none";
+	struct nl_addr *gateway;
+	char gateway_str[40] = "none";
+
+	event = hdr->nlmsg_type == RTM_NEWROUTE ? "new" : "lost";
+	dst = rtnl_route_get_dst (rtnlroute);
+	gateway = rtnl_route_get_gateway (rtnlroute);
+	if (dst)
+		nl_addr2str (dst, dst_str, 40);
+	if (gateway)
+		nl_addr2str (gateway, gateway_str, 40);
+
+	nm_log_dbg (LOGD_IP6, "(%s) %s route: %s via %s",device_get_iface (device), event, dst_str, gateway_str);
+}
+
 static NMIP6Device *
-process_addr (NMIP6Manager *manager, struct nl_msg *msg)
+process_address_change (NMIP6Manager *manager, struct nl_msg *msg)
 {
 	NMIP6ManagerPrivate *priv = NM_IP6_MANAGER_GET_PRIVATE (manager);
 	NMIP6Device *device;
+	struct nlmsghdr *hdr;
 	struct rtnl_addr *rtnladdr;
 	int old_size;
 
-	nm_log_dbg (LOGD_IP6, "processing netlink new/del address message");
-
+	hdr = nlmsg_hdr (msg);
 	rtnladdr = NULL;
 	nl_msg_parse (msg, ref_object, &rtnladdr);
 	if (!rtnladdr) {
@@ -562,39 +886,34 @@ process_addr (NMIP6Manager *manager, struct nl_msg *msg)
 	}
 
 	device = nm_ip6_manager_get_device (manager, rtnl_addr_get_ifindex (rtnladdr));
-	if (!device) {
-		nm_log_dbg (LOGD_IP6, "ignoring message for unknown device");
-		rtnl_addr_put (rtnladdr);
-		return NULL;
-	}
 
 	old_size = nl_cache_nitems (priv->addr_cache);
 	nl_cache_include (priv->addr_cache, (struct nl_object *)rtnladdr, NULL, NULL);
-	rtnl_addr_put (rtnladdr);
 
 	/* The kernel will re-notify us of automatically-added addresses
 	 * every time it gets another router advertisement. We only want
 	 * to notify higher levels if we actually changed something.
 	 */
-	if (nl_cache_nitems (priv->addr_cache) == old_size) {
-		nm_log_dbg (LOGD_IP6, "(%s): address cache unchanged, ignoring message",
-		            device->iface);
+	nm_log_dbg (LOGD_IP6, "(%s): address cache size: %d -> %d:",
+		    device_get_iface (device), old_size, nl_cache_nitems (priv->addr_cache));
+	dump_address_change (device, hdr, rtnladdr);
+	rtnl_addr_put (rtnladdr);
+	if (nl_cache_nitems (priv->addr_cache) == old_size)
 		return NULL;
-	}
 
 	return device;
 }
 
 static NMIP6Device *
-process_route (NMIP6Manager *manager, struct nl_msg *msg)
+process_route_change (NMIP6Manager *manager, struct nl_msg *msg)
 {
 	NMIP6ManagerPrivate *priv = NM_IP6_MANAGER_GET_PRIVATE (manager);
 	NMIP6Device *device;
+	struct nlmsghdr *hdr;
 	struct rtnl_route *rtnlroute;
 	int old_size;
 
-	nm_log_dbg (LOGD_IP6, "processing netlink new/del route message");
-
+	hdr = nlmsg_hdr (msg);
 	rtnlroute = NULL;
 	nl_msg_parse (msg, ref_object, &rtnlroute);
 	if (!rtnlroute) {
@@ -603,53 +922,17 @@ process_route (NMIP6Manager *manager, struct nl_msg *msg)
 	}
 
 	device = nm_ip6_manager_get_device (manager, rtnl_route_get_oif (rtnlroute));
-	if (!device) {
-		nm_log_dbg (LOGD_IP6, "ignoring message for unknown device");
-		rtnl_route_put (rtnlroute);
-		return NULL;
-	}
 
 	old_size = nl_cache_nitems (priv->route_cache);
 	nl_cache_include (priv->route_cache, (struct nl_object *)rtnlroute, NULL, NULL);
-	rtnl_route_put (rtnlroute);
-
-	/* As above in process_addr */
-	if (nl_cache_nitems (priv->route_cache) == old_size) {
-		nm_log_dbg (LOGD_IP6, "(%s): route cache unchanged, ignoring message",
-		            device->iface);
-		return NULL;
-	}
 
-	return device;
-}
-
-static NMIP6Device *
-process_prefix (NMIP6Manager *manager, struct nl_msg *msg)
-{
-	struct prefixmsg *pmsg;
-	NMIP6Device *device;
-
-	/* We don't care about the prefix itself, but if we receive a
-	 * router advertisement telling us to use DHCP, we might not
-	 * get any RTM_NEWADDRs or RTM_NEWROUTEs, so this is our only
-	 * way to notice immediately that an RA was received.
-	 */
-
-	nm_log_dbg (LOGD_IP6, "processing netlink new prefix message");
-
-	if (!nlmsg_valid_hdr (nlmsg_hdr (msg), sizeof(*pmsg))) {
-		nm_log_dbg (LOGD_IP6, "ignoring invalid prefix message");
-		return NULL;
-	}
-
-	pmsg = (struct prefixmsg *) NLMSG_DATA (nlmsg_hdr (msg));
-	device = nm_ip6_manager_get_device (manager, pmsg->prefix_ifindex);
-
-	if (!device || device->addrconf_complete) {
-		nm_log_dbg (LOGD_IP6, "(%s): ignoring unknown or completed device",
-		            device ? device->iface : "(none)");
+	/* As above in process_address_change */
+	nm_log_dbg (LOGD_IP6, "(%s): route cache size: %d -> %d:",
+		    device_get_iface (device), old_size, nl_cache_nitems (priv->route_cache));
+	dump_route_change (device, hdr, rtnlroute);
+	rtnl_route_put (rtnlroute);
+	if (nl_cache_nitems (priv->route_cache) == old_size)
 		return NULL;
-	}
 
 	return device;
 }
@@ -705,7 +988,9 @@ process_nduseropt_rdnss (NMIP6Device *device, struct nd_opt_hdr *opt)
 	 */
 	server.expires = ntohl (rdnss_opt->nd_opt_rdnss_lifetime);
 	if (server.expires > 0)
-		server.expires += now + 10;
+		if (server.expires < 7200)
+			server.expires = 7200;
+		server.expires += now;
 
 	for (addr = (struct in6_addr *) (rdnss_opt + 1); opt_len >= 2; addr++, opt_len -= 2) {
 		char buf[INET6_ADDRSTRLEN + 1];
@@ -836,7 +1121,9 @@ process_nduseropt_dnssl (NMIP6Device *device, struct nd_opt_hdr *opt)
 	 */
 	domain.expires = ntohl (dnssl_opt->nd_opt_dnssl_lifetime);
 	if (domain.expires > 0)
-		domain.expires += now + 10;
+		if (domain.expires < 7200)
+			domain.expires = 7200;
+		domain.expires += now;
 
 	while (opt_len) {
 		const char *domain_str;
@@ -985,28 +1272,6 @@ static struct nla_policy link_prot_policy[IFLA_INET6_MAX + 1] = {
 	[IFLA_INET6_FLAGS]	= { .type = NLA_U32 },
 };
 
-static char *
-ra_flags_to_string (guint32 ra_flags)
-{
-	GString *s = g_string_sized_new (20);
-
-	g_string_append (s, " (");
-	if (ra_flags & IF_RS_SENT)
-		g_string_append_c (s, 'S');
-
-	if (ra_flags & IF_RA_RCVD)
-		g_string_append_c (s, 'R');
-
-	if (ra_flags & IF_RA_OTHERCONF)
-		g_string_append_c (s, 'O');
-
-	if (ra_flags & IF_RA_MANAGED)
-		g_string_append_c (s, 'M');
-
-	g_string_append_c (s, ')');
-	return g_string_free (s, FALSE);
-}
-
 static NMIP6Device *
 process_newlink (NMIP6Manager *manager, struct nl_msg *msg)
 {
@@ -1016,7 +1281,6 @@ process_newlink (NMIP6Manager *manager, struct nl_msg *msg)
 	struct nlattr *tb[IFLA_MAX + 1];
 	struct nlattr *pi[IFLA_INET6_MAX + 1];
 	int err;
-	char *flags_str = NULL;
 
 	/* FIXME: we have to do this manually for now since libnl doesn't yet
 	 * support the IFLA_PROTINFO attribute of NEWLINK messages.  When it does,
@@ -1059,13 +1323,7 @@ process_newlink (NMIP6Manager *manager, struct nl_msg *msg)
 		return NULL;
 	}
 
-	device->ra_flags = nla_get_u32 (pi[IFLA_INET6_FLAGS]);
-
-	if (nm_logging_level_enabled (LOGL_DEBUG))
-		flags_str = ra_flags_to_string (device->ra_flags);
-	nm_log_dbg (LOGD_IP6, "(%s): got IPv6 flags 0x%X%s",
-	            device->iface, device->ra_flags, flags_str ? flags_str : "");
-	g_free (flags_str);
+	device_set_ra_flags (device, nla_get_u32 (pi[IFLA_INET6_FLAGS]));
 
 	return device;
 }
@@ -1076,39 +1334,30 @@ netlink_notification (NMNetlinkMonitor *monitor, struct nl_msg *msg, gpointer us
 	NMIP6Manager *manager = (NMIP6Manager *) user_data;
 	NMIP6Device *device;
 	struct nlmsghdr *hdr;
-	gboolean config_changed = FALSE;
 
 	hdr = nlmsg_hdr (msg);
 	nm_log_dbg (LOGD_HW, "netlink event type %d", hdr->nlmsg_type);
 	switch (hdr->nlmsg_type) {
 	case RTM_NEWADDR:
 	case RTM_DELADDR:
-		device = process_addr (manager, msg);
-		config_changed = TRUE;
+		device = process_address_change (manager, msg);
 		break;
 	case RTM_NEWROUTE:
 	case RTM_DELROUTE:
-		device = process_route (manager, msg);
-		config_changed = TRUE;
-		break;
-	case RTM_NEWPREFIX:
-		device = process_prefix (manager, msg);
+		device = process_route_change (manager, msg);
 		break;
 	case RTM_NEWNDUSEROPT:
 		device = process_nduseropt (manager, msg);
-		config_changed = TRUE;
 		break;
 	case RTM_NEWLINK:
 		device = process_newlink (manager, msg);
-		config_changed = TRUE;
 		break;
 	default:
 		return;
 	}
 
 	if (device) {
-		nm_log_dbg (LOGD_IP6, "(%s): syncing device with netlink changes", device->iface);
-		nm_ip6_device_sync_from_netlink (device, config_changed);
+		nm_ip6_device_sync_from_netlink (device);
 	}
 }
 
@@ -1179,7 +1428,7 @@ nm_ip6_manager_begin_addrconf (NMIP6Manager *manager, int ifindex)
 	device->ra_flags = 0;
 
 	/* Set up a timeout on the transaction to kill it after the timeout */
-	info = callback_info_new (device, 0, FALSE);
+	info = callback_info_new (device, FALSE);
 	device->finish_addrconf_id = g_timeout_add_seconds_full (G_PRIORITY_DEFAULT,
 	                                                         NM_IP6_TIMEOUT,
 	                                                         finish_addrconf,
@@ -1204,7 +1453,7 @@ nm_ip6_manager_begin_addrconf (NMIP6Manager *manager, int ifindex)
 	 * device is already fully configured and schedule the
 	 * ADDRCONF_COMPLETE signal in that case.
 	 */
-	nm_ip6_device_sync_from_netlink (device, FALSE);
+	nm_ip6_device_sync_from_netlink (device);
 }
 
 void
@@ -1235,9 +1484,7 @@ nm_ip6_manager_get_ip6_config (NMIP6Manager *manager, int ifindex)
 	NMIP6Address *ip6addr;
 	struct rtnl_route *rtnlroute;
 	struct nl_addr *nldest, *nlgateway;
-	struct in6_addr *dest, *gateway;
-	gboolean defgw_set = FALSE;
-	struct in6_addr defgw;
+	const struct in6_addr *dest, *gateway;
 	uint32_t metric;
 	NMIP6Route *ip6route;
 	int i;
@@ -1287,11 +1534,9 @@ nm_ip6_manager_get_ip6_config (NMIP6Manager *manager, int ifindex)
 		gateway = nl_addr_get_binary_addr (nlgateway);
 
 		if (rtnl_route_get_dst_len (rtnlroute) == 0) {
-			/* Default gateway route; don't add to normal routes but to each address */
-			if (!defgw_set) {
-				memcpy (&defgw, gateway, sizeof (defgw));
-				defgw_set = TRUE;
-			}
+			/* Default gateway route; cache the router's address for later */
+			if (!nm_ip6_config_get_gateway (config))
+				nm_ip6_config_set_gateway (config, gateway);
 			continue;
 		}
 
@@ -1326,8 +1571,9 @@ nm_ip6_manager_get_ip6_config (NMIP6Manager *manager, int ifindex)
 		nm_ip6_address_set_prefix (ip6addr, rtnl_addr_get_prefixlen (rtnladdr));
 		nm_ip6_address_set_address (ip6addr, addr);
 		nm_ip6_config_take_address (config, ip6addr);
-		if (defgw_set)
-			nm_ip6_address_set_gateway (ip6addr, &defgw);
+		gateway = nm_ip6_config_get_gateway (config);
+		if (gateway)
+			nm_ip6_address_set_gateway (ip6addr, gateway);
 	}
 
 	/* Add DNS servers */
diff --git a/src/logging/Makefile.in b/src/logging/Makefile.in
index c73f71b4..45f84326 100644
--- a/src/logging/Makefile.in
+++ b/src/logging/Makefile.in
@@ -47,7 +47,7 @@ am__aclocal_m4_deps = $(top_srcdir)/m4/compiler_warnings.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)/configure.ac
+	$(top_srcdir)/m4/vapigen.m4 $(top_srcdir)/configure.ac
 am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \
 	$(ACLOCAL_M4)
 mkinstalldirs = $(install_sh) -d
@@ -165,6 +165,10 @@ INTLTOOL_EXTRACT = @INTLTOOL_EXTRACT@
 INTLTOOL_MERGE = @INTLTOOL_MERGE@
 INTLTOOL_PERL = @INTLTOOL_PERL@
 INTLTOOL_UPDATE = @INTLTOOL_UPDATE@
+INTLTOOL_V_MERGE = @INTLTOOL_V_MERGE@
+INTLTOOL_V_MERGE_OPTIONS = @INTLTOOL_V_MERGE_OPTIONS@
+INTLTOOL__v_MERGE_ = @INTLTOOL__v_MERGE_@
+INTLTOOL__v_MERGE_0 = @INTLTOOL__v_MERGE_0@
 INTL_MACOSX_LIBS = @INTL_MACOSX_LIBS@
 INTROSPECTION_CFLAGS = @INTROSPECTION_CFLAGS@
 INTROSPECTION_COMPILER = @INTROSPECTION_COMPILER@
@@ -260,6 +264,9 @@ UDEV_BASE_DIR = @UDEV_BASE_DIR@
 USE_NLS = @USE_NLS@
 UUID_CFLAGS = @UUID_CFLAGS@
 UUID_LIBS = @UUID_LIBS@
+VAPIGEN = @VAPIGEN@
+VAPIGEN_MAKEFILE = @VAPIGEN_MAKEFILE@
+VAPIGEN_VAPIDIR = @VAPIGEN_VAPIDIR@
 VERSION = @VERSION@
 XGETTEXT = @XGETTEXT@
 XGETTEXT_015 = @XGETTEXT_015@
@@ -298,6 +305,8 @@ htmldir = @htmldir@
 includedir = @includedir@
 infodir = @infodir@
 install_sh = @install_sh@
+intltool__v_merge_options_ = @intltool__v_merge_options_@
+intltool__v_merge_options_0 = @intltool__v_merge_options_0@
 libdir = @libdir@
 libexecdir = @libexecdir@
 localedir = @localedir@
diff --git a/src/logging/nm-logging.c b/src/logging/nm-logging.c
index a2b0ebaf..f54adcdd 100644
--- a/src/logging/nm-logging.c
+++ b/src/logging/nm-logging.c
@@ -46,7 +46,7 @@ static guint32 log_domains = \
 	LOGD_DHCP4 | LOGD_DHCP6 | LOGD_PPP | 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_WIMAX | LOGD_INFINIBAND | LOGD_FIREWALL | LOGD_ADSL;
 
 typedef struct {
 	guint32 num;
@@ -89,6 +89,7 @@ static const LogDesc domain_descs[] = {
 	{ LOGD_WIMAX,     "WIMAX" },
 	{ LOGD_INFINIBAND,"INFINIBAND" },
 	{ LOGD_FIREWALL,  "FIREWALL" },
+	{ LOGD_ADSL,      "ADSL" },
 	{ 0, NULL }
 };
 
diff --git a/src/logging/nm-logging.h b/src/logging/nm-logging.h
index 7e27f311..b3595d18 100644
--- a/src/logging/nm-logging.h
+++ b/src/logging/nm-logging.h
@@ -54,6 +54,7 @@ enum {
 	LOGD_WIMAX      = 0x00800000,
 	LOGD_INFINIBAND = 0x01000000,
 	LOGD_FIREWALL   = 0x02000000,
+	LOGD_ADSL       = 0x04000000,
 };
 
 #define LOGD_DHCP (LOGD_DHCP4 | LOGD_DHCP6)
diff --git a/src/main.c b/src/main.c
index 4a21959f..e8ff2e4c 100644
--- a/src/main.c
+++ b/src/main.c
@@ -29,6 +29,7 @@
 #include <errno.h>
 #include <stdlib.h>
 #include <signal.h>
+#include <pthread.h>
 #include <unistd.h>
 #include <fcntl.h>
 #include <sys/stat.h>
@@ -53,6 +54,7 @@
 #include "nm-logging.h"
 #include "nm-policy-hosts.h"
 #include "nm-config.h"
+#include "nm-posix-signals.h"
 
 #if !defined(NM_DIST_VERSION)
 # define NM_DIST_VERSION VERSION
@@ -66,101 +68,107 @@
  */
 static NMManager *manager = NULL;
 static GMainLoop *main_loop = NULL;
-static int quit_pipe[2] = { -1, -1 };
-
 static gboolean quit_early = FALSE;
+static sigset_t signal_set;
 
-static void
-nm_signal_handler (int signo)
+void *signal_handling_thread (void *arg);
+/*
+ * Thread function waiting for signals and processing them.
+ * Wait for signals in signal set. The semantics of sigwait() require that all
+ * threads (including the thread calling sigwait()) have the signal masked, for
+ * reliable operation. Otherwise, a signal that arrives while this thread is
+ * not blocked in sigwait() might be delivered to another thread.
+ */
+void *
+signal_handling_thread (void *arg)
 {
-	static int in_fatal = 0, x;
-
-	/* avoid loops */
-	if (in_fatal > 0)
-		return;
-	++in_fatal;
-
-	switch (signo) {
-	case SIGSEGV:
-	case SIGBUS:
-	case SIGILL:
-	case SIGABRT:
-		nm_log_warn (LOGD_CORE, "caught signal %d. Generating backtrace...", signo);
-		nm_logging_backtrace ();
-		exit (1);
-		break;
-	case SIGFPE:
-	case SIGPIPE:
-		/* let the fatal signals interrupt us */
-		--in_fatal;
-		nm_log_warn (LOGD_CORE, "caught signal %d, shutting down abnormally. Generating backtrace...", signo);
-		nm_logging_backtrace ();
-		x = write (quit_pipe[1], "X", 1);
-		break;
-	case SIGINT:
-	case SIGTERM:
-		/* let the fatal signals interrupt us */
-		--in_fatal;
-		nm_log_info (LOGD_CORE, "caught signal %d, shutting down normally.", signo);
-		quit_early = TRUE;
-		x = write (quit_pipe[1], "X", 1);
-		break;
-	case SIGHUP:
-		--in_fatal;
-		/* Reread config stuff like system config files, VPN service files, etc */
-		break;
-	case SIGUSR1:
-		--in_fatal;
-		/* Play with log levels or something */
-		break;
-	default:
-		signal (signo, nm_signal_handler);
-		break;
-	}
+	int signo;
+
+	while (1) {
+		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);
+			quit_early = TRUE; /* for quitting before entering the main loop */
+			g_main_loop_quit (main_loop);
+			break;
+		case SIGHUP:
+			/* Reread config stuff like system config files, VPN service files, etc */
+			nm_log_info (LOGD_CORE, "caught signal %d, not supported yet.", signo);
+			break;
+		case SIGUSR1:
+			/* Play with log levels or something */
+			nm_log_info (LOGD_CORE, "caught signal %d, not supported yet.", signo);
+			break;
+		default:
+			nm_log_err (LOGD_CORE, "caught unexpected signal %d", signo);
+			break;
+		}
+    }
+    return NULL;
 }
 
+/*
+ * Mask the signals we are interested in and create a signal handling thread.
+ * Because all threads inherit the signal mask from their creator, all threads
+ * in the process will have the signals masked. That's why setup_signals() has
+ * to be called before creating other threads.
+ */
 static gboolean
-quit_watch (GIOChannel *src, GIOCondition condition, gpointer user_data)
-{
-
-	if (condition & G_IO_IN) {
-		nm_log_warn (LOGD_CORE, "quit request received, terminating...");
-		g_main_loop_quit (main_loop);
-	}
-
-	return FALSE;
-}
-
-static void
 setup_signals (void)
 {
-	struct sigaction action;
-	sigset_t mask;
-	GIOChannel *quit_channel;
+	pthread_t signal_thread_id;
+	sigset_t old_sig_mask;
+	int status;
+
+	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);
+
+	/* Block all signals of interest. */
+	status = pthread_sigmask (SIG_BLOCK, &signal_set, &old_sig_mask);
+	if (status != 0) {
+		fprintf (stderr, _("Failed to set signal mask: %d"), status);
+		return FALSE;
+	}
+	/* Save original mask so that we could use it for child processes. */
+	nm_save_original_signal_mask (old_sig_mask);
 
-	/* Set up our quit pipe */
-	if (pipe (quit_pipe) < 0) {
-		fprintf (stderr, _("Failed to initialize SIGTERM pipe: %d"), errno);
-		exit (1);
+	/* Create the signal handling thread. */
+	status = pthread_create (&signal_thread_id, NULL, signal_handling_thread, NULL);
+	if (status != 0) {
+		fprintf (stderr, _("Failed to create signal handling thread: %d"), status);
+		return FALSE;
 	}
-	fcntl (quit_pipe[1], F_SETFL, O_NONBLOCK | fcntl (quit_pipe[1], F_GETFL));
-
-	quit_channel = g_io_channel_unix_new (quit_pipe[0]);
-	g_io_add_watch_full (quit_channel, G_PRIORITY_HIGH, G_IO_IN | G_IO_ERR, quit_watch, NULL, NULL);
-
-	sigemptyset (&mask);
-	action.sa_handler = nm_signal_handler;
-	action.sa_mask = mask;
-	action.sa_flags = 0;
-	sigaction (SIGTERM,  &action, NULL);
-	sigaction (SIGINT,  &action, NULL);
-	sigaction (SIGILL,  &action, NULL);
-	sigaction (SIGBUS,  &action, NULL);
-	sigaction (SIGFPE,  &action, NULL);
-	sigaction (SIGHUP,  &action, NULL);
-	sigaction (SIGSEGV, &action, NULL);
-	sigaction (SIGABRT, &action, NULL);
-	sigaction (SIGUSR1,  &action, NULL);
+
+	return TRUE;
 }
 
 static gboolean
@@ -380,7 +388,7 @@ main (int argc, char *argv[])
 		        "                                          [NONE,HW,RFKILL,ETHER,WIFI,BT,MB,DHCP4,DHCP6,PPP,\n"
 		        "                                           WIFI_SCAN,IP4,IP6,AUTOIP4,DNS,VPN,SHARING,SUPPLICANT,\n"
 		        "                                           AGENTS,SETTINGS,SUSPEND,CORE,DEVICE,OLPC,WIMAX,\n"
-		        "                                           INFINIBAND,FIREWALL]"),
+		        "                                           INFINIBAND,FIREWALL,ADSL]"),
 		        "HW,RFKILL,WIFI" },
 		{ "connectivity-uri", 0, 0, G_OPTION_ARG_STRING, &connectivity_uri, "A http(s) address to check internet connectivity" },
 		{ "connectivity-interval", 0, 0, G_OPTION_ARG_INT, &connectivity_interval, "the interval in seconds how often a connectivity check will be done" },
@@ -393,6 +401,10 @@ main (int argc, char *argv[])
 		exit (1);
 	}
 
+	/* Set up unix signal handling */
+	if (!setup_signals ())
+		exit (1);
+
 	/* Set locale to be able to use environment variables */
 	setlocale (LC_ALL, "");
 
@@ -529,14 +541,19 @@ main (int argc, char *argv[])
 	dbus_glib_global_set_disable_legacy_property_access ();
 #endif
 
-	setup_signals ();
-
 	nm_logging_start (become_daemon);
 
 	nm_log_info (LOGD_CORE, "NetworkManager (version " NM_DIST_VERSION ") is starting...");
 	success = FALSE;
 
 	nm_log_info (LOGD_CORE, "Read config file %s", nm_config_get_path (config));
+	nm_log_info (LOGD_CORE, "WEXT support is %s",
+#if HAVE_WEXT
+	             "enabled"
+#else
+	             "disabled"
+#endif
+	             );
 
 	main_loop = g_main_loop_new (NULL, FALSE);
 
diff --git a/src/modem-manager/Makefile.in b/src/modem-manager/Makefile.in
index 87afed0c..31209330 100644
--- a/src/modem-manager/Makefile.in
+++ b/src/modem-manager/Makefile.in
@@ -47,7 +47,7 @@ am__aclocal_m4_deps = $(top_srcdir)/m4/compiler_warnings.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)/configure.ac
+	$(top_srcdir)/m4/vapigen.m4 $(top_srcdir)/configure.ac
 am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \
 	$(ACLOCAL_M4)
 mkinstalldirs = $(install_sh) -d
@@ -171,6 +171,10 @@ INTLTOOL_EXTRACT = @INTLTOOL_EXTRACT@
 INTLTOOL_MERGE = @INTLTOOL_MERGE@
 INTLTOOL_PERL = @INTLTOOL_PERL@
 INTLTOOL_UPDATE = @INTLTOOL_UPDATE@
+INTLTOOL_V_MERGE = @INTLTOOL_V_MERGE@
+INTLTOOL_V_MERGE_OPTIONS = @INTLTOOL_V_MERGE_OPTIONS@
+INTLTOOL__v_MERGE_ = @INTLTOOL__v_MERGE_@
+INTLTOOL__v_MERGE_0 = @INTLTOOL__v_MERGE_0@
 INTL_MACOSX_LIBS = @INTL_MACOSX_LIBS@
 INTROSPECTION_CFLAGS = @INTROSPECTION_CFLAGS@
 INTROSPECTION_COMPILER = @INTROSPECTION_COMPILER@
@@ -266,6 +270,9 @@ UDEV_BASE_DIR = @UDEV_BASE_DIR@
 USE_NLS = @USE_NLS@
 UUID_CFLAGS = @UUID_CFLAGS@
 UUID_LIBS = @UUID_LIBS@
+VAPIGEN = @VAPIGEN@
+VAPIGEN_MAKEFILE = @VAPIGEN_MAKEFILE@
+VAPIGEN_VAPIDIR = @VAPIGEN_VAPIDIR@
 VERSION = @VERSION@
 XGETTEXT = @XGETTEXT@
 XGETTEXT_015 = @XGETTEXT_015@
@@ -304,6 +311,8 @@ htmldir = @htmldir@
 includedir = @includedir@
 infodir = @infodir@
 install_sh = @install_sh@
+intltool__v_merge_options_ = @intltool__v_merge_options_@
+intltool__v_merge_options_0 = @intltool__v_merge_options_0@
 libdir = @libdir@
 libexecdir = @libexecdir@
 localedir = @localedir@
diff --git a/src/modem-manager/nm-modem.c b/src/modem-manager/nm-modem.c
index 91c0b06d..c9c9e9a4 100644
--- a/src/modem-manager/nm-modem.c
+++ b/src/modem-manager/nm-modem.c
@@ -591,7 +591,7 @@ real_deactivate (NMModem *self, NMDevice *device)
 	case MM_MODEM_IP_METHOD_STATIC:
 	case MM_MODEM_IP_METHOD_DHCP:
 		ifindex = nm_device_get_ip_ifindex (device);
-		if (ifindex >= 0) {
+		if (ifindex > 0) {
 			/* FIXME: use AF_UNSPEC here when we have IPv6 support */
 			nm_system_iface_flush_routes (ifindex, AF_INET);
 			nm_system_iface_flush_addresses (ifindex, AF_UNSPEC);
@@ -614,8 +614,9 @@ static void
 disconnect_done (DBusGProxy *proxy, DBusGProxyCall *call_id, gpointer user_data)
 {
 	GError *error = NULL;
+	gboolean warn = GPOINTER_TO_UINT (user_data);
 
-	if (!dbus_g_proxy_end_call (proxy, call_id, &error, G_TYPE_INVALID)) {
+	if (!dbus_g_proxy_end_call (proxy, call_id, &error, G_TYPE_INVALID) && warn) {
 		nm_log_info (LOGD_MB, "disconnect failed: (%d) %s",
 		             error ? error->code : -1,
 		             error && error->message ? error->message : "(unknown)");
@@ -628,7 +629,7 @@ nm_modem_device_state_changed (NMModem *self,
                                NMDeviceState old_state,
                                NMDeviceStateReason reason)
 {
-	gboolean was_connected = FALSE;
+	gboolean was_connected = FALSE, warn = TRUE;
 	NMModemPrivate *priv;
 
 	g_return_if_fail (self != NULL);
@@ -658,10 +659,13 @@ nm_modem_device_state_changed (NMModem *self,
 		}
 
 		if (was_connected) {
+			/* Don't bother warning on FAILED since the modem is already gone */
+			if (new_state == NM_DEVICE_STATE_FAILED)
+				warn = FALSE;
 			dbus_g_proxy_begin_call (nm_modem_get_proxy (self, MM_DBUS_INTERFACE_MODEM),
 			                         "Disconnect",
 			                         disconnect_done,
-			                         self,
+			                         GUINT_TO_POINTER (warn),
 			                         NULL,
 			                         G_TYPE_INVALID);
 		}
diff --git a/src/nm-activation-request.c b/src/nm-activation-request.c
index 3fc7b538..1a3cb77a 100644
--- a/src/nm-activation-request.c
+++ b/src/nm-activation-request.c
@@ -36,6 +36,7 @@
 #include "nm-device.h"
 #include "nm-active-connection.h"
 #include "nm-settings-connection.h"
+#include "nm-posix-signals.h"
 
 
 G_DEFINE_TYPE (NMActRequest, nm_act_request, NM_TYPE_ACTIVE_CONNECTION)
@@ -129,6 +130,9 @@ nm_act_request_get_secrets (NMActRequest *self,
 	info->callback = callback;
 	info->callback_data = callback_data;
 
+	if (priv->user_requested)
+		flags |= NM_SETTINGS_GET_SECRETS_FLAG_USER_REQUESTED;
+
 	call_id = nm_settings_connection_get_secrets (NM_SETTINGS_CONNECTION (priv->connection),
 	                                              priv->user_requested,
 	                                              priv->user_uid,
@@ -261,6 +265,8 @@ share_child_setup (gpointer user_data G_GNUC_UNUSED)
 	/* We are in the child process at this point */
 	pid_t pid = getpid ();
 	setpgid (pid, pid);
+
+	nm_unblock_posix_signals (NULL);
 }
 
 void
diff --git a/src/nm-connection-provider.c b/src/nm-connection-provider.c
new file mode 100644
index 00000000..401f8dab
--- /dev/null
+++ b/src/nm-connection-provider.c
@@ -0,0 +1,112 @@
+/* -*- Mode: C; tab-width: 4; indent-tabs-mode: t; c-basic-offset: 4 -*- */
+/*
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details:
+ *
+ * Copyright (C) 2012 Red Hat, Inc.
+ */
+
+#include "nm-connection-provider.h"
+
+GSList *
+nm_connection_provider_get_best_connections (NMConnectionProvider *self,
+                                             guint max_requested,
+                                             const char *ctype1,
+                                             const char *ctype2,
+                                             NMConnectionFilterFunc func,
+                                             gpointer func_data)
+{
+	g_return_val_if_fail (NM_IS_CONNECTION_PROVIDER (self), NULL);
+
+	if (NM_CONNECTION_PROVIDER_GET_INTERFACE (self)->get_best_connections)
+		return NM_CONNECTION_PROVIDER_GET_INTERFACE (self)->get_best_connections (self, max_requested, ctype1, ctype2, func, func_data);
+	return NULL;
+}
+
+const GSList *
+nm_connection_provider_get_connections (NMConnectionProvider *self)
+{
+	g_return_val_if_fail (NM_IS_CONNECTION_PROVIDER (self), NULL);
+
+	if (NM_CONNECTION_PROVIDER_GET_INTERFACE (self)->get_connections)
+		return NM_CONNECTION_PROVIDER_GET_INTERFACE (self)->get_connections (self);
+	return NULL;
+}
+
+/*****************************************************************************/
+
+static void
+nm_connection_provider_init (gpointer g_iface)
+{
+	GType iface_type = G_TYPE_FROM_INTERFACE (g_iface);
+	static gboolean initialized = FALSE;
+
+	if (initialized)
+		return;
+	initialized = TRUE;
+
+	/* Signals */
+	g_signal_new (NM_CP_SIGNAL_CONNECTION_ADDED,
+	              iface_type,
+	              G_SIGNAL_RUN_FIRST,
+	              G_STRUCT_OFFSET (NMConnectionProvider, connection_added),
+	              NULL, NULL,
+	              g_cclosure_marshal_VOID__OBJECT,
+	              G_TYPE_NONE, 1, G_TYPE_OBJECT);
+
+	g_signal_new (NM_CP_SIGNAL_CONNECTION_UPDATED,
+	              iface_type,
+	              G_SIGNAL_RUN_FIRST,
+	              G_STRUCT_OFFSET (NMConnectionProvider, connection_updated),
+	              NULL, NULL,
+	              g_cclosure_marshal_VOID__OBJECT,
+	              G_TYPE_NONE, 1, G_TYPE_OBJECT);
+
+	g_signal_new (NM_CP_SIGNAL_CONNECTION_REMOVED,
+	              iface_type,
+	              G_SIGNAL_RUN_FIRST,
+	              G_STRUCT_OFFSET (NMConnectionProvider, connection_removed),
+	              NULL, NULL,
+	              g_cclosure_marshal_VOID__OBJECT,
+	              G_TYPE_NONE, 1, G_TYPE_OBJECT);
+
+	g_signal_new (NM_CP_SIGNAL_CONNECTIONS_LOADED,
+	              iface_type,
+	              G_SIGNAL_RUN_FIRST,
+	              G_STRUCT_OFFSET (NMConnectionProvider, connections_loaded),
+	              NULL, NULL,
+	              g_cclosure_marshal_VOID__VOID,
+	              G_TYPE_NONE, 0);
+}
+
+GType
+nm_connection_provider_get_type (void)
+{
+	static GType cp_type = 0;
+
+	if (!G_UNLIKELY (cp_type)) {
+		const GTypeInfo cp_info = {
+			sizeof (NMConnectionProvider), /* class_size */
+			nm_connection_provider_init,   /* base_init */
+			NULL,       /* base_finalize */
+			NULL,
+			NULL,       /* class_finalize */
+			NULL,       /* class_data */
+			0,
+			0,          /* n_preallocs */
+			NULL
+		};
+
+		cp_type = g_type_register_static (G_TYPE_INTERFACE, "NMConnectionProvider", &cp_info, 0);
+		g_type_interface_add_prerequisite (cp_type, G_TYPE_OBJECT);
+	}
+
+	return cp_type;
+}
diff --git a/src/nm-connection-provider.h b/src/nm-connection-provider.h
new file mode 100644
index 00000000..942651f7
--- /dev/null
+++ b/src/nm-connection-provider.h
@@ -0,0 +1,106 @@
+/* -*- Mode: C; tab-width: 4; indent-tabs-mode: t; c-basic-offset: 4 -*- */
+/*
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details:
+ *
+ * Copyright (C) 2012 Red Hat, Inc.
+ */
+
+#ifndef NM_CONNECTION_PROVIDER_H
+#define NM_CONNECTION_PROVIDER_H
+
+#include <glib-object.h>
+#include <nm-connection.h>
+
+#define NM_TYPE_CONNECTION_PROVIDER      (nm_connection_provider_get_type ())
+#define NM_CONNECTION_PROVIDER(obj)      (G_TYPE_CHECK_INSTANCE_CAST ((obj), NM_TYPE_CONNECTION_PROVIDER, NMConnectionProvider))
+#define NM_IS_CONNECTION_PROVIDER(obj)   (G_TYPE_CHECK_INSTANCE_TYPE ((obj), NM_TYPE_CONNECTION_PROVIDER))
+#define NM_CONNECTION_PROVIDER_GET_INTERFACE(obj) (G_TYPE_INSTANCE_GET_INTERFACE ((obj), NM_TYPE_CONNECTION_PROVIDER, NMConnectionProvider))
+
+typedef struct _NMConnectionProvider NMConnectionProvider;
+
+#define NM_CP_SIGNAL_CONNECTION_ADDED        "cp-connection-added"
+#define NM_CP_SIGNAL_CONNECTION_UPDATED      "cp-connection-updated"
+#define NM_CP_SIGNAL_CONNECTION_REMOVED      "cp-connection-removed"
+#define NM_CP_SIGNAL_CONNECTIONS_LOADED      "cp-connections-loaded"
+
+
+/**
+ * NMConnectionFilterFunc:
+ * @provider: The provider requesting the filtering
+ * @connection: the connection to be filtered
+ * @func_data: the caller-provided data pointer
+ *
+ * Returns: %TRUE to allow the connection, %FALSE to ignore it
+ */
+typedef gboolean (*NMConnectionFilterFunc) (NMConnectionProvider *provider,
+                                            NMConnection *connection,
+                                            gpointer func_data);
+
+
+struct _NMConnectionProvider {
+	GTypeInterface g_iface;
+
+	/* Methods */
+	GSList * (*get_best_connections) (NMConnectionProvider *self,
+	                                  guint max_requested,
+	                                  const char *ctype1,
+	                                  const char *ctype2,
+	                                  NMConnectionFilterFunc func,
+	                                  gpointer func_data);
+
+	const GSList * (*get_connections) (NMConnectionProvider *self);
+
+	/* Signals */
+	void (*connection_added)   (NMConnectionProvider *self, NMConnection *connection);
+
+	void (*connection_updated) (NMConnectionProvider *self, NMConnection *connection);
+
+	void (*connection_removed) (NMConnectionProvider *self, NMConnection *connection);
+
+	void (*connections_loaded) (NMConnectionProvider *self);
+};
+
+GType nm_connection_provider_get_type (void);
+
+/**
+ * nm_connection_provider_get_best_connections:
+ * @self: the #NMConnectionProvider
+ * @max_requested: if non-zero, the maximum number of connections to return
+ * @ctype1: an #NMSetting base type (eg NM_SETTING_WIRELESS_SETTING_NAME) to
+ *   filter connections against
+ * @ctype2: a second #NMSetting base type (eg NM_SETTING_WIRELESS_SETTING_NAME)
+ *   to filter connections against
+ * @func: caller-supplied function for filtering connections
+ * @func_data: caller-supplied data passed to @func
+ *
+ * Returns: a #GSList of #NMConnection objects in sorted order representing the
+ *   "best" or highest-priority connections filtered by @ctype1 and/or @ctype2,
+ *   and/or @func.  Caller is responsible for freeing the returned #GSList, but
+ *   the contained values do not need to be unreffed.
+ */
+GSList *nm_connection_provider_get_best_connections (NMConnectionProvider *self,
+                                                     guint max_requested,
+                                                     const char *ctype1,
+                                                     const char *ctype2,
+                                                     NMConnectionFilterFunc func,
+                                                     gpointer func_data);
+
+/**
+ * nm_connection_provider_get_connections:
+ * @self: the #NMConnectionProvider
+ *
+ * Returns: a #GSList of #NMConnection objects representing all known
+ *   connections.  Returned list is owned by the connection provider and must
+ *   not be freed.
+ */
+const GSList *nm_connection_provider_get_connections (NMConnectionProvider *self);
+
+#endif /* NM_CONNECTION_PROVIDER_H */
diff --git a/src/nm-device-adsl.c b/src/nm-device-adsl.c
new file mode 100644
index 00000000..e171b46e
--- /dev/null
+++ b/src/nm-device-adsl.c
@@ -0,0 +1,841 @@
+/* -*- 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.
+ *
+ * Pantelis Koukousoulas <pktoss@gmail.com>
+ */
+
+#include <config.h>
+
+#include <sys/socket.h>
+#include <linux/atmdev.h>
+#include <linux/atmbr2684.h>
+
+#include <errno.h>
+#include <sys/ioctl.h>
+#include <sys/types.h>
+#include <unistd.h>
+
+#include <glib.h>
+#include <glib/gi18n.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include "nm-device-adsl.h"
+#include "nm-device-private.h"
+#include "nm-properties-changed-signal.h"
+#include "NetworkManagerUtils.h"
+#include "nm-logging.h"
+#include "nm-enum-types.h"
+#include "nm-system.h"
+#include "nm-netlink-monitor.h"
+
+#include "ppp-manager/nm-ppp-manager.h"
+#include "nm-setting-adsl.h"
+
+#include "nm-device-adsl-glue.h"
+
+G_DEFINE_TYPE (NMDeviceAdsl, nm_device_adsl, NM_TYPE_DEVICE)
+
+#define NM_DEVICE_ADSL_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), NM_TYPE_DEVICE_ADSL, NMDeviceAdslPrivate))
+
+#define NM_ADSL_ERROR (nm_adsl_error_quark ())
+
+static GQuark
+nm_adsl_error_quark (void)
+{
+	static GQuark quark = 0;
+	if (!quark)
+		quark = g_quark_from_static_string ("nm-adsl-error");
+	return quark;
+}
+
+/**********************************************/
+
+typedef struct {
+	gboolean      disposed;
+	gboolean      carrier;
+	guint         carrier_poll_id;
+	int           atm_index;
+
+	/* Watch for 'nas' interfaces going away */
+	NMNetlinkMonitor *monitor;
+	guint             netlink_id;
+
+	/* PPP */
+	NMPPPManager *ppp_manager;
+
+	/* RFC 2684 bridging (PPPoE over ATM) */
+	int           brfd;
+	int           nas_ifindex;
+	char *        nas_ifname;
+} NMDeviceAdslPrivate;
+
+enum {
+	PROPERTIES_CHANGED,
+	LAST_SIGNAL
+};
+
+static guint signals[LAST_SIGNAL] = { 0 };
+
+enum {
+	PROP_0,
+	PROP_CARRIER,
+
+	LAST_PROP
+};
+
+/**************************************************************/
+
+static guint32
+real_get_generic_capabilities (NMDevice *dev)
+{
+	guint32 caps = NM_DEVICE_CAP_NM_SUPPORTED;
+	caps |= NM_DEVICE_CAP_CARRIER_DETECT;
+	return caps;
+}
+
+static gboolean
+real_can_interrupt_activation (NMDevice *dev)
+{
+	NMDeviceAdsl *self = NM_DEVICE_ADSL (dev);
+	gboolean interrupt = FALSE;
+
+	/* Devices that support carrier detect can interrupt activation
+	 * if the link becomes inactive.
+	 */
+	if (NM_DEVICE_ADSL_GET_PRIVATE (self)->carrier == FALSE)
+		interrupt = TRUE;
+
+	return interrupt;
+}
+
+static gboolean
+real_is_available (NMDevice *dev)
+{
+	NMDeviceAdsl *self = NM_DEVICE_ADSL (dev);
+
+	/* Can't do anything if there isn't a carrier */
+	if (!NM_DEVICE_ADSL_GET_PRIVATE (self)->carrier)
+		return FALSE;
+
+	return TRUE;
+}
+
+static gboolean
+real_check_connection_compatible (NMDevice *device,
+                                  NMConnection *connection,
+                                  GError **error)
+{
+	NMSettingAdsl *s_adsl;
+	const char *protocol;
+
+	if (!nm_connection_is_type (connection, NM_SETTING_ADSL_SETTING_NAME)) {
+		g_set_error (error,
+		             NM_ADSL_ERROR, NM_ADSL_ERROR_CONNECTION_NOT_ADSL,
+		             "The connection was not an ADSL connection.");
+		return FALSE;
+	}
+
+	s_adsl = nm_connection_get_setting_adsl (connection);
+	if (!s_adsl) {
+		g_set_error (error,
+		             NM_ADSL_ERROR, NM_ADSL_ERROR_CONNECTION_INVALID,
+		             "The connection was not a valid ADSL connection.");
+		return FALSE;
+	}
+
+	/* FIXME: we don't yet support IPoATM */
+	protocol = nm_setting_adsl_get_protocol (s_adsl);
+	if (g_strcmp0 (protocol, NM_SETTING_ADSL_PROTOCOL_IPOATM) == 0) {
+		g_set_error (error,
+		             NM_ADSL_ERROR, NM_ADSL_ERROR_CONNECTION_INVALID,
+		             "IPoATM connections are not yet supported.");
+		return FALSE;
+	}
+
+	return TRUE;
+}
+
+static gboolean
+real_complete_connection (NMDevice *device,
+                          NMConnection *connection,
+                          const char *specific_object,
+                          const GSList *existing_connections,
+                          GError **error)
+{
+	NMSettingAdsl *s_adsl;
+
+	/*
+	 * We can't telepathically figure out the username, so if
+	 * it wasn't given, we can't complete the connection.
+	 */
+	s_adsl = nm_connection_get_setting_adsl (connection);
+	if (s_adsl && !nm_setting_verify (NM_SETTING (s_adsl), NULL, error))
+		return FALSE;
+
+	nm_utils_complete_generic (connection,
+	                           NM_SETTING_ADSL_SETTING_NAME,
+	                           existing_connections,
+	                           _("ADSL connection %d"),
+	                           NULL,
+	                           FALSE); /* No IPv6 yet by default */
+
+
+	return TRUE;
+}
+
+static NMConnection *
+real_get_best_auto_connection (NMDevice *dev,
+                               GSList *connections,
+                               char **specific_object)
+{
+	GSList *iter;
+
+	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;
+	}
+	return NULL;
+}
+
+/**************************************************************/
+
+static void
+set_nas_iface (NMDeviceAdsl *self, int idx, const char *name)
+{
+	NMDeviceAdslPrivate *priv = NM_DEVICE_ADSL_GET_PRIVATE (self);
+
+	g_return_if_fail (name != NULL);
+
+	g_warn_if_fail (priv->nas_ifindex <= 0);
+	if (idx > 0)
+		priv->nas_ifindex = idx;
+	else
+		priv->nas_ifindex = nm_netlink_iface_to_index (name);
+	g_warn_if_fail (priv->nas_ifindex > 0);
+
+	g_warn_if_fail (priv->nas_ifname == NULL);
+	priv->nas_ifname = g_strdup (name);
+}
+
+static gboolean
+br2684_create_iface (NMDeviceAdsl *self, NMSettingAdsl *s_adsl)
+{
+	NMDeviceAdslPrivate *priv = NM_DEVICE_ADSL_GET_PRIVATE (self);
+	const char *iface = nm_device_get_iface (NM_DEVICE (self));
+	struct atm_newif_br2684 ni;
+	int err, fd;
+	gboolean success = FALSE;
+	guint num = 0;
+
+	g_return_val_if_fail (s_adsl != NULL, FALSE);
+
+	fd = socket (PF_ATMPVC, SOCK_DGRAM, ATM_AAL5);
+	if (fd < 0) {
+		nm_log_err (LOGD_ADSL, "(%s): failed to open ATM control socket (%d)",
+		            iface, errno);
+		return FALSE;
+	}
+
+	memset (&ni, 0, sizeof (ni));
+	ni.backend_num = ATM_BACKEND_BR2684;
+	ni.media = BR2684_MEDIA_ETHERNET;
+	ni.mtu = 1500;
+
+	/* Loop attempting to create an interface that doesn't exist yet.  The
+	 * kernel can create one for us automatically, but due to API issues it
+	 * cannot return that name to us.  Since we want to know the name right
+	 * away, just brute-force it.
+	 */
+	while (num < 10000) {
+		memset (&ni.ifname, 0, sizeof (ni.ifname));
+		snprintf (ni.ifname, sizeof (ni.ifname), "nas%d", num);
+
+		err = ioctl (fd, ATM_NEWBACKENDIF, &ni);
+		if (err == 0) {
+			set_nas_iface (self, -1, ni.ifname);
+			nm_log_info (LOGD_ADSL, "(%s): using NAS interface %s (%d)",
+			             iface, priv->nas_ifname, priv->nas_ifindex);
+			success = TRUE;
+			break;
+		} else if (errno == -EEXIST) {
+			/* Try again */
+			num++;
+		} else {
+			nm_log_warn (LOGD_ADSL, "(%s): failed to create br2684 interface (%d)",
+			             iface, errno);
+			break;
+		}
+	}
+
+	close (fd);
+	return success;
+}
+
+static gboolean
+br2684_assign_vcc (NMDeviceAdsl *self, NMSettingAdsl *s_adsl)
+{
+	NMDeviceAdslPrivate *priv = NM_DEVICE_ADSL_GET_PRIVATE (self);
+	const char *iface = nm_device_get_iface (NM_DEVICE (self));
+	struct sockaddr_atmpvc addr;
+	struct atm_backend_br2684 be;
+	struct atm_qos qos;
+	int err, bufsize = 8192;
+	const char *encapsulation;
+	gboolean is_llc;
+
+	g_return_val_if_fail (priv->brfd == -1, FALSE);
+	g_return_val_if_fail (priv->nas_ifname != NULL, FALSE);
+
+	priv->brfd = socket (PF_ATMPVC, SOCK_DGRAM, ATM_AAL5);
+	if (priv->brfd < 0) {
+		nm_log_err (LOGD_ADSL, "(%s): failed to open ATM control socket (%d)",
+		            iface, errno);
+		return FALSE;
+	}
+
+	err = setsockopt (priv->brfd, SOL_SOCKET, SO_SNDBUF, &bufsize, sizeof (bufsize));
+	if (err != 0) {
+		nm_log_err (LOGD_ADSL, "(%s): failed to set SNDBUF option (%d)",
+		            iface, errno);
+		goto error;
+	}
+
+	/* QoS */
+	memset (&qos, 0, sizeof (qos));
+	qos.aal = ATM_AAL5;
+	qos.txtp.traffic_class = ATM_UBR;
+	qos.txtp.max_sdu = 1524;
+	qos.txtp.pcr = ATM_MAX_PCR;
+	qos.rxtp = qos.txtp;
+
+	err = setsockopt (priv->brfd, SOL_ATM, SO_ATMQOS, &qos, sizeof (qos));
+	if (err != 0) {
+		nm_log_err (LOGD_ADSL, "(%s): failed to set QoS (%d)",
+		            iface, errno);
+		goto error;
+	}
+
+	encapsulation = nm_setting_adsl_get_encapsulation (s_adsl);
+
+	/* VPI/VCI */
+	memset (&addr, 0, sizeof (addr));
+	addr.sap_family = AF_ATMPVC;
+	addr.sap_addr.itf = priv->atm_index;
+	addr.sap_addr.vpi = (guint16) nm_setting_adsl_get_vpi (s_adsl);
+	addr.sap_addr.vci = (int) nm_setting_adsl_get_vci (s_adsl);
+
+	nm_log_dbg (LOGD_ADSL, "(%s): assigning address %d.%d.%d encapsulation %s",
+	            nm_device_get_iface (NM_DEVICE (self)),
+	            priv->atm_index, addr.sap_addr.vpi, addr.sap_addr.vci,
+	            encapsulation);
+
+	err = connect (priv->brfd, (struct sockaddr*) &addr, sizeof (addr));
+	if (err != 0) {
+		nm_log_err (LOGD_ADSL, "(%s): failed to set VPI/VCI (%d)",
+		            iface, errno);
+		goto error;
+	}
+
+	/* And last attach the VCC to the interface */
+	is_llc = (g_strcmp0 (encapsulation, "llc") == 0);
+
+	memset (&be, 0, sizeof (be));
+	be.backend_num = ATM_BACKEND_BR2684;
+	be.ifspec.method = BR2684_FIND_BYIFNAME;
+	strcpy (be.ifspec.spec.ifname, priv->nas_ifname);
+	be.fcs_in = BR2684_FCSIN_NO;
+	be.fcs_out = BR2684_FCSOUT_NO;
+	be.encaps = is_llc ? BR2684_ENCAPS_LLC : BR2684_ENCAPS_VC;
+	err = ioctl (priv->brfd, ATM_SETBACKEND, &be);
+	if (err != 0) {
+		nm_log_err (LOGD_ADSL, "(%s): failed to attach VCC (%d)",
+		            iface, errno);
+		goto error;
+	}
+
+	return TRUE;
+
+error:
+	close (priv->brfd);
+	priv->brfd = -1;
+	return FALSE;
+}
+
+static void
+netlink_notification (NMNetlinkMonitor *monitor,
+                      struct nl_msg *msg,
+                      gpointer user_data)
+{
+	NMDeviceAdsl *self = NM_DEVICE_ADSL (user_data);
+	NMDeviceAdslPrivate *priv = NM_DEVICE_ADSL_GET_PRIVATE (self);
+	NMDevice *device = NM_DEVICE (user_data);
+	struct nlmsghdr *hdr = nlmsg_hdr (msg);
+	const char *iface = nm_device_get_iface (device);
+
+	/* This only gets called for PPPoE connections and "nas" interfaces */
+
+	if ((hdr->nlmsg_type == RTM_DELLINK) && (priv->nas_ifindex >= 0)) {
+		struct ifinfomsg *ifi = nlmsg_data (hdr);
+
+		if (ifi->ifi_index == priv->nas_ifindex) {
+			/* NAS device went away for some reason; kill the connection */
+			nm_log_dbg (LOGD_ADSL, "(%s): NAS interface disappeared", iface);
+			nm_device_state_changed (device,
+			                         NM_DEVICE_STATE_FAILED,
+			                         NM_DEVICE_STATE_REASON_BR2684_FAILED);
+		}
+	}
+}
+
+static NMActStageReturn
+real_act_stage2_config (NMDevice *device, NMDeviceStateReason *out_reason)
+{
+	NMDeviceAdsl *self = NM_DEVICE_ADSL (device);
+	NMDeviceAdslPrivate *priv = NM_DEVICE_ADSL_GET_PRIVATE (self);
+	NMActStageReturn ret = NM_ACT_STAGE_RETURN_FAILURE;
+	NMSettingAdsl *s_adsl;
+	const char *protocol;
+
+	g_assert (out_reason);
+
+	s_adsl = nm_connection_get_setting_adsl (nm_device_get_connection (device));
+	g_assert (s_adsl);
+
+	protocol = nm_setting_adsl_get_protocol (s_adsl);
+	nm_log_dbg (LOGD_ADSL, "(%s): using ADSL protocol '%s'",
+	             nm_device_get_iface (device), protocol);
+
+	if (g_strcmp0 (protocol, NM_SETTING_ADSL_PROTOCOL_PPPOE) == 0) {
+
+		/* PPPoE needs RFC2684 bridging before we can do PPP over it */
+		if (!br2684_create_iface (self, s_adsl)) {
+			*out_reason = NM_DEVICE_STATE_REASON_BR2684_FAILED;
+			goto done;
+		}
+
+		/* Set up the VCC */
+		if (!br2684_assign_vcc (self, s_adsl)) {
+			*out_reason = NM_DEVICE_STATE_REASON_BR2684_FAILED;
+			goto done;
+		}
+
+		/* Watch for the 'nas' interface going away */
+		priv->netlink_id = g_signal_connect (priv->monitor, "notification",
+		                                     G_CALLBACK (netlink_notification),
+		                                     self);
+
+		nm_log_dbg (LOGD_ADSL, "(%s): ATM setup successful", nm_device_get_iface (device));
+
+		/* otherwise we're good for stage3 */
+		nm_system_iface_set_up (priv->nas_ifindex, TRUE, NULL);
+		ret = NM_ACT_STAGE_RETURN_SUCCESS;
+
+	} else if (g_strcmp0 (protocol, NM_SETTING_ADSL_PROTOCOL_PPPOA) == 0) {
+		/* PPPoA doesn't need anything special */
+		ret = NM_ACT_STAGE_RETURN_SUCCESS;
+	} else {
+		nm_log_warn (LOGD_ADSL, "(%s): unhandled ADSL protocol '%s'",
+		             nm_device_get_iface (device), protocol);
+	}
+
+done:
+	return ret;
+}
+
+static void
+ppp_state_changed (NMPPPManager *ppp_manager, NMPPPStatus status, gpointer user_data)
+{
+	NMDevice *device = NM_DEVICE (user_data);
+
+	switch (status) {
+	case NM_PPP_STATUS_DISCONNECT:
+		nm_device_state_changed (device, NM_DEVICE_STATE_FAILED, NM_DEVICE_STATE_REASON_PPP_DISCONNECT);
+		break;
+	case NM_PPP_STATUS_DEAD:
+		nm_device_state_changed (device, NM_DEVICE_STATE_FAILED, NM_DEVICE_STATE_REASON_PPP_FAILED);
+		break;
+	default:
+		break;
+	}
+}
+
+static void
+ppp_ip4_config (NMPPPManager *ppp_manager,
+                const char *iface,
+                NMIP4Config *config,
+                gpointer user_data)
+{
+	NMDevice *device = NM_DEVICE (user_data);
+
+	/* Ignore PPP IP4 events that come in after initial configuration */
+	if (nm_device_activate_ip4_state_in_conf (device)) {
+		nm_device_set_ip_iface (device, iface);
+		nm_device_activate_schedule_ip4_config_result (device, config);
+	}
+}
+
+static NMActStageReturn
+real_act_stage3_ip4_config_start (NMDevice *device,
+                                  NMIP4Config **out_config,
+                                  NMDeviceStateReason *reason)
+{
+	NMDeviceAdsl *self = NM_DEVICE_ADSL (device);
+	NMDeviceAdslPrivate *priv = NM_DEVICE_ADSL_GET_PRIVATE (self);
+	NMConnection *connection;
+	NMSettingAdsl *s_adsl;
+	NMActRequest *req;
+	GError *err = NULL;
+	NMActStageReturn ret = NM_ACT_STAGE_RETURN_FAILURE;
+	const char *iface = nm_device_get_iface (device);
+	const char *ppp_iface;
+
+	req = nm_device_get_act_request (device);
+	g_assert (req);
+
+	connection = nm_act_request_get_connection (req);
+	g_assert (req);
+
+	s_adsl = nm_connection_get_setting_adsl (connection);
+	g_assert (s_adsl);
+
+	/* PPPoE uses the NAS inteface, not the ATM interface */
+	if (g_strcmp0 (nm_setting_adsl_get_protocol (s_adsl), NM_SETTING_ADSL_PROTOCOL_PPPOE) == 0) {
+		g_assert (priv->nas_ifname);
+		ppp_iface = priv->nas_ifname;
+
+		nm_log_dbg (LOGD_ADSL, "(%s): starting PPPoE on NAS interface %s",
+			        iface, priv->nas_ifname);
+	} else {
+		ppp_iface = iface;
+		nm_log_dbg (LOGD_ADSL, "(%s): starting PPPoA", iface);
+	}
+
+	priv->ppp_manager = nm_ppp_manager_new (ppp_iface);
+	if (nm_ppp_manager_start (priv->ppp_manager, req, nm_setting_adsl_get_username (s_adsl), 30, &err)) {
+		g_signal_connect (priv->ppp_manager, "state-changed",
+		                  G_CALLBACK (ppp_state_changed),
+		                  self);
+		g_signal_connect (priv->ppp_manager, "ip4-config",
+		                  G_CALLBACK (ppp_ip4_config),
+		                  self);
+		ret = NM_ACT_STAGE_RETURN_POSTPONE;
+	} else {
+		nm_log_warn (LOGD_ADSL, "(%s): PPP failed to start: %s", iface, err->message);
+		g_error_free (err);
+
+		g_object_unref (priv->ppp_manager);
+		priv->ppp_manager = NULL;
+
+		*reason = NM_DEVICE_STATE_REASON_PPP_START_FAILED;
+	}
+
+	return ret;
+}
+
+static void
+real_deactivate (NMDevice *device)
+{
+	NMDeviceAdsl *self = NM_DEVICE_ADSL (device);
+	NMDeviceAdslPrivate *priv = NM_DEVICE_ADSL_GET_PRIVATE (self);
+
+	if (priv->ppp_manager) {
+		g_object_unref (priv->ppp_manager);
+		priv->ppp_manager = NULL;
+	}
+
+	if (priv->netlink_id) {
+		g_signal_handler_disconnect (priv->monitor, priv->netlink_id);
+		priv->netlink_id = 0;
+	}
+
+	if (priv->brfd >= 0) {
+		close (priv->brfd);
+		priv->brfd = -1;
+	}
+
+	/* FIXME: kernel has no way of explicitly deleting the 'nasX' interface yet,
+	 * so it gets leaked.  It does get destroyed when it's no longer in use,
+	 * but we have no control over that.
+	 */
+	if (priv->nas_ifindex >= 0)
+		priv->nas_ifindex = -1;
+	g_free (priv->nas_ifname);
+	priv->nas_ifname = NULL;
+}
+
+/**************************************************************/
+
+static void
+set_carrier (NMDeviceAdsl *self, const gboolean carrier)
+{
+	NMDeviceAdslPrivate *priv;
+	NMDeviceState state;
+
+	g_return_if_fail (NM_IS_DEVICE (self));
+
+	priv = NM_DEVICE_ADSL_GET_PRIVATE (self);
+
+	if (priv->carrier == carrier)
+		return;
+
+	priv->carrier = carrier;
+	g_object_notify (G_OBJECT (self), NM_DEVICE_ADSL_CARRIER);
+
+	state = nm_device_get_state (NM_DEVICE (self));
+	nm_log_info (LOGD_HW, "(%s): carrier now %s (device state %d)",
+	             nm_device_get_iface (NM_DEVICE (self)),
+	             carrier ? "ON" : "OFF",
+	             state);
+
+	if (state == NM_DEVICE_STATE_UNAVAILABLE) {
+		if (priv->carrier)
+			nm_device_state_changed (NM_DEVICE (self), NM_DEVICE_STATE_DISCONNECTED, NM_DEVICE_STATE_REASON_CARRIER);
+	} else if (state >= NM_DEVICE_STATE_DISCONNECTED) {
+		if (!priv->carrier)
+			nm_device_state_changed (NM_DEVICE (self), NM_DEVICE_STATE_UNAVAILABLE, NM_DEVICE_STATE_REASON_CARRIER);
+	}
+}
+
+static gboolean
+carrier_update_cb (gpointer user_data)
+{
+	NMDeviceAdsl *self = NM_DEVICE_ADSL (user_data);
+	GError *error = NULL;
+	gboolean carrier = FALSE;
+	char *path, *contents;
+	const char *iface;
+	gboolean success;
+
+	iface = nm_device_get_iface (NM_DEVICE (self));
+
+	path  = g_strdup_printf ("/sys/class/atm/%s/carrier", iface);
+	success = g_file_get_contents (path, &contents, NULL, &error);
+	g_free (path);
+
+	if (!success) {
+		nm_log_dbg (LOGD_ADSL, "error reading %s: (%d) %s",
+		            path,
+		            error ? error->code : -1,
+		            error && error->message ? error->message : "(unknown)");
+		g_clear_error (&error);
+		return TRUE;
+	}
+
+	carrier = (gboolean) atoi (contents);
+	g_free (contents);
+	set_carrier (self, carrier);
+	return TRUE;
+}
+
+/**************************************************************/
+
+NMDevice *
+nm_device_adsl_new (const char *udi,
+                    const char *iface,
+                    const char *driver)
+{
+	g_return_val_if_fail (udi != NULL, NULL);
+
+	return (NMDevice *) g_object_new (NM_TYPE_DEVICE_ADSL,
+	                                  NM_DEVICE_UDI, udi,
+	                                  NM_DEVICE_IFACE, iface,
+	                                  NM_DEVICE_DRIVER, driver,
+	                                  NM_DEVICE_TYPE_DESC, "ADSL",
+	                                  NM_DEVICE_DEVICE_TYPE, NM_DEVICE_TYPE_ADSL,
+	                                  NULL);
+}
+
+static int
+get_atm_index (const char *iface, GError **error)
+{
+	char *path, *contents;
+	int idx = -1;
+
+	path = g_strdup_printf ("/sys/class/atm/%s/atmindex", iface);
+	if (g_file_get_contents (path, &contents, NULL, error))
+		idx = atoi (contents);
+	g_free (path);
+	g_free (contents);
+	return idx;
+}
+
+static GObject*
+constructor (GType type,
+			 guint n_construct_params,
+			 GObjectConstructParam *construct_params)
+{
+	GObject *object;
+	NMDeviceAdslPrivate *priv;
+	GError *error = NULL;
+
+	object = G_OBJECT_CLASS (nm_device_adsl_parent_class)->constructor (type,
+	                                                                    n_construct_params,
+	                                                                    construct_params);
+	if (!object)
+		return NULL;
+
+	priv = NM_DEVICE_ADSL_GET_PRIVATE (object);
+
+	priv->atm_index = get_atm_index (nm_device_get_iface (NM_DEVICE (object)), &error);
+	if (priv->atm_index < 0) {
+		nm_log_dbg (LOGD_ADSL, "error reading ATM device index: (%d) %s",
+		            error ? error->code : -1,
+		            error && error->message ? error->message : "(unknown)");
+		g_clear_error (&error);
+		g_object_unref (object);
+		return NULL;
+	} else {
+		nm_log_dbg (LOGD_ADSL, "(%s): ATM device index %d",
+				    nm_device_get_iface (NM_DEVICE (object)), priv->atm_index);
+	}
+
+	/* Poll the carrier */
+	priv->carrier_poll_id = g_timeout_add_seconds (5, carrier_update_cb, object);
+
+	return object;
+}
+
+static void
+dispose (GObject *object)
+{
+	NMDeviceAdsl *self = NM_DEVICE_ADSL (object);
+	NMDeviceAdslPrivate *priv = NM_DEVICE_ADSL_GET_PRIVATE (self);
+
+	if (priv->disposed) {
+		G_OBJECT_CLASS (nm_device_adsl_parent_class)->dispose (object);
+		return;
+	}
+
+	priv->disposed = TRUE;
+
+	if (priv->carrier_poll_id) {
+		g_source_remove (priv->carrier_poll_id);
+		priv->carrier_poll_id = 0;
+	}
+
+	if (priv->netlink_id) {
+		g_source_remove (priv->netlink_id);
+		priv->netlink_id = 0;
+	}
+
+	if (priv->monitor) {
+		nm_netlink_monitor_unsubscribe (priv->monitor, RTNLGRP_LINK);
+		g_object_unref (priv->monitor);
+		priv->monitor = NULL;
+	}
+
+	g_free (priv->nas_ifname);
+	priv->nas_ifname = NULL;
+
+	G_OBJECT_CLASS (nm_device_adsl_parent_class)->dispose (object);
+}
+
+static void
+get_property (GObject *object, guint prop_id,
+              GValue *value, GParamSpec *pspec)
+{
+	NMDeviceAdsl *self = NM_DEVICE_ADSL (object);
+	NMDeviceAdslPrivate *priv = NM_DEVICE_ADSL_GET_PRIVATE(self);
+
+	switch (prop_id) {
+	case PROP_CARRIER:
+		g_value_set_boolean (value, priv->carrier);
+		break;
+	default:
+		G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+		break;
+	}
+}
+
+static void
+set_property (GObject *object, guint prop_id,
+			  const GValue *value, GParamSpec *pspec)
+{
+	switch (prop_id) {
+	default:
+		G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+		break;
+	}
+}
+
+static void
+nm_device_adsl_init (NMDeviceAdsl *self)
+{
+	NMDeviceAdslPrivate *priv = NM_DEVICE_ADSL_GET_PRIVATE (self);
+
+	priv->monitor = nm_netlink_monitor_get ();
+	nm_netlink_monitor_subscribe (priv->monitor, RTNLGRP_LINK, NULL);
+}
+
+static void
+nm_device_adsl_class_init (NMDeviceAdslClass *klass)
+{
+	GObjectClass *object_class = G_OBJECT_CLASS (klass);
+	NMDeviceClass *parent_class = NM_DEVICE_CLASS (klass);
+
+	g_type_class_add_private (object_class, sizeof (NMDeviceAdslPrivate));
+
+	object_class->constructor  = constructor;
+	object_class->dispose      = dispose;
+	object_class->get_property = get_property;
+	object_class->set_property = set_property;
+
+	parent_class->get_generic_capabilities = real_get_generic_capabilities;
+	parent_class->can_interrupt_activation = real_can_interrupt_activation;
+	parent_class->is_available = real_is_available;
+
+	parent_class->check_connection_compatible = real_check_connection_compatible;
+	parent_class->get_best_auto_connection = real_get_best_auto_connection;
+	parent_class->complete_connection = real_complete_connection;
+
+	parent_class->act_stage2_config = real_act_stage2_config;
+	parent_class->act_stage3_ip4_config_start = real_act_stage3_ip4_config_start;
+	parent_class->deactivate = real_deactivate;
+
+	/* properties */
+	g_object_class_install_property
+		(object_class, PROP_CARRIER,
+		 g_param_spec_boolean (NM_DEVICE_ADSL_CARRIER,
+							   "Carrier",
+							   "Carrier",
+							   FALSE,
+							   G_PARAM_READABLE));
+
+	/* Signals */
+	signals[PROPERTIES_CHANGED] =
+		nm_properties_changed_signal_new (object_class,
+		                                  G_STRUCT_OFFSET (NMDeviceAdslClass, properties_changed));
+
+	dbus_g_object_type_install_info (G_TYPE_FROM_CLASS (klass),
+	                                 &dbus_glib_nm_device_adsl_object_info);
+}
diff --git a/src/nm-device-adsl.h b/src/nm-device-adsl.h
new file mode 100644
index 00000000..50ea43e3
--- /dev/null
+++ b/src/nm-device-adsl.h
@@ -0,0 +1,66 @@
+/* -*- 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.
+ *
+ * Author: Pantelis Koukousoulas <pktoss@gmail.com>
+ * Copyright (C) 2009 - 2011 Red Hat Inc.
+ */
+
+#ifndef NM_DEVICE_ADSL_H
+#define NM_DEVICE_ADSL_H
+
+#include <glib-object.h>
+
+// Parent class
+#include "nm-device.h"
+
+G_BEGIN_DECLS
+
+#define NM_TYPE_DEVICE_ADSL            (nm_device_adsl_get_type ())
+#define NM_DEVICE_ADSL(obj)            (G_TYPE_CHECK_INSTANCE_CAST ((obj), NM_TYPE_DEVICE_ADSL, NMDeviceAdsl))
+#define NM_DEVICE_ADSL_CLASS(klass)    (G_TYPE_CHECK_CLASS_CAST ((klass),  NM_TYPE_DEVICE_ADSL, NMDeviceAdslClass))
+#define NM_IS_DEVICE_ADSL(obj)         (G_TYPE_CHECK_INSTANCE_TYPE ((obj), NM_TYPE_DEVICE_ADSL))
+#define NM_IS_DEVICE_ADSL_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass),  NM_TYPE_DEVICE_ADSL))
+#define NM_DEVICE_ADSL_GET_CLASS(obj)  (G_TYPE_INSTANCE_GET_CLASS ((obj),  NM_TYPE_DEVICE_ADSL, NMDeviceAdslClass))
+
+typedef enum {
+	NM_ADSL_ERROR_CONNECTION_NOT_ADSL = 0,
+	NM_ADSL_ERROR_CONNECTION_INVALID,
+	NM_ADSL_ERROR_CONNECTION_INCOMPATIBLE,
+} NMAdslError;
+
+#define NM_DEVICE_ADSL_CARRIER "carrier"
+
+typedef struct {
+	NMDevice parent;
+} NMDeviceAdsl;
+
+typedef struct {
+	NMDeviceClass parent;
+
+	/* Signals */
+	void (*properties_changed) (NMDeviceAdsl *device, GHashTable *properties);
+} NMDeviceAdslClass;
+
+GType nm_device_adsl_get_type (void);
+
+NMDevice *nm_device_adsl_new (const char *udi,
+                              const char *iface,
+                              const char *driver);
+
+G_END_DECLS
+
+#endif	/* NM_DEVICE_ADSL_H */
diff --git a/src/nm-device-bt.c b/src/nm-device-bt.c
index 726762b6..f61aeb57 100644
--- a/src/nm-device-bt.c
+++ b/src/nm-device-bt.c
@@ -668,14 +668,18 @@ nm_device_bt_modem_removed (NMDeviceBt *self, NMModem *modem)
 	if (modem != priv->modem)
 		return FALSE;
 
+	/* Fail the device if the modem was removed while active */
 	state = nm_device_get_state (NM_DEVICE (self));
-	nm_modem_device_state_changed (priv->modem,
-	                               NM_DEVICE_STATE_DISCONNECTED,
-	                               state,
-	                               NM_DEVICE_STATE_REASON_USER_REQUESTED);
+	if (   state == NM_DEVICE_STATE_ACTIVATED
+	    || nm_device_is_activating (NM_DEVICE (self))) {
+		nm_device_state_changed (NM_DEVICE (self),
+		                         NM_DEVICE_STATE_FAILED,
+		                         NM_DEVICE_STATE_REASON_BT_FAILED);
+	} else {
+		g_object_unref (priv->modem);
+		priv->modem = NULL;
+	}
 
-	g_object_unref (priv->modem);
-	priv->modem = NULL;
 	return TRUE;
 }
 
diff --git a/src/nm-device-ethernet.c b/src/nm-device-ethernet.c
index df0ae94f..ede31cc1 100644
--- a/src/nm-device-ethernet.c
+++ b/src/nm-device-ethernet.c
@@ -753,8 +753,9 @@ link_timeout_cb (gpointer user_data)
 	req = nm_device_get_act_request (dev);
 
 	if (nm_device_get_state (dev) == NM_DEVICE_STATE_ACTIVATED) {
-		nm_device_state_changed (dev, NM_DEVICE_STATE_DISCONNECTED,
-		                         NM_DEVICE_STATE_REASON_SUPPLICANT_DISCONNECT);
+		nm_device_state_changed (dev,
+		                         NM_DEVICE_STATE_FAILED,
+		                         NM_DEVICE_STATE_REASON_SUPPLICANT_TIMEOUT);
 		return FALSE;
 	}
 
diff --git a/src/nm-device-modem.c b/src/nm-device-modem.c
index 7f81e981..e7cd9259 100644
--- a/src/nm-device-modem.c
+++ b/src/nm-device-modem.c
@@ -311,11 +311,12 @@ real_set_enabled (NMDevice *device, gboolean enabled)
 		nm_modem_set_mm_enabled (priv->modem, enabled);
 
 		if (enabled == FALSE) {
-			state = nm_device_get_state (NM_DEVICE (device));
-			if (state == NM_DEVICE_STATE_ACTIVATED) {
-				nm_device_state_changed (NM_DEVICE (device),
+			state = nm_device_get_state (device);
+			if (nm_device_is_activating (device) || state == NM_DEVICE_STATE_ACTIVATED) {
+				/* user-initiated action, hence DISCONNECTED not FAILED */
+				nm_device_state_changed (device,
 				                         NM_DEVICE_STATE_DISCONNECTED,
-				                         NM_DEVICE_STATE_REASON_NONE);
+				                         NM_DEVICE_STATE_REASON_USER_REQUESTED);
 			}
 		}
 	}
diff --git a/src/nm-device-olpc-mesh.c b/src/nm-device-olpc-mesh.c
index f6390c16..8e3cb952 100644
--- a/src/nm-device-olpc-mesh.c
+++ b/src/nm-device-olpc-mesh.c
@@ -55,6 +55,9 @@
 #include "nm-manager.h"
 #include "nm-enum-types.h"
 #include "wifi-utils.h"
+#if HAVE_WEXT
+#include "wifi-utils-wext.h"
+#endif
 
 /* This is a bug; but we can't really change API now... */
 #include "NetworkManagerVPN.h"
@@ -153,9 +156,16 @@ constructor (GType type,
 	            nm_device_get_iface (NM_DEVICE (self)),
 	            nm_device_get_ifindex (NM_DEVICE (self)));
 
-	priv->wifi_data = wifi_utils_init (nm_device_get_iface (NM_DEVICE (self)),
-	                                   nm_device_get_ifindex (NM_DEVICE (self)),
-	                                   FALSE);
+	/*
+	 * The kernel driver now uses nl80211, but we force use of WEXT because
+	 * the cfg80211 interactions are not quite ready to support access to
+	 * mesh control through nl80211 just yet.
+	 */
+#if HAVE_WEXT
+	priv->wifi_data = wifi_wext_init (nm_device_get_iface (NM_DEVICE (self)),
+	                                  nm_device_get_ifindex (NM_DEVICE (self)),
+	                                  FALSE);
+#endif
 	if (priv->wifi_data == NULL) {
 		nm_log_warn (LOGD_HW | LOGD_OLPC_MESH, "(%s): failed to initialize WiFi driver",
 		             nm_device_get_iface (NM_DEVICE (self)));
diff --git a/src/nm-device-private.h b/src/nm-device-private.h
index 9b78db12..824beb5a 100644
--- a/src/nm-device-private.h
+++ b/src/nm-device-private.h
@@ -67,4 +67,6 @@ gboolean nm_device_dhcp4_renew (NMDevice *device, gboolean release);
 
 gboolean nm_device_match_ip_config (NMDevice *device, NMConnection *connection);
 
+NMConnectionProvider *nm_device_get_connection_provider (NMDevice *device);
+
 #endif	/* NM_DEVICE_PRIVATE_H */
diff --git a/src/nm-device-vlan.c b/src/nm-device-vlan.c
index 14be849f..b9c93234 100644
--- a/src/nm-device-vlan.c
+++ b/src/nm-device-vlan.c
@@ -643,17 +643,17 @@ nm_device_vlan_new (const char *udi, const char *iface, NMDevice *parent)
 			g_object_unref (device);
 			return NULL;
 		}
-		priv->vlan_id = vlan_id;
 
 		if (   parent_ifindex < 0
 		    || parent_ifindex != nm_device_get_ip_ifindex (parent)
-		    || priv->vlan_id < 0) {
+		    || vlan_id < 0) {
 			nm_log_warn (LOGD_DEVICE, "(%s): VLAN parent ifindex (%d) or VLAN ID (%d) invalid.",
 			             iface, parent_ifindex, priv->vlan_id);
 			g_object_unref (device);
 			return NULL;
 		}
 
+		priv->vlan_id = vlan_id;
 		priv->parent = g_object_ref (parent);
 		priv->parent_state_id = g_signal_connect (priv->parent,
 		                                          "state-changed",
diff --git a/src/nm-device-wifi.c b/src/nm-device-wifi.c
index ed964a57..5fbbac7a 100644
--- a/src/nm-device-wifi.c
+++ b/src/nm-device-wifi.c
@@ -56,6 +56,7 @@
 #include "nm-setting-ip4-config.h"
 #include "nm-setting-ip6-config.h"
 #include "nm-system.h"
+#include "nm-manager-auth.h"
 #include "nm-settings-connection.h"
 #include "nm-enum-types.h"
 #include "wifi-utils.h"
@@ -64,11 +65,15 @@ static gboolean impl_device_get_access_points (NMDeviceWifi *device,
                                                GPtrArray **aps,
                                                GError **err);
 
+static void impl_device_request_scan (NMDeviceWifi *device,
+                                      GHashTable *options,
+                                      DBusGMethodInvocation *context);
+
 #include "nm-device-wifi-glue.h"
 
 
 /* All of these are in seconds */
-#define SCAN_INTERVAL_MIN 0
+#define SCAN_INTERVAL_MIN 3
 #define SCAN_INTERVAL_STEP 20
 #define SCAN_INTERVAL_MAX 120
 
@@ -138,7 +143,7 @@ struct _NMDeviceWifiPrivate {
 	guint32           rate;
 	gboolean          enabled; /* rfkilled or not */
 	
-	glong             scheduled_scan_time;
+	time_t            scheduled_scan_time;
 	guint8            scan_interval; /* seconds */
 	guint             pending_scan_id;
 	guint             scanlist_cull_id;
@@ -153,7 +158,7 @@ struct _NMDeviceWifiPrivate {
 	NMDeviceWifiCapabilities capabilities;
 };
 
-static gboolean request_wireless_scan (gpointer user_data);
+static gboolean check_scanning_allowed (NMDeviceWifi *self);
 
 static void schedule_scan (NMDeviceWifi *self, gboolean backoff);
 
@@ -193,6 +198,8 @@ static void supplicant_iface_notify_scanning_cb (NMSupplicantInterface * iface,
 
 static void schedule_scanlist_cull (NMDeviceWifi *self);
 
+static gboolean request_wireless_scan (gpointer user_data);
+
 /*****************************************************************/
 
 #define NM_WIFI_ERROR (nm_wifi_error_quark ())
@@ -1014,14 +1021,6 @@ real_check_connection_compatible (NMDevice *device,
 	const GByteArray *mac;
 	const GSList *mac_blacklist, *mac_blacklist_iter;
 
-	if (is_adhoc_wpa (connection)) {
-		g_set_error_literal (error,
-				             NM_WIFI_ERROR,
-				             NM_WIFI_ERROR_CONNECTION_INCOMPATIBLE,
-				             "WPA Ad-Hoc disabled due to kernel bugs");
-		return FALSE;
-	}
-
 	s_con = nm_connection_get_setting_connection (connection);
 	g_assert (s_con);
 
@@ -1040,6 +1039,7 @@ real_check_connection_compatible (NMDevice *device,
 		return FALSE;
 	}
 
+
 	mac = nm_setting_wireless_get_mac_address (s_wireless);
 	if (mac && memcmp (mac->data, &priv->perm_hw_addr, ETH_ALEN)) {
 		g_set_error (error,
@@ -1067,6 +1067,14 @@ real_check_connection_compatible (NMDevice *device,
 		}
 	}
 
+	if (is_adhoc_wpa (connection)) {
+		g_set_error_literal (error,
+		                     NM_WIFI_ERROR,
+		                     NM_WIFI_ERROR_CONNECTION_INCOMPATIBLE,
+		                     "WPA Ad-Hoc disabled due to kernel bugs");
+		return FALSE;
+	}
+
 	// FIXME: check channel/freq/band against bands the hardware supports
 	// FIXME: check encryption against device capabilities
 	// FIXME: check bitrate against device capabilities
@@ -1233,9 +1241,9 @@ real_complete_connection (NMDevice *device,
 	 */
 	if (is_adhoc_wpa (connection)) {
 		g_set_error_literal (error,
-				             NM_SETTING_WIRELESS_ERROR,
-				             NM_SETTING_WIRELESS_ERROR_INVALID_PROPERTY,
-				             "WPA Ad-Hoc disabled due to kernel bugs");
+		                     NM_SETTING_WIRELESS_ERROR,
+		                     NM_SETTING_WIRELESS_ERROR_INVALID_PROPERTY,
+		                     "WPA Ad-Hoc disabled due to kernel bugs");
 		return FALSE;
 	}
 
@@ -1257,9 +1265,9 @@ real_complete_connection (NMDevice *device,
 		/* Make sure the setting MAC (if any) matches the device's permanent MAC */
 		if (memcmp (setting_mac->data, priv->perm_hw_addr, ETH_ALEN)) {
 			g_set_error (error,
-				         NM_SETTING_WIRELESS_ERROR,
-				         NM_SETTING_WIRELESS_ERROR_INVALID_PROPERTY,
-				         NM_SETTING_WIRELESS_MAC_ADDRESS);
+			             NM_SETTING_WIRELESS_ERROR,
+			             NM_SETTING_WIRELESS_ERROR_INVALID_PROPERTY,
+			             NM_SETTING_WIRELESS_MAC_ADDRESS);
 			return FALSE;
 		}
 	} else {
@@ -1442,6 +1450,80 @@ impl_device_get_access_points (NMDeviceWifi *self,
 	return TRUE;
 }
 
+static void
+request_scan_cb (NMDevice *device,
+                 DBusGMethodInvocation *context,
+                 GError *error,
+                 gpointer user_data)
+{
+	NMDeviceWifi *self = NM_DEVICE_WIFI (device);
+
+	if (error) {
+		dbus_g_method_return_error (context, error);
+		g_clear_error (&error);
+	} else if (!check_scanning_allowed (self)) {
+		error = g_error_new_literal (NM_WIFI_ERROR,
+		                             NM_WIFI_ERROR_SCAN_NOT_ALLOWED,
+		                             "Scanning not allowed at this time");
+		dbus_g_method_return_error (context, error);
+		g_error_free (error);
+	} else {
+		cancel_pending_scan (self);
+		request_wireless_scan (self);
+		dbus_g_method_return (context);
+	}
+}
+
+static void
+impl_device_request_scan (NMDeviceWifi *self,
+                          GHashTable *options,
+                          DBusGMethodInvocation *context)
+{
+	NMDeviceWifiPrivate *priv = NM_DEVICE_WIFI_GET_PRIVATE (self);
+	NMDevice *device = NM_DEVICE (self);
+	time_t last_scan;
+	GError *error;
+
+	if (   !priv->enabled
+	    || !priv->supplicant.iface
+	    || nm_device_get_state (device) < NM_DEVICE_STATE_DISCONNECTED
+	    || nm_device_is_activating (device)) {
+		error = g_error_new_literal (NM_WIFI_ERROR,
+		                             NM_WIFI_ERROR_SCAN_NOT_ALLOWED,
+		                             "Scanning not allowed while unavailable or activating");
+		goto error;
+	}
+
+	if (nm_supplicant_interface_get_scanning (priv->supplicant.iface)) {
+		error = g_error_new_literal (NM_WIFI_ERROR,
+		                             NM_WIFI_ERROR_SCAN_NOT_ALLOWED,
+		                             "Scanning not allowed while already scanning");
+		goto error;
+	}
+
+	last_scan = nm_supplicant_interface_get_last_scan_time (priv->supplicant.iface);
+	if ((time (NULL) - last_scan) < 10) {
+		error = g_error_new_literal (NM_WIFI_ERROR,
+		                             NM_WIFI_ERROR_SCAN_NOT_ALLOWED,
+		                             "Scanning not allowed immediately following previous scan");
+		goto error;
+	}
+
+	/* Ask the manager to authenticate this request for us */
+	g_signal_emit_by_name (device,
+	                       NM_DEVICE_AUTH_REQUEST,
+	                       context,
+	                       NM_AUTH_PERMISSION_NETWORK_CONTROL,
+	                       TRUE,
+	                       request_scan_cb,
+	                       NULL);
+	return;
+
+error:
+	dbus_g_method_return_error (context, error);
+	g_error_free (error);
+}
+
 static gboolean
 scanning_allowed (NMDeviceWifi *self)
 {
@@ -1544,20 +1626,102 @@ check_scanning_allowed (NMDeviceWifi *self)
 }
 
 static gboolean
+hidden_filter_func (NMConnectionProvider *provider,
+                    NMConnection *connection,
+                    gpointer user_data)
+{
+	NMSettingWireless *s_wifi;
+
+	s_wifi = (NMSettingWireless *) nm_connection_get_setting_wireless (connection);
+	return s_wifi ? nm_setting_wireless_get_hidden (s_wifi) : FALSE;
+}
+
+static GPtrArray *
+build_hidden_probe_list (NMDeviceWifi *self)
+{
+	NMDeviceWifiPrivate *priv = NM_DEVICE_WIFI_GET_PRIVATE (self);
+	guint max_scan_ssids = nm_supplicant_interface_get_max_scan_ssids (priv->supplicant.iface);
+	NMConnectionProvider *provider = nm_device_get_connection_provider (NM_DEVICE (self));
+	GSList *connections, *iter;
+	GPtrArray *ssids = NULL;
+	static GByteArray *nullssid = NULL;
+
+	/* Need at least two: wildcard SSID and one or more hidden SSIDs */
+	if (max_scan_ssids < 2)
+		return NULL;
+
+	/* Static wildcard SSID used for every scan */
+	if (G_UNLIKELY (nullssid == NULL))
+		nullssid = g_byte_array_new ();
+
+	connections = nm_connection_provider_get_best_connections (provider,
+	                                                           max_scan_ssids - 1,
+	                                                           NM_SETTING_WIRELESS_SETTING_NAME,
+	                                                           NULL,
+	                                                           hidden_filter_func,
+	                                                           NULL);
+	if (connections && connections->data) {
+		ssids = g_ptr_array_sized_new (max_scan_ssids - 1);
+		g_ptr_array_add (ssids, nullssid);  /* Add wildcard SSID */
+	}
+
+	for (iter = connections; iter; iter = g_slist_next (iter)) {
+		NMConnection *connection = iter->data;
+		NMSettingWireless *s_wifi;
+		const GByteArray *ssid;
+
+		s_wifi = (NMSettingWireless *) nm_connection_get_setting_wireless (connection);
+		g_assert (s_wifi);
+		ssid = nm_setting_wireless_get_ssid (s_wifi);
+		g_assert (ssid);
+		g_ptr_array_add (ssids, (gpointer) ssid);
+	}
+	g_slist_free (connections);
+
+	return ssids;
+}
+
+static gboolean
 request_wireless_scan (gpointer user_data)
 {
 	NMDeviceWifi *self = NM_DEVICE_WIFI (user_data);
 	NMDeviceWifiPrivate *priv = NM_DEVICE_WIFI_GET_PRIVATE (self);
 	gboolean backoff = FALSE;
+	GPtrArray *ssids = NULL;
 
 	if (check_scanning_allowed (self)) {
 		nm_log_dbg (LOGD_WIFI_SCAN, "(%s): scanning requested",
 		            nm_device_get_iface (NM_DEVICE (self)));
 
-		if (nm_supplicant_interface_request_scan (priv->supplicant.iface)) {
+		ssids = build_hidden_probe_list (self);
+
+		if (nm_logging_level_enabled (LOGL_DEBUG)) {
+			if (ssids) {
+				guint i;
+				char *foo;
+
+				for (i = 0; i < ssids->len; i++) {
+					foo = nm_utils_ssid_to_utf8 (g_ptr_array_index (ssids, i));
+					nm_log_dbg (LOGD_WIFI_SCAN, "(%s): (%d) probe scanning SSID '%s'",
+					            nm_device_get_iface (NM_DEVICE (self)),
+					            i, foo ? foo : "<hidden>");
+					g_free (foo);
+				}
+			} else {
+				nm_log_dbg (LOGD_WIFI_SCAN, "(%s): no SSIDs to probe scan",
+				            nm_device_get_iface (NM_DEVICE (self)));
+			}
+		}
+
+		if (nm_supplicant_interface_request_scan (priv->supplicant.iface, ssids)) {
 			/* success */
 			backoff = TRUE;
 		}
+
+		if (ssids) {
+			/* Elements owned by the connections, so we don't free them here */
+			g_ptr_array_free (ssids, TRUE);
+		}
 	} else {
 		nm_log_dbg (LOGD_WIFI_SCAN, "(%s): scan requested but not allowed at this time",
 		            nm_device_get_iface (NM_DEVICE (self)));
@@ -1579,13 +1743,11 @@ static void
 schedule_scan (NMDeviceWifi *self, gboolean backoff)
 {
 	NMDeviceWifiPrivate *priv = NM_DEVICE_WIFI_GET_PRIVATE (self);
-	GTimeVal now;
-
-	g_get_current_time (&now);
+	time_t now = time (NULL);
 
 	/* Cancel the pending scan if it would happen later than (now + the scan_interval) */
 	if (priv->pending_scan_id) {
-		if (now.tv_sec + priv->scan_interval < priv->scheduled_scan_time)
+		if (now + priv->scan_interval < priv->scheduled_scan_time)
 			cancel_pending_scan (self);
 	}
 
@@ -1600,7 +1762,7 @@ schedule_scan (NMDeviceWifi *self, gboolean backoff)
 		                                               request_wireless_scan,
 		                                               self);
 
-		priv->scheduled_scan_time = now.tv_sec + priv->scan_interval;
+		priv->scheduled_scan_time = now + priv->scan_interval;
 		if (backoff && (priv->scan_interval < (SCAN_INTERVAL_MAX / factor))) {
 				priv->scan_interval += (SCAN_INTERVAL_STEP / factor);
 				/* Ensure the scan interval will never be less than 20s... */
@@ -1643,8 +1805,7 @@ supplicant_iface_scan_done_cb (NMSupplicantInterface *iface,
 	            nm_device_get_iface (NM_DEVICE (self)),
 	            success ? "successful" : "failed");
 
-	if (check_scanning_allowed (self))
-		schedule_scan (self, TRUE);
+	schedule_scan (self, success);
 
 	/* Ensure that old APs get removed, which otherwise only
 	 * happens when there are new BSSes.
@@ -1763,7 +1924,7 @@ static gboolean
 cull_scan_list (NMDeviceWifi *self)
 {
 	NMDeviceWifiPrivate *priv = NM_DEVICE_WIFI_GET_PRIVATE (self);
-	GTimeVal now;
+	time_t now = time (NULL);
 	GSList *outdated_list = NULL;
 	GSList *elt;
 	guint32 removed = 0, total = 0;
@@ -1776,7 +1937,6 @@ cull_scan_list (NMDeviceWifi *self)
 	/* Walk the access point list and remove any access points older than
 	 * three times the inactive scan interval.
 	 */
-	g_get_current_time (&now);
 	for (elt = priv->ap_list; elt; elt = g_slist_next (elt), total++) {
 		NMAccessPoint *ap = elt->data;
 		const guint prune_interval_s = SCAN_INTERVAL_MAX * 3;
@@ -1796,7 +1956,7 @@ cull_scan_list (NMDeviceWifi *self)
 		    && g_object_get_data (G_OBJECT (ap), WPAS_REMOVED_TAG) == NULL)
 			continue;
 
-		if (nm_ap_get_last_seen (ap) + prune_interval_s < now.tv_sec)
+		if (nm_ap_get_last_seen (ap) + prune_interval_s < now)
 			outdated_list = g_slist_append (outdated_list, ap);
 	}
 
@@ -1886,7 +2046,6 @@ supplicant_iface_bss_updated_cb (NMSupplicantInterface *iface,
 {
 	NMDeviceState state;
 	NMAccessPoint *ap;
-	GTimeVal now;
 
 	g_return_if_fail (self != NULL);
 	g_return_if_fail (object_path != NULL);
@@ -1899,10 +2058,8 @@ supplicant_iface_bss_updated_cb (NMSupplicantInterface *iface,
 
 	/* Update the AP's last-seen property */
 	ap = get_ap_by_supplicant_path (self, object_path);
-	if (ap) {
-		g_get_current_time (&now);
-		nm_ap_set_last_seen (ap, now.tv_sec);
-	}
+	if (ap)
+		nm_ap_set_last_seen (ap, (guint32) time (NULL));
 
 	/* Remove outdated access points */
 	schedule_scanlist_cull (self);
@@ -1991,8 +2148,11 @@ link_timeout_cb (gpointer user_data)
 	 * to reassociate within the timeout period, so the connection must
 	 * fail.
 	 */
-	if (nm_device_get_state (dev) == NM_DEVICE_STATE_ACTIVATED)
-		nm_device_state_changed (dev, NM_DEVICE_STATE_DISCONNECTED, NM_DEVICE_STATE_REASON_SUPPLICANT_TIMEOUT);
+	if (nm_device_get_state (dev) == NM_DEVICE_STATE_ACTIVATED) {
+		nm_device_state_changed (dev,
+		                         NM_DEVICE_STATE_FAILED,
+		                         NM_DEVICE_STATE_REASON_SUPPLICANT_TIMEOUT);
+	}
 
 	return FALSE;
 }
@@ -3365,7 +3525,7 @@ get_property (GObject *object, guint prop_id,
 
 static void
 set_property (GObject *object, guint prop_id,
-			  const GValue *value, GParamSpec *pspec)
+              const GValue *value, GParamSpec *pspec)
 {
 	NMDeviceWifiPrivate *priv = NM_DEVICE_WIFI_GET_PRIVATE (object);
 
@@ -3409,7 +3569,7 @@ nm_device_wifi_class_init (NMDeviceWifiClass *klass)
 	parent_class->is_available = real_is_available;
 	parent_class->check_connection_compatible = real_check_connection_compatible;
 	parent_class->complete_connection = real_complete_connection;
-    parent_class->set_enabled = real_set_enabled;
+	parent_class->set_enabled = real_set_enabled;
 
 	parent_class->act_stage1_prepare = real_act_stage1_prepare;
 	parent_class->act_stage2_config = real_act_stage2_config;
diff --git a/src/nm-device-wifi.h b/src/nm-device-wifi.h
index 1e665fc3..b22c78b3 100644
--- a/src/nm-device-wifi.h
+++ b/src/nm-device-wifi.h
@@ -46,6 +46,7 @@ typedef enum {
 	NM_WIFI_ERROR_CONNECTION_INVALID,          /*< nick=ConnectionInvalid >*/
 	NM_WIFI_ERROR_CONNECTION_INCOMPATIBLE,     /*< nick=ConnectionIncompatible >*/
 	NM_WIFI_ERROR_ACCESS_POINT_NOT_FOUND,      /*< nick=AccessPointNotFound >*/
+	NM_WIFI_ERROR_SCAN_NOT_ALLOWED,            /*< nick=ScanNotAllowed >*/
 } NMWifiError;
 
 #define NM_DEVICE_WIFI_HW_ADDRESS          "hw-address"
diff --git a/src/nm-device-wired.c b/src/nm-device-wired.c
index a476faad..60e5f262 100644
--- a/src/nm-device-wired.c
+++ b/src/nm-device-wired.c
@@ -162,6 +162,7 @@ set_carrier (NMDeviceWired *self,
 {
 	NMDeviceWiredPrivate *priv;
 	NMDeviceState state;
+	guint32 caps;
 
 	g_return_if_fail (NM_IS_DEVICE (self));
 
@@ -172,16 +173,25 @@ set_carrier (NMDeviceWired *self,
 	/* Clear any previous deferred action */
 	carrier_action_defer_clear (self);
 
+	/* Warn if we try to set carrier down on a device that
+	 * doesn't support carrier detect.  These devices assume
+	 * the carrier is always up.
+	 */
+	caps = nm_device_get_capabilities (NM_DEVICE (self));
+	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));
-	nm_log_info (LOGD_HW | NM_DEVICE_WIRED_LOG_LEVEL (NM_DEVICE (self)),
-	             "(%s): carrier now %s (device state %d%s)",
-	             nm_device_get_iface (NM_DEVICE (self)),
-	             carrier ? "ON" : "OFF",
-	             state,
-	             defer_action ? ", deferring action for 4 seconds" : "");
+	if (state >= NM_DEVICE_STATE_UNAVAILABLE) {
+		nm_log_info (LOGD_HW | NM_DEVICE_WIRED_LOG_LEVEL (NM_DEVICE (self)),
+		             "(%s): carrier now %s (device state %d%s)",
+		             nm_device_get_iface (NM_DEVICE (self)),
+		             carrier ? "ON" : "OFF",
+		             state,
+		             defer_action ? ", deferring action for 4 seconds" : "");
+	}
 
 	if (defer_action)
 		priv->carrier_action_defer_id = g_timeout_add_seconds (4, carrier_action_defer_cb, self);
@@ -200,10 +210,8 @@ carrier_on (NMNetlinkMonitor *monitor,
 
 	/* Make sure signal is for us */
 	if (idx == nm_device_get_ifindex (device)) {
-		/* Ignore spurious netlink messages */
 		caps = nm_device_get_capabilities (device);
-		if (!(caps & NM_DEVICE_CAP_CARRIER_DETECT))
-			return;
+		g_return_if_fail (caps & NM_DEVICE_CAP_CARRIER_DETECT);
 
 		set_carrier (self, TRUE, FALSE);
 		set_speed (self, ethtool_get_speed (self));
@@ -224,10 +232,8 @@ carrier_off (NMNetlinkMonitor *monitor,
 		NMDeviceState state;
 		gboolean defer = FALSE;
 
-		/* Ignore spurious netlink messages */
 		caps = nm_device_get_capabilities (device);
-		if (!(caps & NM_DEVICE_CAP_CARRIER_DETECT))
-			return;
+		g_return_if_fail (caps & NM_DEVICE_CAP_CARRIER_DETECT);
 
 		/* Defer carrier-off event actions while connected by a few seconds
 		 * so that tripping over a cable, power-cycling a switch, or breaking
@@ -350,11 +356,15 @@ static gboolean
 real_hw_bring_up (NMDevice *dev, gboolean *no_firmware)
 {
 	gboolean success, carrier;
+	guint32 caps;
 
 	success = nm_system_iface_set_up (nm_device_get_ip_ifindex (dev), TRUE, no_firmware);
 	if (success) {
-		carrier = get_carrier_sync (NM_DEVICE_WIRED (dev));
-		set_carrier (NM_DEVICE_WIRED (dev), carrier, carrier ? FALSE : TRUE);
+		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;
 }
diff --git a/src/nm-device.c b/src/nm-device.c
index 1dc94ee9..cf01003c 100644
--- a/src/nm-device.c
+++ b/src/nm-device.c
@@ -27,6 +27,8 @@
 #include <string.h>
 #include <unistd.h>
 #include <errno.h>
+#include <linux/sockios.h>
+#include <linux/ethtool.h>
 #include <sys/ioctl.h>
 #include <signal.h>
 #include <sys/types.h>
@@ -43,7 +45,6 @@
 #include "nm-system.h"
 #include "nm-dhcp-manager.h"
 #include "nm-dbus-manager.h"
-#include "nm-dns-manager.h"
 #include "nm-utils.h"
 #include "nm-logging.h"
 #include "nm-netlink-monitor.h"
@@ -61,6 +62,9 @@
 #include "nm-properties-changed-signal.h"
 #include "nm-enum-types.h"
 #include "nm-settings-connection.h"
+#include "nm-connection-provider.h"
+#include "nm-posix-signals.h"
+#include "nm-manager-auth.h"
 
 static void impl_device_disconnect (NMDevice *device, DBusGMethodInvocation *context);
 
@@ -87,8 +91,10 @@ nm_device_error_quark (void)
 
 enum {
 	STATE_CHANGED,
-	DISCONNECT_REQUEST,
 	AUTOCONNECT_ALLOWED,
+	AUTH_REQUEST,
+	IP4_CONFIG_CHANGED,
+	IP6_CONFIG_CHANGED,
 	LAST_SIGNAL,
 };
 static guint signals[LAST_SIGNAL] = { 0 };
@@ -99,6 +105,8 @@ enum {
 	PROP_IFACE,
 	PROP_IP_IFACE,
 	PROP_DRIVER,
+	PROP_DRIVER_VERSION,
+	PROP_FIRMWARE_VERSION,
 	PROP_CAPABILITIES,
 	PROP_IP4_ADDRESS,
 	PROP_IP4_CONFIG,
@@ -110,6 +118,7 @@ enum {
 	PROP_ACTIVE_CONNECTION,
 	PROP_DEVICE_TYPE,
 	PROP_MANAGED,
+	PROP_AUTOCONNECT,
 	PROP_FIRMWARE_MISSING,
 	PROP_TYPE_DESC,
 	PROP_RFKILL_TYPE,
@@ -117,6 +126,8 @@ enum {
 	LAST_PROP
 };
 
+#define DEFAULT_AUTOCONNECT TRUE
+
 /***********************************************************/
 
 G_DEFINE_ABSTRACT_TYPE (NMDevice, nm_device, G_TYPE_OBJECT)
@@ -153,6 +164,8 @@ typedef struct {
 	char *        type_desc;
 	guint32       capabilities;
 	char *        driver;
+	char *        driver_version;
+	char *        firmware_version;
 	gboolean      managed; /* whether managed by NM or not */
 	RfKillType    rfkill_type;
 	gboolean      firmware_missing;
@@ -221,11 +234,13 @@ typedef struct {
 	/* IP6 config from DHCP */
 	NMIP6Config *   dhcp6_ip6_config;
 
-	/* inhibit autoconnect feature */
-	gboolean	autoconnect_inhibit;
+	/* allow autoconnect feature */
+	gboolean        autoconnect;
 
 	/* master interface for bridge, bond, vlan, etc */
 	NMDevice *	master;
+
+	NMConnectionProvider *con_provider;
 } NMDevicePrivate;
 
 static void nm_device_take_down (NMDevice *dev, gboolean wait, NMDeviceStateReason reason);
@@ -239,7 +254,6 @@ static gboolean nm_device_set_ip4_config (NMDevice *dev,
                                           NMDeviceStateReason *reason);
 static gboolean nm_device_set_ip6_config (NMDevice *dev,
                                           NMIP6Config *config,
-                                          gboolean assumed,
                                           NMDeviceStateReason *reason);
 
 static gboolean nm_device_activate_ip6_config_commit (gpointer user_data);
@@ -259,6 +273,7 @@ nm_device_init (NMDevice *self)
 	priv->state_reason = NM_DEVICE_STATE_REASON_NONE;
 	priv->dhcp_timeout = 0;
 	priv->rfkill_type = RFKILL_TYPE_UNKNOWN;
+	priv->autoconnect = DEFAULT_AUTOCONNECT;
 }
 
 static void
@@ -332,18 +347,57 @@ update_ip6_privacy_save (NMDevice *self)
 	}
 }
 
+/*
+ * Get driver info from SIOCETHTOOL ioctl() for 'iface'
+ * Returns driver and firmware versions to 'driver_version and' 'firmware_version'
+ */
+static gboolean
+device_get_driver_info (const char *iface, char **driver_version, char **firmware_version)
+{
+	struct ethtool_drvinfo drvinfo;
+	struct ifreq req;
+	int fd;
+
+	fd = socket (PF_INET, SOCK_DGRAM, 0);
+	if (fd < 0) {
+		nm_log_warn (LOGD_HW, "couldn't open control socket.");
+		return FALSE;
+	}
+
+	/* Get driver and firmware version info */
+	memset (&req, 0, sizeof (struct ifreq));
+	strncpy (req.ifr_name, iface, IFNAMSIZ);
+	drvinfo.cmd = ETHTOOL_GDRVINFO;
+	req.ifr_data = &drvinfo;
+
+	errno = 0;
+	if (ioctl (fd, SIOCETHTOOL, &req) < 0) {
+		nm_log_dbg (LOGD_HW, "SIOCETHTOOL ioctl() failed: cmd=ETHTOOL_GDRVINFO, iface=%s, errno=%d",
+		            iface, errno);
+		close (fd);
+		return FALSE;
+	}
+	if (driver_version)
+		*driver_version = g_strdup (drvinfo.version);
+	if (firmware_version)
+		*firmware_version = g_strdup (drvinfo.fw_version);
+
+	close (fd);
+	return TRUE;
+}
+
 static GObject*
 constructor (GType type,
-			 guint n_construct_params,
-			 GObjectConstructParam *construct_params)
+             guint n_construct_params,
+             GObjectConstructParam *construct_params)
 {
 	GObject *object;
 	NMDevice *dev;
 	NMDevicePrivate *priv;
 
 	object = G_OBJECT_CLASS (nm_device_parent_class)->constructor (type,
-													   n_construct_params,
-													   construct_params);
+	                         n_construct_params,
+	                         construct_params);
 	if (!object)
 		return NULL;
 
@@ -370,6 +424,8 @@ constructor (GType type,
 
 	priv->fw_manager = nm_firewall_manager_get ();
 
+	device_get_driver_info (priv->iface, &priv->driver_version, &priv->firmware_version);
+
 	update_accept_ra_save (dev);
 	update_ip6_privacy_save (dev);
 
@@ -503,7 +559,8 @@ nm_device_set_ip_iface (NMDevice *self, const char *iface)
 	priv->ip_iface = g_strdup (iface);
 	if (priv->ip_iface) {
 		priv->ip_ifindex = nm_netlink_iface_to_index (priv->ip_iface);
-		if (priv->ip_ifindex < 0) {
+		if (priv->ip_ifindex <= 0) {
+			/* Device IP interface must always be a kernel network interface */
 			nm_log_warn (LOGD_HW, "(%s): failed to look up interface index", iface);
 		}
 	}
@@ -526,6 +583,22 @@ nm_device_get_driver (NMDevice *self)
 	return NM_DEVICE_GET_PRIVATE (self)->driver;
 }
 
+const char *
+nm_device_get_driver_version (NMDevice *self)
+{
+	g_return_val_if_fail (self != NULL, NULL);
+
+	return NM_DEVICE_GET_PRIVATE (self)->driver_version;
+}
+
+const char *
+nm_device_get_firmware_version (NMDevice *self)
+{
+	g_return_val_if_fail (self != NULL, NULL);
+
+	return NM_DEVICE_GET_PRIVATE (self)->firmware_version;
+}
+
 
 /*
  * Get/set functions for type
@@ -539,12 +612,52 @@ nm_device_get_device_type (NMDevice *self)
 }
 
 
+/**
+ * nm_device_get_priority():
+ * @dev: the #NMDevice
+ *
+ * Returns: the device's routing priority.  Lower numbers means a "better"
+ *  device, eg higher priority.
+ */
 int
 nm_device_get_priority (NMDevice *dev)
 {
-	g_return_val_if_fail (NM_IS_DEVICE (dev), -1);
+	g_return_val_if_fail (NM_IS_DEVICE (dev), 100);
 
-	return (int) nm_device_get_device_type (dev);
+	/* Device 'priority' is used for two things:
+	 *
+	 * a) two devices on the same IP subnet: the "better" (ie, lower number)
+	 *     device is the default outgoing device for that subnet
+	 * b) default route: the "better" device gets the default route.  This can
+	 *     always be modified by setting a connection to never-default=TRUE, in
+	 *     which case that device will never take the default route when
+	 *     it's using that connection.
+	 */
+
+	switch (nm_device_get_device_type (dev)) {
+	case NM_DEVICE_TYPE_ETHERNET:
+		return 1;
+	case NM_DEVICE_TYPE_INFINIBAND:
+		return 2;
+	case NM_DEVICE_TYPE_ADSL:
+		return 3;
+	case NM_DEVICE_TYPE_WIMAX:
+		return 4;
+	case NM_DEVICE_TYPE_BOND:
+		return 5;
+	case NM_DEVICE_TYPE_VLAN:
+		return 6;
+	case NM_DEVICE_TYPE_MODEM:
+		return 7;
+	case NM_DEVICE_TYPE_BT:
+		return 8;
+	case NM_DEVICE_TYPE_WIFI:
+		return 9;
+	case NM_DEVICE_TYPE_OLPC_MESH:
+		return 10;
+	default:
+		return 20;
+	}
 }
 
 
@@ -585,6 +698,30 @@ nm_device_get_type_desc (NMDevice *self)
 	return NM_DEVICE_GET_PRIVATE (self)->type_desc;
 }
 
+void
+nm_device_set_connection_provider (NMDevice *device,
+                                   NMConnectionProvider *provider)
+{
+	NMDevicePrivate *priv;
+
+	g_return_if_fail (device != NULL);
+	g_return_if_fail (provider != NULL);
+	g_return_if_fail (NM_IS_CONNECTION_PROVIDER (provider));
+
+	priv = NM_DEVICE_GET_PRIVATE (device);
+	g_return_if_fail (priv->con_provider == NULL);
+
+	priv->con_provider = provider;
+}
+
+NMConnectionProvider *
+nm_device_get_connection_provider (NMDevice *device)
+{
+	g_return_val_if_fail (device != NULL, NULL);
+
+	return NM_DEVICE_GET_PRIVATE (device)->con_provider;
+}
+
 /**
  * nm_device_enslave_slave:
  * @dev: the master device
@@ -716,10 +853,10 @@ nm_device_autoconnect_allowed (NMDevice *self)
 	g_value_take_object (&instance, self);
 
 	g_value_init (&retval, G_TYPE_BOOLEAN);
-	if (priv->autoconnect_inhibit)
-		g_value_set_boolean (&retval, FALSE);
-	else
+	if (priv->autoconnect)
 		g_value_set_boolean (&retval, TRUE);
+	else
+		g_value_set_boolean (&retval, FALSE);
 
 	/* Use g_signal_emitv() rather than g_signal_emit() to avoid the return
 	 * value being changed if no handlers are connected */
@@ -776,14 +913,6 @@ nm_device_complete_connection (NMDevice *self,
 	if (success)
 		success = nm_connection_verify (connection, error);
 
-	/* If ip6-privacy is unknown, enable it with temporary address preferred */
-	if (success) {
-		NMSettingIP6Config *s_ip6 = nm_connection_get_setting_ip6_config (connection);
-		if (s_ip6 && nm_setting_ip6_config_get_ip6_privacy (s_ip6) == NM_SETTING_IP6_CONFIG_PRIVACY_UNKNOWN)
-			g_object_set (s_ip6, NM_SETTING_IP6_CONFIG_IP6_PRIVACY,
-			              NM_SETTING_IP6_CONFIG_PRIVACY_PREFER_TEMP_ADDR, NULL);
-	}
-
 	return success;
 }
 
@@ -1311,6 +1440,12 @@ aipd_child_setup (gpointer user_data G_GNUC_UNUSED)
 	 */
 	pid_t pid = getpid ();
 	setpgid (pid, pid);
+
+	/*
+	 * We blocked signals in main(). We need to restore original signal
+	 * mask for avahi-autoipd here so that it can receive signals.
+	 */
+	nm_unblock_posix_signals (NULL);
 }
 
 static NMActStageReturn
@@ -1715,6 +1850,10 @@ merge_ip6_configs (NMIP6Config *dst, NMIP6Config *src)
 	for (i = 0; i < nm_ip6_config_get_num_nameservers (src); i++)
 		nm_ip6_config_add_nameserver (dst, nm_ip6_config_get_nameserver (src, i));
 
+	/* default gateway */
+	if (!nm_ip6_config_get_gateway (dst))
+		nm_ip6_config_set_gateway (dst, nm_ip6_config_get_gateway (src));
+
 	/* routes */
 	for (i = 0; i < nm_ip6_config_get_num_routes (src); i++)
 		nm_ip6_config_add_route (dst, nm_ip6_config_get_route (src, i));
@@ -1738,7 +1877,7 @@ ip6_config_merge_and_apply (NMDevice *self,
 {
 	NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE (self);
 	NMConnection *connection;
-	gboolean assumed, success;
+	gboolean success;
 	NMIP6Config *composite;
 
 	connection = nm_device_get_connection (self);
@@ -1761,8 +1900,7 @@ ip6_config_merge_and_apply (NMDevice *self,
 	/* Merge user overrides into the composite config */
 	nm_utils_merge_ip6_config (composite, nm_connection_get_setting_ip6_config (connection));
 
-	assumed = nm_act_request_get_assumed (priv->act_request);
-	success = nm_device_set_ip6_config (self, composite, assumed, out_reason);
+	success = nm_device_set_ip6_config (self, composite, out_reason);
 	g_object_unref (composite);
 	return success;
 }
@@ -2532,6 +2670,8 @@ share_child_setup (gpointer user_data G_GNUC_UNUSED)
 	/* We are in the child process at this point */
 	pid_t pid = getpid ();
 	setpgid (pid, pid);
+
+	nm_unblock_posix_signals (NULL);
 }
 
 static gboolean
@@ -3092,7 +3232,7 @@ nm_device_deactivate (NMDevice *self, NMDeviceStateReason reason)
 	/* Take out any entries in the routing table and any IP address the device had. */
 	ifindex = nm_device_get_ip_ifindex (self);
 	family = tried_ipv6 ? AF_UNSPEC : AF_INET;
-	if (ifindex >= 0) {
+	if (ifindex > 0) {
 		nm_system_iface_flush_routes (ifindex, family);
 		nm_system_iface_flush_addresses (ifindex, family);
 	}
@@ -3100,35 +3240,59 @@ nm_device_deactivate (NMDevice *self, NMDeviceStateReason reason)
 
 	/* Clean up nameservers and addresses */
 	nm_device_set_ip4_config (self, NULL, FALSE, &ignored);
-	nm_device_set_ip6_config (self, NULL, FALSE, &ignored);
+	nm_device_set_ip6_config (self, NULL, &ignored);
 }
 
-gboolean
-nm_device_disconnect (NMDevice *device, GError **error)
+static void
+disconnect_cb (NMDevice *device,
+               DBusGMethodInvocation *context,
+               GError *error,
+               gpointer user_data)
 {
-	NMDevicePrivate *priv;
-
-	g_return_val_if_fail (device != NULL, FALSE);
-	g_return_val_if_fail (NM_IS_DEVICE (device), FALSE);
+	NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE (device);
+	GError *local = NULL;
 
-	priv = NM_DEVICE_GET_PRIVATE (device);
-	if (priv->state <= NM_DEVICE_STATE_DISCONNECTED) {
-		g_set_error_literal (error, NM_DEVICE_ERROR, NM_DEVICE_ERROR_NOT_ACTIVE,
-		                     "Cannot disconnect an inactive device.");
-		return FALSE;
+	if (error)
+		dbus_g_method_return_error (context, error);
+	else {
+		/* Authorized */
+		if (priv->state <= NM_DEVICE_STATE_DISCONNECTED) {
+			local = g_error_new_literal (NM_DEVICE_ERROR,
+			                             NM_DEVICE_ERROR_NOT_ACTIVE,
+			                             "Device is not active");
+			dbus_g_method_return_error (context, local);
+			g_error_free (local);
+		} else {
+			priv->autoconnect = FALSE;
+			nm_device_state_changed (device,
+			                         NM_DEVICE_STATE_DISCONNECTED,
+			                         NM_DEVICE_STATE_REASON_USER_REQUESTED);
+			dbus_g_method_return (context);
+		}
 	}
-
-	priv->autoconnect_inhibit = TRUE;	
-	nm_device_state_changed (device,
-	                         NM_DEVICE_STATE_DISCONNECTED,
-	                         NM_DEVICE_STATE_REASON_USER_REQUESTED);
-	return TRUE;
 }
 
 static void
 impl_device_disconnect (NMDevice *device, DBusGMethodInvocation *context)
 {
-	g_signal_emit (device, signals[DISCONNECT_REQUEST], 0, context);
+	GError *error = NULL;
+
+	if (NM_DEVICE_GET_PRIVATE (device)->act_request == NULL) {
+		error = g_error_new_literal (NM_DEVICE_ERROR,
+		                             NM_DEVICE_ERROR_NOT_ACTIVE,
+		                             "This device is not active");
+		dbus_g_method_return_error (context, error);
+		g_error_free (error);
+		return;
+	}
+
+	/* Ask the manager to authenticate this request for us */
+	g_signal_emit (device, signals[AUTH_REQUEST], 0,
+	               context,
+	               NM_AUTH_PERMISSION_NETWORK_CONTROL,
+	               TRUE,
+	               disconnect_cb,
+	               NULL);
 }
 
 static gboolean
@@ -3222,6 +3386,7 @@ nm_device_activate (NMDevice *self, NMActRequest *req, GError **error)
 	}
 
 	priv->act_request = g_object_ref (req);
+	g_object_notify (G_OBJECT (self), NM_DEVICE_ACTIVE_CONNECTION);
 
 	if (!nm_act_request_get_assumed (req)) {
 		NMActiveConnection *dep_ac;
@@ -3345,7 +3510,6 @@ nm_device_set_ip4_config (NMDevice *self,
 	NMIP4Config *old_config = NULL;
 	gboolean success = TRUE;
 	NMIP4ConfigCompareFlags diff = NM_IP4_COMPARE_FLAG_ALL;
-	NMDnsManager *dns_mgr;
 	int ip_ifindex;
 
 	g_return_val_if_fail (NM_IS_DEVICE (self), FALSE);
@@ -3353,23 +3517,18 @@ nm_device_set_ip4_config (NMDevice *self,
 
 	priv = NM_DEVICE_GET_PRIVATE (self);
 	ip_iface = nm_device_get_ip_iface (self);
+	ip_ifindex = nm_device_get_ip_ifindex (self);
 
 	old_config = priv->ip4_config;
 
-	if (new_config && old_config)
+	if (new_config && old_config) {
 		diff = nm_ip4_config_diff (new_config, old_config);
-
-	/* No actual change, do nothing */
-	if (diff == NM_IP4_COMPARE_FLAG_NONE)
+		if (diff == NM_IP4_COMPARE_FLAG_NONE)
+			return TRUE;  /* no actual change */
+	} else if (!new_config && !old_config)
 		return TRUE;
 
-	dns_mgr = nm_dns_manager_get (NULL);
-	if (old_config) {
-		/* Remove any previous IP4 Config from the DNS manager */
-		nm_dns_manager_remove_ip4_config (dns_mgr, ip_iface, old_config);
-		g_object_unref (old_config);
-		priv->ip4_config = NULL;
-	}
+	priv->ip4_config = NULL;
 
 	if (new_config) {
 		priv->ip4_config = g_object_ref (new_config);
@@ -3377,25 +3536,22 @@ nm_device_set_ip4_config (NMDevice *self,
 		/* Don't touch the device's actual IP config if the connection is
 		 * assumed when NM starts.
 		 */
-		if (!assumed) {
-			ip_ifindex = nm_device_get_ip_ifindex (self);
+		if (!assumed)
 			success = nm_system_apply_ip4_config (ip_ifindex, new_config, nm_device_get_priority (self), diff);
-		}
 
 		if (success || assumed) {
 			/* Export over D-Bus */
 			if (!nm_ip4_config_get_dbus_path (new_config))
 				nm_ip4_config_export (new_config);
-
-			/* Add the DNS information to the DNS manager */
-			nm_dns_manager_add_ip4_config (dns_mgr, ip_iface, new_config, NM_DNS_IP_CONFIG_TYPE_DEFAULT);
-
 			_update_ip4_address (self);
 		}
 	}
-	g_object_unref (dns_mgr);
 
 	g_object_notify (G_OBJECT (self), NM_DEVICE_IP4_CONFIG);
+	g_signal_emit (self, signals[IP4_CONFIG_CHANGED], 0, priv->ip4_config, old_config);
+
+	if (old_config)
+		g_object_unref (old_config);
 
 	return success;
 }
@@ -3403,7 +3559,6 @@ nm_device_set_ip4_config (NMDevice *self,
 static gboolean
 nm_device_set_ip6_config (NMDevice *self,
                           NMIP6Config *new_config,
-                          gboolean assumed,
                           NMDeviceStateReason *reason)
 {
 	NMDevicePrivate *priv;
@@ -3411,7 +3566,6 @@ nm_device_set_ip6_config (NMDevice *self,
 	NMIP6Config *old_config = NULL;
 	gboolean success = TRUE;
 	NMIP6ConfigCompareFlags diff = NM_IP6_COMPARE_FLAG_ALL;
-	NMDnsManager *dns_mgr;
 	int ip_ifindex;
 
 	g_return_val_if_fail (NM_IS_DEVICE (self), FALSE);
@@ -3423,42 +3577,32 @@ nm_device_set_ip6_config (NMDevice *self,
 
 	old_config = priv->ip6_config;
 
-	if (new_config && old_config)
+	if (new_config && old_config) {
 		diff = nm_ip6_config_diff (new_config, old_config);
-
-	/* No actual change, do nothing */
-	if (diff == NM_IP6_COMPARE_FLAG_NONE)
+		if (diff == NM_IP6_COMPARE_FLAG_NONE)
+			return TRUE;  /* no actual change */
+	} else if (!new_config && !old_config)
 		return TRUE;
 
-	dns_mgr = nm_dns_manager_get (NULL);
-	if (old_config) {
-		/* Remove any previous IP6 Config from the DNS manager */
-		nm_dns_manager_remove_ip6_config (dns_mgr, ip_iface, old_config);
-		g_object_unref (old_config);
-		priv->ip6_config = NULL;
-	}
+	priv->ip6_config = NULL;
 
 	if (new_config) {
 		priv->ip6_config = g_object_ref (new_config);
 
-		/* Don't touch the device's actual IP config if the connection is
-		 * assumed when NM starts.
-		 */
-		if (!assumed)
-			success = nm_system_apply_ip6_config (ip_ifindex, new_config, nm_device_get_priority (self), diff);
+		success = nm_system_apply_ip6_config (ip_ifindex, new_config, nm_device_get_priority (self), diff);
 
-		if (success || assumed) {
+		if (success) {
 			/* Export over D-Bus */
 			if (!nm_ip6_config_get_dbus_path (new_config))
 				nm_ip6_config_export (new_config);
-
-			/* Add the DNS information to the DNS manager */
-			nm_dns_manager_add_ip6_config (dns_mgr, ip_iface, new_config, NM_DNS_IP_CONFIG_TYPE_DEFAULT);
 		}
 	}
-	g_object_unref (dns_mgr);
 
 	g_object_notify (G_OBJECT (self), NM_DEVICE_IP6_CONFIG);
+	g_signal_emit (self, signals[IP6_CONFIG_CHANGED], 0, priv->ip6_config, old_config);
+
+	if (old_config)
+		g_object_unref (old_config);
 
 	return success;
 }
@@ -3683,6 +3827,8 @@ finalize (GObject *object)
 	g_free (priv->iface);
 	g_free (priv->ip_iface);
 	g_free (priv->driver);
+	g_free (priv->driver_version);
+	g_free (priv->firmware_version);
 	g_free (priv->type_desc);
 	if (priv->dhcp_anycast_address)
 		g_byte_array_free (priv->dhcp_anycast_address, TRUE);
@@ -3710,18 +3856,31 @@ set_property (GObject *object, guint prop_id,
 		g_free (priv->iface);
 		priv->ifindex = 0;
 		priv->iface = g_value_dup_string (value);
-		if (priv->iface) {
+
+		/* Only look up the ifindex if it appears to be an actual kernel
+		 * interface name.  eg Bluetooth devices won't have one until we know
+		 * the IP interface.
+		 */
+		if (priv->iface && !strchr (priv->iface, ':')) {
 			priv->ifindex = nm_netlink_iface_to_index (priv->iface);
-			if (priv->ifindex <= 0) {
+			if (priv->ifindex <= 0)
 				nm_log_warn (LOGD_HW, "(%s): failed to look up interface index", priv->iface);
-			}
 		}
 		break;
 	case PROP_IP_IFACE:
 		break;
 	case PROP_DRIVER:
+		g_free (priv->driver);
 		priv->driver = g_strdup (g_value_get_string (value));
 		break;
+	case PROP_DRIVER_VERSION:
+		g_free (priv->driver_version);
+		priv->driver_version = g_strdup (g_value_get_string (value));
+		break;
+	case PROP_FIRMWARE_VERSION:
+		g_free (priv->firmware_version);
+		priv->firmware_version = g_strdup (g_value_get_string (value));
+		break;
 	case PROP_CAPABILITIES:
 		priv->capabilities = g_value_get_uint (value);
 		break;
@@ -3731,6 +3890,9 @@ set_property (GObject *object, guint prop_id,
 	case PROP_MANAGED:
 		priv->managed = g_value_get_boolean (value);
 		break;
+	case PROP_AUTOCONNECT:
+		priv->autoconnect = g_value_get_boolean (value);
+		break;
 	case PROP_FIRMWARE_MISSING:
 		priv->firmware_missing = g_value_get_boolean (value);
 		break;
@@ -3787,6 +3949,12 @@ get_property (GObject *object, guint prop_id,
 	case PROP_DRIVER:
 		g_value_set_string (value, priv->driver);
 		break;
+	case PROP_DRIVER_VERSION:
+		g_value_set_string (value, priv->driver_version);
+		break;
+	case PROP_FIRMWARE_VERSION:
+		g_value_set_string (value, priv->firmware_version);
+		break;
 	case PROP_CAPABILITIES:
 		g_value_set_uint (value, priv->capabilities);
 		break;
@@ -3839,6 +4007,9 @@ get_property (GObject *object, guint prop_id,
 	case PROP_MANAGED:
 		g_value_set_boolean (value, priv->managed);
 		break;
+	case PROP_AUTOCONNECT:
+		g_value_set_boolean (value, priv->autoconnect);
+		break;
 	case PROP_FIRMWARE_MISSING:
 		g_value_set_boolean (value, priv->firmware_missing);
 		break;
@@ -3913,6 +4084,22 @@ nm_device_class_init (NMDeviceClass *klass)
 		                      G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY));
 
 	g_object_class_install_property
+		(object_class, PROP_DRIVER_VERSION,
+		 g_param_spec_string (NM_DEVICE_DRIVER_VERSION,
+		                      "Driver Version",
+		                      "Driver Version",
+		                      NULL,
+		                      G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY));
+
+	g_object_class_install_property
+		(object_class, PROP_FIRMWARE_VERSION,
+		 g_param_spec_string (NM_DEVICE_FIRMWARE_VERSION,
+		                      "Firmware Version",
+		                      "Firmware Version",
+		                      NULL,
+		                      G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY));
+
+	g_object_class_install_property
 		(object_class, PROP_CAPABILITIES,
 		 g_param_spec_uint (NM_DEVICE_CAPABILITIES,
 		                    "Capabilities",
@@ -4000,6 +4187,14 @@ nm_device_class_init (NMDeviceClass *klass)
 		                       G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY));
 
 	g_object_class_install_property
+		(object_class, PROP_AUTOCONNECT,
+		 g_param_spec_boolean (NM_DEVICE_AUTOCONNECT,
+		                       "Autoconnect",
+		                       "Autoconnect",
+		                       DEFAULT_AUTOCONNECT,
+		                       G_PARAM_READWRITE));
+
+	g_object_class_install_property
 		(object_class, PROP_FIRMWARE_MISSING,
 		 g_param_spec_boolean (NM_DEVICE_FIRMWARE_MISSING,
 		                       "FirmwareMissing",
@@ -4043,14 +4238,6 @@ nm_device_class_init (NMDeviceClass *klass)
 		              G_TYPE_NONE, 3,
 		              G_TYPE_UINT, G_TYPE_UINT, G_TYPE_UINT);
 
-	signals[DISCONNECT_REQUEST] =
-		g_signal_new (NM_DEVICE_DISCONNECT_REQUEST,
-		              G_OBJECT_CLASS_TYPE (object_class),
-		              G_SIGNAL_RUN_FIRST,
-		              0, NULL, NULL,
-		              g_cclosure_marshal_VOID__POINTER,
-		              G_TYPE_NONE, 1, G_TYPE_POINTER);
-
 	signals[AUTOCONNECT_ALLOWED] =
 		g_signal_new ("autoconnect-allowed",
 		              G_OBJECT_CLASS_TYPE (object_class),
@@ -4060,6 +4247,31 @@ nm_device_class_init (NMDeviceClass *klass)
 		              _nm_marshal_BOOLEAN__VOID,
 		              G_TYPE_BOOLEAN, 0);
 
+	signals[AUTH_REQUEST] =
+		g_signal_new (NM_DEVICE_AUTH_REQUEST,
+		              G_OBJECT_CLASS_TYPE (object_class),
+		              G_SIGNAL_RUN_FIRST,
+		              0, NULL, NULL,
+		              /* dbus-glib context, permission, allow_interaction, callback, user_data */
+		              _nm_marshal_VOID__POINTER_STRING_BOOLEAN_POINTER_POINTER,
+		              G_TYPE_NONE, 5, G_TYPE_POINTER, G_TYPE_STRING, G_TYPE_BOOLEAN, G_TYPE_POINTER, G_TYPE_POINTER);
+
+	signals[IP4_CONFIG_CHANGED] =
+		g_signal_new (NM_DEVICE_IP4_CONFIG_CHANGED,
+		              G_OBJECT_CLASS_TYPE (object_class),
+		              G_SIGNAL_RUN_FIRST,
+		              0, NULL, NULL,
+		              _nm_marshal_VOID__OBJECT_OBJECT,
+		              G_TYPE_NONE, 2, G_TYPE_OBJECT, G_TYPE_OBJECT);
+
+	signals[IP6_CONFIG_CHANGED] =
+		g_signal_new (NM_DEVICE_IP6_CONFIG_CHANGED,
+		              G_OBJECT_CLASS_TYPE (object_class),
+		              G_SIGNAL_RUN_FIRST,
+		              0, NULL, NULL,
+		              _nm_marshal_VOID__OBJECT_OBJECT,
+		              G_TYPE_NONE, 2, G_TYPE_OBJECT, G_TYPE_OBJECT);
+
 	dbus_g_object_type_install_info (G_TYPE_FROM_CLASS (klass),
 	                                 &dbus_glib_nm_device_interface_object_info);
 
@@ -4225,6 +4437,8 @@ reason_to_string (NMDeviceStateReason reason)
 		return "infiniband-mode";
 	case NM_DEVICE_STATE_REASON_DEPENDENCY_FAILED:
 		return "dependency-failed";
+	case NM_DEVICE_STATE_REASON_BR2684_FAILED:
+		return "br2684 bridge failed";
 	default:
 		break;
 	}
@@ -4307,7 +4521,7 @@ nm_device_state_changed (NMDevice *device,
 			nm_device_deactivate (device, reason);
 		break;
 	default:
-		priv->autoconnect_inhibit = FALSE;
+		priv->autoconnect = TRUE;
 		break;
 	}
 
@@ -4627,12 +4841,11 @@ nm_device_set_dhcp_anycast_address (NMDevice *device, guint8 *addr)
 	}
 }
 
-
-void
-nm_device_clear_autoconnect_inhibit (NMDevice *device)
+gboolean
+nm_device_get_autoconnect (NMDevice *device)
 {
-	NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE (device);
-	g_return_if_fail (priv);
-	priv->autoconnect_inhibit = FALSE;
+	g_return_val_if_fail (NM_IS_DEVICE (device), FALSE);
+
+	return NM_DEVICE_GET_PRIVATE (device)->autoconnect;
 }
 
diff --git a/src/nm-device.h b/src/nm-device.h
index bf76ecb5..91d9166a 100644
--- a/src/nm-device.h
+++ b/src/nm-device.h
@@ -15,7 +15,7 @@
  * with this program; if not, write to the Free Software Foundation, Inc.,
  * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
  *
- * Copyright (C) 2005 - 2011 Red Hat, Inc.
+ * Copyright (C) 2005 - 2012 Red Hat, Inc.
  * Copyright (C) 2006 - 2008 Novell, Inc.
  */
 
@@ -23,7 +23,7 @@
 #define NM_DEVICE_H
 
 #include <glib-object.h>
-#include <dbus/dbus.h>
+#include <dbus/dbus-glib.h>
 #include <netinet/in.h>
 
 #include "NetworkManager.h"
@@ -34,12 +34,15 @@
 #include "nm-dhcp6-config.h"
 #include "nm-connection.h"
 #include "nm-rfkill.h"
+#include "nm-connection-provider.h"
 
 /* Properties */
 #define NM_DEVICE_UDI              "udi"
 #define NM_DEVICE_IFACE            "interface"
 #define NM_DEVICE_IP_IFACE         "ip-interface"
 #define NM_DEVICE_DRIVER           "driver"
+#define NM_DEVICE_DRIVER_VERSION   "driver-version"
+#define NM_DEVICE_FIRMWARE_VERSION "firmware-version"
 #define NM_DEVICE_CAPABILITIES     "capabilities"
 #define NM_DEVICE_IP4_ADDRESS      "ip4-address"
 #define NM_DEVICE_IP4_CONFIG       "ip4-config"
@@ -51,13 +54,16 @@
 #define NM_DEVICE_ACTIVE_CONNECTION "active-connection"
 #define NM_DEVICE_DEVICE_TYPE      "device-type" /* ugh */
 #define NM_DEVICE_MANAGED          "managed"
+#define NM_DEVICE_AUTOCONNECT      "autoconnect"
 #define NM_DEVICE_FIRMWARE_MISSING "firmware-missing"
 #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 */
 
-/* Internal signal */
-#define NM_DEVICE_DISCONNECT_REQUEST "disconnect-request"
+/* Internal signals */
+#define NM_DEVICE_AUTH_REQUEST "auth-request"
+#define NM_DEVICE_IP4_CONFIG_CHANGED "ip4-config-changed"
+#define NM_DEVICE_IP6_CONFIG_CHANGED "ip6-config-changed"
 
 
 G_BEGIN_DECLS
@@ -169,6 +175,11 @@ typedef struct {
 } NMDeviceClass;
 
 
+typedef void (*NMDeviceAuthRequestFunc) (NMDevice *device,
+                                         DBusGMethodInvocation *context,
+                                         GError *error,
+                                         gpointer user_data);
+
 GType nm_device_get_type (void);
 
 const char *    nm_device_get_path (NMDevice *dev);
@@ -180,6 +191,8 @@ int             nm_device_get_ifindex	(NMDevice *dev);
 const char *	nm_device_get_ip_iface	(NMDevice *dev);
 int             nm_device_get_ip_ifindex(NMDevice *dev);
 const char *	nm_device_get_driver	(NMDevice *dev);
+const char *	nm_device_get_driver_version	(NMDevice *dev);
+const char *	nm_device_get_firmware_version	(NMDevice *dev);
 const char *	nm_device_get_type_desc (NMDevice *dev);
 NMDeviceType	nm_device_get_device_type	(NMDevice *dev);
 
@@ -243,7 +256,7 @@ void nm_device_set_managed (NMDevice *device,
                             gboolean managed,
                             NMDeviceStateReason reason);
 
-void nm_device_clear_autoconnect_inhibit (NMDevice *device);
+gboolean nm_device_get_autoconnect (NMDevice *device);
 
 void nm_device_handle_autoip4_event (NMDevice *self,
                                      const char *event,
@@ -261,7 +274,7 @@ gboolean nm_device_get_firmware_missing (NMDevice *self);
 
 gboolean nm_device_activate (NMDevice *device, NMActRequest *req, GError **error);
 
-gboolean nm_device_disconnect (NMDevice *device, GError **error);
+void nm_device_set_connection_provider (NMDevice *device, NMConnectionProvider *provider);
 
 G_END_DECLS
 
diff --git a/src/nm-ip4-config.c b/src/nm-ip4-config.c
index ef284d80..0722981e 100644
--- a/src/nm-ip4-config.c
+++ b/src/nm-ip4-config.c
@@ -143,11 +143,17 @@ nm_ip4_config_add_address (NMIP4Config *config,
                            NMIP4Address *address)
 {
 	NMIP4ConfigPrivate *priv;
+	GSList *iter;
 
 	g_return_if_fail (NM_IS_IP4_CONFIG (config));
 	g_return_if_fail (address != NULL);
 
 	priv = NM_IP4_CONFIG_GET_PRIVATE (config);
+	for (iter = priv->addresses; iter; iter = g_slist_next (iter)) {
+		if (nm_ip4_address_compare ((NMIP4Address *) iter->data, address))
+			return;
+	}
+
 	priv->addresses = g_slist_append (priv->addresses, nm_ip4_address_dup (address));
 }
 
@@ -210,7 +216,8 @@ void nm_ip4_config_add_nameserver (NMIP4Config *config, guint32 nameserver)
 		guint32 s = g_array_index (priv->nameservers, guint32, i);
 
 		/* No dupes */
-		g_return_if_fail (nameserver != s);
+		if (nameserver == s)
+			return;
 	}
 
 	g_array_append_val (priv->nameservers, nameserver);
@@ -254,7 +261,8 @@ void nm_ip4_config_add_wins (NMIP4Config *config, guint32 wins)
 		guint32 s = g_array_index (priv->wins, guint32, i);
 
 		/* No dupes */
-		g_return_if_fail (wins != s);
+		if (wins == s)
+			return;
 	}
 
 	g_array_append_val (priv->wins, wins);
@@ -301,11 +309,17 @@ void
 nm_ip4_config_add_route (NMIP4Config *config, NMIP4Route *route)
 {
 	NMIP4ConfigPrivate *priv;
+	GSList *iter;
 
 	g_return_if_fail (NM_IS_IP4_CONFIG (config));
 	g_return_if_fail (route != NULL);
 
 	priv = NM_IP4_CONFIG_GET_PRIVATE (config);
+	for (iter = priv->routes; iter; iter = g_slist_next (iter)) {
+		if (nm_ip4_route_compare ((NMIP4Route *) iter->data, route))
+			return;
+	}
+
 	priv->routes = g_slist_append (priv->routes, nm_ip4_route_dup (route));
 }
 
@@ -743,7 +757,7 @@ nm_ip4_config_diff (NMIP4Config *a, NMIP4Config *b)
 	NMIP4ConfigCompareFlags flags = NM_IP4_COMPARE_FLAG_NONE;
 
 	if ((a && !b) || (b && !a))
-		return 0xFFFFFFFF;
+		return NM_IP4_COMPARE_FLAG_ALL;
 	if (!a && !b)
 		return NM_IP4_COMPARE_FLAG_NONE;
 
@@ -799,6 +813,68 @@ nm_ip4_config_diff (NMIP4Config *a, NMIP4Config *b)
 	return flags;
 }
 
+static inline void
+hash_u32 (GChecksum *sum, guint32 n)
+{
+	g_checksum_update (sum, (const guint8 *) &n, sizeof (n));
+}
+
+void
+nm_ip4_config_hash (NMIP4Config *config, GChecksum *sum, gboolean dns_only)
+{
+	guint32 i, n;
+	const char *s;
+
+	g_return_if_fail (config != NULL);
+	g_return_if_fail (sum != NULL);
+
+	if (dns_only == FALSE) {
+		for (i = 0; i < nm_ip4_config_get_num_addresses (config); i++) {
+			NMIP4Address *a = nm_ip4_config_get_address (config, i);
+
+			hash_u32 (sum, nm_ip4_address_get_address (a));
+			hash_u32 (sum, nm_ip4_address_get_prefix (a));
+			hash_u32 (sum, nm_ip4_address_get_gateway (a));
+		}
+
+		for (i = 0; i < nm_ip4_config_get_num_routes (config); i++) {
+			NMIP4Route *r = nm_ip4_config_get_route (config, i);
+
+			hash_u32 (sum, nm_ip4_route_get_dest (r));
+			hash_u32 (sum, nm_ip4_route_get_prefix (r));
+			hash_u32 (sum, nm_ip4_route_get_next_hop (r));
+			hash_u32 (sum, nm_ip4_route_get_metric (r));
+		}
+
+		n = nm_ip4_config_get_ptp_address (config);
+		if (n)
+			hash_u32 (sum, n);
+
+		for (i = 0; i < nm_ip4_config_get_num_nis_servers (config); i++)
+			hash_u32 (sum, nm_ip4_config_get_nis_server (config, i));
+
+		s = nm_ip4_config_get_nis_domain (config);
+		if (s)
+			g_checksum_update (sum, (const guint8 *) s, strlen (s));
+	}
+
+	for (i = 0; i < nm_ip4_config_get_num_nameservers (config); i++)
+		hash_u32 (sum, nm_ip4_config_get_nameserver (config, i));
+
+	for (i = 0; i < nm_ip4_config_get_num_wins (config); i++)
+		hash_u32 (sum, nm_ip4_config_get_wins (config, i));
+
+	for (i = 0; i < nm_ip4_config_get_num_domains (config); i++) {
+		s = nm_ip4_config_get_domain (config, i);
+		g_checksum_update (sum, (const guint8 *) s, strlen (s));
+	}
+
+	for (i = 0; i < nm_ip4_config_get_num_searches (config); i++) {
+		s = nm_ip4_config_get_search (config, i);
+		g_checksum_update (sum, (const guint8 *) s, strlen (s));
+	}
+}
+
 static void
 nm_ip4_config_init (NMIP4Config *config)
 {
diff --git a/src/nm-ip4-config.h b/src/nm-ip4-config.h
index 2d27acff..6b86bc47 100644
--- a/src/nm-ip4-config.h
+++ b/src/nm-ip4-config.h
@@ -139,4 +139,6 @@ typedef enum {
 /* Returns a bitfield representing how the two IP4 configs differ */
 NMIP4ConfigCompareFlags nm_ip4_config_diff (NMIP4Config *a, NMIP4Config *b);
 
+void nm_ip4_config_hash (NMIP4Config *config, GChecksum *sum, gboolean dns_only);
+
 #endif /* NM_IP4_CONFIG_H */
diff --git a/src/nm-ip6-config.c b/src/nm-ip6-config.c
index f06e4069..511cbf46 100644
--- a/src/nm-ip6-config.c
+++ b/src/nm-ip6-config.c
@@ -53,6 +53,8 @@ typedef struct {
 	GPtrArray *domains;
 	GPtrArray *searches;
 
+	gboolean gateway_set;
+	struct in6_addr gateway;
 	GSList *routes;
 
 	gboolean never_default;
@@ -138,11 +140,17 @@ nm_ip6_config_add_address (NMIP6Config *config,
                            NMIP6Address *address)
 {
 	NMIP6ConfigPrivate *priv;
+	GSList *iter;
 
 	g_return_if_fail (NM_IS_IP6_CONFIG (config));
 	g_return_if_fail (address != NULL);
 
 	priv = NM_IP6_CONFIG_GET_PRIVATE (config);
+	for (iter = priv->addresses; iter; iter = g_slist_next (iter)) {
+		if (nm_ip6_address_compare ((NMIP6Address *) iter->data, address))
+			return;
+	}
+
 	priv->addresses = g_slist_append (priv->addresses, nm_ip6_address_dup (address));
 }
 
@@ -205,8 +213,10 @@ void nm_ip6_config_add_nameserver (NMIP6Config *config, const struct in6_addr *n
 
 	/* No dupes */
 	nameservers = (struct in6_addr *)priv->nameservers->data;
-	for (i = 0; i < priv->nameservers->len; i++)
-		g_return_if_fail (IN6_ARE_ADDR_EQUAL (nameserver, &nameservers[i]) == FALSE);
+	for (i = 0; i < priv->nameservers->len; i++) {
+		if (IN6_ARE_ADDR_EQUAL (nameserver, &nameservers[i]))
+			return;
+	}
 
 	g_array_append_val (priv->nameservers, *nameserver);
 }
@@ -237,6 +247,30 @@ void nm_ip6_config_reset_nameservers (NMIP6Config *config)
 }
 
 void
+nm_ip6_config_set_gateway (NMIP6Config *config, const struct in6_addr *gateway)
+{
+	NMIP6ConfigPrivate *priv;
+
+	g_return_if_fail (NM_IS_IP6_CONFIG (config));
+
+	priv = NM_IP6_CONFIG_GET_PRIVATE (config);
+	if (gateway)
+		memcpy (&priv->gateway, gateway, sizeof (priv->gateway));
+	priv->gateway_set = !!gateway;
+}
+
+const struct in6_addr *
+nm_ip6_config_get_gateway (NMIP6Config *config)
+{
+	NMIP6ConfigPrivate *priv;
+
+	g_return_val_if_fail (NM_IS_IP6_CONFIG (config), NULL);
+
+	priv = NM_IP6_CONFIG_GET_PRIVATE (config);
+	return priv->gateway_set ? &priv->gateway : NULL;
+}
+
+void
 nm_ip6_config_take_route (NMIP6Config *config, NMIP6Route *route)
 {
 	NMIP6ConfigPrivate *priv;
@@ -252,11 +286,17 @@ void
 nm_ip6_config_add_route (NMIP6Config *config, NMIP6Route *route)
 {
 	NMIP6ConfigPrivate *priv;
+	GSList *iter;
 
 	g_return_if_fail (NM_IS_IP6_CONFIG (config));
 	g_return_if_fail (route != NULL);
 
 	priv = NM_IP6_CONFIG_GET_PRIVATE (config);
+	for (iter = priv->routes; iter; iter = g_slist_next (iter)) {
+		if (nm_ip6_route_compare ((NMIP6Route *) iter->data, route))
+			return;
+	}
+
 	priv->routes = g_slist_append (priv->routes, nm_ip6_route_dup (route));
 }
 
@@ -598,7 +638,7 @@ nm_ip6_config_diff (NMIP6Config *a, NMIP6Config *b)
 	NMIP6ConfigCompareFlags flags = NM_IP6_COMPARE_FLAG_NONE;
 
 	if ((a && !b) || (b && !a))
-		return 0xFFFFFFFF;
+		return NM_IP6_COMPARE_FLAG_ALL;
 	if (!a && !b)
 		return NM_IP6_COMPARE_FLAG_NONE;
 
@@ -637,6 +677,65 @@ nm_ip6_config_diff (NMIP6Config *a, NMIP6Config *b)
 	return flags;
 }
 
+static inline void
+hash_u32 (GChecksum *sum, guint32 n)
+{
+	g_checksum_update (sum, (const guint8 *) &n, sizeof (n));
+}
+
+static inline void
+hash_in6addr (GChecksum *sum, const struct in6_addr *a)
+{
+	g_checksum_update (sum, (const guint8 *) a, sizeof (*a));
+}
+
+void
+nm_ip6_config_hash (NMIP6Config *config, GChecksum *sum, gboolean dns_only)
+{
+	guint32 i;
+	const struct in6_addr *in6a;
+	const char *s;
+
+	g_return_if_fail (config != NULL);
+	g_return_if_fail (sum != NULL);
+
+	if (dns_only == FALSE) {
+		for (i = 0; i < nm_ip6_config_get_num_addresses (config); i++) {
+			NMIP6Address *a = nm_ip6_config_get_address (config, i);
+
+			hash_in6addr (sum, nm_ip6_address_get_address (a));
+			hash_u32 (sum, nm_ip6_address_get_prefix (a));
+			hash_in6addr (sum, nm_ip6_address_get_gateway (a));
+		}
+
+		for (i = 0; i < nm_ip6_config_get_num_routes (config); i++) {
+			NMIP6Route *r = nm_ip6_config_get_route (config, i);
+
+			hash_in6addr (sum, nm_ip6_route_get_dest (r));
+			hash_u32 (sum, nm_ip6_route_get_prefix (r));
+			hash_in6addr (sum, nm_ip6_route_get_next_hop (r));
+			hash_u32 (sum, nm_ip6_route_get_metric (r));
+		}
+
+		in6a = nm_ip6_config_get_ptp_address (config);
+		if (in6a)
+			hash_in6addr (sum, in6a);
+	}
+
+	for (i = 0; i < nm_ip6_config_get_num_nameservers (config); i++)
+		hash_in6addr (sum, nm_ip6_config_get_nameserver (config, i));
+
+	for (i = 0; i < nm_ip6_config_get_num_domains (config); i++) {
+		s = nm_ip6_config_get_domain (config, i);
+		g_checksum_update (sum, (const guint8 *) s, strlen (s));
+	}
+
+	for (i = 0; i < nm_ip6_config_get_num_searches (config); i++) {
+		s = nm_ip6_config_get_search (config, i);
+		g_checksum_update (sum, (const guint8 *) s, strlen (s));
+	}
+}
+
 static void
 nm_ip6_config_init (NMIP6Config *config)
 {
@@ -645,6 +744,7 @@ nm_ip6_config_init (NMIP6Config *config)
 	priv->nameservers = g_array_new (FALSE, TRUE, sizeof (struct in6_addr));
 	priv->domains = g_ptr_array_sized_new (3);
 	priv->searches = g_ptr_array_sized_new (3);
+	priv->gateway_set = FALSE;
 }
 
 static void
diff --git a/src/nm-ip6-config.h b/src/nm-ip6-config.h
index 1e75a121..2e8ae18f 100644
--- a/src/nm-ip6-config.h
+++ b/src/nm-ip6-config.h
@@ -67,6 +67,9 @@ const struct in6_addr *nm_ip6_config_get_nameserver      (NMIP6Config *config, g
 guint32       nm_ip6_config_get_num_nameservers (NMIP6Config *config);
 void          nm_ip6_config_reset_nameservers   (NMIP6Config *config);
 
+void                   nm_ip6_config_set_gateway  (NMIP6Config *config, const struct in6_addr *gateway);
+const struct in6_addr *nm_ip6_config_get_gateway  (NMIP6Config *config);
+
 void          nm_ip6_config_take_route          (NMIP6Config *config, NMIP6Route *route);
 void          nm_ip6_config_add_route           (NMIP6Config *config, NMIP6Route *route);
 void          nm_ip6_config_replace_route       (NMIP6Config *config, guint32 i, NMIP6Route *new_route);
@@ -117,4 +120,6 @@ typedef enum {
 /* Returns a bitfield representing how the two IP6 configs differ */
 NMIP6ConfigCompareFlags nm_ip6_config_diff (NMIP6Config *a, NMIP6Config *b);
 
+void nm_ip6_config_hash (NMIP6Config *config, GChecksum *sum, gboolean dns_only);
+
 #endif /* NM_IP6_CONFIG_H */
diff --git a/src/nm-manager.c b/src/nm-manager.c
index 7c812bdc..f2816cd7 100644
--- a/src/nm-manager.c
+++ b/src/nm-manager.c
@@ -48,6 +48,7 @@
 #include "nm-device-infiniband.h"
 #include "nm-device-bond.h"
 #include "nm-device-vlan.h"
+#include "nm-device-adsl.h"
 #include "nm-system.h"
 #include "nm-properties-changed-signal.h"
 #include "nm-setting-bluetooth.h"
@@ -127,18 +128,16 @@ static gboolean impl_manager_set_logging (NMManager *manager,
 #include "nm-manager-glue.h"
 
 static void bluez_manager_bdaddr_added_cb (NMBluezManager *bluez_mgr,
-					   const char *bdaddr,
-					   const char *name,
-					   const char *object_path,
-					   guint32 uuids,
-					   NMManager *manager);
+                                           const char *bdaddr,
+                                           const char *name,
+                                           const char *object_path,
+                                           guint32 uuids,
+                                           NMManager *manager);
 
 static void bluez_manager_bdaddr_removed_cb (NMBluezManager *bluez_mgr,
-					     const char *bdaddr,
-					     const char *object_path,
-					     gpointer user_data);
-
-static void bluez_manager_resync_devices (NMManager *self);
+                                             const char *bdaddr,
+                                             const char *object_path,
+                                             gpointer user_data);
 
 static void add_device (NMManager *self, NMDevice *device);
 
@@ -356,19 +355,20 @@ manager_sleeping (NMManager *self)
 static void
 vpn_manager_connection_activated_cb (NMVPNManager *manager,
                                      NMVPNConnection *vpn,
-                                     NMVPNConnectionState state,
-                                     NMVPNConnectionStateReason reason,
                                      gpointer user_data)
 {
+	NMConnection *connection = nm_vpn_connection_get_connection (vpn);
+
 	/* Update timestamp for the VPN connection */
-	nm_settings_connection_update_timestamp (NM_SETTINGS_CONNECTION (nm_vpn_connection_get_connection (vpn)),
+	nm_settings_connection_update_timestamp (NM_SETTINGS_CONNECTION (connection),
 	                                         (guint64) time (NULL), TRUE);
 }
 
 static void
 vpn_manager_connection_deactivated_cb (NMVPNManager *manager,
                                        NMVPNConnection *vpn,
-                                       NMVPNConnectionState state,
+                                       NMVPNConnectionState new_state,
+                                       NMVPNConnectionState old_state,
                                        NMVPNConnectionStateReason reason,
                                        gpointer user_data)
 {
@@ -1160,8 +1160,6 @@ connection_added (NMSettings *settings,
                   NMSettingsConnection *connection,
                   NMManager *manager)
 {
-	bluez_manager_resync_devices (manager);
-
 	if (connection_needs_virtual_device (NM_CONNECTION (connection)))
 		system_create_virtual_device (manager, NM_CONNECTION (connection));
 }
@@ -1171,8 +1169,6 @@ connection_changed (NMSettings *settings,
                      NMSettingsConnection *connection,
                      NMManager *manager)
 {
-	bluez_manager_resync_devices (manager);
-
 	/* FIXME: Some virtual devices may need to be updated in the future. */
 }
 
@@ -1181,8 +1177,6 @@ connection_removed (NMSettings *settings,
                     NMSettingsConnection *connection,
                     NMManager *manager)
 {
-	bluez_manager_resync_devices (manager);
-
 	/*
 	 * Do not delete existing virtual devices to keep connectivity up.
 	 * Virtual devices are reused when NetworkManager is restarted.
@@ -1539,111 +1533,96 @@ manager_modem_enabled_changed (NMModem *device, gpointer user_data)
 	nm_manager_rfkill_update (NM_MANAGER (user_data), RFKILL_TYPE_WWAN);
 }
 
-static GError *
-deactivate_disconnect_check_error (GError *auth_error,
-                                   NMAuthCallResult result,
-                                   const char *detail)
-{
-	if (auth_error) {
-		nm_log_dbg (LOGD_CORE, "%s request failed: %s", detail, auth_error->message);
-		return g_error_new (NM_MANAGER_ERROR,
-		                    NM_MANAGER_ERROR_PERMISSION_DENIED,
-		                    "%s request failed: %s",
-		                    detail, auth_error->message);
-	} else if (result != NM_AUTH_CALL_RESULT_YES) {
-		return g_error_new (NM_MANAGER_ERROR,
-		                    NM_MANAGER_ERROR_PERMISSION_DENIED,
-		                    "Not authorized to %s connections",
-		                    detail);
-	}
-	return NULL;
-}
-
 static void
-disconnect_net_auth_done_cb (NMAuthChain *chain,
-                             GError *auth_error,
-                             DBusGMethodInvocation *context,
-                             gpointer user_data)
+device_auth_done_cb (NMAuthChain *chain,
+                     GError *auth_error,
+                     DBusGMethodInvocation *context,
+                     gpointer user_data)
 {
 	NMManager *self = NM_MANAGER (user_data);
 	NMManagerPrivate *priv = NM_MANAGER_GET_PRIVATE (self);
 	GError *error = NULL;
 	NMAuthCallResult result;
 	NMDevice *device;
+	const char *permission;
+	NMDeviceAuthRequestFunc callback;
 
 	priv->auth_chains = g_slist_remove (priv->auth_chains, chain);
 
-	result = GPOINTER_TO_UINT (nm_auth_chain_get_data (chain, NM_AUTH_PERMISSION_NETWORK_CONTROL));
-	error = deactivate_disconnect_check_error (auth_error, result, "Disconnect");
-	if (!error) {
-		device = nm_auth_chain_get_data (chain, "device");
-		if (!nm_device_disconnect (device, &error))
-			g_assert (error);
+	permission = nm_auth_chain_get_data (chain, "requested-permission");
+	g_assert (permission);
+	callback = nm_auth_chain_get_data (chain, "callback");
+	g_assert (callback);
+	device = nm_auth_chain_get_data (chain, "device");
+	g_assert (device);
+
+	result = GPOINTER_TO_UINT (nm_auth_chain_get_data (chain, permission));
+	if (auth_error) {
+		/* translate the auth error into a manager permission denied error */
+		nm_log_dbg (LOGD_CORE, "%s request failed: %s", permission, auth_error->message);
+		error = g_error_new (NM_MANAGER_ERROR,
+		                     NM_MANAGER_ERROR_PERMISSION_DENIED,
+		                     "%s request failed: %s",
+		                     permission, auth_error->message);
+	} else if (result != NM_AUTH_CALL_RESULT_YES) {
+		nm_log_dbg (LOGD_CORE, "%s request failed: not authorized", permission);
+		error = g_error_new (NM_MANAGER_ERROR,
+		                     NM_MANAGER_ERROR_PERMISSION_DENIED,
+		                     "%s request failed: not authorized",
+		                     permission);
 	}
 
-	if (error)
-		dbus_g_method_return_error (context, error);
-	else
-		dbus_g_method_return (context);
+	g_assert (error || (result == NM_AUTH_CALL_RESULT_YES));
+
+	callback (device,
+	          context,
+	          error,
+	          nm_auth_chain_get_data (chain, "user-data"));
 
 	g_clear_error (&error);
 	nm_auth_chain_unref (chain);
 }
 
 static void
-manager_device_disconnect_request (NMDevice *device,
-                                   DBusGMethodInvocation *context,
-                                   NMManager *self)
+device_auth_request_cb (NMDevice *device,
+                        DBusGMethodInvocation *context,
+                        const char *permission,
+                        gboolean allow_interaction,
+                        NMDeviceAuthRequestFunc callback,
+                        gpointer user_data,
+                        NMManager *self)
 {
 	NMManagerPrivate *priv = NM_MANAGER_GET_PRIVATE (self);
-	NMActRequest *req;
 	GError *error = NULL;
 	gulong sender_uid = G_MAXULONG;
 	char *error_desc = NULL;
+	NMAuthChain *chain;
 
-	req = nm_device_get_act_request (device);
-	if (!req) {
-		error = g_error_new_literal (NM_MANAGER_ERROR,
-		                             NM_MANAGER_ERROR_UNKNOWN_CONNECTION,
-		                             "This device is not active");
-		dbus_g_method_return_error (context, error);
-		g_error_free (error);
-		return;
-	}
-
-	/* Need to check the caller's permissions and stuff before we can
-	 * deactivate the connection.
-	 */
-	if (!nm_auth_get_caller_uid (context,
-		                         priv->dbus_mgr,
-	                             &sender_uid,
-	                             &error_desc)) {
+	/* Get the caller's UID for the root check */
+	if (!nm_auth_get_caller_uid (context, priv->dbus_mgr, &sender_uid, &error_desc)) {
 		error = g_error_new_literal (NM_MANAGER_ERROR,
 		                             NM_MANAGER_ERROR_PERMISSION_DENIED,
 		                             error_desc);
-		dbus_g_method_return_error (context, error);
+		callback (device, context, error, user_data);
 		g_error_free (error);
 		g_free (error_desc);
 		return;
 	}
 
 	/* Yay for root */
-	if (0 == sender_uid) {
-		if (!nm_device_disconnect (device, &error)) {
-			dbus_g_method_return_error (context, error);
-			g_clear_error (&error);
-		} else
-			dbus_g_method_return (context);
-	} else {
-		NMAuthChain *chain;
-
-		/* Otherwise validate the user request */
-		chain = nm_auth_chain_new (context, NULL, disconnect_net_auth_done_cb, self);
+	if (0 == sender_uid)
+		callback (device, context, NULL, user_data);
+	else {
+		/* Otherwise validate the non-root request */
+		chain = nm_auth_chain_new (context, NULL, device_auth_done_cb, self);
 		g_assert (chain);
 		priv->auth_chains = g_slist_append (priv->auth_chains, chain);
 
 		nm_auth_chain_set_data (chain, "device", g_object_ref (device), g_object_unref);
-		nm_auth_chain_add_call (chain, NM_AUTH_PERMISSION_NETWORK_CONTROL, TRUE);
+		nm_auth_chain_set_data (chain, "requested-permission", g_strdup (permission), g_free);
+		nm_auth_chain_set_data (chain, "callback", callback, NULL);
+		nm_auth_chain_set_data (chain, "user-data", user_data, NULL);
+		nm_auth_chain_add_call (chain, permission, allow_interaction);
 	}
 }
 
@@ -1678,15 +1657,17 @@ add_device (NMManager *self, NMDevice *device)
 		return;
 	}
 
+	nm_device_set_connection_provider (device, NM_CONNECTION_PROVIDER (priv->settings));
+
 	priv->devices = g_slist_append (priv->devices, device);
 
 	g_signal_connect (device, "state-changed",
 					  G_CALLBACK (manager_device_state_changed),
 					  self);
 
-	g_signal_connect (device, NM_DEVICE_DISCONNECT_REQUEST,
-					  G_CALLBACK (manager_device_disconnect_request),
-					  self);
+	g_signal_connect (device, NM_DEVICE_AUTH_REQUEST,
+	                  G_CALLBACK (device_auth_request_cb),
+	                  self);
 
 	if (devtype == NM_DEVICE_TYPE_WIFI) {
 		/* Attach to the access-point-added signal so that the manager can fill
@@ -1791,120 +1772,6 @@ add_device (NMManager *self, NMDevice *device)
 	}
 }
 
-static gboolean
-bdaddr_matches_connection (NMSettingBluetooth *s_bt, const char *bdaddr)
-{
-	const GByteArray *arr;
-	gboolean ret = FALSE;
-
-	arr = nm_setting_bluetooth_get_bdaddr (s_bt);
-
-	if (   arr != NULL 
-	       && arr->len == ETH_ALEN) {
-		char *str;
-
-		str = g_strdup_printf ("%02X:%02X:%02X:%02X:%02X:%02X",
-				       arr->data[0],
-				       arr->data[1],
-				       arr->data[2],
-				       arr->data[3],
-				       arr->data[4],
-				       arr->data[5]);
-		ret = g_str_equal (str, bdaddr);
-		g_free (str);
-	}
-
-	return ret;
-}
-
-static NMConnection *
-bluez_manager_find_connection (NMManager *manager,
-                               const char *bdaddr,
-                               guint32 capabilities)
-{
-	NMManagerPrivate *priv = NM_MANAGER_GET_PRIVATE (manager);
-	NMConnection *found = NULL;
-	GSList *connections, *l;
-
-	connections = nm_settings_get_connections (priv->settings);
-
-	for (l = connections; l != NULL; l = l->next) {
-		NMConnection *candidate = NM_CONNECTION (l->data);
-		NMSettingConnection *s_con;
-		NMSettingBluetooth *s_bt;
-		const char *con_type;
-		const char *bt_type;
-
-		s_con = nm_connection_get_setting_connection (candidate);
-		g_assert (s_con);
-		con_type = nm_setting_connection_get_connection_type (s_con);
-		g_assert (con_type);
-		if (!g_str_equal (con_type, NM_SETTING_BLUETOOTH_SETTING_NAME))
-			continue;
-
-		s_bt = nm_connection_get_setting_bluetooth (candidate);
-		if (!s_bt)
-			continue;
-
-		if (!bdaddr_matches_connection (s_bt, bdaddr))
-			continue;
-
-		bt_type = nm_setting_bluetooth_get_connection_type (s_bt);
-		if (   g_str_equal (bt_type, NM_SETTING_BLUETOOTH_TYPE_DUN)
-		    && !(capabilities & NM_BT_CAPABILITY_DUN))
-		    	continue;
-		if (   g_str_equal (bt_type, NM_SETTING_BLUETOOTH_TYPE_PANU)
-		    && !(capabilities & NM_BT_CAPABILITY_NAP))
-		    	continue;
-
-		found = candidate;
-		break;
-	}
-
-	g_slist_free (connections);
-	return found;
-}
-
-static void
-bluez_manager_resync_devices (NMManager *self)
-{
-	NMManagerPrivate *priv = NM_MANAGER_GET_PRIVATE (self);
-	GSList *iter, *gone = NULL, *keep = NULL;
-
-	/* Remove devices from the device list that don't have a corresponding connection */
-	for (iter = priv->devices; iter; iter = g_slist_next (iter)) {
-		NMDevice *candidate = NM_DEVICE (iter->data);
-		guint32 uuids;
-		const char *bdaddr;
-
-		if (nm_device_get_device_type (candidate) == NM_DEVICE_TYPE_BT) {
-			uuids = nm_device_bt_get_capabilities (NM_DEVICE_BT (candidate));
-			bdaddr = nm_device_bt_get_hw_address (NM_DEVICE_BT (candidate));
-
-			if (bluez_manager_find_connection (self, bdaddr, uuids))
-				keep = g_slist_prepend (keep, candidate);
-			else
-				gone = g_slist_prepend (gone, candidate);
-		} else
-			keep = g_slist_prepend (keep, candidate);
-	}
-
-	/* Only touch the device list if anything actually changed */
-	if (g_slist_length (gone)) {
-		g_slist_free (priv->devices);
-		priv->devices = keep;
-
-		while (g_slist_length (gone))
-			gone = remove_one_device (self, gone, NM_DEVICE (gone->data), FALSE);
-	} else {
-		g_slist_free (keep);
-		g_slist_free (gone);
-	}
-
-	/* Now look for devices without connections */
-	nm_bluez_manager_query_devices (priv->bluez_mgr);
-}
-
 static void
 bluez_manager_bdaddr_added_cb (NMBluezManager *bluez_mgr,
                                const char *bdaddr,
@@ -1926,12 +1793,6 @@ bluez_manager_bdaddr_added_cb (NMBluezManager *bluez_mgr,
 	if (nm_manager_get_device_by_udi (manager, object_path))
 		return;
 
-	if (has_dun == FALSE && has_nap == FALSE)
-		return;
-
-	if (!bluez_manager_find_connection (manager, bdaddr, capabilities))
-		return;
-
 	device = nm_device_bt_new (object_path, bdaddr, name, capabilities, FALSE);
 	if (device) {
 		nm_log_info (LOGD_HW, "BT device %s (%s) added (%s%s%s)",
@@ -1953,19 +1814,15 @@ bluez_manager_bdaddr_removed_cb (NMBluezManager *bluez_mgr,
 {
 	NMManager *self = NM_MANAGER (user_data);
 	NMManagerPrivate *priv = NM_MANAGER_GET_PRIVATE (self);
-	GSList *iter;
+	NMDevice *device;
 
 	g_return_if_fail (bdaddr != NULL);
 	g_return_if_fail (object_path != NULL);
 
-	for (iter = priv->devices; iter; iter = iter->next) {
-		NMDevice *device = NM_DEVICE (iter->data);
-
-		if (!strcmp (nm_device_get_udi (device), object_path)) {
-			nm_log_info (LOGD_HW, "BT device %s removed", bdaddr);
-			priv->devices = remove_one_device (self, priv->devices, device, FALSE);
-			break;
-		}
+	device = nm_manager_get_device_by_udi (self, object_path);
+	if (device) {
+		nm_log_info (LOGD_HW, "BT device %s removed", bdaddr);
+		priv->devices = remove_one_device (self, priv->devices, device, FALSE);
 	}
 }
 
@@ -2155,6 +2012,12 @@ is_vlan (int ifindex)
 	return (nm_system_get_iface_type (ifindex, NULL) == NM_IFACE_TYPE_VLAN);
 }
 
+static gboolean
+is_adsl (GUdevDevice *device)
+{
+	return (g_strcmp0 (g_udev_device_get_subsystem (device), "atm") == 0);
+}
+
 static void
 udev_device_added_cb (NMUdevManager *udev_mgr,
                       GUdevDevice *udev_device,
@@ -2174,14 +2037,22 @@ udev_device_added_cb (NMUdevManager *udev_mgr,
 	g_return_if_fail (iface != NULL);
 	g_return_if_fail (sysfs_path != NULL);
 	g_return_if_fail (driver != NULL);
-	g_return_if_fail (ifindex >= 0);
 
-	device = find_device_by_ifindex (self, ifindex);
-	if (device) {
-		/* If it's a virtual device we may need to update its UDI */
-		if (nm_system_get_iface_type (ifindex, iface) != NM_IFACE_TYPE_UNSPEC)
-			g_object_set (G_OBJECT (device), NM_DEVICE_UDI, sysfs_path, NULL);
-		return;
+	/* Most devices will have an ifindex here */
+	if (ifindex > 0) {
+		device = find_device_by_ifindex (self, ifindex);
+		if (device) {
+			/* If it's a virtual device we may need to update its UDI */
+			if (nm_system_get_iface_type (ifindex, iface) != NM_IFACE_TYPE_UNSPEC)
+				g_object_set (G_OBJECT (device), NM_DEVICE_UDI, sysfs_path, NULL);
+			return;
+		}
+	} else {
+		/* But ATM/ADSL devices don't */
+		g_return_if_fail (is_adsl (udev_device));
+		device = find_device_by_ip_iface (self, iface);
+		if (device)
+			return;
 	}
 
 	/* Try registered device factories */
@@ -2233,7 +2104,9 @@ udev_device_added_cb (NMUdevManager *udev_mgr,
 				}
 			} else
 				nm_log_err (LOGD_HW, "(%s): failed to get VLAN parent ifindex", iface);
-		} else
+		} else if (is_adsl (udev_device))
+			device = nm_device_adsl_new (sysfs_path, iface, driver);
+		else
 			device = nm_device_ethernet_new (sysfs_path, iface, driver);
 	}
 
@@ -3098,8 +2971,18 @@ deactivate_net_auth_done_cb (NMAuthChain *chain,
 	priv->auth_chains = g_slist_remove (priv->auth_chains, chain);
 
 	result = GPOINTER_TO_UINT (nm_auth_chain_get_data (chain, NM_AUTH_PERMISSION_NETWORK_CONTROL));
-	error = deactivate_disconnect_check_error (auth_error, result, "Deactivate");
-	if (!error) {
+	if (auth_error) {
+		nm_log_dbg (LOGD_CORE, "Disconnect request failed: %s", auth_error->message);
+		error = g_error_new (NM_MANAGER_ERROR,
+		                     NM_MANAGER_ERROR_PERMISSION_DENIED,
+		                     "Deactivate request failed: %s",
+		                     auth_error->message);
+	} else if (result != NM_AUTH_CALL_RESULT_YES) {
+		error = g_error_new_literal (NM_MANAGER_ERROR,
+		                             NM_MANAGER_ERROR_PERMISSION_DENIED,
+		                             "Not authorized to deactivate connections");
+	} else {
+		/* success; deactivation allowed */
 		active_path = nm_auth_chain_get_data (chain, "path");
 		if (!nm_manager_deactivate_connection (self,
 		                                       active_path,
@@ -3246,15 +3129,13 @@ do_sleep_wake (NMManager *self)
 					nm_device_set_enabled (device, enabled);
 			}
 
-			nm_device_clear_autoconnect_inhibit (device);
+			g_object_set (G_OBJECT (device), NM_DEVICE_AUTOCONNECT, TRUE, NULL);
+
 			if (nm_device_spec_match_list (device, unmanaged_specs))
 				nm_device_set_managed (device, FALSE, NM_DEVICE_STATE_REASON_NOW_UNMANAGED);
 			else
 				nm_device_set_managed (device, TRUE, NM_DEVICE_STATE_REASON_NOW_MANAGED);
 		}
-
-		/* Ask for new bluetooth devices */
-		bluez_manager_resync_devices (self);
 	}
 
 	nm_manager_update_state (self);
@@ -3671,7 +3552,7 @@ nm_manager_start (NMManager *self)
 	system_hostname_changed_cb (priv->settings, NULL, self);
 
 	nm_udev_manager_query_devices (priv->udev_mgr);
-	bluez_manager_resync_devices (self);
+	nm_bluez_manager_query_devices (priv->bluez_mgr);
 
 	/* Query devices again to ensure that we catch all virtual interfaces (like
 	 * VLANs) that require a parent.  If during the first pass the VLAN
@@ -3766,7 +3647,8 @@ firmware_dir_changed (GFileMonitor *monitor,
 	}
 }
 
-#define PERM_DENIED_ERROR "org.freedesktop.NetworkManager.PermissionDenied"
+#define NM_PERM_DENIED_ERROR "org.freedesktop.NetworkManager.PermissionDenied"
+#define DEV_PERM_DENIED_ERROR "org.freedesktop.NetworkManager.Device.PermissionDenied"
 
 static void
 prop_set_auth_done_cb (NMAuthChain *chain,
@@ -3779,9 +3661,13 @@ prop_set_auth_done_cb (NMAuthChain *chain,
 	DBusGConnection *bus;
 	DBusConnection *dbus_connection;
 	NMAuthCallResult result;
-	DBusMessage *reply, *request;
-	const char *permission, *prop;
+	DBusMessage *reply = NULL, *request;
+	GError *ret_error;
+	const char *permission, *prop, *objpath;
 	gboolean set_enabled = TRUE;
+	gboolean is_device = FALSE;
+	size_t objpath_len;
+	size_t devpath_len;
 
 	priv->auth_chains = g_slist_remove (priv->auth_chains, chain);
 
@@ -3789,9 +3675,16 @@ prop_set_auth_done_cb (NMAuthChain *chain,
 	permission = nm_auth_chain_get_data (chain, "permission");
 	prop = nm_auth_chain_get_data (chain, "prop");
 	set_enabled = GPOINTER_TO_UINT (nm_auth_chain_get_data (chain, "enabled"));
+	objpath = nm_auth_chain_get_data (chain, "objectpath");
+
+	objpath_len = strlen (objpath);
+	devpath_len = strlen (NM_DBUS_PATH "/Devices");
+	if (   strncmp (objpath, NM_DBUS_PATH "/Devices", devpath_len) == 0
+	    && objpath_len > devpath_len)
+		is_device = TRUE;
 
 	if (error) {
-		reply = dbus_message_new_error (request, PERM_DENIED_ERROR,
+		reply = dbus_message_new_error (request, is_device ? DEV_PERM_DENIED_ERROR : NM_PERM_DENIED_ERROR,
 		                                "Not authorized to perform this operation");
 	} else {
 		/* Caller has had a chance to obtain authorization, so we only need to
@@ -3799,11 +3692,27 @@ prop_set_auth_done_cb (NMAuthChain *chain,
 		 */
 		result = GPOINTER_TO_UINT (nm_auth_chain_get_data (chain, permission));
 		if (result != NM_AUTH_CALL_RESULT_YES) {
-			reply = dbus_message_new_error (request, PERM_DENIED_ERROR,
-				                            "Not authorized to perform this operation");
+			reply = dbus_message_new_error (request, is_device ? DEV_PERM_DENIED_ERROR : NM_PERM_DENIED_ERROR,
+			                                "Not authorized to perform this operation");
 		} else {
-			g_object_set (self, prop, set_enabled, NULL);
-			reply = dbus_message_new_method_return (request);
+			if (is_device) {
+				/* Find the device */
+				NMDevice *device = nm_manager_get_device_by_path (self, objpath);
+				if (device) {
+					g_object_set (device, prop, set_enabled, NULL);
+					reply = dbus_message_new_method_return (request);
+				}
+				else {
+					ret_error = g_error_new_literal (NM_MANAGER_ERROR,
+					                                 NM_MANAGER_ERROR_UNKNOWN_DEVICE,
+					                                 "Can't find device for this operation");
+					dbus_g_method_return_error (context, ret_error);
+					g_error_free (ret_error);
+				}
+			} else {
+				g_object_set (self, prop, set_enabled, NULL);
+				reply = dbus_message_new_method_return (request);
+			}
 		}
 	}
 
@@ -3831,6 +3740,7 @@ prop_filter (DBusConnection *connection,
 	const char *propiface = NULL;
 	const char *propname = NULL;
 	const char *sender = NULL;
+	const char *objpath = NULL;
 	const char *glib_propname = NULL, *permission = NULL;
 	DBusError dbus_error;
 	gulong uid = G_MAXULONG;
@@ -3852,7 +3762,7 @@ prop_filter (DBusConnection *connection,
 	if (dbus_message_iter_get_arg_type (&iter) != DBUS_TYPE_STRING)
 		return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
 	dbus_message_iter_get_basic (&iter, &propiface);
-	if (!propiface || strcmp (propiface, NM_DBUS_INTERFACE))
+	if (!propiface || (strcmp (propiface, NM_DBUS_INTERFACE) && strcmp (propiface, NM_DBUS_INTERFACE_DEVICE)))
 		return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
 	dbus_message_iter_next (&iter);
 
@@ -3871,6 +3781,9 @@ prop_filter (DBusConnection *connection,
 	} else if (!strcmp (propname, "WimaxEnabled")) {
 		glib_propname = NM_MANAGER_WIMAX_ENABLED;
 		permission = NM_AUTH_PERMISSION_ENABLE_DISABLE_WIMAX;
+	} else if (!strcmp (propname, "Autoconnect")) {
+		glib_propname = NM_DEVICE_AUTOCONNECT;
+		permission = NM_AUTH_PERMISSION_NETWORK_CONTROL;
 	} else
 		return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
 
@@ -3884,15 +3797,22 @@ prop_filter (DBusConnection *connection,
 
 	sender = dbus_message_get_sender (message);
 	if (!sender) {
-		reply = dbus_message_new_error (message, PERM_DENIED_ERROR,
+		reply = dbus_message_new_error (message, NM_PERM_DENIED_ERROR,
 		                                "Could not determine D-Bus requestor");
 		goto out;
 	}
 
+	objpath = dbus_message_get_path (message);
+	if (!objpath) {
+		reply = dbus_message_new_error (message, NM_PERM_DENIED_ERROR,
+		                                "Could not determine D-Bus object path");
+		goto out;
+	}
+
 	dbus_error_init (&dbus_error);
 	uid = dbus_bus_get_unix_user (connection, sender, &dbus_error);
 	if (dbus_error_is_set (&dbus_error)) {
-		reply = dbus_message_new_error (message, PERM_DENIED_ERROR,
+		reply = dbus_message_new_error (message, NM_PERM_DENIED_ERROR,
 		                                "Could not determine the user ID of the requestor");
 		dbus_error_free (&dbus_error);
 		goto out;
@@ -3907,6 +3827,7 @@ prop_filter (DBusConnection *connection,
 		nm_auth_chain_set_data (chain, "permission", g_strdup (permission), g_free);
 		nm_auth_chain_set_data (chain, "enabled", GUINT_TO_POINTER (set_enabled), NULL);
 		nm_auth_chain_set_data (chain, "message", dbus_message_ref (message), (GDestroyNotify) dbus_message_unref);
+		nm_auth_chain_set_data (chain, "objectpath", g_strdup (objpath), g_free);
 		nm_auth_chain_add_call (chain, permission, TRUE);
 	} else {
 		/* Yay for root */
@@ -4013,17 +3934,17 @@ nm_manager_new (NMSettings *settings,
 	                  G_CALLBACK (udev_manager_rfkill_changed_cb),
 	                  singleton);
 
-	priv->bluez_mgr = nm_bluez_manager_get ();
+	priv->bluez_mgr = nm_bluez_manager_get (NM_CONNECTION_PROVIDER (priv->settings));
 
 	g_signal_connect (priv->bluez_mgr,
-			  "bdaddr-added",
-			  G_CALLBACK (bluez_manager_bdaddr_added_cb),
-			  singleton);
+	                  NM_BLUEZ_MANAGER_BDADDR_ADDED,
+	                  G_CALLBACK (bluez_manager_bdaddr_added_cb),
+	                  singleton);
 
 	g_signal_connect (priv->bluez_mgr,
-			  "bdaddr-removed",
-			  G_CALLBACK (bluez_manager_bdaddr_removed_cb),
-			  singleton);
+	                  NM_BLUEZ_MANAGER_BDADDR_REMOVED,
+	                  G_CALLBACK (bluez_manager_bdaddr_removed_cb),
+	                  singleton);
 
 	return singleton;
 }
diff --git a/src/nm-netlink-compat.c b/src/nm-netlink-compat.c
index 974121ad..e30ec37a 100644
--- a/src/nm-netlink-compat.c
+++ b/src/nm-netlink-compat.c
@@ -121,7 +121,7 @@ rtnl_link_vlan_get_id (struct rtnl_link *l)
 	if ((if_name = rtnl_link_get_name (l)) == NULL)
 		return -1;
 
-	strcpy (if_request.device1, if_name);
+	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.");
@@ -158,7 +158,7 @@ rtnl_link_vlan_set_flags (struct rtnl_link *l, unsigned int flags)
 	}
 
 	memset (&if_request, 0, sizeof (struct vlan_ioctl_args));
-	strcpy (if_request.device1, if_name);
+	g_strlcpy (if_request.device1, if_name, sizeof (if_request.device1));
 	if_request.cmd = SET_VLAN_FLAG_CMD;
 	if_request.u.flag = flags;
 
@@ -190,7 +190,7 @@ rtnl_link_vlan_set_ingress_map (struct rtnl_link *l, int from, uint32_t to)
 	}
 
 	memset (&if_request, 0, sizeof (struct vlan_ioctl_args));
-	strcpy (if_request.device1, if_name);
+	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;
@@ -223,7 +223,7 @@ rtnl_link_vlan_set_egress_map (struct rtnl_link *l, int from, uint32_t to)
 	}
 
 	memset (&if_request, 0, sizeof (struct vlan_ioctl_args));
-	strcpy (if_request.device1, if_name);
+	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;
diff --git a/src/nm-netlink-utils.c b/src/nm-netlink-utils.c
index 99aebcb8..be8c17ed 100644
--- a/src/nm-netlink-utils.c
+++ b/src/nm-netlink-utils.c
@@ -136,7 +136,7 @@ nm_netlink_route_new (int ifindex,
 	route = rtnl_route_alloc ();
 	g_return_val_if_fail (route != NULL, NULL);
 
-	if (ifindex >= 0)
+	if (ifindex > 0)
 		rtnl_route_set_oif (route, ifindex);
 	if (family != AF_UNSPEC)
 		rtnl_route_set_family (route, family);
@@ -385,7 +385,7 @@ foreach_route_cb (struct nl_object *object, void *user_data)
 	if (nm_logging_level_enabled (LOGL_DEBUG))
 		dump_route (route);
 
-	if (   info->ifindex >= 0
+	if (   info->ifindex > 0
 	    && rtnl_route_get_oif (route) != info->ifindex)
 		return;
 
diff --git a/src/nm-policy.c b/src/nm-policy.c
index babf1649..57b1ee36 100644
--- a/src/nm-policy.c
+++ b/src/nm-policy.c
@@ -15,7 +15,7 @@
  * with this program; if not, write to the Free Software Foundation, Inc.,
  * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
  *
- * Copyright (C) 2004 - 2011 Red Hat, Inc.
+ * Copyright (C) 2004 - 2012 Red Hat, Inc.
  * Copyright (C) 2007 - 2008 Novell, Inc.
  */
 
@@ -81,7 +81,7 @@ static void schedule_activate_all (NMPolicy *policy);
 
 
 static NMDevice *
-get_best_ip4_device (NMManager *manager, NMActRequest **out_req)
+get_best_ip4_device (NMManager *manager)
 {
 	GSList *devices, *iter;
 	NMDevice *best = NULL;
@@ -89,8 +89,6 @@ get_best_ip4_device (NMManager *manager, NMActRequest **out_req)
 
 	g_return_val_if_fail (manager != NULL, NULL);
 	g_return_val_if_fail (NM_IS_MANAGER (manager), NULL);
-	g_return_val_if_fail (out_req != NULL, NULL);
-	g_return_val_if_fail (*out_req == NULL, NULL);
 
 	devices = nm_manager_get_devices (manager);
 	for (iter = devices; iter; iter = g_slist_next (iter)) {
@@ -148,7 +146,6 @@ get_best_ip4_device (NMManager *manager, NMActRequest **out_req)
 		if (prio > 0 && prio < best_prio) {
 			best = dev;
 			best_prio = prio;
-			*out_req = req;
 		}
 	}
 
@@ -156,7 +153,7 @@ get_best_ip4_device (NMManager *manager, NMActRequest **out_req)
 }
 
 static NMDevice *
-get_best_ip6_device (NMManager *manager, NMActRequest **out_req)
+get_best_ip6_device (NMManager *manager)
 {
 	GSList *devices, *iter;
 	NMDevice *best = NULL;
@@ -164,8 +161,6 @@ get_best_ip6_device (NMManager *manager, NMActRequest **out_req)
 
 	g_return_val_if_fail (manager != NULL, NULL);
 	g_return_val_if_fail (NM_IS_MANAGER (manager), NULL);
-	g_return_val_if_fail (out_req != NULL, NULL);
-	g_return_val_if_fail (*out_req == NULL, NULL);
 
 	devices = nm_manager_get_devices (manager);
 	for (iter = devices; iter; iter = g_slist_next (iter)) {
@@ -222,7 +217,6 @@ get_best_ip6_device (NMManager *manager, NMActRequest **out_req)
 		if (prio > 0 && prio < best_prio) {
 			best = dev;
 			best_prio = prio;
-			*out_req = req;
 		}
 	}
 
@@ -295,8 +289,6 @@ static void
 update_system_hostname (NMPolicy *policy, NMDevice *best4, NMDevice *best6)
 {
 	char *configured_hostname = NULL;
-	NMActRequest *best_req4 = NULL;
-	NMActRequest *best_req6 = NULL;
 	const char *dhcp_hostname, *p;
 
 	g_return_if_fail (policy != NULL);
@@ -325,9 +317,9 @@ update_system_hostname (NMPolicy *policy, NMDevice *best4, NMDevice *best6)
 
 	/* Try automatically determined hostname from the best device's IP config */
 	if (!best4)
-		best4 = get_best_ip4_device (policy->manager, &best_req4);
+		best4 = get_best_ip4_device (policy->manager);
 	if (!best6)
-		best6 = get_best_ip6_device (policy->manager, &best_req6);
+		best6 = get_best_ip6_device (policy->manager);
 
 	if (!best4 && !best6) {
 		/* No best device; fall back to original hostname or if there wasn't
@@ -433,270 +425,370 @@ update_system_hostname (NMPolicy *policy, NMDevice *best4, NMDevice *best6)
 }
 
 static void
-update_ip4_routing_and_dns (NMPolicy *policy, gboolean force_update)
+update_default_ac (NMPolicy *policy,
+                   NMActiveConnection *best,
+                   void (*set_active_func)(NMActiveConnection*, gboolean))
 {
-	NMDnsIPConfigType dns_type = NM_DNS_IP_CONFIG_TYPE_BEST_DEVICE;
-	NMDevice *best = NULL;
-	NMActRequest *best_req = NULL;
-	NMDnsManager *dns_mgr;
-	GSList *devices = NULL, *iter, *vpns;
-	NMIP4Config *ip4_config = NULL;
-	NMIP4Address *addr;
-	const char *ip_iface = NULL;
-	NMConnection *connection = NULL;
-	NMSettingConnection *s_con = NULL;
-	const char *connection_id;
-	int ip_ifindex = 0;
+	GSList *devices, *vpns, *iter;
+	NMActRequest *req;
 
-	best = get_best_ip4_device (policy->manager, &best_req);
-	if (!best)
-		goto out;
-	if (!force_update && (best == policy->default_device4))
-		goto out;
+	/* Clear the 'default[6]' flag on all active connections that aren't the new
+	 * default active connection.  We'll set the new default after; this ensures
+	 * we don't ever have two marked 'default[6]' simultaneously.
+	 */
+	devices = nm_manager_get_devices (policy->manager);
+	for (iter = devices; iter; iter = g_slist_next (iter)) {
+		req = nm_device_get_act_request (NM_DEVICE (iter->data));
+		if (req && (NM_ACTIVE_CONNECTION (req) != best))
+			set_active_func (NM_ACTIVE_CONNECTION (req), FALSE);
+	}
+
+	vpns = nm_vpn_manager_get_active_connections (policy->vpn_manager);
+	for (iter = vpns; iter; iter = g_slist_next (iter)) {
+		if (NM_ACTIVE_CONNECTION (iter->data) != best)
+			set_active_func (NM_ACTIVE_CONNECTION (iter->data), FALSE);
+	}
+	g_slist_free (vpns);
+
+	/* Mark new default active connection */
+	if (best)
+		set_active_func (best, TRUE);
+}
+
+static NMIP4Config *
+get_best_ip4_config (NMPolicy *policy,
+                     gboolean ignore_never_default,
+                     const char **out_ip_iface,
+                     int *out_ip_ifindex,
+                     NMActiveConnection **out_ac,
+                     NMDevice **out_device,
+                     NMVPNConnection **out_vpn)
+{
+	GSList *vpns, *iter;
+	NMDevice *device;
+	NMActRequest *req = NULL;
+	NMIP4Config *ip4_config = NULL;
 
 	/* If a VPN connection is active, it is preferred */
 	vpns = nm_vpn_manager_get_active_connections (policy->vpn_manager);
 	for (iter = vpns; iter; iter = g_slist_next (iter)) {
 		NMVPNConnection *candidate = NM_VPN_CONNECTION (iter->data);
-		NMConnection *vpn_connection;
+		NMIP4Config *vpn_ip4;
+		NMConnection *tmp;
 		NMSettingIP4Config *s_ip4;
-		gboolean can_default = TRUE;
 		NMVPNConnectionState vpn_state;
 
-		/* If it's marked 'never-default', don't make it default */
-		vpn_connection = nm_vpn_connection_get_connection (candidate);
-		g_assert (vpn_connection);
-
-		/* Check the active IP4 config from the VPN service daemon */
-		ip4_config = nm_vpn_connection_get_ip4_config (candidate);
-		if (ip4_config && nm_ip4_config_get_never_default (ip4_config))
-			can_default = FALSE;
-
-		/* Check the user's preference from the NMConnection */
-		s_ip4 = nm_connection_get_setting_ip4_config (vpn_connection);
-		if (s_ip4 && nm_setting_ip4_config_get_never_default (s_ip4))
-			can_default = FALSE;
+		tmp = nm_vpn_connection_get_connection (candidate);
+		g_assert (tmp);
 
 		vpn_state = nm_vpn_connection_get_vpn_state (candidate);
-		if (can_default && (vpn_state == NM_VPN_CONNECTION_STATE_ACTIVATED)) {
-			NMIP4Config *parent_ip4;
-			NMDevice *parent;
-
-			ip_iface = nm_vpn_connection_get_ip_iface (candidate);
-			ip_ifindex = nm_vpn_connection_get_ip_ifindex (candidate);
-			connection = nm_vpn_connection_get_connection (candidate);
-			addr = nm_ip4_config_get_address (ip4_config, 0);
+		if (vpn_state != NM_VPN_CONNECTION_STATE_ACTIVATED)
+			continue;
 
-			parent = nm_vpn_connection_get_parent_device (candidate);
-			parent_ip4 = nm_device_get_ip4_config (parent);
+		vpn_ip4 = nm_vpn_connection_get_ip4_config (candidate);
+		if (!vpn_ip4)
+			continue;
 
-			nm_system_replace_default_ip4_route_vpn (ip_ifindex,
-			                                         nm_ip4_address_get_gateway (addr),
-			                                         nm_vpn_connection_get_ip4_internal_gateway (candidate),
-			                                         nm_ip4_config_get_mss (ip4_config),
-			                                         nm_device_get_ip_ifindex (parent),
-			                                         nm_ip4_config_get_mss (parent_ip4));
+		if (ignore_never_default == FALSE) {
+			/* Check for a VPN-provided config never-default */
+			if (nm_ip4_config_get_never_default (vpn_ip4))
+				continue;
 
-			dns_type = NM_DNS_IP_CONFIG_TYPE_VPN;
+			/* Check the user's preference from the NMConnection */
+			s_ip4 = nm_connection_get_setting_ip4_config (tmp);
+			if (s_ip4 && nm_setting_ip4_config_get_never_default (s_ip4))
+				continue;
 		}
+
+		ip4_config = vpn_ip4;
+		if (out_vpn)
+			*out_vpn = candidate;
+		if (out_ac)
+			*out_ac = NM_ACTIVE_CONNECTION (candidate);
+		if (out_ip_iface)
+			*out_ip_iface = nm_vpn_connection_get_ip_iface (candidate);
+		if (out_ip_ifindex)
+			*out_ip_ifindex = nm_vpn_connection_get_ip_ifindex (candidate);
+		break;
 	}
 	g_slist_free (vpns);
 
-	/* The best device gets the default route if a VPN connection didn't */
-	if (!ip_iface || !ip4_config) {
-		connection = nm_act_request_get_connection (best_req);
-		ip_iface = nm_device_get_ip_iface (best);
-		ip_ifindex = nm_device_get_ip_ifindex (best);
-		ip4_config = nm_device_get_ip4_config (best);
-		g_assert (ip4_config);
-		addr = nm_ip4_config_get_address (ip4_config, 0);
-
-		nm_system_replace_default_ip4_route (ip_ifindex,
-		                                     nm_ip4_address_get_gateway (addr),
-		                                     nm_ip4_config_get_mss (ip4_config));
-		dns_type = NM_DNS_IP_CONFIG_TYPE_BEST_DEVICE;
+	/* If no VPN connections, we use the best device instead */
+	if (!ip4_config) {
+		device = get_best_ip4_device (policy->manager);
+		if (device) {
+			ip4_config = nm_device_get_ip4_config (device);
+			g_assert (ip4_config);
+			req = nm_device_get_act_request (device);
+			g_assert (req);
+
+			if (out_device)
+				*out_device = device;
+			if (out_ac)
+				*out_ac = NM_ACTIVE_CONNECTION (req);
+			if (out_ip_iface)
+				*out_ip_iface = nm_device_get_ip_iface (device);
+			if (out_ip_ifindex)
+				*out_ip_ifindex = nm_device_get_ip_ifindex (device);
+		}
 	}
 
-	if (!ip_iface || !ip4_config) {
-		nm_log_warn (LOGD_CORE, "couldn't determine IP interface (%p) or IPv4 config (%p)!",
-		             ip_iface, ip4_config);
-		goto out;
-	}
+	return ip4_config;
+}
 
-	/* Update the default active connection.  Only mark the new default
-	 * active connection after setting default = FALSE on all other connections
-	 * first.  The order is important, we don't want two connections marked
-	 * default at the same time ever.
-	 */
-	devices = nm_manager_get_devices (policy->manager);
-	for (iter = devices; iter; iter = g_slist_next (iter)) {
-		NMDevice *dev = NM_DEVICE (iter->data);
-		NMActRequest *req;
+static void
+update_ip4_dns (NMPolicy *policy, NMDnsManager *dns_mgr)
+{
+	NMIP4Config *ip4_config;
+	const char *ip_iface = NULL;
+	NMVPNConnection *vpn = NULL;
+	NMDnsIPConfigType dns_type = NM_DNS_IP_CONFIG_TYPE_BEST_DEVICE;
 
-		req = nm_device_get_act_request (dev);
-		if (req && (req != best_req))
-			nm_active_connection_set_default (NM_ACTIVE_CONNECTION (req), FALSE);
+	ip4_config = get_best_ip4_config (policy, TRUE, &ip_iface, NULL, NULL, NULL, &vpn);
+	if (ip4_config) {
+		if (vpn)
+			dns_type = NM_DNS_IP_CONFIG_TYPE_VPN;
+
+		/* Tell the DNS manager this config is preferred by re-adding it with
+		 * a different IP config type.
+		 */
+		nm_dns_manager_add_ip4_config (dns_mgr, ip_iface, ip4_config, dns_type);
 	}
+}
 
-	dns_mgr = nm_dns_manager_get (NULL);
-	nm_dns_manager_add_ip4_config (dns_mgr, ip_iface, ip4_config, dns_type);
-	g_object_unref (dns_mgr);
+static void
+update_ip4_routing (NMPolicy *policy, gboolean force_update)
+{
+	NMDevice *best = NULL, *parent;
+	NMConnection *connection = NULL;
+	NMVPNConnection *vpn = NULL;
+	NMActiveConnection *best_ac = NULL;
+	NMIP4Config *ip4_config = NULL, *parent_ip4;
+	NMIP4Address *addr;
+	const char *ip_iface = NULL;
+	int ip_ifindex = -1;
+	guint32 parent_mss;
 
-	/* Now set new default active connection _after_ updating DNS info, so that
-	 * if the connection is shared dnsmasq picks up the right stuff.
+	/* Note that we might have an IPv4 VPN tunneled over an IPv6-only device,
+	 * so we can get (vpn != NULL && best == NULL).
 	 */
-	if (best_req)
-		nm_active_connection_set_default (NM_ACTIVE_CONNECTION (best_req), TRUE);
+	ip4_config = get_best_ip4_config (policy, FALSE, &ip_iface, &ip_ifindex, &best_ac, &best, &vpn);
+	if (!ip4_config) {
+		policy->default_device4 = NULL;
+		return;
+	}
+	g_assert ((best || vpn) && best_ac);
 
-	if (connection)
-		s_con = nm_connection_get_setting_connection (connection);
+	if (!force_update && best && (best == policy->default_device4))
+		return;
 
-	connection_id = s_con ? nm_setting_connection_get_id (s_con) : NULL;
-	if (connection_id) {
-		nm_log_info (LOGD_CORE, "Policy set '%s' (%s) as default for IPv4 routing and DNS.", connection_id, ip_iface);
+	/* We set the default route to the gateway of the first IP address of the config */
+	addr = nm_ip4_config_get_address (ip4_config, 0);
+	g_assert (addr);
+
+	if (vpn) {
+		parent = nm_vpn_connection_get_parent_device (vpn);
+		parent_ip4 = nm_device_get_ip4_config (parent);
+		parent_mss = parent_ip4 ? nm_ip4_config_get_mss (parent_ip4) : 0;
+
+		nm_system_replace_default_ip4_route_vpn (ip_ifindex,
+		                                         nm_ip4_address_get_gateway (addr),
+		                                         nm_vpn_connection_get_ip4_internal_gateway (vpn),
+		                                         nm_ip4_config_get_mss (ip4_config),
+		                                         nm_device_get_ip_ifindex (parent),
+		                                         parent_mss);
 	} else {
-		nm_log_info (LOGD_CORE, "Policy set (%s) as default for IPv4 routing and DNS.", ip_iface);
+		nm_system_replace_default_ip4_route (ip_ifindex,
+		                                     nm_ip4_address_get_gateway (addr),
+		                                     nm_ip4_config_get_mss (ip4_config));
 	}
 
-out:
+	update_default_ac (policy, best_ac, nm_active_connection_set_default);
 	policy->default_device4 = best;
+
+	connection = nm_active_connection_get_connection (best_ac);
+	nm_log_info (LOGD_CORE, "Policy set '%s' (%s) as default for IPv4 routing and DNS.",
+	             nm_connection_get_id (connection), ip_iface);
 }
 
-static void
-update_ip6_routing_and_dns (NMPolicy *policy, gboolean force_update)
+static NMIP6Config *
+get_best_ip6_config (NMPolicy *policy,
+                     gboolean ignore_never_default,
+                     const char **out_ip_iface,
+                     int *out_ip_ifindex,
+                     NMActiveConnection **out_ac,
+                     NMDevice **out_device,
+                     NMVPNConnection **out_vpn)
 {
-	NMDnsIPConfigType dns_type = NM_DNS_IP_CONFIG_TYPE_BEST_DEVICE;
-	NMDevice *best = NULL;
-	NMActRequest *best_req = NULL;
-	NMDnsManager *dns_mgr;
-	GSList *devices = NULL, *iter;
-#if 0
-	GSList *vpns;
-#endif
+	GSList *vpns, *iter;
+	NMDevice *device;
+	NMActRequest *req = NULL;
 	NMIP6Config *ip6_config = NULL;
-	NMIP6Address *addr;
-	const char *ip_iface = NULL;
-	int ip_ifindex = -1;
-	NMConnection *connection = NULL;
-	NMSettingConnection *s_con = NULL;
-	const char *connection_id;
 
-	best = get_best_ip6_device (policy->manager, &best_req);
-	if (!best)
-		goto out;
-	if (!force_update && (best == policy->default_device6))
-		goto out;
-
-#if 0
 	/* If a VPN connection is active, it is preferred */
 	vpns = nm_vpn_manager_get_active_connections (policy->vpn_manager);
 	for (iter = vpns; iter; iter = g_slist_next (iter)) {
 		NMVPNConnection *candidate = NM_VPN_CONNECTION (iter->data);
-		NMConnection *vpn_connection;
+		NMIP6Config *vpn_ip6;
+		NMConnection *tmp;
 		NMSettingIP6Config *s_ip6;
-		gboolean can_default = TRUE;
 		NMVPNConnectionState vpn_state;
 
-		/* If it's marked 'never-default', don't make it default */
-		vpn_connection = nm_vpn_connection_get_connection (candidate);
-		g_assert (vpn_connection);
-		s_ip6 = nm_connection_get_setting_ip6_config (vpn_connection);
-		if (s_ip6 && nm_setting_ip6_config_get_never_default (s_ip6))
-			can_default = FALSE;
+		tmp = nm_vpn_connection_get_connection (candidate);
+		g_assert (tmp);
 
 		vpn_state = nm_vpn_connection_get_vpn_state (candidate);
-		if (can_default && (vpn_state == NM_VPN_CONNECTION_STATE_ACTIVATED)) {
-			NMIP6Config *parent_ip6;
-			NMDevice *parent;
-
-			ip_iface = nm_vpn_connection_get_ip_iface (candidate);
-			connection = nm_vpn_connection_get_connection (candidate);
-			ip6_config = nm_vpn_connection_get_ip6_config (candidate);
-			addr = nm_ip6_config_get_address (ip6_config, 0);
+		if (vpn_state != NM_VPN_CONNECTION_STATE_ACTIVATED)
+			continue;
 
-			parent = nm_vpn_connection_get_parent_device (candidate);
-			parent_ip6 = nm_device_get_ip6_config (parent);
+		vpn_ip6 = nm_vpn_connection_get_ip6_config (candidate);
+		if (!vpn_ip6)
+			continue;
 
-			nm_system_replace_default_ip6_route_vpn (ip_iface,
-			                                         nm_ip6_address_get_gateway (addr),
-			                                         nm_vpn_connection_get_ip4_internal_gateway (candidate),
-			                                         nm_ip6_config_get_mss (ip4_config),
-			                                         nm_device_get_ip_iface (parent),
-			                                         nm_ip6_config_get_mss (parent_ip4));
+		if (ignore_never_default == FALSE) {
+			/* Check for a VPN-provided config never-default */
+			if (nm_ip6_config_get_never_default (vpn_ip6))
+				continue;
 
-			dns_type = NM_DNS_IP_CONFIG_TYPE_VPN;
+			/* Check the user's preference from the NMConnection */
+			s_ip6 = nm_connection_get_setting_ip6_config (tmp);
+			if (s_ip6 && nm_setting_ip6_config_get_never_default (s_ip6))
+				continue;
 		}
+
+		ip6_config = vpn_ip6;
+		if (out_vpn)
+			*out_vpn = candidate;
+		if (out_ac)
+			*out_ac = NM_ACTIVE_CONNECTION (candidate);
+		if (out_ip_iface)
+			*out_ip_iface = nm_vpn_connection_get_ip_iface (candidate);
+		if (out_ip_ifindex)
+			*out_ip_ifindex = nm_vpn_connection_get_ip_ifindex (candidate);
+		break;
 	}
 	g_slist_free (vpns);
-#endif
 
-	/* The best device gets the default route if a VPN connection didn't */
-	if (!ip_iface || !ip6_config) {
-		connection = nm_act_request_get_connection (best_req);
-		ip_iface = nm_device_get_ip_iface (best);
-		ip_ifindex = nm_device_get_ip_ifindex (best);
-		ip6_config = nm_device_get_ip6_config (best);
-		g_assert (ip6_config);
-		addr = nm_ip6_config_get_address (ip6_config, 0);
-
-		nm_system_replace_default_ip6_route (ip_ifindex, nm_ip6_address_get_gateway (addr));
-
-		dns_type = NM_DNS_IP_CONFIG_TYPE_BEST_DEVICE;
+	/* If no VPN connections, we use the best device instead */
+	if (!ip6_config) {
+		device = get_best_ip6_device (policy->manager);
+		if (device) {
+			req = nm_device_get_act_request (device);
+			g_assert (req);
+			ip6_config = nm_device_get_ip6_config (device);
+			g_assert (ip6_config);
+
+			if (out_device)
+				*out_device = device;
+			if (out_ac)
+				*out_ac = NM_ACTIVE_CONNECTION (req);
+			if (out_ip_iface)
+				*out_ip_iface = nm_device_get_ip_iface (device);
+			if (out_ip_ifindex)
+				*out_ip_ifindex = nm_device_get_ip_ifindex (device);
+		}
 	}
 
-	if (!ip_iface || !ip6_config) {
-		nm_log_warn (LOGD_CORE, "couldn't determine IP interface (%p) or IPv6 config (%p)!",
-		             ip_iface, ip6_config);
-		goto out;
-	}
+	return ip6_config;
+}
 
-	/* Update the default active connection.  Only mark the new default
-	 * active connection after setting default = FALSE on all other connections
-	 * first.  The order is important, we don't want two connections marked
-	 * default at the same time ever.
-	 */
-	devices = nm_manager_get_devices (policy->manager);
-	for (iter = devices; iter; iter = g_slist_next (iter)) {
-		NMDevice *dev = NM_DEVICE (iter->data);
-		NMActRequest *req;
+static void
+update_ip6_dns (NMPolicy *policy, NMDnsManager *dns_mgr)
+{
+	NMIP6Config *ip6_config;
+	const char *ip_iface = NULL;
+	NMVPNConnection *vpn = NULL;
+	NMDnsIPConfigType dns_type = NM_DNS_IP_CONFIG_TYPE_BEST_DEVICE;
 
-		req = nm_device_get_act_request (dev);
-		if (req && (req != best_req))
-			nm_active_connection_set_default6 (NM_ACTIVE_CONNECTION (req), FALSE);
+	ip6_config = get_best_ip6_config (policy, TRUE, &ip_iface, NULL, NULL, NULL, &vpn);
+	if (ip6_config) {
+		if (vpn)
+			dns_type = NM_DNS_IP_CONFIG_TYPE_VPN;
+
+		/* Tell the DNS manager this config is preferred by re-adding it with
+		 * a different IP config type.
+		 */
+		nm_dns_manager_add_ip6_config (dns_mgr, ip_iface, ip6_config, dns_type);
 	}
+}
 
-	dns_mgr = nm_dns_manager_get (NULL);
-	nm_dns_manager_add_ip6_config (dns_mgr, ip_iface, ip6_config, dns_type);
-	g_object_unref (dns_mgr);
+static void
+update_ip6_routing (NMPolicy *policy, gboolean force_update)
+{
+	NMDevice *best = NULL, *parent;
+	NMConnection *connection = NULL;
+	NMVPNConnection *vpn = NULL;
+	NMActiveConnection *best_ac = NULL;
+	NMIP6Config *ip6_config = NULL, *parent_ip6;
+	NMIP6Address *addr;
+	const char *ip_iface = NULL;
+	int ip_ifindex = -1;
+	guint32 parent_mss;
 
-	/* Now set new default active connection _after_ updating DNS info, so that
-	 * if the connection is shared dnsmasq picks up the right stuff.
+	/* Note that we might have an IPv6 VPN tunneled over an IPv4-only device,
+	 * so we can get (vpn != NULL && best == NULL).
 	 */
-	if (best_req)
-		nm_active_connection_set_default6 (NM_ACTIVE_CONNECTION (best_req), TRUE);
+	ip6_config = get_best_ip6_config (policy, FALSE, &ip_iface, &ip_ifindex, &best_ac, &best, &vpn);
+	if (!ip6_config) {
+		policy->default_device6 = NULL;
+		return;
+	}
+	g_assert ((best || vpn) && best_ac);
 
-	if (connection)
-		s_con = nm_connection_get_setting_connection (connection);
+	if (!force_update && best && (best == policy->default_device6))
+		return;
 
-	connection_id = s_con ? nm_setting_connection_get_id (s_con) : NULL;
-	if (connection_id) {
-		nm_log_info (LOGD_CORE, "Policy set '%s' (%s) as default for IPv6 routing and DNS.", connection_id, ip_iface);
+	/* We set the default route to the gateway of the first IP address of the config */
+	addr = nm_ip6_config_get_address (ip6_config, 0);
+	g_assert (addr);
+
+	if (vpn) {
+		parent = nm_vpn_connection_get_parent_device (vpn);
+		parent_ip6 = nm_device_get_ip6_config (parent);
+		parent_mss = parent_ip6 ? nm_ip6_config_get_mss (parent_ip6) : 0;
+
+		nm_system_replace_default_ip6_route_vpn (ip_ifindex,
+		                                         nm_ip6_address_get_gateway (addr),
+		                                         nm_vpn_connection_get_ip6_internal_gateway (vpn),
+		                                         nm_ip6_config_get_mss (ip6_config),
+		                                         nm_device_get_ip_ifindex (parent),
+		                                         parent_mss);
 	} else {
-		nm_log_info (LOGD_CORE, "Policy set (%s) as default for IPv6 routing and DNS.", ip_iface);
+		if (memcmp (nm_ip6_address_get_gateway (addr)->s6_addr, in6addr_any.s6_addr, sizeof (in6addr_any.s6_addr)) != 0)
+			nm_system_replace_default_ip6_route (ip_ifindex, nm_ip6_address_get_gateway (addr));
+		else if (nm_ip6_config_get_gateway (ip6_config))
+			nm_system_replace_default_ip6_route (ip_ifindex, nm_ip6_config_get_gateway (ip6_config));
+		else
+			nm_log_dbg (LOGD_IP6, "missing default IPv6 route");
 	}
 
-out:
+	update_default_ac (policy, best_ac, nm_active_connection_set_default6);
 	policy->default_device6 = best;
+
+	connection = nm_active_connection_get_connection (best_ac);
+	nm_log_info (LOGD_CORE, "Policy set '%s' (%s) as default for IPv6 routing and DNS.",
+	             nm_connection_get_id (connection), ip_iface);
 }
 
 static void
 update_routing_and_dns (NMPolicy *policy, gboolean force_update)
 {
-	update_ip4_routing_and_dns (policy, force_update);
-	update_ip6_routing_and_dns (policy, force_update);
+	NMDnsManager *mgr;
+
+	mgr = nm_dns_manager_get (NULL);
+	nm_dns_manager_begin_updates (mgr, __func__);
+
+	update_ip4_dns (policy, mgr);
+	update_ip6_dns (policy, mgr);
+
+	update_ip4_routing (policy, force_update);
+	update_ip6_routing (policy, force_update);
 
 	/* Update the system hostname */
 	update_system_hostname (policy, policy->default_device4, policy->default_device6);
+
+	nm_dns_manager_end_updates (mgr, __func__);
+	g_object_unref (mgr);
 }
 
 static void
@@ -842,17 +934,96 @@ vpn_connection_activated (NMVPNManager *manager,
                           NMVPNConnection *vpn,
                           gpointer user_data)
 {
+	NMDnsManager *mgr;
+	NMIP4Config *ip4_config;
+	NMIP6Config *ip6_config;
+	const char *ip_iface;
+
+	mgr = nm_dns_manager_get (NULL);
+	nm_dns_manager_begin_updates (mgr, __func__);
+
+	ip_iface = nm_vpn_connection_get_ip_iface (vpn);
+
+	/* Add the VPN connection's IP configs from DNS */
+
+	ip4_config = nm_vpn_connection_get_ip4_config (vpn);
+	if (ip4_config)
+		nm_dns_manager_add_ip4_config (mgr, ip_iface, ip4_config, NM_DNS_IP_CONFIG_TYPE_VPN);
+
+	ip6_config = nm_vpn_connection_get_ip6_config (vpn);
+	if (ip6_config)
+		nm_dns_manager_add_ip6_config (mgr, ip_iface, ip6_config, NM_DNS_IP_CONFIG_TYPE_VPN);
+
 	update_routing_and_dns ((NMPolicy *) user_data, TRUE);
+
+	nm_dns_manager_end_updates (mgr, __func__);
 }
 
 static void
 vpn_connection_deactivated (NMVPNManager *manager,
                             NMVPNConnection *vpn,
-                            NMVPNConnectionState state,
+                            NMVPNConnectionState new_state,
+                            NMVPNConnectionState old_state,
                             NMVPNConnectionStateReason reason,
                             gpointer user_data)
 {
+	NMDnsManager *mgr;
+	NMIP4Config *ip4_config, *parent_ip4 = NULL;
+	NMIP6Config *ip6_config, *parent_ip6 = NULL;
+	const char *ip_iface;
+	NMDevice *parent;
+
+	mgr = nm_dns_manager_get (NULL);
+	nm_dns_manager_begin_updates (mgr, __func__);
+
+	ip_iface = nm_vpn_connection_get_ip_iface (vpn);
+	parent = nm_vpn_connection_get_parent_device (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);
+
+		/* Re-apply routes and addresses of the VPN connection's parent interface,
+		 * which the VPN might have overridden.
+		 */
+		if (parent) {
+			parent_ip4 = nm_device_get_ip4_config (parent);
+			if (parent_ip4) {
+				if (!nm_system_apply_ip4_config (nm_device_get_ip_ifindex (parent),
+				                                 parent_ip4,
+				                                 nm_device_get_priority (parent),
+				                                 NM_IP4_COMPARE_FLAG_ADDRESSES | NM_IP4_COMPARE_FLAG_ROUTES)) {
+					nm_log_err (LOGD_VPN, "failed to re-apply VPN parent device IPv4 addresses and routes.");
+				}
+			}
+		}
+	}
+
+	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);
+
+		/* Re-apply routes and addresses of the VPN connection's parent interface,
+		 * which the VPN might have overridden.
+		 */
+		if (parent) {
+			parent_ip6 = nm_device_get_ip6_config (parent);
+			if (parent_ip6) {
+				if (!nm_system_apply_ip6_config (nm_device_get_ip_ifindex (parent),
+				                                 parent_ip6,
+				                                 nm_device_get_priority (parent),
+				                                 NM_IP6_COMPARE_FLAG_ADDRESSES | NM_IP6_COMPARE_FLAG_ROUTES)) {
+					nm_log_err (LOGD_VPN, "failed to re-apply VPN parent device IPv6 addresses and routes.");
+				}
+			}
+		}
+	}
+
 	update_routing_and_dns ((NMPolicy *) user_data, TRUE);
+
+	nm_dns_manager_end_updates (mgr, __func__);
 }
 
 static void
@@ -976,15 +1147,6 @@ reset_connections_retries (gpointer user_data)
 	return FALSE;
 }
 
-static NMConnection *
-get_device_connection (NMDevice *device)
-{
-	NMActRequest *req = NULL;
-
-	req = nm_device_get_act_request (device);
-	return req ? nm_act_request_get_connection (req) : NULL;
-}
-
 static void schedule_activate_all (NMPolicy *policy);
 
 static void
@@ -1025,7 +1187,11 @@ device_state_changed (NMDevice *device,
                       gpointer user_data)
 {
 	NMPolicy *policy = (NMPolicy *) user_data;
-	NMConnection *connection = get_device_connection (device);
+	NMConnection *connection = nm_device_get_connection (device);
+	const char *ip_iface = nm_device_get_ip_iface (device);
+	NMIP4Config *ip4_config;
+	NMIP6Config *ip6_config;
+	NMDnsManager *dns_mgr;
 
 	if (connection)
 		g_object_set_data (G_OBJECT (connection), FAILURE_REASON_TAG, GUINT_TO_POINTER (0));
@@ -1081,20 +1247,33 @@ device_state_changed (NMDevice *device,
 			nm_connection_clear_secrets (connection);
 		}
 
-		update_routing_and_dns (policy, FALSE);
+		/* Add device's new IPv4 and IPv6 configs to DNS */
+
+		dns_mgr = nm_dns_manager_get (NULL);
+		nm_dns_manager_begin_updates (dns_mgr, __func__);
+
+		ip4_config = nm_device_get_ip4_config (device);
+		if (ip4_config) {
+			nm_dns_manager_add_ip4_config (dns_mgr, ip_iface, ip4_config, NM_DNS_IP_CONFIG_TYPE_DEFAULT);
+			update_ip4_dns (policy, dns_mgr);
+		}
+		ip6_config = nm_device_get_ip6_config (device);
+		if (ip6_config) {
+			nm_dns_manager_add_ip6_config (dns_mgr, ip_iface, ip6_config, NM_DNS_IP_CONFIG_TYPE_DEFAULT);
+			update_ip6_dns (policy, dns_mgr);
+		}
+
+		nm_dns_manager_end_updates (dns_mgr, __func__);
+		g_object_unref (dns_mgr);
+
+		/* And make sure the best devices have the default route */
+		update_ip4_routing (policy, FALSE);
+		update_ip6_routing (policy, FALSE);
 		break;
 	case NM_DEVICE_STATE_UNMANAGED:
-		if (   old_state == NM_DEVICE_STATE_UNAVAILABLE
-		    || old_state == NM_DEVICE_STATE_DISCONNECTED) {
-			/* If the device was never activated, there's no point in
-			 * updating routing or DNS.  This allows us to keep the previous
-			 * resolv.conf or routes from before NM started if no device was
-			 * ever managed by NM.
-			 */
-			break;
-		}
 	case NM_DEVICE_STATE_UNAVAILABLE:
-		update_routing_and_dns (policy, FALSE);
+		if (old_state > NM_DEVICE_STATE_DISCONNECTED)
+			update_routing_and_dns (policy, FALSE);
 		break;
 	case NM_DEVICE_STATE_DISCONNECTED:
 		/* Reset RETRIES_TAG when carrier on. If cable was unplugged
@@ -1102,8 +1281,10 @@ device_state_changed (NMDevice *device,
 		if (reason == NM_DEVICE_STATE_REASON_CARRIER && old_state == NM_DEVICE_STATE_UNAVAILABLE)
 			reset_retries_all (policy->settings, device);
 
+		if (old_state > NM_DEVICE_STATE_DISCONNECTED)
+			update_routing_and_dns (policy, FALSE);
+
 		/* Device is now available for auto-activation */
-		update_routing_and_dns (policy, FALSE);
 		schedule_activate_check (policy, device, 0);
 		break;
 
@@ -1119,11 +1300,86 @@ device_state_changed (NMDevice *device,
 }
 
 static void
-device_ip_config_changed (NMDevice *device,
-                          GParamSpec *pspec,
-                          gpointer user_data)
+device_ip4_config_changed (NMDevice *device,
+                           NMIP4Config *new_config,
+                           NMIP4Config *old_config,
+                           gpointer user_data)
 {
-	update_routing_and_dns ((NMPolicy *) user_data, TRUE);
+	NMPolicy *policy = user_data;
+	NMDnsManager *dns_mgr;
+	const char *ip_iface = nm_device_get_ip_iface (device);
+	NMIP4ConfigCompareFlags diff = NM_IP4_COMPARE_FLAG_ALL;
+
+	dns_mgr = nm_dns_manager_get (NULL);
+	nm_dns_manager_begin_updates (dns_mgr, __func__);
+
+	/* Old configs get removed immediately */
+	if (old_config)
+		nm_dns_manager_remove_ip4_config (dns_mgr, ip_iface, 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.
+	 * Prevents unecessary changes to DNS information.
+	 */
+	if (!nm_device_is_activating (device)) {
+		if (new_config)
+			nm_dns_manager_add_ip4_config (dns_mgr, ip_iface, new_config, NM_DNS_IP_CONFIG_TYPE_DEFAULT);
+		update_ip4_dns (policy, dns_mgr);
+
+		/* Only change routing if something actually changed */
+		diff = nm_ip4_config_diff (new_config, old_config);
+		if (diff & (NM_IP4_COMPARE_FLAG_ADDRESSES | NM_IP4_COMPARE_FLAG_PTP_ADDRESS | NM_IP4_COMPARE_FLAG_ROUTES))
+			update_ip4_routing (policy, TRUE);
+	}
+
+	nm_dns_manager_end_updates (dns_mgr, __func__);
+	g_object_unref (dns_mgr);
+}
+
+static void
+device_ip6_config_changed (NMDevice *device,
+                           NMIP6Config *new_config,
+                           NMIP6Config *old_config,
+                           gpointer user_data)
+{
+	NMPolicy *policy = user_data;
+	NMDnsManager *dns_mgr;
+	const char *ip_iface = nm_device_get_ip_iface (device);
+	NMIP4ConfigCompareFlags diff = NM_IP4_COMPARE_FLAG_ALL;
+
+	dns_mgr = nm_dns_manager_get (NULL);
+	nm_dns_manager_begin_updates (dns_mgr, __func__);
+
+	/* Old configs get removed immediately */
+	if (old_config)
+		nm_dns_manager_remove_ip6_config (dns_mgr, ip_iface, 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.
+	 * Prevents unecessary changes to DNS information.
+	 */
+	if (!nm_device_is_activating (device)) {
+		if (new_config)
+			nm_dns_manager_add_ip6_config (dns_mgr, ip_iface, new_config, NM_DNS_IP_CONFIG_TYPE_DEFAULT);
+		update_ip6_dns (policy, dns_mgr);
+
+		/* Only change routing if something actually changed */
+		diff = nm_ip6_config_diff (new_config, old_config);
+		if (diff & (NM_IP6_COMPARE_FLAG_ADDRESSES | NM_IP6_COMPARE_FLAG_PTP_ADDRESS | NM_IP6_COMPARE_FLAG_ROUTES))
+			update_ip6_routing (policy, TRUE);
+	}
+
+	nm_dns_manager_end_updates (dns_mgr, __func__);
+	g_object_unref (dns_mgr);
+}
+
+static void
+device_autoconnect_changed (NMDevice *device,
+                            GParamSpec *pspec,
+                            gpointer user_data)
+{
+	if (nm_device_get_autoconnect (device))
+		schedule_activate_check ((NMPolicy *) user_data, device, 0);
 }
 
 static void
@@ -1167,8 +1423,9 @@ device_added (NMManager *manager, NMDevice *device, gpointer user_data)
 	NMPolicy *policy = (NMPolicy *) user_data;
 
 	_connect_device_signal (policy, device, "state-changed", device_state_changed);
-	_connect_device_signal (policy, device, "notify::" NM_DEVICE_IP4_CONFIG, device_ip_config_changed);
-	_connect_device_signal (policy, device, "notify::" NM_DEVICE_IP6_CONFIG, device_ip_config_changed);
+	_connect_device_signal (policy, device, NM_DEVICE_IP4_CONFIG_CHANGED, device_ip4_config_changed);
+	_connect_device_signal (policy, device, NM_DEVICE_IP6_CONFIG_CHANGED, device_ip6_config_changed);
+	_connect_device_signal (policy, device, "notify::" NM_DEVICE_AUTOCONNECT, device_autoconnect_changed);
 
 	switch (nm_device_get_device_type (device)) {
 	case NM_DEVICE_TYPE_WIFI:
@@ -1215,7 +1472,9 @@ device_removed (NMManager *manager, NMDevice *device, gpointer user_data)
 		iter = next;
 	}
 
-	update_routing_and_dns (policy, FALSE);
+	/* Don't update routing and DNS here as we've already handled that
+	 * for devices that need it when the device's state changed to UNMANAGED.
+	 */
 }
 
 static void
@@ -1273,7 +1532,7 @@ firewall_update_zone (NMPolicy *policy, NMConnection *connection)
 	for (iter = devices; iter; iter = g_slist_next (iter)) {
 		NMDevice *dev = NM_DEVICE (iter->data);
 
-		if (   (get_device_connection (dev) == connection)
+		if (   (nm_device_get_connection (dev) == connection)
 		    && (nm_device_get_state (dev) == NM_DEVICE_STATE_ACTIVATED)) {
 			nm_firewall_manager_add_or_change_zone (policy->fw_manager,
 			                                        nm_device_get_ip_iface (dev),
@@ -1299,7 +1558,7 @@ firewall_started (NMFirewallManager *manager,
 	for (iter = devices; iter; iter = g_slist_next (iter)) {
 		NMDevice *dev = NM_DEVICE (iter->data);
 
-		connection = get_device_connection (dev);
+		connection = nm_device_get_connection (dev);
 		s_con = nm_connection_get_setting_connection (connection);
 		if (nm_device_get_state (dev) == NM_DEVICE_STATE_ACTIVATED) {
 			nm_firewall_manager_add_or_change_zone (policy->fw_manager,
diff --git a/src/nm-system.c b/src/nm-system.c
index 91153ec2..b980dc53 100644
--- a/src/nm-system.c
+++ b/src/nm-system.c
@@ -349,14 +349,15 @@ add_ip4_addresses (NMIP4Config *config, int ifindex)
 }
 
 struct rtnl_route *
-nm_system_add_ip4_vpn_gateway_route (NMDevice *parent_device, NMIP4Config *vpn_config)
+nm_system_add_ip4_vpn_gateway_route (NMDevice *parent_device, guint32 vpn_gw)
 {
 	NMIP4Config *parent_config;
-	guint32 parent_gw = 0, parent_prefix = 0, vpn_gw = 0, i;
+	guint32 parent_gw = 0, parent_prefix = 0, i;
 	NMIP4Address *tmp;
 	struct rtnl_route *route = NULL;
 
 	g_return_val_if_fail (NM_IS_DEVICE (parent_device), NULL);
+	g_return_val_if_fail (vpn_gw != 0, NULL);
 
 	/* Set up a route to the VPN gateway's public IP address through the default
 	 * network device if the VPN gateway is on a different subnet.
@@ -374,15 +375,7 @@ nm_system_add_ip4_vpn_gateway_route (NMDevice *parent_device, NMIP4Config *vpn_c
 		}
 	}
 
-	for (i = 0; i < nm_ip4_config_get_num_addresses (vpn_config); i++) {
-		tmp = nm_ip4_config_get_address (vpn_config, i);
-		if (nm_ip4_address_get_gateway (tmp)) {
-			vpn_gw = nm_ip4_address_get_gateway (tmp);
-			break;
-		}
-	}
-
-	if (!parent_gw || !vpn_gw)
+	if (!parent_gw)
 		return NULL;
 
 	/* If the VPN gateway is in the same subnet as one of the parent device's
@@ -479,7 +472,7 @@ nm_system_set_ip6_route (int ifindex,
 	struct rtnl_route *route;
 	int err = 0;
 
-	g_return_val_if_fail (ifindex >= 0, -1);
+	g_return_val_if_fail (ifindex > 0, -1);
 
 	nlh = nm_netlink_get_default_handle ();
 	g_return_val_if_fail (nlh != NULL, -1);
@@ -520,6 +513,96 @@ nm_system_set_ip6_route (int ifindex,
 }
 
 static gboolean
+ip6_dest_in_same_subnet (NMIP6Config *config, const struct in6_addr *dest, guint32 dest_prefix)
+{
+	int num;
+	int i;
+
+	num = nm_ip6_config_get_num_addresses (config);
+	for (i = 0; i < num; i++) {
+		NMIP6Address *addr = nm_ip6_config_get_address (config, i);
+		guint32 prefix = nm_ip6_address_get_prefix (addr);
+		const struct in6_addr *address = nm_ip6_address_get_address (addr);
+
+		if (prefix <= dest_prefix) {
+			const guint8 *maskbytes = (const guint8 *)address;
+			const guint8 *addrbytes = (const guint8 *)dest;
+			int nbytes, nbits;
+
+			/* Copied from g_inet_address_mask_matches() */
+			nbytes = prefix / 8;
+			if (nbytes != 0 && memcmp (maskbytes, addrbytes, nbytes) != 0)
+				continue;
+
+			nbits = prefix % 8;
+			if (nbits == 0)
+				return TRUE;
+
+			if (maskbytes[nbytes] == (addrbytes[nbytes] & (0xFF << (8 - nbits))))
+				return TRUE;
+		}
+	}
+
+	return FALSE;
+}
+
+struct rtnl_route *
+nm_system_add_ip6_vpn_gateway_route (NMDevice *parent_device,
+                                     const struct in6_addr *vpn_gw)
+{
+	NMIP6Config *parent_config;
+	const struct in6_addr *parent_gw = NULL;
+	guint32 parent_prefix = 0;
+	int i, err;
+	NMIP6Address *tmp;
+	struct rtnl_route *route = NULL;
+
+	g_return_val_if_fail (NM_IS_DEVICE (parent_device), NULL);
+	g_return_val_if_fail (vpn_gw != NULL, NULL);
+
+	/* This is all just the same as
+	 * nm_system_add_ip4_vpn_gateway_route(), except with an IPv6
+	 * address for the VPN gateway.
+	 */
+
+	parent_config = nm_device_get_ip6_config (parent_device);
+	g_return_val_if_fail (parent_config != NULL, NULL);
+
+	for (i = 0; i < nm_ip6_config_get_num_addresses (parent_config); i++) {
+		tmp = nm_ip6_config_get_address (parent_config, i);
+		if (nm_ip6_address_get_gateway (tmp)) {
+			parent_gw = nm_ip6_address_get_gateway (tmp);
+			parent_prefix = nm_ip6_address_get_prefix (tmp);
+			break;
+		}
+	}
+
+	if (!parent_gw)
+		return NULL;
+
+	if (ip6_dest_in_same_subnet (parent_config, vpn_gw, parent_prefix)) {
+		err = nm_system_set_ip6_route (nm_device_get_ip_ifindex (parent_device),
+		                               vpn_gw, 128, NULL, 0,
+		                               nm_ip6_config_get_mss (parent_config),
+		                               RTPROT_UNSPEC, RT_TABLE_UNSPEC,
+		                               &route);
+	} else {
+		err = nm_system_set_ip6_route (nm_device_get_ip_ifindex (parent_device),
+		                               vpn_gw, 128, parent_gw, 0,
+		                               nm_ip6_config_get_mss (parent_config),
+		                               RTPROT_UNSPEC, RT_TABLE_UNSPEC,
+		                               &route);
+	}
+
+	if (err) {
+		nm_log_err (LOGD_DEVICE | LOGD_IP6,
+		            "(%s): failed to add IPv6 route to VPN gateway (%d)",
+		            nm_device_get_iface (parent_device), err);
+	}
+	return route;
+}
+
+static gboolean
 add_ip6_addresses (NMIP6Config *config, int ifindex)
 {
 	char *iface;
@@ -909,7 +992,7 @@ nm_system_replace_default_ip4_route_vpn (int ifindex,
 		goto out;
 
 	if ((err != -NLE_OBJ_NOTFOUND) && (err != -NLE_FAILURE)) {
-		nm_log_err (LOGD_DEVICE | LOGD_IP4,
+		nm_log_err (LOGD_DEVICE | LOGD_VPN | LOGD_IP4,
 		            "(%s): failed to set IPv4 default route: %d",
 		            iface, err);
 		goto out;
@@ -924,7 +1007,7 @@ nm_system_replace_default_ip4_route_vpn (int ifindex,
 	err = replace_default_ip4_route (ifindex, int_gw, mss);
 	if (err != 0) {
 		nm_netlink_route_delete (gw_route);
-		nm_log_err (LOGD_DEVICE | LOGD_IP4,
+		nm_log_err (LOGD_DEVICE | LOGD_VPN | LOGD_IP4,
 		            "(%s): failed to set IPv4 default route (pass #2): %d",
 		            iface, err);
 	} else
@@ -989,7 +1072,7 @@ out:
 }
 
 static struct rtnl_route *
-add_ip6_route_to_gateway (int ifindex, const struct in6_addr *gw)
+add_ip6_route_to_gateway (int ifindex, const struct in6_addr *gw, int mss)
 {
 	struct nl_sock *nlh;
 	struct rtnl_route *route = NULL;
@@ -999,7 +1082,7 @@ add_ip6_route_to_gateway (int ifindex, const struct in6_addr *gw)
 	g_return_val_if_fail (nlh != NULL, NULL);
 
 	/* Gateway might be over a bridge; try adding a route to gateway first */
-	route = nm_netlink_route_new (ifindex, AF_INET6, 0,
+	route = nm_netlink_route_new (ifindex, AF_INET6, mss,
 	                              NMNL_PROP_SCOPE, RT_SCOPE_LINK,
 	                              NMNL_PROP_TABLE, RT_TABLE_MAIN,
 	                              NULL);
@@ -1023,7 +1106,7 @@ add_ip6_route_to_gateway (int ifindex, const struct in6_addr *gw)
 }
 
 static int
-replace_default_ip6_route (int ifindex, const struct in6_addr *gw)
+add_default_ip6_route (int ifindex, const struct in6_addr *gw, int mss)
 {
 	struct rtnl_route *route = NULL;
 	struct nl_sock *nlh;
@@ -1034,25 +1117,81 @@ replace_default_ip6_route (int ifindex, const struct in6_addr *gw)
 	nlh = nm_netlink_get_default_handle ();
 	g_return_val_if_fail (nlh != NULL, -ENOMEM);
 
-	route = nm_netlink_route_new (ifindex, AF_INET6, 0,
+	route = nm_netlink_route_new (ifindex, AF_INET6, mss,
 	                              NMNL_PROP_SCOPE, RT_SCOPE_UNIVERSE,
 	                              NMNL_PROP_TABLE, RT_TABLE_MAIN,
+	                              NMNL_PROP_PRIO, 1,
 	                              NULL);
 	g_return_val_if_fail (route != NULL, -ENOMEM);
 
 	/* Add the new default route */
-	err = nm_netlink_route6_add (route, &in6addr_any, 0, gw, NLM_F_REPLACE);
-	if (err == -NLE_EXIST) {
-		/* FIXME: even though we use NLM_F_REPLACE the kernel won't replace
-		 * the route if it's the same.  Suppress the pointless error.
-		 */
+	err = nm_netlink_route6_add (route, &in6addr_any, 0, gw, NLM_F_CREATE);
+	if (err == -NLE_EXIST)
 		err = 0;
-	}
 
 	rtnl_route_put (route);
 	return err;
 }
 
+static struct rtnl_route *
+find_static_default_routes (struct rtnl_route *route,
+                            struct nl_addr *dst,
+                            const char *iface,
+                            gpointer user_data)
+{
+	GList **def_routes = user_data;
+
+	if (   nl_addr_get_prefixlen (dst) == 0
+	    && rtnl_route_get_protocol (route) == RTPROT_STATIC) {
+		rtnl_route_get (route);
+		*def_routes = g_list_prepend (*def_routes, route);
+	}
+
+	return NULL;
+}
+
+static int
+replace_default_ip6_route (int ifindex, const struct in6_addr *gw, int mss)
+{
+	GList *def_routes, *iter;
+	struct rtnl_route *route;
+	char *iface;
+	char gw_str[INET6_ADDRSTRLEN + 1];
+
+	g_return_val_if_fail (ifindex > 0, FALSE);
+	g_return_val_if_fail (gw != NULL, FALSE);
+
+	if (nm_logging_level_enabled (LOGL_DEBUG)) {
+		memset (gw_str, 0, sizeof (gw_str));
+		if (inet_ntop (AF_INET6, gw, gw_str, sizeof (gw_str) - 1))
+			nm_log_dbg (LOGD_IP6, "Setting IPv6 default route via %s", gw_str);
+	}
+
+	/* We can't just use NLM_F_REPLACE here like in the IPv4 case, because
+	 * the kernel doesn't like it if we replace the default routes it
+	 * creates. (See rh#785772.) So we delete any non-kernel default routes,
+	 * and then add a new default route of our own with a lower metric than
+	 * the kernel ones.
+	 */
+	def_routes = NULL;
+	nm_netlink_foreach_route (ifindex, AF_INET6, RT_SCOPE_UNIVERSE, TRUE,
+	                          find_static_default_routes, &def_routes);
+	for (iter = def_routes; iter; iter = iter->next) {
+		route = iter->data;
+		if (!nm_netlink_route_delete (route)) {
+			iface = nm_netlink_index_to_iface (ifindex);
+			nm_log_err (LOGD_DEVICE | LOGD_IP6,
+			            "(%s): failed to delete existing IPv6 default route",
+			            iface);
+			g_free (iface);
+		}
+		rtnl_route_put (route);
+	}
+	g_list_free (def_routes);
+
+	return add_default_ip6_route (ifindex, gw, mss);
+}
+
 /*
  * nm_system_replace_default_ip6_route
  *
@@ -1067,11 +1206,8 @@ nm_system_replace_default_ip6_route (int ifindex, const struct in6_addr *gw)
 	char *iface;
 	int err;
 
-	err = replace_default_ip6_route (ifindex, gw);
-	if (err == 0)
-		return TRUE;
-
-	if (err == -NLE_EXIST)
+	err = replace_default_ip6_route (ifindex, gw, 0);
+	if (err == 0 || err == -NLE_EXIST)
 		return TRUE;
 
 	iface = nm_netlink_index_to_iface (ifindex);
@@ -1086,12 +1222,12 @@ nm_system_replace_default_ip6_route (int ifindex, const struct in6_addr *gw)
 	}
 
 	/* Try adding a direct route to the gateway first */
-	gw_route = add_ip6_route_to_gateway (ifindex, gw);
+	gw_route = add_ip6_route_to_gateway (ifindex, gw, 0);
 	if (!gw_route)
 		goto out;
 
 	/* Try adding the original route again */
-	err = replace_default_ip6_route (ifindex, gw);
+	err = replace_default_ip6_route (ifindex, gw, 0);
 	if (err != 0) {
 		nm_netlink_route_delete (gw_route);
 		nm_log_err (LOGD_DEVICE | LOGD_IP6,
@@ -1107,6 +1243,60 @@ out:
 	return success;
 }
 
+gboolean
+nm_system_replace_default_ip6_route_vpn (int ifindex,
+                                         const struct in6_addr *ext_gw,
+                                         const struct in6_addr *int_gw,
+                                         guint32 mss,
+                                         int parent_ifindex,
+                                         guint32 parent_mss)
+{
+	struct rtnl_route *gw_route = NULL;
+	struct nl_sock *nlh;
+	gboolean success = FALSE;
+	int err;
+	char *iface;
+
+	nlh = nm_netlink_get_default_handle ();
+	g_return_val_if_fail (nlh != NULL, FALSE);
+
+	err = replace_default_ip6_route (ifindex, int_gw, mss);
+	if (err == 0)
+		return TRUE;
+
+	iface = nm_netlink_index_to_iface (ifindex);
+	if (!iface)
+		goto out;
+
+	if ((err != -NLE_OBJ_NOTFOUND) && (err != -NLE_FAILURE)) {
+		nm_log_err (LOGD_DEVICE | LOGD_VPN | LOGD_IP6,
+		            "(%s): failed to set IPv6 default route: %d",
+		            iface, err);
+		goto out;
+	}
+
+	/* Try adding a direct route to the gateway first */
+	gw_route = add_ip6_route_to_gateway (parent_ifindex, ext_gw, parent_mss);
+	if (!gw_route)
+		goto out;
+
+	/* Try adding the original route again */
+	err = replace_default_ip6_route (ifindex, int_gw, mss);
+	if (err != 0) {
+		nm_netlink_route_delete (gw_route);
+		nm_log_err (LOGD_DEVICE | LOGD_VPN | LOGD_IP6,
+		            "(%s): failed to set IPv6 default route (pass #2): %d",
+		            iface, err);
+	} else
+		success = TRUE;
+
+out:
+	if (gw_route)
+		rtnl_route_put (gw_route);
+	g_free (iface);
+	return success;
+}
+
 /*
  * nm_system_iface_flush_addresses
  *
@@ -1435,9 +1625,9 @@ nm_system_iface_enslave (gint master_ifindex,
 	struct nl_sock *sock;
 	int err;
 
-	g_return_val_if_fail (master_ifindex >= 0, FALSE);
+	g_return_val_if_fail (master_ifindex > 0, FALSE);
 	g_return_val_if_fail (master_iface != NULL, FALSE);
-	g_return_val_if_fail (slave_ifindex >= 0, FALSE);
+	g_return_val_if_fail (slave_ifindex > 0, FALSE);
 	g_return_val_if_fail (slave_iface != NULL, FALSE);
 
 	sock = nm_netlink_get_default_handle ();
@@ -1520,9 +1710,9 @@ nm_system_iface_release (gint master_ifindex,
 	struct nl_sock *sock;
 	int err;
 
-	g_return_val_if_fail (master_ifindex >= 0, FALSE);
+	g_return_val_if_fail (master_ifindex > 0, FALSE);
 	g_return_val_if_fail (master_iface != NULL, FALSE);
-	g_return_val_if_fail (slave_ifindex >= 0, FALSE);
+	g_return_val_if_fail (slave_ifindex > 0, FALSE);
 	g_return_val_if_fail (slave_iface != NULL, FALSE);
 
 	sock = nm_netlink_get_default_handle ();
@@ -1561,7 +1751,7 @@ nm_system_get_iface_type (int ifindex, const char *name)
 	char *type;
 	int res = NM_IFACE_TYPE_UNSPEC;
 
-	g_return_val_if_fail (ifindex >= 0 || name, NM_IFACE_TYPE_UNSPEC);
+	g_return_val_if_fail (ifindex > 0 || name, NM_IFACE_TYPE_UNSPEC);
 
 	nlh = nm_netlink_get_default_handle ();
 	if (!nlh)
@@ -1706,7 +1896,7 @@ nm_system_iface_compat_add_vlan_device (const char *master, int vid)
 	}
 
 	memset (&if_request, 0, sizeof (struct vlan_ioctl_args));
-	strcpy (if_request.device1, master);
+	g_strlcpy (if_request.device1, master, sizeof (if_request.device1));
 	if_request.cmd = ADD_VLAN_CMD;
 	if_request.u.VID = vid;
 
@@ -1732,7 +1922,7 @@ nm_system_iface_compat_rem_vlan_device (const char *iface)
 	}
 
 	memset (&if_request, 0, sizeof (struct vlan_ioctl_args));
-        strcpy (if_request.device1, iface);
+	g_strlcpy (if_request.device1, iface, sizeof (if_request.device1));
 	if_request.cmd = DEL_VLAN_CMD;
 
 	if (ioctl (fd, SIOCSIFVLAN, &if_request) < 0) {
@@ -1868,7 +2058,7 @@ nm_system_add_vlan_iface (NMConnection *connection,
 	guint32 vlan_flags = 0;
 	guint32 num, i, from, to;
 
-	g_return_val_if_fail (parent_ifindex >= 0, FALSE);
+	g_return_val_if_fail (parent_ifindex > 0, FALSE);
 
 	nlh = nm_netlink_get_default_handle ();
 	g_return_val_if_fail (nlh != NULL, FALSE);
diff --git a/src/nm-system.h b/src/nm-system.h
index 84ae6c27..1acb8853 100644
--- a/src/nm-system.h
+++ b/src/nm-system.h
@@ -53,8 +53,17 @@ gboolean		nm_system_replace_default_ip4_route_vpn (int ifindex,
                                                          int parent_ifindex,
                                                          guint32 parent_mss);
 
-struct rtnl_route *nm_system_add_ip4_vpn_gateway_route (NMDevice *parent_device, NMIP4Config *vpn_config);
+gboolean		nm_system_replace_default_ip6_route_vpn (int ifindex,
+                                                         const struct in6_addr *ext_gw,
+                                                         const struct in6_addr *int_gw,
+                                                         guint32 mss,
+                                                         int parent_ifindex,
+                                                         guint32 parent_mss);
 
+struct rtnl_route *nm_system_add_ip4_vpn_gateway_route (NMDevice *parent_device,
+                                                        guint32 vpn_gw);
+struct rtnl_route *nm_system_add_ip6_vpn_gateway_route (NMDevice *parent_device,
+                                                        const struct in6_addr *vpn_gw);
 
 gboolean        nm_system_iface_flush_addresses         (int ifindex, int family);
 
diff --git a/src/nm-udev-manager.c b/src/nm-udev-manager.c
index 45262f87..57b36d38 100644
--- a/src/nm-udev-manager.c
+++ b/src/nm-udev-manager.c
@@ -329,52 +329,34 @@ rfkill_remove (NMUdevManager *self,
 	}
 }
 
-static void
-net_add (NMUdevManager *self, GUdevDevice *udev_device)
+static gboolean
+dev_get_attrs (GUdevDevice *udev_device,
+               const char **out_ifname,
+               const char **out_path,
+               char **out_driver,
+               int *out_ifindex)
 {
 	GUdevDevice *parent = NULL, *grandparent = NULL;
-	gint ifindex;
-	gint etype;
-	const char *ifname, *driver, *path, *subsys, *tmp;
-	gboolean is_ctc;
+	const char *ifname, *driver, *path, *subsys;
+	gint ifindex = -1;
+	gboolean success = FALSE;
 
-	g_return_if_fail (udev_device != NULL);
+	g_return_val_if_fail (udev_device != NULL, FALSE);
+	g_return_val_if_fail (out_ifname != NULL, FALSE);
+	g_return_val_if_fail (out_path != NULL, FALSE);
+	g_return_val_if_fail (out_driver != NULL, FALSE);
+	g_return_val_if_fail (out_ifindex != NULL, FALSE);
 
 	ifname = g_udev_device_get_name (udev_device);
 	if (!ifname) {
 		nm_log_dbg (LOGD_HW, "failed to get device's interface");
-		return;
-	}
-
-	etype = g_udev_device_get_sysfs_attr_as_int (udev_device, "type");
-	is_ctc = (strncmp (ifname, "ctc", 3) == 0) && (etype == 256);
-
-	/* Ignore devices that don't report Ethernet encapsulation, except for
-	 * s390 CTC-type devices that report 256 for some reason.
-	 * FIXME: use something other than interface name to detect CTC here.
-	 */
-	if ((etype != ARPHRD_ETHER) && (etype != ARPHRD_INFINIBAND) && (is_ctc == FALSE)) {
-		nm_log_dbg (LOGD_HW, "(%s): ignoring interface with type %d", ifname, etype);
-		return;
-	}
-
-	/* Not all ethernet devices are immediately usable; newer mobile broadband
-	 * devices (Ericsson, Option, Sierra) require setup on the tty before the
-	 * ethernet device is usable.  2.6.33 and later kernels set the 'DEVTYPE'
-	 * uevent variable which we can use to ignore the interface as a NMDevice
-	 * subclass.  ModemManager will pick it up though and so we'll handle it
-	 * through the mobile broadband stuff.
-	 */
-	tmp = g_udev_device_get_property (udev_device, "DEVTYPE");
-	if (g_strcmp0 (tmp, "wwan") == 0) {
-		nm_log_dbg (LOGD_HW, "(%s): ignoring interface with devtype '%s'", ifname, tmp);
-		return;
+		return FALSE;
 	}
 
 	path = g_udev_device_get_sysfs_path (udev_device);
 	if (!path) {
 		nm_log_warn (LOGD_HW, "couldn't determine device path; ignoring...");
-		return;
+		return FALSE;
 	}
 
 	driver = g_udev_device_get_driver (udev_device);
@@ -399,11 +381,8 @@ net_add (NMUdevManager *self, GUdevDevice *udev_device)
 		}
 	}
 
-	ifindex = g_udev_device_get_sysfs_attr_as_int (udev_device, "ifindex");
-	if (ifindex <= 0) {
-		nm_log_warn (LOGD_HW, "%s: device had invalid ifindex %d; ignoring...", path, (guint32) ifindex);
-		goto out;
-	}
+	if (g_udev_device_get_sysfs_attr (udev_device, "ifindex"))
+		ifindex = g_udev_device_get_sysfs_attr_as_int (udev_device, "ifindex");
 
 	if (!driver) {
 		switch (nm_system_get_iface_type (ifindex, ifname)) {
@@ -425,13 +404,69 @@ net_add (NMUdevManager *self, GUdevDevice *udev_device)
 		}
 	}
 
-	g_signal_emit (self, signals[DEVICE_ADDED], 0, udev_device, ifname, path, driver, ifindex);
+	*out_ifname = ifname;
+	*out_path = path;
+	*out_driver = g_strdup (driver);
+	*out_ifindex = ifindex;
+	success = TRUE;
 
 out:
 	if (grandparent)
 		g_object_unref (grandparent);
 	if (parent)
 		g_object_unref (parent);
+
+	return success;
+}
+
+static void
+net_add (NMUdevManager *self, GUdevDevice *udev_device)
+{
+	gint ifindex = -1;
+	gint etype;
+	const char *ifname = NULL, *path = NULL, *tmp;
+	char *driver = NULL;
+	gboolean is_ctc;
+
+	g_return_if_fail (udev_device != NULL);
+
+	if (!dev_get_attrs (udev_device, &ifname, &path, &driver, &ifindex))
+		return;
+
+	if (ifindex < 0) {
+		nm_log_warn (LOGD_HW, "%s: device had invalid ifindex %d; ignoring...", path, ifindex);
+		goto out;
+	}
+
+	etype = g_udev_device_get_sysfs_attr_as_int (udev_device, "type");
+	is_ctc = (strncmp (ifname, "ctc", 3) == 0) && (etype == 256);
+
+	/* Ignore devices that don't report Ethernet encapsulation, except for
+	 * s390 CTC-type devices that report 256 for some reason.
+	 * FIXME: use something other than interface name to detect CTC here.
+	 */
+	if ((etype != ARPHRD_ETHER) && (etype != ARPHRD_INFINIBAND) && (is_ctc == FALSE)) {
+		nm_log_dbg (LOGD_HW, "(%s): ignoring interface with type %d", ifname, etype);
+		goto out;
+	}
+
+	/* Not all ethernet devices are immediately usable; newer mobile broadband
+	 * devices (Ericsson, Option, Sierra) require setup on the tty before the
+	 * ethernet device is usable.  2.6.33 and later kernels set the 'DEVTYPE'
+	 * uevent variable which we can use to ignore the interface as a NMDevice
+	 * subclass.  ModemManager will pick it up though and so we'll handle it
+	 * through the mobile broadband stuff.
+	 */
+	tmp = g_udev_device_get_property (udev_device, "DEVTYPE");
+	if (g_strcmp0 (tmp, "wwan") == 0) {
+		nm_log_dbg (LOGD_HW, "(%s): ignoring interface with devtype '%s'", ifname, tmp);
+		goto out;
+	}
+
+	g_signal_emit (self, signals[DEVICE_ADDED], 0, udev_device, ifname, path, driver, ifindex);
+
+out:
+	g_free (driver);
 }
 
 static void
@@ -440,6 +475,30 @@ net_remove (NMUdevManager *self, GUdevDevice *device)
 	g_signal_emit (self, signals[DEVICE_REMOVED], 0, device);
 }
 
+static void
+adsl_add (NMUdevManager *self, GUdevDevice *udev_device)
+{
+	gint ifindex = -1;
+	const char *ifname = NULL, *path = NULL;
+	char *driver = NULL;
+
+	g_return_if_fail (udev_device != NULL);
+
+	nm_log_dbg (LOGD_HW, "adsl_add: ATM Device detected from udev. Adding ..");
+
+	if (dev_get_attrs (udev_device, &ifname, &path, &driver, &ifindex))
+		g_signal_emit (self, signals[DEVICE_ADDED], 0, udev_device, ifname, path, driver, ifindex);
+	g_free (driver);
+}
+
+static void
+adsl_remove (NMUdevManager *self, GUdevDevice *device)
+{
+	nm_log_dbg (LOGD_HW, "adsl_remove: Removing ATM Device");
+
+	g_signal_emit (self, signals[DEVICE_REMOVED], 0, device);
+}
+
 void
 nm_udev_manager_query_devices (NMUdevManager *self)
 {
@@ -455,6 +514,14 @@ nm_udev_manager_query_devices (NMUdevManager *self)
 		g_object_unref (G_UDEV_DEVICE (iter->data));
 	}
 	g_list_free (devices);
+
+
+	devices = g_udev_client_query_by_subsystem (priv->client, "atm");
+	for (iter = devices; iter; iter = g_list_next (iter)) {
+		adsl_add (self, G_UDEV_DEVICE (iter->data));
+		g_object_unref (G_UDEV_DEVICE (iter->data));
+	}
+	g_list_free (devices);
 }
 
 static void
@@ -475,18 +542,23 @@ handle_uevent (GUdevClient *client,
 	nm_log_dbg (LOGD_HW, "UDEV event: action '%s' subsys '%s' device '%s'",
 	            action, subsys, g_udev_device_get_name (device));
 
-	g_return_if_fail (!strcmp (subsys, "rfkill") || !strcmp (subsys, "net"));
+	g_return_if_fail (!strcmp (subsys, "rfkill") || !strcmp (subsys, "net") ||
+	                  !strcmp (subsys, "atm"));
 
 	if (!strcmp (action, "add")) {
 		if (!strcmp (subsys, "rfkill"))
 			rfkill_add (self, device);
 		else if (!strcmp (subsys, "net"))
 			net_add (self, device);
+		else if (!strcmp (subsys, "atm"))
+			adsl_add (self, device);
 	} else if (!strcmp (action, "remove")) {
 		if (!strcmp (subsys, "rfkill"))
 			rfkill_remove (self, device);
 		else if (!strcmp (subsys, "net"))
 			net_remove (self, device);
+		else if (!strcmp (subsys, "atm"))
+			adsl_remove (self, device);
 	}
 
 	recheck_killswitches (self);
@@ -496,7 +568,7 @@ static void
 nm_udev_manager_init (NMUdevManager *self)
 {
 	NMUdevManagerPrivate *priv = NM_UDEV_MANAGER_GET_PRIVATE (self);
-	const char *subsys[3] = { "rfkill", "net", NULL };
+	const char *subsys[4] = { "rfkill", "net", "atm", NULL };
 	GList *switches, *iter;
 	guint32 i;
 
diff --git a/src/nm-wifi-ap.c b/src/nm-wifi-ap.c
index 92a99b69..6a607960 100644
--- a/src/nm-wifi-ap.c
+++ b/src/nm-wifi-ap.c
@@ -509,7 +509,6 @@ NMAccessPoint *
 nm_ap_new_from_properties (const char *supplicant_path, GHashTable *properties)
 {
 	NMAccessPoint *ap;
-	GTimeVal cur_time;
 	const struct ether_addr * addr;
 	const char bad_bssid1[ETH_ALEN] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 };
 	const char bad_bssid2[ETH_ALEN] = { 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF };
@@ -531,8 +530,7 @@ nm_ap_new_from_properties (const char *supplicant_path, GHashTable *properties)
 		return NULL;
 	}
 
-	g_get_current_time (&cur_time);
-	nm_ap_set_last_seen (ap, cur_time.tv_sec);
+	nm_ap_set_last_seen (ap, (guint32) time (NULL));
 
 	if (!nm_ap_get_ssid (ap))
 		nm_ap_set_broadcast (ap, FALSE);
@@ -966,16 +964,15 @@ void nm_ap_set_mode (NMAccessPoint *ap, const NM80211Mode mode)
 	NMAccessPointPrivate *priv;
 
 	g_return_if_fail (NM_IS_AP (ap));
+	g_return_if_fail (   mode == NM_802_11_MODE_ADHOC
+	                  || mode == NM_802_11_MODE_INFRA);
 
-	if (mode == NM_802_11_MODE_ADHOC || mode == NM_802_11_MODE_INFRA) {
-		priv = NM_AP_GET_PRIVATE (ap);
+	priv = NM_AP_GET_PRIVATE (ap);
 
-		if (priv->mode != mode) {
-			priv->mode = mode;
-			g_object_notify (G_OBJECT (ap), NM_AP_MODE);
-		}
-	} else
-		nm_log_warn (LOGD_WIFI, "Invalid AP mode '%d'", mode);
+	if (priv->mode != mode) {
+		priv->mode = mode;
+		g_object_notify (G_OBJECT (ap), NM_AP_MODE);
+	}
 }
 
 
diff --git a/src/org.freedesktop.NetworkManager.conf b/src/org.freedesktop.NetworkManager.conf
index 15b11b7e..7df1c8e8 100644
--- a/src/org.freedesktop.NetworkManager.conf
+++ b/src/org.freedesktop.NetworkManager.conf
@@ -43,15 +43,12 @@
                        send_interface="org.freedesktop.NetworkManager.Connection.Active"/>
 
                 <allow send_destination="org.freedesktop.NetworkManager"
-                       send_interface="org.freedesktop.NetworkManager.Device.Cdma"/>
+                       send_interface="org.freedesktop.NetworkManager.Device.Modem"/>
 
                 <allow send_destination="org.freedesktop.NetworkManager"
                        send_interface="org.freedesktop.NetworkManager.Device.Wired"/>
 
                 <allow send_destination="org.freedesktop.NetworkManager"
-                       send_interface="org.freedesktop.NetworkManager.Device.Gsm"/>
-
-                <allow send_destination="org.freedesktop.NetworkManager"
                        send_interface="org.freedesktop.NetworkManager.Device.Serial"/>
 
                 <allow send_destination="org.freedesktop.NetworkManager"
@@ -115,7 +112,5 @@
                        send_interface="org.freedesktop.NetworkManager"
                        send_member="wake"/>
         </policy>
-
-        <limit name="max_replies_per_connection">512</limit>
 </busconfig>
 
diff --git a/src/posix-signals/Makefile.am b/src/posix-signals/Makefile.am
new file mode 100644
index 00000000..88c3d8d4
--- /dev/null
+++ b/src/posix-signals/Makefile.am
@@ -0,0 +1,15 @@
+noinst_LTLIBRARIES = libnm-posix-signals.la
+
+libnm_posix_signals_la_SOURCES = \
+	nm-posix-signals.c \
+	nm-posix-signals.h
+
+libnm_posix_signals_la_CPPFLAGS = \
+	$(GLIB_CFLAGS) \
+	-DLIBEXECDIR=\"$(libexecdir)\" \
+	-DG_DISABLE_DEPRECATED
+
+libnm_posix_signals_la_LIBADD = \
+	-ldl \
+	$(GLIB_LIBS)
+
diff --git a/src/posix-signals/Makefile.in b/src/posix-signals/Makefile.in
new file mode 100644
index 00000000..3cacb29f
--- /dev/null
+++ b/src/posix-signals/Makefile.in
@@ -0,0 +1,640 @@
+# Makefile.in generated by automake 1.11.1 from Makefile.am.
+# @configure_input@
+
+# Copyright (C) 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002,
+# 2003, 2004, 2005, 2006, 2007, 2008, 2009  Free Software Foundation,
+# Inc.
+# This Makefile.in is free software; the Free Software Foundation
+# gives unlimited permission to copy and/or distribute it,
+# with or without modifications, as long as this notice is preserved.
+
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY, to the extent permitted by law; without
+# even the implied warranty of MERCHANTABILITY or FITNESS FOR A
+# PARTICULAR PURPOSE.
+
+@SET_MAKE@
+
+VPATH = @srcdir@
+pkgdatadir = $(datadir)/@PACKAGE@
+pkgincludedir = $(includedir)/@PACKAGE@
+pkglibdir = $(libdir)/@PACKAGE@
+pkglibexecdir = $(libexecdir)/@PACKAGE@
+am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd
+install_sh_DATA = $(install_sh) -c -m 644
+install_sh_PROGRAM = $(install_sh) -c
+install_sh_SCRIPT = $(install_sh) -c
+INSTALL_HEADER = $(INSTALL_DATA)
+transform = $(program_transform_name)
+NORMAL_INSTALL = :
+PRE_INSTALL = :
+POST_INSTALL = :
+NORMAL_UNINSTALL = :
+PRE_UNINSTALL = :
+POST_UNINSTALL = :
+build_triplet = @build@
+host_triplet = @host@
+subdir = src/posix-signals
+DIST_COMMON = $(srcdir)/Makefile.am $(srcdir)/Makefile.in
+ACLOCAL_M4 = $(top_srcdir)/aclocal.m4
+am__aclocal_m4_deps = $(top_srcdir)/m4/compiler_warnings.m4 \
+	$(top_srcdir)/m4/gettext.m4 $(top_srcdir)/m4/gtk-doc.m4 \
+	$(top_srcdir)/m4/iconv.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
+am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \
+	$(ACLOCAL_M4)
+mkinstalldirs = $(install_sh) -d
+CONFIG_HEADER = $(top_builddir)/config.h
+CONFIG_CLEAN_FILES =
+CONFIG_CLEAN_VPATH_FILES =
+LTLIBRARIES = $(noinst_LTLIBRARIES)
+am__DEPENDENCIES_1 =
+libnm_posix_signals_la_DEPENDENCIES = $(am__DEPENDENCIES_1)
+am_libnm_posix_signals_la_OBJECTS =  \
+	libnm_posix_signals_la-nm-posix-signals.lo
+libnm_posix_signals_la_OBJECTS = $(am_libnm_posix_signals_la_OBJECTS)
+AM_V_lt = $(am__v_lt_$(V))
+am__v_lt_ = $(am__v_lt_$(AM_DEFAULT_VERBOSITY))
+am__v_lt_0 = --silent
+DEFAULT_INCLUDES = -I.@am__isrc@ -I$(top_builddir)
+depcomp = $(SHELL) $(top_srcdir)/build-aux/depcomp
+am__depfiles_maybe = depfiles
+am__mv = mv -f
+COMPILE = $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) \
+	$(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS)
+LTCOMPILE = $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) \
+	$(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) \
+	$(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) \
+	$(AM_CFLAGS) $(CFLAGS)
+AM_V_CC = $(am__v_CC_$(V))
+am__v_CC_ = $(am__v_CC_$(AM_DEFAULT_VERBOSITY))
+am__v_CC_0 = @echo "  CC    " $@;
+AM_V_at = $(am__v_at_$(V))
+am__v_at_ = $(am__v_at_$(AM_DEFAULT_VERBOSITY))
+am__v_at_0 = @
+CCLD = $(CC)
+LINK = $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) \
+	$(LIBTOOLFLAGS) --mode=link $(CCLD) $(AM_CFLAGS) $(CFLAGS) \
+	$(AM_LDFLAGS) $(LDFLAGS) -o $@
+AM_V_CCLD = $(am__v_CCLD_$(V))
+am__v_CCLD_ = $(am__v_CCLD_$(AM_DEFAULT_VERBOSITY))
+am__v_CCLD_0 = @echo "  CCLD  " $@;
+AM_V_GEN = $(am__v_GEN_$(V))
+am__v_GEN_ = $(am__v_GEN_$(AM_DEFAULT_VERBOSITY))
+am__v_GEN_0 = @echo "  GEN   " $@;
+SOURCES = $(libnm_posix_signals_la_SOURCES)
+DIST_SOURCES = $(libnm_posix_signals_la_SOURCES)
+ETAGS = etags
+CTAGS = ctags
+DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST)
+ACLOCAL = @ACLOCAL@
+ALL_LINGUAS = @ALL_LINGUAS@
+AMTAR = @AMTAR@
+AM_DEFAULT_VERBOSITY = @AM_DEFAULT_VERBOSITY@
+AR = @AR@
+AUTOCONF = @AUTOCONF@
+AUTOHEADER = @AUTOHEADER@
+AUTOMAKE = @AUTOMAKE@
+AWK = @AWK@
+CC = @CC@
+CCDEPMODE = @CCDEPMODE@
+CFLAGS = @CFLAGS@
+CPP = @CPP@
+CPPFLAGS = @CPPFLAGS@
+CXX = @CXX@
+CXXCPP = @CXXCPP@
+CXXDEPMODE = @CXXDEPMODE@
+CXXFLAGS = @CXXFLAGS@
+CYGPATH_W = @CYGPATH_W@
+DATADIRNAME = @DATADIRNAME@
+DBUS_CFLAGS = @DBUS_CFLAGS@
+DBUS_LIBS = @DBUS_LIBS@
+DBUS_SYS_DIR = @DBUS_SYS_DIR@
+DEFS = @DEFS@
+DEPDIR = @DEPDIR@
+DHCLIENT_PATH = @DHCLIENT_PATH@
+DHCLIENT_VERSION = @DHCLIENT_VERSION@
+DHCPCD_PATH = @DHCPCD_PATH@
+DISABLE_DEPRECATED = @DISABLE_DEPRECATED@
+DLLTOOL = @DLLTOOL@
+DSYMUTIL = @DSYMUTIL@
+DUMPBIN = @DUMPBIN@
+ECHO_C = @ECHO_C@
+ECHO_N = @ECHO_N@
+ECHO_T = @ECHO_T@
+EGREP = @EGREP@
+EXEEXT = @EXEEXT@
+FGREP = @FGREP@
+GETTEXT_MACRO_VERSION = @GETTEXT_MACRO_VERSION@
+GETTEXT_PACKAGE = @GETTEXT_PACKAGE@
+GIO_CFLAGS = @GIO_CFLAGS@
+GIO_LIBS = @GIO_LIBS@
+GLIB_CFLAGS = @GLIB_CFLAGS@
+GLIB_GENMARSHAL = @GLIB_GENMARSHAL@
+GLIB_LIBS = @GLIB_LIBS@
+GLIB_MAKEFILE = @GLIB_MAKEFILE@
+GLIB_MKENUMS = @GLIB_MKENUMS@
+GMODULE_CFLAGS = @GMODULE_CFLAGS@
+GMODULE_LIBS = @GMODULE_LIBS@
+GMSGFMT = @GMSGFMT@
+GMSGFMT_015 = @GMSGFMT_015@
+GNUTLS_CFLAGS = @GNUTLS_CFLAGS@
+GNUTLS_LIBS = @GNUTLS_LIBS@
+GREP = @GREP@
+GTKDOC_CHECK = @GTKDOC_CHECK@
+GTKDOC_DEPS_CFLAGS = @GTKDOC_DEPS_CFLAGS@
+GTKDOC_DEPS_LIBS = @GTKDOC_DEPS_LIBS@
+GTKDOC_MKPDF = @GTKDOC_MKPDF@
+GTKDOC_REBASE = @GTKDOC_REBASE@
+GUDEV_CFLAGS = @GUDEV_CFLAGS@
+GUDEV_LIBS = @GUDEV_LIBS@
+HTML_DIR = @HTML_DIR@
+INSTALL = @INSTALL@
+INSTALL_DATA = @INSTALL_DATA@
+INSTALL_PROGRAM = @INSTALL_PROGRAM@
+INSTALL_SCRIPT = @INSTALL_SCRIPT@
+INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@
+INTLLIBS = @INTLLIBS@
+INTLTOOL_EXTRACT = @INTLTOOL_EXTRACT@
+INTLTOOL_MERGE = @INTLTOOL_MERGE@
+INTLTOOL_PERL = @INTLTOOL_PERL@
+INTLTOOL_UPDATE = @INTLTOOL_UPDATE@
+INTLTOOL_V_MERGE = @INTLTOOL_V_MERGE@
+INTLTOOL_V_MERGE_OPTIONS = @INTLTOOL_V_MERGE_OPTIONS@
+INTLTOOL__v_MERGE_ = @INTLTOOL__v_MERGE_@
+INTLTOOL__v_MERGE_0 = @INTLTOOL__v_MERGE_0@
+INTL_MACOSX_LIBS = @INTL_MACOSX_LIBS@
+INTROSPECTION_CFLAGS = @INTROSPECTION_CFLAGS@
+INTROSPECTION_COMPILER = @INTROSPECTION_COMPILER@
+INTROSPECTION_GENERATE = @INTROSPECTION_GENERATE@
+INTROSPECTION_GIRDIR = @INTROSPECTION_GIRDIR@
+INTROSPECTION_LIBS = @INTROSPECTION_LIBS@
+INTROSPECTION_MAKEFILE = @INTROSPECTION_MAKEFILE@
+INTROSPECTION_SCANNER = @INTROSPECTION_SCANNER@
+INTROSPECTION_TYPELIBDIR = @INTROSPECTION_TYPELIBDIR@
+IPTABLES_PATH = @IPTABLES_PATH@
+IWMX_SDK_CFLAGS = @IWMX_SDK_CFLAGS@
+IWMX_SDK_LIBS = @IWMX_SDK_LIBS@
+KERNEL_FIRMWARE_DIR = @KERNEL_FIRMWARE_DIR@
+LD = @LD@
+LDFLAGS = @LDFLAGS@
+LIBDL = @LIBDL@
+LIBGCRYPT_CFLAGS = @LIBGCRYPT_CFLAGS@
+LIBGCRYPT_CONFIG = @LIBGCRYPT_CONFIG@
+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_GENL3_CFLAGS = @LIBNL_GENL3_CFLAGS@
+LIBNL_GENL3_LIBS = @LIBNL_GENL3_LIBS@
+LIBNL_LIBS = @LIBNL_LIBS@
+LIBNL_ROUTE3_CFLAGS = @LIBNL_ROUTE3_CFLAGS@
+LIBNL_ROUTE3_LIBS = @LIBNL_ROUTE3_LIBS@
+LIBOBJS = @LIBOBJS@
+LIBS = @LIBS@
+LIBSOUP_CFLAGS = @LIBSOUP_CFLAGS@
+LIBSOUP_LIBS = @LIBSOUP_LIBS@
+LIBTOOL = @LIBTOOL@
+LIPO = @LIPO@
+LN_S = @LN_S@
+LTLIBICONV = @LTLIBICONV@
+LTLIBINTL = @LTLIBINTL@
+LTLIBOBJS = @LTLIBOBJS@
+MAINT = @MAINT@
+MAKEINFO = @MAKEINFO@
+MANIFEST_TOOL = @MANIFEST_TOOL@
+MKDIR_P = @MKDIR_P@
+MOC = @MOC@
+MSGFMT = @MSGFMT@
+MSGFMT_015 = @MSGFMT_015@
+MSGMERGE = @MSGMERGE@
+NM = @NM@
+NMEDIT = @NMEDIT@
+NM_MAJOR_VERSION = @NM_MAJOR_VERSION@
+NM_MICRO_VERSION = @NM_MICRO_VERSION@
+NM_MINOR_VERSION = @NM_MINOR_VERSION@
+NM_VERSION = @NM_VERSION@
+NSS_CFLAGS = @NSS_CFLAGS@
+NSS_LIBS = @NSS_LIBS@
+OBJDUMP = @OBJDUMP@
+OBJEXT = @OBJEXT@
+OTOOL = @OTOOL@
+OTOOL64 = @OTOOL64@
+PACKAGE = @PACKAGE@
+PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@
+PACKAGE_NAME = @PACKAGE_NAME@
+PACKAGE_STRING = @PACKAGE_STRING@
+PACKAGE_TARNAME = @PACKAGE_TARNAME@
+PACKAGE_URL = @PACKAGE_URL@
+PACKAGE_VERSION = @PACKAGE_VERSION@
+PATH_SEPARATOR = @PATH_SEPARATOR@
+PKGCONFIG_PATH = @PKGCONFIG_PATH@
+PKG_CONFIG = @PKG_CONFIG@
+PKG_CONFIG_LIBDIR = @PKG_CONFIG_LIBDIR@
+PKG_CONFIG_PATH = @PKG_CONFIG_PATH@
+POLKIT_CFLAGS = @POLKIT_CFLAGS@
+POLKIT_LIBS = @POLKIT_LIBS@
+POSUB = @POSUB@
+PPPD_PLUGIN_DIR = @PPPD_PLUGIN_DIR@
+QT_CFLAGS = @QT_CFLAGS@
+QT_LIBS = @QT_LIBS@
+RANLIB = @RANLIB@
+RESOLVCONF_PATH = @RESOLVCONF_PATH@
+SED = @SED@
+SET_MAKE = @SET_MAKE@
+SHELL = @SHELL@
+STRIP = @STRIP@
+SYSTEMD_CFLAGS = @SYSTEMD_CFLAGS@
+SYSTEMD_LIBS = @SYSTEMD_LIBS@
+SYSTEM_CA_PATH = @SYSTEM_CA_PATH@
+UDEV_BASE_DIR = @UDEV_BASE_DIR@
+USE_NLS = @USE_NLS@
+UUID_CFLAGS = @UUID_CFLAGS@
+UUID_LIBS = @UUID_LIBS@
+VAPIGEN = @VAPIGEN@
+VAPIGEN_MAKEFILE = @VAPIGEN_MAKEFILE@
+VAPIGEN_VAPIDIR = @VAPIGEN_VAPIDIR@
+VERSION = @VERSION@
+XGETTEXT = @XGETTEXT@
+XGETTEXT_015 = @XGETTEXT_015@
+XGETTEXT_EXTRA_OPTIONS = @XGETTEXT_EXTRA_OPTIONS@
+abs_builddir = @abs_builddir@
+abs_srcdir = @abs_srcdir@
+abs_top_builddir = @abs_top_builddir@
+abs_top_srcdir = @abs_top_srcdir@
+ac_ct_AR = @ac_ct_AR@
+ac_ct_CC = @ac_ct_CC@
+ac_ct_CXX = @ac_ct_CXX@
+ac_ct_DUMPBIN = @ac_ct_DUMPBIN@
+am__include = @am__include@
+am__leading_dot = @am__leading_dot@
+am__quote = @am__quote@
+am__tar = @am__tar@
+am__untar = @am__untar@
+bindir = @bindir@
+build = @build@
+build_alias = @build_alias@
+build_cpu = @build_cpu@
+build_os = @build_os@
+build_vendor = @build_vendor@
+builddir = @builddir@
+datadir = @datadir@
+datarootdir = @datarootdir@
+docdir = @docdir@
+dvidir = @dvidir@
+exec_prefix = @exec_prefix@
+host = @host@
+host_alias = @host_alias@
+host_cpu = @host_cpu@
+host_os = @host_os@
+host_vendor = @host_vendor@
+htmldir = @htmldir@
+includedir = @includedir@
+infodir = @infodir@
+install_sh = @install_sh@
+intltool__v_merge_options_ = @intltool__v_merge_options_@
+intltool__v_merge_options_0 = @intltool__v_merge_options_0@
+libdir = @libdir@
+libexecdir = @libexecdir@
+localedir = @localedir@
+localstatedir = @localstatedir@
+mandir = @mandir@
+mkdir_p = @mkdir_p@
+oldincludedir = @oldincludedir@
+pdfdir = @pdfdir@
+prefix = @prefix@
+program_transform_name = @program_transform_name@
+psdir = @psdir@
+sbindir = @sbindir@
+sharedstatedir = @sharedstatedir@
+srcdir = @srcdir@
+sysconfdir = @sysconfdir@
+systemdsystemunitdir = @systemdsystemunitdir@
+target_alias = @target_alias@
+top_build_prefix = @top_build_prefix@
+top_builddir = @top_builddir@
+top_srcdir = @top_srcdir@
+noinst_LTLIBRARIES = libnm-posix-signals.la
+libnm_posix_signals_la_SOURCES = \
+	nm-posix-signals.c \
+	nm-posix-signals.h
+
+libnm_posix_signals_la_CPPFLAGS = \
+	$(GLIB_CFLAGS) \
+	-DLIBEXECDIR=\"$(libexecdir)\" \
+	-DG_DISABLE_DEPRECATED
+
+libnm_posix_signals_la_LIBADD = \
+	-ldl \
+	$(GLIB_LIBS)
+
+all: all-am
+
+.SUFFIXES:
+.SUFFIXES: .c .lo .o .obj
+$(srcdir)/Makefile.in: @MAINTAINER_MODE_TRUE@ $(srcdir)/Makefile.am  $(am__configure_deps)
+	@for dep in $?; do \
+	  case '$(am__configure_deps)' in \
+	    *$$dep*) \
+	      ( cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh ) \
+	        && { if test -f $@; then exit 0; else break; fi; }; \
+	      exit 1;; \
+	  esac; \
+	done; \
+	echo ' cd $(top_srcdir) && $(AUTOMAKE) --gnu src/posix-signals/Makefile'; \
+	$(am__cd) $(top_srcdir) && \
+	  $(AUTOMAKE) --gnu src/posix-signals/Makefile
+.PRECIOUS: Makefile
+Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status
+	@case '$?' in \
+	  *config.status*) \
+	    cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh;; \
+	  *) \
+	    echo ' cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe)'; \
+	    cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe);; \
+	esac;
+
+$(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES)
+	cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+
+$(top_srcdir)/configure: @MAINTAINER_MODE_TRUE@ $(am__configure_deps)
+	cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+$(ACLOCAL_M4): @MAINTAINER_MODE_TRUE@ $(am__aclocal_m4_deps)
+	cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+$(am__aclocal_m4_deps):
+
+clean-noinstLTLIBRARIES:
+	-test -z "$(noinst_LTLIBRARIES)" || rm -f $(noinst_LTLIBRARIES)
+	@list='$(noinst_LTLIBRARIES)'; for p in $$list; do \
+	  dir="`echo $$p | sed -e 's|/[^/]*$$||'`"; \
+	  test "$$dir" != "$$p" || dir=.; \
+	  echo "rm -f \"$${dir}/so_locations\""; \
+	  rm -f "$${dir}/so_locations"; \
+	done
+libnm-posix-signals.la: $(libnm_posix_signals_la_OBJECTS) $(libnm_posix_signals_la_DEPENDENCIES) 
+	$(AM_V_CCLD)$(LINK)  $(libnm_posix_signals_la_OBJECTS) $(libnm_posix_signals_la_LIBADD) $(LIBS)
+
+mostlyclean-compile:
+	-rm -f *.$(OBJEXT)
+
+distclean-compile:
+	-rm -f *.tab.c
+
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libnm_posix_signals_la-nm-posix-signals.Plo@am__quote@
+
+.c.o:
+@am__fastdepCC_TRUE@	$(AM_V_CC)depbase=`echo $@ | sed 's|[^/]*$$|$(DEPDIR)/&|;s|\.o$$||'`;\
+@am__fastdepCC_TRUE@	$(COMPILE) -MT $@ -MD -MP -MF $$depbase.Tpo -c -o $@ $< &&\
+@am__fastdepCC_TRUE@	$(am__mv) $$depbase.Tpo $$depbase.Po
+@am__fastdepCC_FALSE@	$(AM_V_CC) @AM_BACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@	source='$<' object='$@' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@	DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@	$(COMPILE) -c -o $@ $<
+
+.c.obj:
+@am__fastdepCC_TRUE@	$(AM_V_CC)depbase=`echo $@ | sed 's|[^/]*$$|$(DEPDIR)/&|;s|\.obj$$||'`;\
+@am__fastdepCC_TRUE@	$(COMPILE) -MT $@ -MD -MP -MF $$depbase.Tpo -c -o $@ `$(CYGPATH_W) '$<'` &&\
+@am__fastdepCC_TRUE@	$(am__mv) $$depbase.Tpo $$depbase.Po
+@am__fastdepCC_FALSE@	$(AM_V_CC) @AM_BACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@	source='$<' object='$@' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@	DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@	$(COMPILE) -c -o $@ `$(CYGPATH_W) '$<'`
+
+.c.lo:
+@am__fastdepCC_TRUE@	$(AM_V_CC)depbase=`echo $@ | sed 's|[^/]*$$|$(DEPDIR)/&|;s|\.lo$$||'`;\
+@am__fastdepCC_TRUE@	$(LTCOMPILE) -MT $@ -MD -MP -MF $$depbase.Tpo -c -o $@ $< &&\
+@am__fastdepCC_TRUE@	$(am__mv) $$depbase.Tpo $$depbase.Plo
+@am__fastdepCC_FALSE@	$(AM_V_CC) @AM_BACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@	source='$<' object='$@' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@	DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@	$(LTCOMPILE) -c -o $@ $<
+
+libnm_posix_signals_la-nm-posix-signals.lo: nm-posix-signals.c
+@am__fastdepCC_TRUE@	$(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libnm_posix_signals_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT libnm_posix_signals_la-nm-posix-signals.lo -MD -MP -MF $(DEPDIR)/libnm_posix_signals_la-nm-posix-signals.Tpo -c -o libnm_posix_signals_la-nm-posix-signals.lo `test -f 'nm-posix-signals.c' || echo '$(srcdir)/'`nm-posix-signals.c
+@am__fastdepCC_TRUE@	$(AM_V_at)$(am__mv) $(DEPDIR)/libnm_posix_signals_la-nm-posix-signals.Tpo $(DEPDIR)/libnm_posix_signals_la-nm-posix-signals.Plo
+@am__fastdepCC_FALSE@	$(AM_V_CC) @AM_BACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@	source='nm-posix-signals.c' object='libnm_posix_signals_la-nm-posix-signals.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@	DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@	$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libnm_posix_signals_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o libnm_posix_signals_la-nm-posix-signals.lo `test -f 'nm-posix-signals.c' || echo '$(srcdir)/'`nm-posix-signals.c
+
+mostlyclean-libtool:
+	-rm -f *.lo
+
+clean-libtool:
+	-rm -rf .libs _libs
+
+ID: $(HEADERS) $(SOURCES) $(LISP) $(TAGS_FILES)
+	list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \
+	unique=`for i in $$list; do \
+	    if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \
+	  done | \
+	  $(AWK) '{ files[$$0] = 1; nonempty = 1; } \
+	      END { if (nonempty) { for (i in files) print i; }; }'`; \
+	mkid -fID $$unique
+tags: TAGS
+
+TAGS:  $(HEADERS) $(SOURCES)  $(TAGS_DEPENDENCIES) \
+		$(TAGS_FILES) $(LISP)
+	set x; \
+	here=`pwd`; \
+	list='$(SOURCES) $(HEADERS)  $(LISP) $(TAGS_FILES)'; \
+	unique=`for i in $$list; do \
+	    if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \
+	  done | \
+	  $(AWK) '{ files[$$0] = 1; nonempty = 1; } \
+	      END { if (nonempty) { for (i in files) print i; }; }'`; \
+	shift; \
+	if test -z "$(ETAGS_ARGS)$$*$$unique"; then :; else \
+	  test -n "$$unique" || unique=$$empty_fix; \
+	  if test $$# -gt 0; then \
+	    $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \
+	      "$$@" $$unique; \
+	  else \
+	    $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \
+	      $$unique; \
+	  fi; \
+	fi
+ctags: CTAGS
+CTAGS:  $(HEADERS) $(SOURCES)  $(TAGS_DEPENDENCIES) \
+		$(TAGS_FILES) $(LISP)
+	list='$(SOURCES) $(HEADERS)  $(LISP) $(TAGS_FILES)'; \
+	unique=`for i in $$list; do \
+	    if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \
+	  done | \
+	  $(AWK) '{ files[$$0] = 1; nonempty = 1; } \
+	      END { if (nonempty) { for (i in files) print i; }; }'`; \
+	test -z "$(CTAGS_ARGS)$$unique" \
+	  || $(CTAGS) $(CTAGSFLAGS) $(AM_CTAGSFLAGS) $(CTAGS_ARGS) \
+	     $$unique
+
+GTAGS:
+	here=`$(am__cd) $(top_builddir) && pwd` \
+	  && $(am__cd) $(top_srcdir) \
+	  && gtags -i $(GTAGS_ARGS) "$$here"
+
+distclean-tags:
+	-rm -f TAGS ID GTAGS GRTAGS GSYMS GPATH tags
+
+distdir: $(DISTFILES)
+	@srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \
+	topsrcdirstrip=`echo "$(top_srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \
+	list='$(DISTFILES)'; \
+	  dist_files=`for file in $$list; do echo $$file; done | \
+	  sed -e "s|^$$srcdirstrip/||;t" \
+	      -e "s|^$$topsrcdirstrip/|$(top_builddir)/|;t"`; \
+	case $$dist_files in \
+	  */*) $(MKDIR_P) `echo "$$dist_files" | \
+			   sed '/\//!d;s|^|$(distdir)/|;s,/[^/]*$$,,' | \
+			   sort -u` ;; \
+	esac; \
+	for file in $$dist_files; do \
+	  if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \
+	  if test -d $$d/$$file; then \
+	    dir=`echo "/$$file" | sed -e 's,/[^/]*$$,,'`; \
+	    if test -d "$(distdir)/$$file"; then \
+	      find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \
+	    fi; \
+	    if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \
+	      cp -fpR $(srcdir)/$$file "$(distdir)$$dir" || exit 1; \
+	      find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \
+	    fi; \
+	    cp -fpR $$d/$$file "$(distdir)$$dir" || exit 1; \
+	  else \
+	    test -f "$(distdir)/$$file" \
+	    || cp -p $$d/$$file "$(distdir)/$$file" \
+	    || exit 1; \
+	  fi; \
+	done
+check-am: all-am
+check: check-am
+all-am: Makefile $(LTLIBRARIES)
+installdirs:
+install: install-am
+install-exec: install-exec-am
+install-data: install-data-am
+uninstall: uninstall-am
+
+install-am: all-am
+	@$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am
+
+installcheck: installcheck-am
+install-strip:
+	$(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \
+	  install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \
+	  `test -z '$(STRIP)' || \
+	    echo "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'"` install
+mostlyclean-generic:
+
+clean-generic:
+
+distclean-generic:
+	-test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES)
+	-test . = "$(srcdir)" || test -z "$(CONFIG_CLEAN_VPATH_FILES)" || rm -f $(CONFIG_CLEAN_VPATH_FILES)
+
+maintainer-clean-generic:
+	@echo "This command is intended for maintainers to use"
+	@echo "it deletes files that may require special tools to rebuild."
+clean: clean-am
+
+clean-am: clean-generic clean-libtool clean-noinstLTLIBRARIES \
+	mostlyclean-am
+
+distclean: distclean-am
+	-rm -rf ./$(DEPDIR)
+	-rm -f Makefile
+distclean-am: clean-am distclean-compile distclean-generic \
+	distclean-tags
+
+dvi: dvi-am
+
+dvi-am:
+
+html: html-am
+
+html-am:
+
+info: info-am
+
+info-am:
+
+install-data-am:
+
+install-dvi: install-dvi-am
+
+install-dvi-am:
+
+install-exec-am:
+
+install-html: install-html-am
+
+install-html-am:
+
+install-info: install-info-am
+
+install-info-am:
+
+install-man:
+
+install-pdf: install-pdf-am
+
+install-pdf-am:
+
+install-ps: install-ps-am
+
+install-ps-am:
+
+installcheck-am:
+
+maintainer-clean: maintainer-clean-am
+	-rm -rf ./$(DEPDIR)
+	-rm -f Makefile
+maintainer-clean-am: distclean-am maintainer-clean-generic
+
+mostlyclean: mostlyclean-am
+
+mostlyclean-am: mostlyclean-compile mostlyclean-generic \
+	mostlyclean-libtool
+
+pdf: pdf-am
+
+pdf-am:
+
+ps: ps-am
+
+ps-am:
+
+uninstall-am:
+
+.MAKE: install-am install-strip
+
+.PHONY: CTAGS GTAGS all all-am check check-am clean clean-generic \
+	clean-libtool clean-noinstLTLIBRARIES ctags distclean \
+	distclean-compile distclean-generic distclean-libtool \
+	distclean-tags distdir dvi dvi-am html html-am info info-am \
+	install install-am install-data install-data-am install-dvi \
+	install-dvi-am install-exec 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-strip installcheck installcheck-am installdirs \
+	maintainer-clean maintainer-clean-generic mostlyclean \
+	mostlyclean-compile mostlyclean-generic mostlyclean-libtool \
+	pdf pdf-am ps ps-am tags uninstall uninstall-am
+
+
+# Tell versions [3.59,3.63) of GNU make to not export all variables.
+# Otherwise a system limit (for SysV at least) may be exceeded.
+.NOEXPORT:
diff --git a/src/posix-signals/nm-posix-signals.c b/src/posix-signals/nm-posix-signals.c
new file mode 100644
index 00000000..22fed831
--- /dev/null
+++ b/src/posix-signals/nm-posix-signals.c
@@ -0,0 +1,62 @@
+/* -*- 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) 2012 Red Hat, Inc.
+ */
+
+#include "config.h"
+
+#include <signal.h>
+
+#include "nm-posix-signals.h"
+
+
+/* Stores the original signal mask of NetworkManager process */
+static sigset_t nm_original_signal_mask;
+
+void
+nm_save_original_signal_mask (sigset_t sig_mask)
+{
+	nm_original_signal_mask = sig_mask;
+}
+
+const sigset_t *
+nm_get_original_signal_mask (void)
+{
+	return &nm_original_signal_mask;
+}
+
+/* 
+ * Unblock signals.
+ * If a signal set is passed, those signals are unblocked. If user_data is NULL
+ * the process' signal mask is set to the saved original mask.
+ * Note: This function can be used in g_spawn_* as GSpawnChildSetupFunc()
+ *       callback.
+ */
+void
+nm_unblock_posix_signals (gpointer user_data)
+{
+	sigset_t *user_sigset = (sigset_t *) user_data;
+
+	if (user_sigset != NULL) {
+		pthread_sigmask (SIG_UNBLOCK, user_sigset, NULL);
+	} else {
+		const sigset_t *orig_sig_mask = nm_get_original_signal_mask ();
+		pthread_sigmask (SIG_SETMASK, orig_sig_mask, NULL);
+	}
+}
+
diff --git a/src/posix-signals/nm-posix-signals.h b/src/posix-signals/nm-posix-signals.h
new file mode 100644
index 00000000..81be5e1c
--- /dev/null
+++ b/src/posix-signals/nm-posix-signals.h
@@ -0,0 +1,36 @@
+/* -*- 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) 2012 Red Hat, Inc.
+ */
+
+#ifndef NM_POSIX_SIGNALS_H
+#define NM_POSIX_SIGNALS_H
+
+#include <glib.h>
+#include <signal.h>
+
+/*
+ * This function can be used in g_spawn_* as GSpawnChildSetupFunc()
+ * callback.
+ */
+void nm_unblock_posix_signals (gpointer user_data);
+
+void nm_save_original_signal_mask (sigset_t sig_mask);
+const sigset_t *nm_get_original_signal_mask (void);
+
+#endif /* NM_POSIX_SIGNALS_H */
diff --git a/src/ppp-manager/Makefile.am b/src/ppp-manager/Makefile.am
index 8df2f584..36e54ec9 100644
--- a/src/ppp-manager/Makefile.am
+++ b/src/ppp-manager/Makefile.am
@@ -7,7 +7,8 @@ INCLUDES = \
 	-I${top_srcdir}/src \
 	-I${top_srcdir}/src/generated \
 	-I${top_builddir}/src/generated \
-	-I${top_srcdir}/src/logging
+	-I${top_srcdir}/src/logging \
+	-I${top_srcdir}/src/posix-signals
 
 noinst_LTLIBRARIES = libppp-manager.la
 
@@ -33,6 +34,7 @@ libppp_manager_la_CPPFLAGS = \
 libppp_manager_la_LIBADD = \
 	$(top_builddir)/src/generated/libnm-generated.la \
 	$(top_builddir)/src/logging/libnm-logging.la \
+	$(top_builddir)/src/posix-signals/libnm-posix-signals.la \
 	$(DBUS_LIBS) \
 	$(GLIB_LIBS)
 
diff --git a/src/ppp-manager/Makefile.in b/src/ppp-manager/Makefile.in
index 55355a7d..c9ff095a 100644
--- a/src/ppp-manager/Makefile.in
+++ b/src/ppp-manager/Makefile.in
@@ -47,7 +47,7 @@ am__aclocal_m4_deps = $(top_srcdir)/m4/compiler_warnings.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)/configure.ac
+	$(top_srcdir)/m4/vapigen.m4 $(top_srcdir)/configure.ac
 am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \
 	$(ACLOCAL_M4)
 mkinstalldirs = $(install_sh) -d
@@ -81,6 +81,7 @@ am__DEPENDENCIES_1 =
 libppp_manager_la_DEPENDENCIES =  \
 	$(top_builddir)/src/generated/libnm-generated.la \
 	$(top_builddir)/src/logging/libnm-logging.la \
+	$(top_builddir)/src/posix-signals/libnm-posix-signals.la \
 	$(am__DEPENDENCIES_1) $(am__DEPENDENCIES_1)
 am_libppp_manager_la_OBJECTS = libppp_manager_la-nm-ppp-manager.lo
 libppp_manager_la_OBJECTS = $(am_libppp_manager_la_OBJECTS)
@@ -204,6 +205,10 @@ INTLTOOL_EXTRACT = @INTLTOOL_EXTRACT@
 INTLTOOL_MERGE = @INTLTOOL_MERGE@
 INTLTOOL_PERL = @INTLTOOL_PERL@
 INTLTOOL_UPDATE = @INTLTOOL_UPDATE@
+INTLTOOL_V_MERGE = @INTLTOOL_V_MERGE@
+INTLTOOL_V_MERGE_OPTIONS = @INTLTOOL_V_MERGE_OPTIONS@
+INTLTOOL__v_MERGE_ = @INTLTOOL__v_MERGE_@
+INTLTOOL__v_MERGE_0 = @INTLTOOL__v_MERGE_0@
 INTL_MACOSX_LIBS = @INTL_MACOSX_LIBS@
 INTROSPECTION_CFLAGS = @INTROSPECTION_CFLAGS@
 INTROSPECTION_COMPILER = @INTROSPECTION_COMPILER@
@@ -299,6 +304,9 @@ UDEV_BASE_DIR = @UDEV_BASE_DIR@
 USE_NLS = @USE_NLS@
 UUID_CFLAGS = @UUID_CFLAGS@
 UUID_LIBS = @UUID_LIBS@
+VAPIGEN = @VAPIGEN@
+VAPIGEN_MAKEFILE = @VAPIGEN_MAKEFILE@
+VAPIGEN_VAPIDIR = @VAPIGEN_VAPIDIR@
 VERSION = @VERSION@
 XGETTEXT = @XGETTEXT@
 XGETTEXT_015 = @XGETTEXT_015@
@@ -337,6 +345,8 @@ htmldir = @htmldir@
 includedir = @includedir@
 infodir = @infodir@
 install_sh = @install_sh@
+intltool__v_merge_options_ = @intltool__v_merge_options_@
+intltool__v_merge_options_0 = @intltool__v_merge_options_0@
 libdir = @libdir@
 libexecdir = @libexecdir@
 localedir = @localedir@
@@ -366,7 +376,8 @@ INCLUDES = \
 	-I${top_srcdir}/src \
 	-I${top_srcdir}/src/generated \
 	-I${top_builddir}/src/generated \
-	-I${top_srcdir}/src/logging
+	-I${top_srcdir}/src/logging \
+	-I${top_srcdir}/src/posix-signals
 
 noinst_LTLIBRARIES = libppp-manager.la
 libppp_manager_la_SOURCES = \
@@ -385,6 +396,7 @@ libppp_manager_la_CPPFLAGS = \
 libppp_manager_la_LIBADD = \
 	$(top_builddir)/src/generated/libnm-generated.la \
 	$(top_builddir)/src/logging/libnm-logging.la \
+	$(top_builddir)/src/posix-signals/libnm-posix-signals.la \
 	$(DBUS_LIBS) \
 	$(GLIB_LIBS)
 
diff --git a/src/ppp-manager/nm-ppp-manager.c b/src/ppp-manager/nm-ppp-manager.c
index 59698c34..73cc566f 100644
--- a/src/ppp-manager/nm-ppp-manager.c
+++ b/src/ppp-manager/nm-ppp-manager.c
@@ -16,7 +16,7 @@
  * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
  *
  * Copyright (C) 2008 Novell, Inc.
- * Copyright (C) 2008 - 2011 Red Hat, Inc.
+ * Copyright (C) 2008 - 2012 Red Hat, Inc.
  */
 
 #include <config.h>
@@ -47,11 +47,13 @@
 #include "nm-setting-connection.h"
 #include "nm-setting-ppp.h"
 #include "nm-setting-pppoe.h"
+#include "nm-setting-adsl.h"
 #include "nm-setting-gsm.h"
 #include "nm-setting-cdma.h"
 #include "nm-dbus-manager.h"
 #include "nm-logging.h"
 #include "nm-marshal.h"
+#include "nm-posix-signals.h"
 
 static void impl_ppp_manager_need_secrets (NMPPPManager *manager,
                                            DBusGMethodInvocation *context);
@@ -304,18 +306,20 @@ monitor_cb (gpointer user_data)
 {
 	NMPPPManager *manager = NM_PPP_MANAGER (user_data);
 	NMPPPManagerPrivate *priv = NM_PPP_MANAGER_GET_PRIVATE (manager);
-	struct ifpppstatsreq req;
+	struct ifreq req;
+	struct ppp_stats stats;
 
 	memset (&req, 0, sizeof (req));
-	req.stats_ptr = (caddr_t) &req.stats;
+	memset (&stats, 0, sizeof (stats));
+	req.ifr_data = (caddr_t) &stats;
 
-	strncpy (req.ifr__name, priv->ip_iface, sizeof (req.ifr__name));
+	strncpy (req.ifr_name, priv->ip_iface, sizeof (req.ifr_name));
 	if (ioctl (priv->monitor_fd, SIOCGPPPSTATS, &req) < 0) {
 		nm_log_warn (LOGD_PPP, "could not read ppp stats: %s", strerror (errno));
 	} else {
 		g_signal_emit (manager, signals[STATS], 0, 
-		               req.stats.p.ppp_ibytes,
-		               req.stats.p.ppp_obytes);
+		               stats.p.ppp_ibytes,
+		               stats.p.ppp_obytes);
 	}
 
 	return TRUE;
@@ -391,6 +395,9 @@ extract_details_from_connection (NMConnection *connection,
 	if (NM_IS_SETTING_PPPOE (setting)) {
 		*username = nm_setting_pppoe_get_username (NM_SETTING_PPPOE (setting));
 		*password = nm_setting_pppoe_get_password (NM_SETTING_PPPOE (setting));
+	} else if (NM_IS_SETTING_ADSL (setting)) {
+		*username = nm_setting_adsl_get_username (NM_SETTING_ADSL (setting));
+		*password = nm_setting_adsl_get_password (NM_SETTING_ADSL (setting));
 	} else if (NM_IS_SETTING_GSM (setting)) {
 		*username = nm_setting_gsm_get_username (NM_SETTING_GSM (setting));
 		*password = nm_setting_gsm_get_password (NM_SETTING_GSM (setting));
@@ -792,6 +799,7 @@ static NMCmdLine *
 create_pppd_cmd_line (NMPPPManager *self,
                       NMSettingPPP *setting, 
                       NMSettingPPPOE *pppoe,
+                      NMSettingAdsl  *adsl,
                       const char *ppp_name,
                       GError **err)
 {
@@ -819,6 +827,10 @@ create_pppd_cmd_line (NMPPPManager *self,
 	/* NM handles setting the default route */
 	nm_cmd_line_add_string (cmd, "nodefaultroute");
 
+	/* Allow IPv6 to be configured by IPV6CP */
+	nm_cmd_line_add_string (cmd, "ipv6");
+	nm_cmd_line_add_string (cmd, ",");
+
 	ppp_debug = !!getenv ("NM_PPP_DEBUG");
 	if (   nm_logging_level_enabled (LOGL_DEBUG)
 	    && nm_logging_domain_enabled (LOGD_PPP))
@@ -848,6 +860,34 @@ create_pppd_cmd_line (NMPPPManager *self,
 			nm_cmd_line_add_string (cmd, "rp_pppoe_service");
 			nm_cmd_line_add_string (cmd, pppoe_service);
 		}
+	} else if (adsl) {
+		const gchar *protocol = nm_setting_adsl_get_protocol (adsl);
+
+		if (!strcmp (protocol, NM_SETTING_ADSL_PROTOCOL_PPPOA)) {
+			guint32 vpi = nm_setting_adsl_get_vpi (adsl);
+			guint32 vci = nm_setting_adsl_get_vci (adsl);
+			const char *encaps = nm_setting_adsl_get_encapsulation (adsl);
+			gchar *vpivci;
+
+			nm_cmd_line_add_string (cmd, "plugin");
+			nm_cmd_line_add_string (cmd, "pppoatm.so");
+
+			vpivci = g_strdup_printf("%d.%d", vpi, vci);
+			nm_cmd_line_add_string (cmd, vpivci);
+			g_free (vpivci);
+
+			if (g_strcmp0 (encaps, NM_SETTING_ADSL_ENCAPSULATION_LLC) == 0)
+				nm_cmd_line_add_string (cmd, "llc-encaps");
+			else if (g_strcmp0 (encaps, NM_SETTING_ADSL_ENCAPSULATION_VCMUX) == 0)
+				nm_cmd_line_add_string (cmd, "vc-encaps");
+
+		} else if (!strcmp (protocol, NM_SETTING_ADSL_PROTOCOL_PPPOE)) {
+			nm_cmd_line_add_string (cmd, "plugin");
+			nm_cmd_line_add_string (cmd, "rp-pppoe.so");
+			nm_cmd_line_add_string (cmd, priv->parent_iface);
+		}
+
+		nm_cmd_line_add_string (cmd, "noipdefault");
 	} else {
 		nm_cmd_line_add_string (cmd, priv->parent_iface);
 		/* Don't send some random address as the local address */
@@ -924,6 +964,12 @@ pppd_child_setup (gpointer user_data G_GNUC_UNUSED)
 	/* We are in the child process at this point */
 	pid_t pid = getpid ();
 	setpgid (pid, pid);
+
+	/*
+	 * We blocked signals in main(). We need to restore original signal
+	 * mask for pppd here so that it can receive signals.
+	 */
+	nm_unblock_posix_signals (NULL);
 }
 
 static void
@@ -965,6 +1011,7 @@ nm_ppp_manager_start (NMPPPManager *manager,
 	NMSettingPPP *s_ppp;
 	gboolean s_ppp_created = FALSE;
 	NMSettingPPPOE *pppoe_setting;
+	NMSettingAdsl *adsl_setting;
 	NMCmdLine *ppp_cmd;
 	char *cmd_str;
 	struct stat st;
@@ -1006,7 +1053,9 @@ nm_ppp_manager_start (NMPPPManager *manager,
 	if (pppoe_setting)
 		pppoe_fill_defaults (s_ppp);
 
-	ppp_cmd = create_pppd_cmd_line (manager, s_ppp, pppoe_setting, ppp_name, err);
+	adsl_setting = (NMSettingAdsl *) nm_connection_get_setting (connection, NM_TYPE_SETTING_ADSL);
+
+	ppp_cmd = create_pppd_cmd_line (manager, s_ppp, pppoe_setting, adsl_setting, ppp_name, err);
 	if (!ppp_cmd)
 		goto out;
 
diff --git a/src/settings/Makefile.in b/src/settings/Makefile.in
index d1278206..b8cbffc4 100644
--- a/src/settings/Makefile.in
+++ b/src/settings/Makefile.in
@@ -47,7 +47,7 @@ am__aclocal_m4_deps = $(top_srcdir)/m4/compiler_warnings.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)/configure.ac
+	$(top_srcdir)/m4/vapigen.m4 $(top_srcdir)/configure.ac
 am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \
 	$(ACLOCAL_M4)
 mkinstalldirs = $(install_sh) -d
@@ -230,6 +230,10 @@ INTLTOOL_EXTRACT = @INTLTOOL_EXTRACT@
 INTLTOOL_MERGE = @INTLTOOL_MERGE@
 INTLTOOL_PERL = @INTLTOOL_PERL@
 INTLTOOL_UPDATE = @INTLTOOL_UPDATE@
+INTLTOOL_V_MERGE = @INTLTOOL_V_MERGE@
+INTLTOOL_V_MERGE_OPTIONS = @INTLTOOL_V_MERGE_OPTIONS@
+INTLTOOL__v_MERGE_ = @INTLTOOL__v_MERGE_@
+INTLTOOL__v_MERGE_0 = @INTLTOOL__v_MERGE_0@
 INTL_MACOSX_LIBS = @INTL_MACOSX_LIBS@
 INTROSPECTION_CFLAGS = @INTROSPECTION_CFLAGS@
 INTROSPECTION_COMPILER = @INTROSPECTION_COMPILER@
@@ -325,6 +329,9 @@ UDEV_BASE_DIR = @UDEV_BASE_DIR@
 USE_NLS = @USE_NLS@
 UUID_CFLAGS = @UUID_CFLAGS@
 UUID_LIBS = @UUID_LIBS@
+VAPIGEN = @VAPIGEN@
+VAPIGEN_MAKEFILE = @VAPIGEN_MAKEFILE@
+VAPIGEN_VAPIDIR = @VAPIGEN_VAPIDIR@
 VERSION = @VERSION@
 XGETTEXT = @XGETTEXT@
 XGETTEXT_015 = @XGETTEXT_015@
@@ -363,6 +370,8 @@ htmldir = @htmldir@
 includedir = @includedir@
 infodir = @infodir@
 install_sh = @install_sh@
+intltool__v_merge_options_ = @intltool__v_merge_options_@
+intltool__v_merge_options_0 = @intltool__v_merge_options_0@
 libdir = @libdir@
 libexecdir = @libexecdir@
 localedir = @localedir@
diff --git a/src/settings/nm-settings-connection.c b/src/settings/nm-settings-connection.c
index 5d240c77..ddc758c7 100644
--- a/src/settings/nm-settings-connection.c
+++ b/src/settings/nm-settings-connection.c
@@ -1355,7 +1355,7 @@ dbus_secrets_auth_cb (NMSettingsConnection *self,
 			                                          TRUE,
 			                                          sender_uid,
 			                                          setting_name,
-			                                          NM_SETTINGS_GET_SECRETS_FLAG_NONE,
+			                                          NM_SETTINGS_GET_SECRETS_FLAG_USER_REQUESTED,
 			                                          NULL,
 			                                          dbus_get_agent_secrets_cb,
 			                                          context,
diff --git a/src/settings/nm-settings.c b/src/settings/nm-settings.c
index 1ead4f8b..96564605 100644
--- a/src/settings/nm-settings.c
+++ b/src/settings/nm-settings.c
@@ -49,6 +49,7 @@
 #include <nm-setting-serial.h>
 #include <nm-setting-vpn.h>
 #include <nm-setting-wired.h>
+#include <nm-setting-adsl.h>
 #include <nm-setting-wireless.h>
 #include <nm-setting-wireless-security.h>
 #include <nm-setting-bond.h>
@@ -68,6 +69,7 @@
 #include "plugins/keyfile/plugin.h"
 #include "nm-agent-manager.h"
 #include "nm-settings-utils.h"
+#include "nm-connection-provider.h"
 
 #define CONFIG_KEY_NO_AUTO_DEFAULT "no-auto-default"
 
@@ -110,6 +112,12 @@ static void impl_settings_save_hostname (NMSettings *self,
 
 static void unmanaged_specs_changed (NMSystemConfigInterface *config, gpointer user_data);
 
+static void connection_provider_init (NMConnectionProvider *cp_class);
+
+G_DEFINE_TYPE_EXTENDED (NMSettings, nm_settings, G_TYPE_OBJECT, 0,
+                        G_IMPLEMENT_INTERFACE (NM_TYPE_CONNECTION_PROVIDER, connection_provider_init))
+
+
 typedef struct {
 	NMDBusManager *dbus_mgr;
 	DBusGConnection *bus;
@@ -127,8 +135,6 @@ typedef struct {
 	GSList *unmanaged_specs;
 } NMSettingsPrivate;
 
-G_DEFINE_TYPE (NMSettings, nm_settings, G_TYPE_OBJECT)
-
 #define NM_SETTINGS_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), NM_TYPE_SETTINGS, NMSettingsPrivate))
 
 enum {
@@ -186,6 +192,7 @@ load_connections (NMSettings *self)
 	unmanaged_specs_changed (NULL, self);
 
 	g_signal_emit (self, signals[CONNECTIONS_LOADED], 0);
+	g_signal_emit_by_name (self, NM_CP_SIGNAL_CONNECTIONS_LOADED);
 }
 
 void
@@ -674,6 +681,7 @@ connection_removed (NMSettingsConnection *obj, gpointer user_data)
 
 	/* Re-emit for listeners like NMPolicy */
 	g_signal_emit (NM_SETTINGS (user_data), signals[CONNECTION_REMOVED], 0, connection);
+	g_signal_emit_by_name (NM_SETTINGS (user_data), NM_CP_SIGNAL_CONNECTION_REMOVED, connection);
 
 	g_object_unref (connection);
 }
@@ -701,6 +709,7 @@ connection_updated (NMSettingsConnection *connection, gpointer user_data)
 	               signals[CONNECTION_UPDATED],
 	               0,
 	               connection);
+	g_signal_emit_by_name (NM_SETTINGS (user_data), NM_CP_SIGNAL_CONNECTION_UPDATED, connection);
 }
 
 static void
@@ -849,6 +858,7 @@ claim_connection (NMSettings *self,
 	if (priv->connections_loaded) {
 		/* Internal added signal */
 		g_signal_emit (self, signals[CONNECTION_ADDED], 0, connection);
+		g_signal_emit_by_name (self, NM_CP_SIGNAL_CONNECTION_ADDED, connection);
 
 		/* Exported D-Bus signal */
 		g_signal_emit (self, signals[NEW_CONNECTION], 0, connection);
@@ -1621,6 +1631,100 @@ nm_settings_device_removed (NMSettings *self, NMDevice *device)
 
 /***************************************************************/
 
+static gint
+best_connection_sort (gconstpointer a, gconstpointer b, gpointer user_data)
+{
+	NMSettingsConnection *ac = (NMSettingsConnection *) a;
+	NMSettingsConnection *bc = (NMSettingsConnection *) b;
+	guint64 ats, bts;
+
+	if (!ac && bc)
+		return -1;
+	else if (ac && !bc)
+		return 1;
+	else if (!ac && !bc)
+		return 0;
+
+	g_assert (ac && bc);
+
+	/* In the future we may use connection priorities in addition to timestamps */
+	ats = nm_settings_connection_get_timestamp (ac);
+	bts = nm_settings_connection_get_timestamp (bc);
+
+	if (ats < bts)
+		return -1;
+	else if (ats > bts)
+		return 1;
+	return 0;
+}
+
+static GSList *
+get_best_connections (NMConnectionProvider *provider,
+                      guint max_requested,
+                      const char *ctype1,
+                      const char *ctype2,
+                      NMConnectionFilterFunc func,
+                      gpointer func_data)
+{
+	NMSettings *self = NM_SETTINGS (provider);
+	NMSettingsPrivate *priv = NM_SETTINGS_GET_PRIVATE (self);
+	GSList *sorted = NULL;
+	GHashTableIter iter;
+	NMSettingsConnection *connection;
+	guint added = 0;
+	guint64 oldest = 0;
+
+	g_hash_table_iter_init (&iter, priv->connections);
+	while (g_hash_table_iter_next (&iter, NULL, (gpointer) &connection)) {
+		if (ctype1 && !nm_connection_is_type (NM_CONNECTION (connection), ctype1))
+			continue;
+		if (ctype2 && !nm_connection_is_type (NM_CONNECTION (connection), ctype2))
+			continue;
+		if (func && !func (provider, NM_CONNECTION (connection), func_data))
+			continue;
+
+		/* Don't bother with a connection that's older than the oldest one in the list */
+		if (   max_requested
+		    && added >= max_requested
+		    && nm_settings_connection_get_timestamp (connection) <= oldest)
+			continue;
+
+		/* List is sorted with oldest first */
+		sorted = g_slist_insert_sorted_with_data (sorted, connection, best_connection_sort, NULL);
+		added++;
+
+		if (max_requested && added > max_requested) {
+			/* Over the limit, remove the oldest one */
+			sorted = g_slist_delete_link (sorted, sorted);
+			added--;
+		}
+
+		oldest = nm_settings_connection_get_timestamp (NM_SETTINGS_CONNECTION (sorted->data));
+	}
+
+	return g_slist_reverse (sorted);
+}
+
+static const GSList *
+get_connections (NMConnectionProvider *provider)
+{
+	static GSList *list = NULL;
+	NMSettings *self = NM_SETTINGS (provider);
+	GHashTableIter iter;
+	NMSettingsConnection *connection;
+
+	/* Lazily free the list with every call so we can keep it 'const' for callers */
+	g_slist_free (list);
+	list = NULL;
+
+	g_hash_table_iter_init (&iter, NM_SETTINGS_GET_PRIVATE (self)->connections);
+	while (g_hash_table_iter_next (&iter, NULL, (gpointer) &connection))
+		list = g_slist_prepend (list, connection);
+	return g_slist_reverse (list);
+}
+
+/***************************************************************/
+
 NMSettings *
 nm_settings_new (const char *config_file,
                  const char **plugins,
@@ -1660,6 +1764,13 @@ nm_settings_new (const char *config_file,
 }
 
 static void
+connection_provider_init (NMConnectionProvider *cp_class)
+{
+    cp_class->get_best_connections = get_best_connections;
+    cp_class->get_connections = get_connections;
+}
+
+static void
 nm_settings_init (NMSettings *self)
 {
 	NMSettingsPrivate *priv = NM_SETTINGS_GET_PRIVATE (self);
@@ -1873,6 +1984,7 @@ nm_settings_class_init (NMSettingsClass *class)
 	dbus_g_error_domain_register (NM_SETTING_PPP_ERROR, NULL, NM_TYPE_SETTING_PPP_ERROR);
 	dbus_g_error_domain_register (NM_SETTING_PPPOE_ERROR, NULL, NM_TYPE_SETTING_PPPOE_ERROR);
 	dbus_g_error_domain_register (NM_SETTING_SERIAL_ERROR, NULL, NM_TYPE_SETTING_SERIAL_ERROR);
+	dbus_g_error_domain_register (NM_SETTING_ADSL_ERROR, NULL, NM_TYPE_SETTING_ADSL_ERROR);
 	dbus_g_error_domain_register (NM_SETTING_VPN_ERROR, NULL, NM_TYPE_SETTING_VPN_ERROR);
 	dbus_g_error_domain_register (NM_SETTING_WIRED_ERROR, NULL, NM_TYPE_SETTING_WIRED_ERROR);
 	dbus_g_error_domain_register (NM_SETTING_WIRELESS_SECURITY_ERROR, NULL, NM_TYPE_SETTING_WIRELESS_SECURITY_ERROR);
diff --git a/src/settings/plugins/Makefile.am b/src/settings/plugins/Makefile.am
index 5df57d5e..d4ba12f0 100644
--- a/src/settings/plugins/Makefile.am
+++ b/src/settings/plugins/Makefile.am
@@ -1,4 +1,4 @@
-SUBDIRS=keyfile
+SUBDIRS=keyfile example
 
 if TARGET_REDHAT
 SUBDIRS+=ifcfg-rh
diff --git a/src/settings/plugins/Makefile.in b/src/settings/plugins/Makefile.in
index 0997f445..11560049 100644
--- a/src/settings/plugins/Makefile.in
+++ b/src/settings/plugins/Makefile.in
@@ -51,7 +51,7 @@ am__aclocal_m4_deps = $(top_srcdir)/m4/compiler_warnings.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)/configure.ac
+	$(top_srcdir)/m4/vapigen.m4 $(top_srcdir)/configure.ac
 am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \
 	$(ACLOCAL_M4)
 mkinstalldirs = $(install_sh) -d
@@ -80,7 +80,7 @@ AM_RECURSIVE_TARGETS = $(RECURSIVE_TARGETS:-recursive=) \
 	distdir
 ETAGS = etags
 CTAGS = ctags
-DIST_SUBDIRS = keyfile ifcfg-rh ifcfg-suse ifupdown ifnet
+DIST_SUBDIRS = keyfile example ifcfg-rh ifcfg-suse ifupdown ifnet
 DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST)
 am__relativize = \
   dir0=`pwd`; \
@@ -179,6 +179,10 @@ INTLTOOL_EXTRACT = @INTLTOOL_EXTRACT@
 INTLTOOL_MERGE = @INTLTOOL_MERGE@
 INTLTOOL_PERL = @INTLTOOL_PERL@
 INTLTOOL_UPDATE = @INTLTOOL_UPDATE@
+INTLTOOL_V_MERGE = @INTLTOOL_V_MERGE@
+INTLTOOL_V_MERGE_OPTIONS = @INTLTOOL_V_MERGE_OPTIONS@
+INTLTOOL__v_MERGE_ = @INTLTOOL__v_MERGE_@
+INTLTOOL__v_MERGE_0 = @INTLTOOL__v_MERGE_0@
 INTL_MACOSX_LIBS = @INTL_MACOSX_LIBS@
 INTROSPECTION_CFLAGS = @INTROSPECTION_CFLAGS@
 INTROSPECTION_COMPILER = @INTROSPECTION_COMPILER@
@@ -274,6 +278,9 @@ UDEV_BASE_DIR = @UDEV_BASE_DIR@
 USE_NLS = @USE_NLS@
 UUID_CFLAGS = @UUID_CFLAGS@
 UUID_LIBS = @UUID_LIBS@
+VAPIGEN = @VAPIGEN@
+VAPIGEN_MAKEFILE = @VAPIGEN_MAKEFILE@
+VAPIGEN_VAPIDIR = @VAPIGEN_VAPIDIR@
 VERSION = @VERSION@
 XGETTEXT = @XGETTEXT@
 XGETTEXT_015 = @XGETTEXT_015@
@@ -312,6 +319,8 @@ htmldir = @htmldir@
 includedir = @includedir@
 infodir = @infodir@
 install_sh = @install_sh@
+intltool__v_merge_options_ = @intltool__v_merge_options_@
+intltool__v_merge_options_0 = @intltool__v_merge_options_0@
 libdir = @libdir@
 libexecdir = @libexecdir@
 localedir = @localedir@
@@ -332,8 +341,8 @@ target_alias = @target_alias@
 top_build_prefix = @top_build_prefix@
 top_builddir = @top_builddir@
 top_srcdir = @top_srcdir@
-SUBDIRS = keyfile $(am__append_1) $(am__append_2) $(am__append_3) \
-	$(am__append_4) $(am__append_5)
+SUBDIRS = keyfile example $(am__append_1) $(am__append_2) \
+	$(am__append_3) $(am__append_4) $(am__append_5)
 all: all-recursive
 
 .SUFFIXES:
diff --git a/src/settings/plugins/example/Makefile.am b/src/settings/plugins/example/Makefile.am
new file mode 100644
index 00000000..027f6f89
--- /dev/null
+++ b/src/settings/plugins/example/Makefile.am
@@ -0,0 +1,40 @@
+INCLUDES = \
+	-I$(top_srcdir)/src/settings \
+	-I$(top_srcdir)/include \
+	-I$(top_builddir)/include \
+	-I$(top_srcdir)/libnm-util \
+	-I$(top_builddir)/libnm-util
+
+# 'noinst' here because this is an example plugin we don't want to install
+noinst_LTLIBRARIES = libnm-settings-plugin-example.la
+
+# The actual plugins typically pull reader.c and writer.c out into
+# their own static library so that unit tests can use them without
+# having to build the entire plugin.  But since this is a simple
+# plugin we don't do that yet.
+
+libnm_settings_plugin_example_la_SOURCES = \
+	nm-example-connection.c \
+	nm-example-connection.h \
+	plugin.c \
+	plugin.h \
+	errors.c \
+	common.h \
+	reader.c \
+	writer.c
+
+libnm_settings_plugin_example_la_CPPFLAGS = \
+	$(GLIB_CFLAGS) \
+	$(GMODULE_CFLAGS) \
+	$(DBUS_CFLAGS) \
+	-DSYSCONFDIR=\"$(sysconfdir)\" \
+	-DG_DISABLE_DEPRECATED
+
+libnm_settings_plugin_example_la_LIBADD = \
+	$(top_builddir)/libnm-util/libnm-util.la \
+	$(GLIB_LIBS) \
+	$(GMODULE_LIBS) \
+	$(GIO_LIBS)
+
+libnm_settings_plugin_example_la_LDFLAGS = -module -avoid-version
+
diff --git a/src/settings/plugins/example/Makefile.in b/src/settings/plugins/example/Makefile.in
new file mode 100644
index 00000000..463ebac9
--- /dev/null
+++ b/src/settings/plugins/example/Makefile.in
@@ -0,0 +1,712 @@
+# Makefile.in generated by automake 1.11.1 from Makefile.am.
+# @configure_input@
+
+# Copyright (C) 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002,
+# 2003, 2004, 2005, 2006, 2007, 2008, 2009  Free Software Foundation,
+# Inc.
+# This Makefile.in is free software; the Free Software Foundation
+# gives unlimited permission to copy and/or distribute it,
+# with or without modifications, as long as this notice is preserved.
+
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY, to the extent permitted by law; without
+# even the implied warranty of MERCHANTABILITY or FITNESS FOR A
+# PARTICULAR PURPOSE.
+
+@SET_MAKE@
+
+VPATH = @srcdir@
+pkgdatadir = $(datadir)/@PACKAGE@
+pkgincludedir = $(includedir)/@PACKAGE@
+pkglibdir = $(libdir)/@PACKAGE@
+pkglibexecdir = $(libexecdir)/@PACKAGE@
+am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd
+install_sh_DATA = $(install_sh) -c -m 644
+install_sh_PROGRAM = $(install_sh) -c
+install_sh_SCRIPT = $(install_sh) -c
+INSTALL_HEADER = $(INSTALL_DATA)
+transform = $(program_transform_name)
+NORMAL_INSTALL = :
+PRE_INSTALL = :
+POST_INSTALL = :
+NORMAL_UNINSTALL = :
+PRE_UNINSTALL = :
+POST_UNINSTALL = :
+build_triplet = @build@
+host_triplet = @host@
+subdir = src/settings/plugins/example
+DIST_COMMON = README $(srcdir)/Makefile.am $(srcdir)/Makefile.in
+ACLOCAL_M4 = $(top_srcdir)/aclocal.m4
+am__aclocal_m4_deps = $(top_srcdir)/m4/compiler_warnings.m4 \
+	$(top_srcdir)/m4/gettext.m4 $(top_srcdir)/m4/gtk-doc.m4 \
+	$(top_srcdir)/m4/iconv.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
+am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \
+	$(ACLOCAL_M4)
+mkinstalldirs = $(install_sh) -d
+CONFIG_HEADER = $(top_builddir)/config.h
+CONFIG_CLEAN_FILES =
+CONFIG_CLEAN_VPATH_FILES =
+LTLIBRARIES = $(noinst_LTLIBRARIES)
+am__DEPENDENCIES_1 =
+libnm_settings_plugin_example_la_DEPENDENCIES =  \
+	$(top_builddir)/libnm-util/libnm-util.la $(am__DEPENDENCIES_1) \
+	$(am__DEPENDENCIES_1) $(am__DEPENDENCIES_1)
+am_libnm_settings_plugin_example_la_OBJECTS =  \
+	libnm_settings_plugin_example_la-nm-example-connection.lo \
+	libnm_settings_plugin_example_la-plugin.lo \
+	libnm_settings_plugin_example_la-errors.lo \
+	libnm_settings_plugin_example_la-reader.lo \
+	libnm_settings_plugin_example_la-writer.lo
+libnm_settings_plugin_example_la_OBJECTS =  \
+	$(am_libnm_settings_plugin_example_la_OBJECTS)
+AM_V_lt = $(am__v_lt_$(V))
+am__v_lt_ = $(am__v_lt_$(AM_DEFAULT_VERBOSITY))
+am__v_lt_0 = --silent
+libnm_settings_plugin_example_la_LINK = $(LIBTOOL) $(AM_V_lt) --tag=CC \
+	$(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=link $(CCLD) \
+	$(AM_CFLAGS) $(CFLAGS) \
+	$(libnm_settings_plugin_example_la_LDFLAGS) $(LDFLAGS) -o $@
+DEFAULT_INCLUDES = -I.@am__isrc@ -I$(top_builddir)
+depcomp = $(SHELL) $(top_srcdir)/build-aux/depcomp
+am__depfiles_maybe = depfiles
+am__mv = mv -f
+COMPILE = $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) \
+	$(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS)
+LTCOMPILE = $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) \
+	$(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) \
+	$(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) \
+	$(AM_CFLAGS) $(CFLAGS)
+AM_V_CC = $(am__v_CC_$(V))
+am__v_CC_ = $(am__v_CC_$(AM_DEFAULT_VERBOSITY))
+am__v_CC_0 = @echo "  CC    " $@;
+AM_V_at = $(am__v_at_$(V))
+am__v_at_ = $(am__v_at_$(AM_DEFAULT_VERBOSITY))
+am__v_at_0 = @
+CCLD = $(CC)
+LINK = $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) \
+	$(LIBTOOLFLAGS) --mode=link $(CCLD) $(AM_CFLAGS) $(CFLAGS) \
+	$(AM_LDFLAGS) $(LDFLAGS) -o $@
+AM_V_CCLD = $(am__v_CCLD_$(V))
+am__v_CCLD_ = $(am__v_CCLD_$(AM_DEFAULT_VERBOSITY))
+am__v_CCLD_0 = @echo "  CCLD  " $@;
+AM_V_GEN = $(am__v_GEN_$(V))
+am__v_GEN_ = $(am__v_GEN_$(AM_DEFAULT_VERBOSITY))
+am__v_GEN_0 = @echo "  GEN   " $@;
+SOURCES = $(libnm_settings_plugin_example_la_SOURCES)
+DIST_SOURCES = $(libnm_settings_plugin_example_la_SOURCES)
+ETAGS = etags
+CTAGS = ctags
+DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST)
+ACLOCAL = @ACLOCAL@
+ALL_LINGUAS = @ALL_LINGUAS@
+AMTAR = @AMTAR@
+AM_DEFAULT_VERBOSITY = @AM_DEFAULT_VERBOSITY@
+AR = @AR@
+AUTOCONF = @AUTOCONF@
+AUTOHEADER = @AUTOHEADER@
+AUTOMAKE = @AUTOMAKE@
+AWK = @AWK@
+CC = @CC@
+CCDEPMODE = @CCDEPMODE@
+CFLAGS = @CFLAGS@
+CPP = @CPP@
+CPPFLAGS = @CPPFLAGS@
+CXX = @CXX@
+CXXCPP = @CXXCPP@
+CXXDEPMODE = @CXXDEPMODE@
+CXXFLAGS = @CXXFLAGS@
+CYGPATH_W = @CYGPATH_W@
+DATADIRNAME = @DATADIRNAME@
+DBUS_CFLAGS = @DBUS_CFLAGS@
+DBUS_LIBS = @DBUS_LIBS@
+DBUS_SYS_DIR = @DBUS_SYS_DIR@
+DEFS = @DEFS@
+DEPDIR = @DEPDIR@
+DHCLIENT_PATH = @DHCLIENT_PATH@
+DHCLIENT_VERSION = @DHCLIENT_VERSION@
+DHCPCD_PATH = @DHCPCD_PATH@
+DISABLE_DEPRECATED = @DISABLE_DEPRECATED@
+DLLTOOL = @DLLTOOL@
+DSYMUTIL = @DSYMUTIL@
+DUMPBIN = @DUMPBIN@
+ECHO_C = @ECHO_C@
+ECHO_N = @ECHO_N@
+ECHO_T = @ECHO_T@
+EGREP = @EGREP@
+EXEEXT = @EXEEXT@
+FGREP = @FGREP@
+GETTEXT_MACRO_VERSION = @GETTEXT_MACRO_VERSION@
+GETTEXT_PACKAGE = @GETTEXT_PACKAGE@
+GIO_CFLAGS = @GIO_CFLAGS@
+GIO_LIBS = @GIO_LIBS@
+GLIB_CFLAGS = @GLIB_CFLAGS@
+GLIB_GENMARSHAL = @GLIB_GENMARSHAL@
+GLIB_LIBS = @GLIB_LIBS@
+GLIB_MAKEFILE = @GLIB_MAKEFILE@
+GLIB_MKENUMS = @GLIB_MKENUMS@
+GMODULE_CFLAGS = @GMODULE_CFLAGS@
+GMODULE_LIBS = @GMODULE_LIBS@
+GMSGFMT = @GMSGFMT@
+GMSGFMT_015 = @GMSGFMT_015@
+GNUTLS_CFLAGS = @GNUTLS_CFLAGS@
+GNUTLS_LIBS = @GNUTLS_LIBS@
+GREP = @GREP@
+GTKDOC_CHECK = @GTKDOC_CHECK@
+GTKDOC_DEPS_CFLAGS = @GTKDOC_DEPS_CFLAGS@
+GTKDOC_DEPS_LIBS = @GTKDOC_DEPS_LIBS@
+GTKDOC_MKPDF = @GTKDOC_MKPDF@
+GTKDOC_REBASE = @GTKDOC_REBASE@
+GUDEV_CFLAGS = @GUDEV_CFLAGS@
+GUDEV_LIBS = @GUDEV_LIBS@
+HTML_DIR = @HTML_DIR@
+INSTALL = @INSTALL@
+INSTALL_DATA = @INSTALL_DATA@
+INSTALL_PROGRAM = @INSTALL_PROGRAM@
+INSTALL_SCRIPT = @INSTALL_SCRIPT@
+INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@
+INTLLIBS = @INTLLIBS@
+INTLTOOL_EXTRACT = @INTLTOOL_EXTRACT@
+INTLTOOL_MERGE = @INTLTOOL_MERGE@
+INTLTOOL_PERL = @INTLTOOL_PERL@
+INTLTOOL_UPDATE = @INTLTOOL_UPDATE@
+INTLTOOL_V_MERGE = @INTLTOOL_V_MERGE@
+INTLTOOL_V_MERGE_OPTIONS = @INTLTOOL_V_MERGE_OPTIONS@
+INTLTOOL__v_MERGE_ = @INTLTOOL__v_MERGE_@
+INTLTOOL__v_MERGE_0 = @INTLTOOL__v_MERGE_0@
+INTL_MACOSX_LIBS = @INTL_MACOSX_LIBS@
+INTROSPECTION_CFLAGS = @INTROSPECTION_CFLAGS@
+INTROSPECTION_COMPILER = @INTROSPECTION_COMPILER@
+INTROSPECTION_GENERATE = @INTROSPECTION_GENERATE@
+INTROSPECTION_GIRDIR = @INTROSPECTION_GIRDIR@
+INTROSPECTION_LIBS = @INTROSPECTION_LIBS@
+INTROSPECTION_MAKEFILE = @INTROSPECTION_MAKEFILE@
+INTROSPECTION_SCANNER = @INTROSPECTION_SCANNER@
+INTROSPECTION_TYPELIBDIR = @INTROSPECTION_TYPELIBDIR@
+IPTABLES_PATH = @IPTABLES_PATH@
+IWMX_SDK_CFLAGS = @IWMX_SDK_CFLAGS@
+IWMX_SDK_LIBS = @IWMX_SDK_LIBS@
+KERNEL_FIRMWARE_DIR = @KERNEL_FIRMWARE_DIR@
+LD = @LD@
+LDFLAGS = @LDFLAGS@
+LIBDL = @LIBDL@
+LIBGCRYPT_CFLAGS = @LIBGCRYPT_CFLAGS@
+LIBGCRYPT_CONFIG = @LIBGCRYPT_CONFIG@
+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_GENL3_CFLAGS = @LIBNL_GENL3_CFLAGS@
+LIBNL_GENL3_LIBS = @LIBNL_GENL3_LIBS@
+LIBNL_LIBS = @LIBNL_LIBS@
+LIBNL_ROUTE3_CFLAGS = @LIBNL_ROUTE3_CFLAGS@
+LIBNL_ROUTE3_LIBS = @LIBNL_ROUTE3_LIBS@
+LIBOBJS = @LIBOBJS@
+LIBS = @LIBS@
+LIBSOUP_CFLAGS = @LIBSOUP_CFLAGS@
+LIBSOUP_LIBS = @LIBSOUP_LIBS@
+LIBTOOL = @LIBTOOL@
+LIPO = @LIPO@
+LN_S = @LN_S@
+LTLIBICONV = @LTLIBICONV@
+LTLIBINTL = @LTLIBINTL@
+LTLIBOBJS = @LTLIBOBJS@
+MAINT = @MAINT@
+MAKEINFO = @MAKEINFO@
+MANIFEST_TOOL = @MANIFEST_TOOL@
+MKDIR_P = @MKDIR_P@
+MOC = @MOC@
+MSGFMT = @MSGFMT@
+MSGFMT_015 = @MSGFMT_015@
+MSGMERGE = @MSGMERGE@
+NM = @NM@
+NMEDIT = @NMEDIT@
+NM_MAJOR_VERSION = @NM_MAJOR_VERSION@
+NM_MICRO_VERSION = @NM_MICRO_VERSION@
+NM_MINOR_VERSION = @NM_MINOR_VERSION@
+NM_VERSION = @NM_VERSION@
+NSS_CFLAGS = @NSS_CFLAGS@
+NSS_LIBS = @NSS_LIBS@
+OBJDUMP = @OBJDUMP@
+OBJEXT = @OBJEXT@
+OTOOL = @OTOOL@
+OTOOL64 = @OTOOL64@
+PACKAGE = @PACKAGE@
+PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@
+PACKAGE_NAME = @PACKAGE_NAME@
+PACKAGE_STRING = @PACKAGE_STRING@
+PACKAGE_TARNAME = @PACKAGE_TARNAME@
+PACKAGE_URL = @PACKAGE_URL@
+PACKAGE_VERSION = @PACKAGE_VERSION@
+PATH_SEPARATOR = @PATH_SEPARATOR@
+PKGCONFIG_PATH = @PKGCONFIG_PATH@
+PKG_CONFIG = @PKG_CONFIG@
+PKG_CONFIG_LIBDIR = @PKG_CONFIG_LIBDIR@
+PKG_CONFIG_PATH = @PKG_CONFIG_PATH@
+POLKIT_CFLAGS = @POLKIT_CFLAGS@
+POLKIT_LIBS = @POLKIT_LIBS@
+POSUB = @POSUB@
+PPPD_PLUGIN_DIR = @PPPD_PLUGIN_DIR@
+QT_CFLAGS = @QT_CFLAGS@
+QT_LIBS = @QT_LIBS@
+RANLIB = @RANLIB@
+RESOLVCONF_PATH = @RESOLVCONF_PATH@
+SED = @SED@
+SET_MAKE = @SET_MAKE@
+SHELL = @SHELL@
+STRIP = @STRIP@
+SYSTEMD_CFLAGS = @SYSTEMD_CFLAGS@
+SYSTEMD_LIBS = @SYSTEMD_LIBS@
+SYSTEM_CA_PATH = @SYSTEM_CA_PATH@
+UDEV_BASE_DIR = @UDEV_BASE_DIR@
+USE_NLS = @USE_NLS@
+UUID_CFLAGS = @UUID_CFLAGS@
+UUID_LIBS = @UUID_LIBS@
+VAPIGEN = @VAPIGEN@
+VAPIGEN_MAKEFILE = @VAPIGEN_MAKEFILE@
+VAPIGEN_VAPIDIR = @VAPIGEN_VAPIDIR@
+VERSION = @VERSION@
+XGETTEXT = @XGETTEXT@
+XGETTEXT_015 = @XGETTEXT_015@
+XGETTEXT_EXTRA_OPTIONS = @XGETTEXT_EXTRA_OPTIONS@
+abs_builddir = @abs_builddir@
+abs_srcdir = @abs_srcdir@
+abs_top_builddir = @abs_top_builddir@
+abs_top_srcdir = @abs_top_srcdir@
+ac_ct_AR = @ac_ct_AR@
+ac_ct_CC = @ac_ct_CC@
+ac_ct_CXX = @ac_ct_CXX@
+ac_ct_DUMPBIN = @ac_ct_DUMPBIN@
+am__include = @am__include@
+am__leading_dot = @am__leading_dot@
+am__quote = @am__quote@
+am__tar = @am__tar@
+am__untar = @am__untar@
+bindir = @bindir@
+build = @build@
+build_alias = @build_alias@
+build_cpu = @build_cpu@
+build_os = @build_os@
+build_vendor = @build_vendor@
+builddir = @builddir@
+datadir = @datadir@
+datarootdir = @datarootdir@
+docdir = @docdir@
+dvidir = @dvidir@
+exec_prefix = @exec_prefix@
+host = @host@
+host_alias = @host_alias@
+host_cpu = @host_cpu@
+host_os = @host_os@
+host_vendor = @host_vendor@
+htmldir = @htmldir@
+includedir = @includedir@
+infodir = @infodir@
+install_sh = @install_sh@
+intltool__v_merge_options_ = @intltool__v_merge_options_@
+intltool__v_merge_options_0 = @intltool__v_merge_options_0@
+libdir = @libdir@
+libexecdir = @libexecdir@
+localedir = @localedir@
+localstatedir = @localstatedir@
+mandir = @mandir@
+mkdir_p = @mkdir_p@
+oldincludedir = @oldincludedir@
+pdfdir = @pdfdir@
+prefix = @prefix@
+program_transform_name = @program_transform_name@
+psdir = @psdir@
+sbindir = @sbindir@
+sharedstatedir = @sharedstatedir@
+srcdir = @srcdir@
+sysconfdir = @sysconfdir@
+systemdsystemunitdir = @systemdsystemunitdir@
+target_alias = @target_alias@
+top_build_prefix = @top_build_prefix@
+top_builddir = @top_builddir@
+top_srcdir = @top_srcdir@
+INCLUDES = \
+	-I$(top_srcdir)/src/settings \
+	-I$(top_srcdir)/include \
+	-I$(top_builddir)/include \
+	-I$(top_srcdir)/libnm-util \
+	-I$(top_builddir)/libnm-util
+
+
+# 'noinst' here because this is an example plugin we don't want to install
+noinst_LTLIBRARIES = libnm-settings-plugin-example.la
+
+# The actual plugins typically pull reader.c and writer.c out into
+# their own static library so that unit tests can use them without
+# having to build the entire plugin.  But since this is a simple
+# plugin we don't do that yet.
+libnm_settings_plugin_example_la_SOURCES = \
+	nm-example-connection.c \
+	nm-example-connection.h \
+	plugin.c \
+	plugin.h \
+	errors.c \
+	common.h \
+	reader.c \
+	writer.c
+
+libnm_settings_plugin_example_la_CPPFLAGS = \
+	$(GLIB_CFLAGS) \
+	$(GMODULE_CFLAGS) \
+	$(DBUS_CFLAGS) \
+	-DSYSCONFDIR=\"$(sysconfdir)\" \
+	-DG_DISABLE_DEPRECATED
+
+libnm_settings_plugin_example_la_LIBADD = \
+	$(top_builddir)/libnm-util/libnm-util.la \
+	$(GLIB_LIBS) \
+	$(GMODULE_LIBS) \
+	$(GIO_LIBS)
+
+libnm_settings_plugin_example_la_LDFLAGS = -module -avoid-version
+all: all-am
+
+.SUFFIXES:
+.SUFFIXES: .c .lo .o .obj
+$(srcdir)/Makefile.in: @MAINTAINER_MODE_TRUE@ $(srcdir)/Makefile.am  $(am__configure_deps)
+	@for dep in $?; do \
+	  case '$(am__configure_deps)' in \
+	    *$$dep*) \
+	      ( cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh ) \
+	        && { if test -f $@; then exit 0; else break; fi; }; \
+	      exit 1;; \
+	  esac; \
+	done; \
+	echo ' cd $(top_srcdir) && $(AUTOMAKE) --gnu src/settings/plugins/example/Makefile'; \
+	$(am__cd) $(top_srcdir) && \
+	  $(AUTOMAKE) --gnu src/settings/plugins/example/Makefile
+.PRECIOUS: Makefile
+Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status
+	@case '$?' in \
+	  *config.status*) \
+	    cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh;; \
+	  *) \
+	    echo ' cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe)'; \
+	    cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe);; \
+	esac;
+
+$(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES)
+	cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+
+$(top_srcdir)/configure: @MAINTAINER_MODE_TRUE@ $(am__configure_deps)
+	cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+$(ACLOCAL_M4): @MAINTAINER_MODE_TRUE@ $(am__aclocal_m4_deps)
+	cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+$(am__aclocal_m4_deps):
+
+clean-noinstLTLIBRARIES:
+	-test -z "$(noinst_LTLIBRARIES)" || rm -f $(noinst_LTLIBRARIES)
+	@list='$(noinst_LTLIBRARIES)'; for p in $$list; do \
+	  dir="`echo $$p | sed -e 's|/[^/]*$$||'`"; \
+	  test "$$dir" != "$$p" || dir=.; \
+	  echo "rm -f \"$${dir}/so_locations\""; \
+	  rm -f "$${dir}/so_locations"; \
+	done
+libnm-settings-plugin-example.la: $(libnm_settings_plugin_example_la_OBJECTS) $(libnm_settings_plugin_example_la_DEPENDENCIES) 
+	$(AM_V_CCLD)$(libnm_settings_plugin_example_la_LINK)  $(libnm_settings_plugin_example_la_OBJECTS) $(libnm_settings_plugin_example_la_LIBADD) $(LIBS)
+
+mostlyclean-compile:
+	-rm -f *.$(OBJEXT)
+
+distclean-compile:
+	-rm -f *.tab.c
+
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libnm_settings_plugin_example_la-errors.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libnm_settings_plugin_example_la-nm-example-connection.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libnm_settings_plugin_example_la-plugin.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libnm_settings_plugin_example_la-reader.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libnm_settings_plugin_example_la-writer.Plo@am__quote@
+
+.c.o:
+@am__fastdepCC_TRUE@	$(AM_V_CC)depbase=`echo $@ | sed 's|[^/]*$$|$(DEPDIR)/&|;s|\.o$$||'`;\
+@am__fastdepCC_TRUE@	$(COMPILE) -MT $@ -MD -MP -MF $$depbase.Tpo -c -o $@ $< &&\
+@am__fastdepCC_TRUE@	$(am__mv) $$depbase.Tpo $$depbase.Po
+@am__fastdepCC_FALSE@	$(AM_V_CC) @AM_BACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@	source='$<' object='$@' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@	DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@	$(COMPILE) -c -o $@ $<
+
+.c.obj:
+@am__fastdepCC_TRUE@	$(AM_V_CC)depbase=`echo $@ | sed 's|[^/]*$$|$(DEPDIR)/&|;s|\.obj$$||'`;\
+@am__fastdepCC_TRUE@	$(COMPILE) -MT $@ -MD -MP -MF $$depbase.Tpo -c -o $@ `$(CYGPATH_W) '$<'` &&\
+@am__fastdepCC_TRUE@	$(am__mv) $$depbase.Tpo $$depbase.Po
+@am__fastdepCC_FALSE@	$(AM_V_CC) @AM_BACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@	source='$<' object='$@' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@	DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@	$(COMPILE) -c -o $@ `$(CYGPATH_W) '$<'`
+
+.c.lo:
+@am__fastdepCC_TRUE@	$(AM_V_CC)depbase=`echo $@ | sed 's|[^/]*$$|$(DEPDIR)/&|;s|\.lo$$||'`;\
+@am__fastdepCC_TRUE@	$(LTCOMPILE) -MT $@ -MD -MP -MF $$depbase.Tpo -c -o $@ $< &&\
+@am__fastdepCC_TRUE@	$(am__mv) $$depbase.Tpo $$depbase.Plo
+@am__fastdepCC_FALSE@	$(AM_V_CC) @AM_BACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@	source='$<' object='$@' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@	DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@	$(LTCOMPILE) -c -o $@ $<
+
+libnm_settings_plugin_example_la-nm-example-connection.lo: nm-example-connection.c
+@am__fastdepCC_TRUE@	$(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libnm_settings_plugin_example_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT libnm_settings_plugin_example_la-nm-example-connection.lo -MD -MP -MF $(DEPDIR)/libnm_settings_plugin_example_la-nm-example-connection.Tpo -c -o libnm_settings_plugin_example_la-nm-example-connection.lo `test -f 'nm-example-connection.c' || echo '$(srcdir)/'`nm-example-connection.c
+@am__fastdepCC_TRUE@	$(AM_V_at)$(am__mv) $(DEPDIR)/libnm_settings_plugin_example_la-nm-example-connection.Tpo $(DEPDIR)/libnm_settings_plugin_example_la-nm-example-connection.Plo
+@am__fastdepCC_FALSE@	$(AM_V_CC) @AM_BACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@	source='nm-example-connection.c' object='libnm_settings_plugin_example_la-nm-example-connection.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@	DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@	$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libnm_settings_plugin_example_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o libnm_settings_plugin_example_la-nm-example-connection.lo `test -f 'nm-example-connection.c' || echo '$(srcdir)/'`nm-example-connection.c
+
+libnm_settings_plugin_example_la-plugin.lo: plugin.c
+@am__fastdepCC_TRUE@	$(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libnm_settings_plugin_example_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT libnm_settings_plugin_example_la-plugin.lo -MD -MP -MF $(DEPDIR)/libnm_settings_plugin_example_la-plugin.Tpo -c -o libnm_settings_plugin_example_la-plugin.lo `test -f 'plugin.c' || echo '$(srcdir)/'`plugin.c
+@am__fastdepCC_TRUE@	$(AM_V_at)$(am__mv) $(DEPDIR)/libnm_settings_plugin_example_la-plugin.Tpo $(DEPDIR)/libnm_settings_plugin_example_la-plugin.Plo
+@am__fastdepCC_FALSE@	$(AM_V_CC) @AM_BACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@	source='plugin.c' object='libnm_settings_plugin_example_la-plugin.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@	DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@	$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libnm_settings_plugin_example_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o libnm_settings_plugin_example_la-plugin.lo `test -f 'plugin.c' || echo '$(srcdir)/'`plugin.c
+
+libnm_settings_plugin_example_la-errors.lo: errors.c
+@am__fastdepCC_TRUE@	$(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libnm_settings_plugin_example_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT libnm_settings_plugin_example_la-errors.lo -MD -MP -MF $(DEPDIR)/libnm_settings_plugin_example_la-errors.Tpo -c -o libnm_settings_plugin_example_la-errors.lo `test -f 'errors.c' || echo '$(srcdir)/'`errors.c
+@am__fastdepCC_TRUE@	$(AM_V_at)$(am__mv) $(DEPDIR)/libnm_settings_plugin_example_la-errors.Tpo $(DEPDIR)/libnm_settings_plugin_example_la-errors.Plo
+@am__fastdepCC_FALSE@	$(AM_V_CC) @AM_BACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@	source='errors.c' object='libnm_settings_plugin_example_la-errors.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@	DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@	$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libnm_settings_plugin_example_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o libnm_settings_plugin_example_la-errors.lo `test -f 'errors.c' || echo '$(srcdir)/'`errors.c
+
+libnm_settings_plugin_example_la-reader.lo: reader.c
+@am__fastdepCC_TRUE@	$(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libnm_settings_plugin_example_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT libnm_settings_plugin_example_la-reader.lo -MD -MP -MF $(DEPDIR)/libnm_settings_plugin_example_la-reader.Tpo -c -o libnm_settings_plugin_example_la-reader.lo `test -f 'reader.c' || echo '$(srcdir)/'`reader.c
+@am__fastdepCC_TRUE@	$(AM_V_at)$(am__mv) $(DEPDIR)/libnm_settings_plugin_example_la-reader.Tpo $(DEPDIR)/libnm_settings_plugin_example_la-reader.Plo
+@am__fastdepCC_FALSE@	$(AM_V_CC) @AM_BACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@	source='reader.c' object='libnm_settings_plugin_example_la-reader.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@	DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@	$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libnm_settings_plugin_example_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o libnm_settings_plugin_example_la-reader.lo `test -f 'reader.c' || echo '$(srcdir)/'`reader.c
+
+libnm_settings_plugin_example_la-writer.lo: writer.c
+@am__fastdepCC_TRUE@	$(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libnm_settings_plugin_example_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT libnm_settings_plugin_example_la-writer.lo -MD -MP -MF $(DEPDIR)/libnm_settings_plugin_example_la-writer.Tpo -c -o libnm_settings_plugin_example_la-writer.lo `test -f 'writer.c' || echo '$(srcdir)/'`writer.c
+@am__fastdepCC_TRUE@	$(AM_V_at)$(am__mv) $(DEPDIR)/libnm_settings_plugin_example_la-writer.Tpo $(DEPDIR)/libnm_settings_plugin_example_la-writer.Plo
+@am__fastdepCC_FALSE@	$(AM_V_CC) @AM_BACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@	source='writer.c' object='libnm_settings_plugin_example_la-writer.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@	DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@	$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libnm_settings_plugin_example_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o libnm_settings_plugin_example_la-writer.lo `test -f 'writer.c' || echo '$(srcdir)/'`writer.c
+
+mostlyclean-libtool:
+	-rm -f *.lo
+
+clean-libtool:
+	-rm -rf .libs _libs
+
+ID: $(HEADERS) $(SOURCES) $(LISP) $(TAGS_FILES)
+	list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \
+	unique=`for i in $$list; do \
+	    if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \
+	  done | \
+	  $(AWK) '{ files[$$0] = 1; nonempty = 1; } \
+	      END { if (nonempty) { for (i in files) print i; }; }'`; \
+	mkid -fID $$unique
+tags: TAGS
+
+TAGS:  $(HEADERS) $(SOURCES)  $(TAGS_DEPENDENCIES) \
+		$(TAGS_FILES) $(LISP)
+	set x; \
+	here=`pwd`; \
+	list='$(SOURCES) $(HEADERS)  $(LISP) $(TAGS_FILES)'; \
+	unique=`for i in $$list; do \
+	    if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \
+	  done | \
+	  $(AWK) '{ files[$$0] = 1; nonempty = 1; } \
+	      END { if (nonempty) { for (i in files) print i; }; }'`; \
+	shift; \
+	if test -z "$(ETAGS_ARGS)$$*$$unique"; then :; else \
+	  test -n "$$unique" || unique=$$empty_fix; \
+	  if test $$# -gt 0; then \
+	    $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \
+	      "$$@" $$unique; \
+	  else \
+	    $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \
+	      $$unique; \
+	  fi; \
+	fi
+ctags: CTAGS
+CTAGS:  $(HEADERS) $(SOURCES)  $(TAGS_DEPENDENCIES) \
+		$(TAGS_FILES) $(LISP)
+	list='$(SOURCES) $(HEADERS)  $(LISP) $(TAGS_FILES)'; \
+	unique=`for i in $$list; do \
+	    if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \
+	  done | \
+	  $(AWK) '{ files[$$0] = 1; nonempty = 1; } \
+	      END { if (nonempty) { for (i in files) print i; }; }'`; \
+	test -z "$(CTAGS_ARGS)$$unique" \
+	  || $(CTAGS) $(CTAGSFLAGS) $(AM_CTAGSFLAGS) $(CTAGS_ARGS) \
+	     $$unique
+
+GTAGS:
+	here=`$(am__cd) $(top_builddir) && pwd` \
+	  && $(am__cd) $(top_srcdir) \
+	  && gtags -i $(GTAGS_ARGS) "$$here"
+
+distclean-tags:
+	-rm -f TAGS ID GTAGS GRTAGS GSYMS GPATH tags
+
+distdir: $(DISTFILES)
+	@srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \
+	topsrcdirstrip=`echo "$(top_srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \
+	list='$(DISTFILES)'; \
+	  dist_files=`for file in $$list; do echo $$file; done | \
+	  sed -e "s|^$$srcdirstrip/||;t" \
+	      -e "s|^$$topsrcdirstrip/|$(top_builddir)/|;t"`; \
+	case $$dist_files in \
+	  */*) $(MKDIR_P) `echo "$$dist_files" | \
+			   sed '/\//!d;s|^|$(distdir)/|;s,/[^/]*$$,,' | \
+			   sort -u` ;; \
+	esac; \
+	for file in $$dist_files; do \
+	  if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \
+	  if test -d $$d/$$file; then \
+	    dir=`echo "/$$file" | sed -e 's,/[^/]*$$,,'`; \
+	    if test -d "$(distdir)/$$file"; then \
+	      find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \
+	    fi; \
+	    if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \
+	      cp -fpR $(srcdir)/$$file "$(distdir)$$dir" || exit 1; \
+	      find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \
+	    fi; \
+	    cp -fpR $$d/$$file "$(distdir)$$dir" || exit 1; \
+	  else \
+	    test -f "$(distdir)/$$file" \
+	    || cp -p $$d/$$file "$(distdir)/$$file" \
+	    || exit 1; \
+	  fi; \
+	done
+check-am: all-am
+check: check-am
+all-am: Makefile $(LTLIBRARIES)
+installdirs:
+install: install-am
+install-exec: install-exec-am
+install-data: install-data-am
+uninstall: uninstall-am
+
+install-am: all-am
+	@$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am
+
+installcheck: installcheck-am
+install-strip:
+	$(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \
+	  install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \
+	  `test -z '$(STRIP)' || \
+	    echo "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'"` install
+mostlyclean-generic:
+
+clean-generic:
+
+distclean-generic:
+	-test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES)
+	-test . = "$(srcdir)" || test -z "$(CONFIG_CLEAN_VPATH_FILES)" || rm -f $(CONFIG_CLEAN_VPATH_FILES)
+
+maintainer-clean-generic:
+	@echo "This command is intended for maintainers to use"
+	@echo "it deletes files that may require special tools to rebuild."
+clean: clean-am
+
+clean-am: clean-generic clean-libtool clean-noinstLTLIBRARIES \
+	mostlyclean-am
+
+distclean: distclean-am
+	-rm -rf ./$(DEPDIR)
+	-rm -f Makefile
+distclean-am: clean-am distclean-compile distclean-generic \
+	distclean-tags
+
+dvi: dvi-am
+
+dvi-am:
+
+html: html-am
+
+html-am:
+
+info: info-am
+
+info-am:
+
+install-data-am:
+
+install-dvi: install-dvi-am
+
+install-dvi-am:
+
+install-exec-am:
+
+install-html: install-html-am
+
+install-html-am:
+
+install-info: install-info-am
+
+install-info-am:
+
+install-man:
+
+install-pdf: install-pdf-am
+
+install-pdf-am:
+
+install-ps: install-ps-am
+
+install-ps-am:
+
+installcheck-am:
+
+maintainer-clean: maintainer-clean-am
+	-rm -rf ./$(DEPDIR)
+	-rm -f Makefile
+maintainer-clean-am: distclean-am maintainer-clean-generic
+
+mostlyclean: mostlyclean-am
+
+mostlyclean-am: mostlyclean-compile mostlyclean-generic \
+	mostlyclean-libtool
+
+pdf: pdf-am
+
+pdf-am:
+
+ps: ps-am
+
+ps-am:
+
+uninstall-am:
+
+.MAKE: install-am install-strip
+
+.PHONY: CTAGS GTAGS all all-am check check-am clean clean-generic \
+	clean-libtool clean-noinstLTLIBRARIES ctags distclean \
+	distclean-compile distclean-generic distclean-libtool \
+	distclean-tags distdir dvi dvi-am html html-am info info-am \
+	install install-am install-data install-data-am install-dvi \
+	install-dvi-am install-exec 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-strip installcheck installcheck-am installdirs \
+	maintainer-clean maintainer-clean-generic mostlyclean \
+	mostlyclean-compile mostlyclean-generic mostlyclean-libtool \
+	pdf pdf-am ps ps-am tags uninstall uninstall-am
+
+
+# Tell versions [3.59,3.63) of GNU make to not export all variables.
+# Otherwise a system limit (for SysV at least) may be exceeded.
+.NOEXPORT:
diff --git a/src/settings/plugins/example/README b/src/settings/plugins/example/README
new file mode 100644
index 00000000..224814d1
--- /dev/null
+++ b/src/settings/plugins/example/README
@@ -0,0 +1,35 @@
+Plugins generally have three components:
+
+1) plugin object: manages the individual "connections", which are
+  just objects wrapped around on-disk config data.  The plugin handles requests
+  to add new connections via the NM D-Bus API, and also watches config
+  directories for changes to configuration data.  It also handles reading and
+  writing the persistent hostname, if the plugin supports hostnames.  Plugins
+  implement the NMSystemConfigInterface interface.  See plugin.c.
+
+2) "connections": subclasses of NMSettingsConnection.  They handle updates to
+  configuration data, deletion, etc.  See NMExampleConnection.c.
+
+3) reader/writer code: typically a separate static library that gets linked
+  into the main plugin shared object, so they can be unit tested separately
+  from the plugin.  This code should read config data from disk and create
+  an NMConnection from it, and be capable of taking an NMConnection and writing
+  out appropriate configuration data to disk.
+
+NM will first call the "factory" function that every module must provide, which
+is nm_system_config_factory().  That function creates and returns a singleton
+instance of the plugin's main object, which implements NMSystemConfigInterface.
+That interface is implemented via the object definition in G_DEFINE_TYPE_EXTENDED
+in plugin.c, which registers the interface setup function
+system_config_interface_init(), which when called actually sets up the vtables
+for the functions defined by NMSystemConfigInterface.  Thus there are two
+entry points into the plugin:  nm_system_config_factory() and
+the NMSystemConfigInterface methods.
+
+The plugin also emits various signals (defined by NMSystemConfigInterface)
+which NetworkManager listens for.  These include persistent hostname changes
+(if something modified the file in which the persistent hostname is stored)
+and notifications of new connections if they were created via changes to
+the on-disk files.  The "connection" objects can also emit signals
+(defined by the NMSettingsConnection and NMConnection superclasses) when the
+connections' backing storage gets changed or deleted. 
diff --git a/src/settings/plugins/example/common.h b/src/settings/plugins/example/common.h
new file mode 100644
index 00000000..a4197070
--- /dev/null
+++ b/src/settings/plugins/example/common.h
@@ -0,0 +1,56 @@
+/* -*- Mode: C; tab-width: 4; indent-tabs-mode: t; c-basic-offset: 4 -*- */
+/* NetworkManager system settings service
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * (C) Copyright 2012 Red Hat, Inc.
+ */
+
+#ifndef __COMMON_H__
+#define __COMMON_H__
+
+#include <glib.h>
+
+#include <nm-connection.h>
+
+/* General info about the plugin that the code may want to use for logging
+ * purposes.
+ */
+#define EXAMPLE_PLUGIN_NAME "example"
+#define EXAMPLE_PLUGIN_INFO "(c) 2012 Red Hat, Inc.  To report bugs please use the NetworkManager mailing list."
+
+#define EXAMPLE_DIR SYSCONFDIR"/NetworkManager/example-plugin"
+
+/* Boilerplate stuff for the plugin's error domain.  Bits of the code that
+ * create new errors in the plugin's domain will create errors of
+ * type EXAMPLE_PLUGIN_ERROR like so:
+ *
+ *  error = g_error_new_literal (EXAMPLE_PLUGIN_ERROR,
+ *                               <specific error number>,
+ *                               "This is a really bad error.");
+ */
+#define EXAMPLE_PLUGIN_ERROR (example_plugin_error_quark ())
+GQuark example_plugin_error_quark (void);
+
+/* Prototypes for the reader/writer functions */
+NMConnection *connection_from_file (const char *filename, GError **error);
+
+gboolean write_connection (NMConnection *connection,
+                           const char *existing_path,
+                           char **out_path,
+                           GError **error);
+
+#endif  /* __COMMON_H__ */
+
diff --git a/src/settings/plugins/example/errors.c b/src/settings/plugins/example/errors.c
new file mode 100644
index 00000000..8181f8a3
--- /dev/null
+++ b/src/settings/plugins/example/errors.c
@@ -0,0 +1,40 @@
+/* -*- Mode: C; tab-width: 4; indent-tabs-mode: t; c-basic-offset: 4 -*- */
+/* NetworkManager system settings service
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * (C) Copyright 2012 Red Hat, Inc.
+ */
+
+#include <glib.h>
+#include "common.h"
+
+/* This is boilerplate code for defining the error domain that the plugin may
+ * return to NetworkManager for various operations.  It just registers a
+ * GObject "quark" (a UUID really) for the error which allows glib to keep
+ * track of all the different error domains.
+ */
+GQuark
+example_plugin_error_quark (void)
+{
+	static GQuark error_quark = 0;
+
+	if (G_UNLIKELY (error_quark == 0))
+		error_quark = g_quark_from_static_string ("example-plugin-error-quark");
+
+	return error_quark;
+}
+
+
diff --git a/src/settings/plugins/example/nm-example-connection.c b/src/settings/plugins/example/nm-example-connection.c
new file mode 100644
index 00000000..e4a69f9b
--- /dev/null
+++ b/src/settings/plugins/example/nm-example-connection.c
@@ -0,0 +1,191 @@
+/* -*- Mode: C; tab-width: 4; indent-tabs-mode: t; c-basic-offset: 4 -*- */
+/* NetworkManager system settings service - keyfile plugin
+ *
+ * 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) 2012 Red Hat, Inc.
+ */
+
+#include <string.h>
+#include <glib/gstdio.h>
+#include <NetworkManager.h>
+#include <nm-setting-connection.h>
+#include <nm-utils.h>
+
+#include "nm-system-config-interface.h"
+#include "nm-dbus-glib-types.h"
+#include "nm-example-connection.h"
+#include "common.h"
+
+/* GObject boilerplate; this object is a subclass of NMSettingsConnection
+ * which is specified by the NM_TYPE_SETTINGS_CONNECTION bit here.  That
+ * in turn is a subclass of NMConnection, so it ends up that NMExampleConnection
+ * is a subclass of NMConnection too.
+ */
+G_DEFINE_TYPE (NMExampleConnection, nm_example_connection, NM_TYPE_SETTINGS_CONNECTION)
+
+#define NM_EXAMPLE_CONNECTION_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), NM_TYPE_EXAMPLE_CONNECTION, NMExampleConnectionPrivate))
+
+/* Object private instance data */
+typedef struct {
+	char *path;
+} NMExampleConnectionPrivate;
+
+
+/* Creates a new object which encapsulates an on-disk connection and any
+ * plugin-specific operations or data.
+ */
+NMExampleConnection *
+nm_example_connection_new (const char *full_path,
+                           NMConnection *source,
+                           GError **error)
+{
+	GObject *object;
+	NMExampleConnectionPrivate *priv;
+	NMConnection *tmp;
+	const char *uuid;
+
+	g_return_val_if_fail (full_path != NULL, NULL);
+
+	/* If we're given a connection already, prefer that instead of re-reading */
+	if (source)
+		tmp = g_object_ref (source);
+	else {
+		/* Read the data offdisk and translate it into a simple NMConnection object */
+		tmp = connection_from_file (full_path, error);
+		if (!tmp)
+			return NULL;
+	}
+
+	/* Actually create the new NMExampleConnection object */
+	object = (GObject *) g_object_new (NM_TYPE_EXAMPLE_CONNECTION, NULL);
+	if (!object)
+		goto out;
+
+	priv = NM_EXAMPLE_CONNECTION_GET_PRIVATE (object);
+	priv->path = g_strdup (full_path);
+
+	/* Update our settings with what was read from the file or what got passed
+	 * in as a source NMConnection.
+	 */
+	if (!nm_settings_connection_replace_settings (NM_SETTINGS_CONNECTION (object), tmp, error)) {
+		g_object_unref (object);
+		object = NULL;
+		goto out;
+	}
+
+	/* Make sure we have a UUID; just a sanity check */
+	uuid = nm_connection_get_uuid (NM_CONNECTION (object));
+	if (!uuid) {
+		g_set_error (error, EXAMPLE_PLUGIN_ERROR, 0,
+		             "Connection in file %s had no UUID", full_path);
+		g_object_unref (object);
+		object = NULL;
+	}
+
+out:
+	g_object_unref (tmp);
+	return (NMExampleConnection *) object;
+}
+
+const char *
+nm_example_connection_get_path (NMExampleConnection *self)
+{
+	g_return_val_if_fail (NM_IS_EXAMPLE_CONNECTION (self), NULL);
+
+	/* Simple accessor that returns the file path from our private instance data */
+	return NM_EXAMPLE_CONNECTION_GET_PRIVATE (self)->path;
+}
+
+static void
+commit_changes (NMSettingsConnection *connection,
+                NMSettingsConnectionCommitFunc callback,
+                gpointer user_data)
+{
+	NMExampleConnectionPrivate *priv = NM_EXAMPLE_CONNECTION_GET_PRIVATE (connection);
+	char *path = NULL;
+	GError *error = NULL;
+
+	/* Write the new connection data out to disk.  This function passes
+	 * back the path of the file it wrote out so that we know what that
+	 * path is if the connection is a completely new one.
+	 */
+	if (!write_connection (NM_CONNECTION (connection), priv->path, &path, &error)) {
+		callback (connection, error, user_data);
+		g_clear_error (&error);
+		return;
+	}
+
+	/* Update the filename if it changed */
+	if (path) {
+		g_free (priv->path);
+		priv->path = path;
+	}
+
+	/* Chain up to parent for generic commit stuff */
+	NM_SETTINGS_CONNECTION_CLASS (nm_example_connection_parent_class)->commit_changes (connection,
+	                                                                                   callback,
+	                                                                                   user_data);
+}
+
+static void 
+do_delete (NMSettingsConnection *connection,
+           NMSettingsConnectionDeleteFunc callback,
+           gpointer user_data)
+{
+	NMExampleConnectionPrivate *priv = NM_EXAMPLE_CONNECTION_GET_PRIVATE (connection);
+
+	g_unlink (priv->path);
+
+	/* Chain up to parent for generic deletion stuff */
+	NM_SETTINGS_CONNECTION_CLASS (nm_example_connection_parent_class)->delete (connection,
+	                                                                           callback,
+	                                                                           user_data);
+}
+
+/**************************************************************/
+
+static void
+nm_example_connection_init (NMExampleConnection *connection)
+{
+}
+
+static void
+finalize (GObject *object)
+{
+	NMExampleConnectionPrivate *priv = NM_EXAMPLE_CONNECTION_GET_PRIVATE (object);
+
+	/* Zero out any secrets so we don't leave them in memory */
+	nm_connection_clear_secrets (NM_CONNECTION (object));
+
+	g_free (priv->path);
+
+	G_OBJECT_CLASS (nm_example_connection_parent_class)->finalize (object);
+}
+
+static void
+nm_example_connection_class_init (NMExampleConnectionClass *keyfile_connection_class)
+{
+	GObjectClass *object_class = G_OBJECT_CLASS (keyfile_connection_class);
+	NMSettingsConnectionClass *settings_class = NM_SETTINGS_CONNECTION_CLASS (keyfile_connection_class);
+
+	/* Tells GObject to allocate and zero our instance data pointer */
+	g_type_class_add_private (keyfile_connection_class, sizeof (NMExampleConnectionPrivate));
+
+	/* Overrides of various superclass methods */
+	object_class->finalize = finalize;
+	settings_class->commit_changes = commit_changes;
+	settings_class->delete = do_delete;
+}
diff --git a/src/settings/plugins/example/nm-example-connection.h b/src/settings/plugins/example/nm-example-connection.h
new file mode 100644
index 00000000..d6d09e16
--- /dev/null
+++ b/src/settings/plugins/example/nm-example-connection.h
@@ -0,0 +1,55 @@
+/* -*- Mode: C; tab-width: 4; indent-tabs-mode: t; c-basic-offset: 4 -*- */
+/* NetworkManager system settings service - keyfile plugin
+ *
+ * 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) 2012 Red Hat, Inc.
+ */
+
+#ifndef NM_EXAMPLE_CONNECTION_H
+#define NM_EXAMPLE_CONNECTION_H
+
+#include <nm-settings-connection.h>
+
+G_BEGIN_DECLS
+
+/* GObject boilerplate */
+#define NM_TYPE_EXAMPLE_CONNECTION            (nm_example_connection_get_type ())
+#define NM_EXAMPLE_CONNECTION(obj)            (G_TYPE_CHECK_INSTANCE_CAST ((obj), NM_TYPE_EXAMPLE_CONNECTION, NMExampleConnection))
+#define NM_EXAMPLE_CONNECTION_CLASS(klass)    (G_TYPE_CHECK_CLASS_CAST ((klass), NM_TYPE_EXAMPLE_CONNECTION, NMExampleConnectionClass))
+#define NM_IS_EXAMPLE_CONNECTION(obj)         (G_TYPE_CHECK_INSTANCE_TYPE ((obj), NM_TYPE_EXAMPLE_CONNECTION))
+#define NM_IS_EXAMPLE_CONNECTION_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((obj), NM_TYPE_EXAMPLE_CONNECTION))
+#define NM_EXAMPLE_CONNECTION_GET_CLASS(obj)  (G_TYPE_INSTANCE_GET_CLASS ((obj), NM_TYPE_EXAMPLE_CONNECTION, NMExampleConnectionClass))
+
+typedef struct {
+	NMSettingsConnection parent;
+} NMExampleConnection;
+
+typedef struct {
+	NMSettingsConnectionClass parent;
+} NMExampleConnectionClass;
+
+GType nm_example_connection_get_type (void);
+
+/* Actual API that plugin.c will call */
+NMExampleConnection *nm_example_connection_new (const char *filename,
+                                                NMConnection *source,
+                                                GError **error);
+
+const char *nm_example_connection_get_path (NMExampleConnection *self);
+
+G_END_DECLS
+
+#endif /* NM_EXAMPLE_CONNECTION_H */
diff --git a/src/settings/plugins/example/plugin.c b/src/settings/plugins/example/plugin.c
new file mode 100644
index 00000000..04af03e7
--- /dev/null
+++ b/src/settings/plugins/example/plugin.c
@@ -0,0 +1,868 @@
+/* -*- Mode: C; tab-width: 4; indent-tabs-mode: t; c-basic-offset: 4 -*- */
+/* NetworkManager system settings service - keyfile plugin
+ *
+ * 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) 2012 Red Hat, Inc.
+ */
+
+#include <config.h>
+#include <sys/stat.h>
+#include <unistd.h>
+#include <sys/types.h>
+#include <netinet/ether.h>
+#include <string.h>
+
+#include <gmodule.h>
+#include <glib.h>
+#include <glib/gstdio.h>
+#include <gio/gio.h>
+
+#include <nm-connection.h>
+#include <nm-setting.h>
+#include <nm-setting-connection.h>
+
+#include "plugin.h"
+#include "nm-system-config-interface.h"
+#include "common.h"
+#include "nm-example-connection.h"
+
+static char *plugin_get_hostname (SCPluginExample *plugin);
+static void system_config_interface_init (NMSystemConfigInterface *system_config_interface_class);
+
+/* GObject object definition.  This actually defines the object and tells
+ * GObject about the interfaces this object provides.  Here we provide
+ * the "system config interface" which is the API that NetworkManager uses
+ * to communicate with this plugin.
+ *
+ * Interface and super/sub-class access with GObject works via casting and
+ * GObject magically figures out what needs to be called.  So, given:
+ *
+ *    SCPluginExample *plugin = <new plugin>;
+ *
+ * you can call GObject methods since SCPluginExample inherits from GObject
+ * via the G_TYPE_OBJECT argument of G_DEFINE_TYPE_EXTENDED below:
+ *
+ *    g_object_set_data (G_OBJECT (plugin), ...);
+ *
+ * and since SCPluginExample implements NMSystemConfigInterface via the
+ * G_IMPLEMENT_INTERFACE bit below, we can also call any methods of
+ * NMSystemConfigInterface (defined in NM sources in nm-system-config-interface.c):
+ *
+ *    connections = nm_system_config_interface_get_connections (NM_SYSTEM_CONFIG_INTERFACE (plugin));
+ *
+ * For the call to nm_system_config_interface_get_connections() that eventually
+ * ends up in the get_connections() method in this file because the
+ * system_config_interface_init() function sets up the vtable for this objects
+ * implementation of NMSystemConfigInterface.
+ */
+G_DEFINE_TYPE_EXTENDED (SCPluginExample, sc_plugin_example, G_TYPE_OBJECT, 0,
+                        G_IMPLEMENT_INTERFACE (NM_TYPE_SYSTEM_CONFIG_INTERFACE, system_config_interface_init))
+
+/* Quick define to access the object's private data pointer; this pointer
+ * points to the object's instance data.
+ */
+#define SC_PLUGIN_EXAMPLE_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), SC_TYPE_PLUGIN_EXAMPLE, SCPluginExamplePrivate))
+
+/* Instance data.  When the object is created, a new structure of this type
+ * will be created and zeroed for this instance of the object to use.  This
+ * is actually done by g_type_class_add_private() when called from the object's
+ * class init function.
+ */
+typedef struct {
+	/* This hash holds each connection known to this plugin */
+	GHashTable *connections;
+
+	/* A watch for changes on the directory that holds the configuration files
+	 * so the plugin can respond to configuration changes on-the-fly and
+	 * tell NM that the connection data has changed.  Typically the plugin
+	 * needs to monitor the directory itself (to watch for completely new files)
+	 * while the individual connections watch their individual config files.
+	 */
+	GFileMonitor *monitor;
+	guint monitor_id;
+
+	/* Tracks changes to the global NM config file, just in case our
+	 * plugin has some specific options (like unmanaged devices) that
+	 * might be changed at runtime.
+	 */
+	char *conf_file;
+	GFileMonitor *conf_file_monitor;
+	guint conf_file_monitor_id;
+
+	/* Persistent hostname if the plugin supports hostnames.  Normally used
+	 * for distro plugins; ie Red Hat uses /etc/sysconfig/hostname while
+	 * Debian uses /etc/hostname.  Plugins can abstract the storage location
+	 * and just tell NM what the persisten hostname is and when its backing
+	 * file has changed.  NM handles actually setting the hostname.
+	 */
+	char *hostname;
+} SCPluginExamplePrivate;
+
+static NMSettingsConnection *
+_internal_new_connection (SCPluginExample *self,
+                          const char *full_path,
+                          NMConnection *source,
+                          GError **error)
+{
+	SCPluginExamplePrivate *priv = SC_PLUGIN_EXAMPLE_GET_PRIVATE (self);
+	NMExampleConnection *connection;
+
+	g_return_val_if_fail (full_path != NULL, NULL);
+
+	/* 'source' will usually be NULL if we're going to read the connection
+	 * off disk.  But if the new connection is coming from NetworkManager
+	 * (ie, from a D-Bus AddConnection request) then we'll have 'source' too.
+	 * This function expects the connection to already be written to disk
+	 * so that the NMExampleConnection object can re-read it and intialize
+	 * state in the same manner as when getting a change notification from
+	 * the config directory.  That simplifies things somewhat.
+	 */
+
+	connection = nm_example_connection_new (full_path, source, error);
+	if (connection) {
+		g_hash_table_insert (priv->connections,
+		                     (gpointer) nm_example_connection_get_path (connection),
+		                     connection);
+	}
+
+	return (NMSettingsConnection *) connection;
+}
+
+/* Read each file in our config directory and try to create a new
+ * NMExamplePlugin for it.
+ */
+static void
+read_connections (NMSystemConfigInterface *config)
+{
+	SCPluginExample *self = SC_PLUGIN_EXAMPLE (config);
+	GDir *dir;
+	GError *error = NULL;
+	const char *item;
+
+	dir = g_dir_open (EXAMPLE_DIR, 0, &error);
+	if (!dir) {
+		PLUGIN_WARN (EXAMPLE_PLUGIN_NAME, "Cannot read directory '%s': (%d) %s",
+		             EXAMPLE_DIR,
+		             error ? error->code : -1,
+		             error && error->message ? error->message : "(unknown)");
+		g_clear_error (&error);
+		return;
+	}
+
+	while ((item = g_dir_read_name (dir))) {
+		NMSettingsConnection *connection;
+		char *full_path;
+
+		/* XXX: Check file extension and ignore "~", ".tmp", ".bak", etc */
+
+		full_path = g_build_filename (EXAMPLE_DIR, item, NULL);
+		PLUGIN_PRINT (EXAMPLE_PLUGIN_NAME, "parsing %s ... ", item);
+
+		connection = _internal_new_connection (self, full_path, NULL, &error);
+		if (connection) {
+			PLUGIN_PRINT (EXAMPLE_PLUGIN_NAME, "    read connection '%s'",
+			              nm_connection_get_id (NM_CONNECTION (connection)));
+		} else {
+			PLUGIN_PRINT (EXAMPLE_PLUGIN_NAME, "    error: %s",
+				          (error && error->message) ? error->message : "(unknown)");
+		}
+		g_clear_error (&error);
+		g_free (full_path);
+	}
+	g_dir_close (dir);
+}
+
+static void
+update_connection_settings_commit_cb (NMSettingsConnection *orig, GError *error, gpointer user_data)
+{
+	/* If there was an error updating the connection's internal stuff, then
+	 * we can't do anything except log it and remove the connection.  This might
+	 * happen due to invalid data, but as the data would already have been
+	 * verified before it ever got to this plugin, we shouldn't ever get
+	 * an error here.
+	 */
+	if (error) {
+		g_warning ("%s: '%s' / '%s' invalid: %d",
+		       	   __func__,
+		       	   error ? g_type_name (nm_connection_lookup_setting_type_by_quark (error->domain)) : "(none)",
+		       	   (error && error->message) ? error->message : "(none)",
+		       	   error ? error->code : -1);
+		g_clear_error (&error);
+
+		nm_settings_connection_signal_remove (orig);
+	}
+}
+
+static void
+update_connection_settings (NMExampleConnection *orig,
+                            NMExampleConnection *new)
+{
+	/* This just replaces the orig's internal settings with those from new */
+	nm_settings_connection_replace_and_commit (NM_SETTINGS_CONNECTION (orig),
+	                                           NM_CONNECTION (new),
+	                                           update_connection_settings_commit_cb, NULL);
+}
+
+/* Monitoring */
+
+static void
+remove_connection (SCPluginExample *self,
+                   NMExampleConnection *connection,
+                   const char *name)
+{
+	g_return_if_fail (connection != NULL);
+	g_return_if_fail (name != NULL);
+
+	/* Removing from the hash table should drop the last reference, but since
+	 * we need the object to stay alive across the signal emission to NM,
+	 * we grab a temporary reference.
+	 */
+	g_object_ref (connection);
+	g_hash_table_remove (SC_PLUGIN_EXAMPLE_GET_PRIVATE (self)->connections, name);
+
+	/* Tell NM the connection is gone */
+	nm_settings_connection_signal_remove (NM_SETTINGS_CONNECTION (connection));
+
+	/* Remove the temporary reference; connection will now be destroyed */
+	g_object_unref (connection);
+}
+
+/* Look through all connections we know about and return one with a given UUID */
+static NMExampleConnection *
+find_by_uuid (SCPluginExample *self, const char *uuid)
+{
+	SCPluginExamplePrivate *priv = SC_PLUGIN_EXAMPLE_GET_PRIVATE (self);
+	GHashTableIter iter;
+	gpointer data = NULL;
+
+	g_return_val_if_fail (uuid != NULL, NULL);
+
+	g_hash_table_iter_init (&iter, priv->connections);
+	while (g_hash_table_iter_next (&iter, NULL, &data)) {
+		NMConnection *candidate = NM_CONNECTION (data);
+
+		if (strcmp (uuid, nm_connection_get_uuid (candidate)) == 0)
+			return NM_EXAMPLE_CONNECTION (candidate);
+	}
+	return NULL;
+}
+
+
+static void
+dir_changed (GFileMonitor *monitor,
+             GFile *file,
+             GFile *other_file,
+             GFileMonitorEvent event_type,
+             gpointer user_data)
+{
+	NMSystemConfigInterface *config = NM_SYSTEM_CONFIG_INTERFACE (user_data);
+	SCPluginExample *self = SC_PLUGIN_EXAMPLE (config);
+	SCPluginExamplePrivate *priv = SC_PLUGIN_EXAMPLE_GET_PRIVATE (self);
+	char *full_path;
+	NMExampleConnection *connection;
+	GError *error = NULL;
+
+	full_path = g_file_get_path (file);
+	/* XXX: Check here if you need to ignore this file, ie by checking for
+	 * extensions like "~" and ".bak" or ".tmp".  If so just return;
+	 */
+
+	/* Check if we know about this connection already */
+	connection = g_hash_table_lookup (priv->connections, full_path);
+
+	switch (event_type) {
+	case G_FILE_MONITOR_EVENT_DELETED:
+		if (connection) {
+			PLUGIN_PRINT (EXAMPLE_PLUGIN_NAME, "removed %s.", full_path);
+			remove_connection (SC_PLUGIN_EXAMPLE (config), connection, full_path);
+		}
+		break;
+	case G_FILE_MONITOR_EVENT_CREATED:
+	case G_FILE_MONITOR_EVENT_CHANGES_DONE_HINT:
+		if (connection) {
+			/* Update of an existing connection.  Here we re-read the file and
+			 * compare it against the existing connection to check if anything
+			 * actually changed.
+			 */
+			NMExampleConnection *tmp;
+
+			tmp = nm_example_connection_new (full_path, NULL, &error);
+			if (tmp) {
+				if (!nm_connection_compare (NM_CONNECTION (connection),
+				                            NM_CONNECTION (tmp),
+				                            NM_SETTING_COMPARE_FLAG_IGNORE_AGENT_OWNED_SECRETS |
+				                              NM_SETTING_COMPARE_FLAG_IGNORE_NOT_SAVED_SECRETS)) {
+					/* Connection changed; update our internal connection object */
+					PLUGIN_PRINT (EXAMPLE_PLUGIN_NAME, "updating %s", full_path);
+					update_connection_settings (connection, tmp);
+				}
+				g_object_unref (tmp);
+			} else {
+				/* There was an error parsing the updated connection; it may
+				 * no longer be valid and thus we've got to delete it.  If it
+				 * becomes valid again later we'll get another change
+				 * notification, we'll re-read it, and we'll treat it as new.
+				 */
+				PLUGIN_PRINT (EXAMPLE_PLUGIN_NAME, "    error: %s",
+						      (error && error->message) ? error->message : "(unknown)");
+				remove_connection (SC_PLUGIN_EXAMPLE (config), connection, full_path);
+			}
+			g_clear_error (&error);
+		} else {
+			PLUGIN_PRINT (EXAMPLE_PLUGIN_NAME, "updating %s", full_path);
+
+			/* We don't know about the connection yet, so the change represents
+			 * a completely new connection.
+			 */
+			connection = nm_example_connection_new (full_path, NULL, &error);
+			if (connection) {
+				NMExampleConnection *found = NULL;
+
+				/* Connection renames will show up as different files but with
+				 * the same UUID.  Try to find the original connection.
+				 * A connection rename is treated just like an update except
+				 * there's a bit more housekeeping with the hash table.
+				 */
+				found = find_by_uuid (self, nm_connection_get_uuid (NM_CONNECTION (connection)));
+				if (found) {
+					const char *old_path = nm_example_connection_get_path (connection);
+
+					/* Removing from the hash table should drop the last reference,
+					 * but of course we want to keep the connection around.
+					 */
+					g_object_ref (found);
+					g_hash_table_remove (priv->connections, old_path);
+
+					/* Updating settings should update the NMExampleConnection's
+					 * filename property too.
+					 */
+					update_connection_settings (found, connection);
+
+					/* Re-insert the connection back into the hash with the new filename */
+					g_hash_table_insert (priv->connections,
+					                     (gpointer) nm_example_connection_get_path (found),
+					                     found);
+
+					/* Get rid of the temporary connection */
+					g_object_unref (connection);
+				} else {
+					/* Completely new connection, not a rename. */
+					g_hash_table_insert (priv->connections,
+					                     (gpointer) nm_example_connection_get_path (connection),
+					                     connection);
+					/* Tell NM we found a new connection */
+					g_signal_emit_by_name (config, NM_SYSTEM_CONFIG_INTERFACE_CONNECTION_ADDED, connection);
+				}
+			} else {
+				PLUGIN_PRINT (EXAMPLE_PLUGIN_NAME, "    error: %s",
+						      (error && error->message) ? error->message : "(unknown)");
+				g_clear_error (&error);
+			}
+		}
+		break;
+	default:
+		break;
+	}
+
+	g_free (full_path);
+}
+
+static void
+conf_file_changed (GFileMonitor *monitor,
+				   GFile *file,
+				   GFile *other_file,
+				   GFileMonitorEvent event_type,
+				   gpointer data)
+{
+	SCPluginExample *self = SC_PLUGIN_EXAMPLE (data);
+	SCPluginExamplePrivate *priv = SC_PLUGIN_EXAMPLE_GET_PRIVATE (self);
+	char *tmp;
+
+	switch (event_type) {
+	case G_FILE_MONITOR_EVENT_DELETED:
+	case G_FILE_MONITOR_EVENT_CREATED:
+	case G_FILE_MONITOR_EVENT_CHANGES_DONE_HINT:
+		/* Unmanaged devices option may have changed; just emit the changed
+		 * signal for unmanaged specs and when NM calls back in to get the
+		 * updated specs we'll re-read the config file then.
+		 */
+		g_signal_emit_by_name (self, NM_SYSTEM_CONFIG_INTERFACE_UNMANAGED_SPECS_CHANGED);
+
+		/* Hostname may also have changed; read it and if it did actually
+		 * change, notify NM.
+		 */
+		tmp = plugin_get_hostname (self);
+		if (g_strcmp0 (tmp, priv->hostname) != 0) {
+			g_free (priv->hostname);
+			priv->hostname = tmp;
+			tmp = NULL;
+			g_object_notify (G_OBJECT (self), NM_SYSTEM_CONFIG_INTERFACE_HOSTNAME);
+		}
+		g_free (tmp);
+		break;
+	default:
+		break;
+	}
+}
+
+/* This function starts the inotify monitors that watch the plugin's config
+ * file directory for new connections and changes to existing connections.
+ * At this time all plugins are expected to make NM aware of changes on-the-fly
+ * instead of requiring a SIGHUP or SIGUSR1 or some D-Bus method to say
+ * "reload".
+ */
+static void
+setup_monitoring (NMSystemConfigInterface *config)
+{
+	SCPluginExamplePrivate *priv = SC_PLUGIN_EXAMPLE_GET_PRIVATE (config);
+	GFileMonitor *monitor;
+	GFile *file;
+
+	/* Initialize connection hash here; we use the connection hash as the 
+	 * "are we initialized yet" variable.
+	 */
+	priv->connections = g_hash_table_new_full (g_str_hash, g_str_equal, NULL, g_object_unref);
+
+	/* Set up the watch for our config directory */
+	file = g_file_new_for_path (EXAMPLE_DIR);
+	monitor = g_file_monitor_directory (file, G_FILE_MONITOR_NONE, NULL, NULL);
+	g_object_unref (file);
+	if (monitor) {
+		/* This registers the dir_changed() function to be called whenever
+		 * the GFileMonitor object notices a change in the directory.
+		 */
+		priv->monitor_id = g_signal_connect (monitor, "changed", G_CALLBACK (dir_changed), config);
+		priv->monitor = monitor;
+	}
+
+	/* Set up a watch on our configuration file, basically just for watching
+	 * whether the user has changed the unmanaged devices option or the
+	 * persistent hostname.
+	 */
+	if (priv->conf_file) {
+		file = g_file_new_for_path (priv->conf_file);
+		monitor = g_file_monitor_file (file, G_FILE_MONITOR_NONE, NULL, NULL);
+		g_object_unref (file);
+
+		if (monitor) {
+			priv->conf_file_monitor_id = g_signal_connect (monitor, "changed", G_CALLBACK (conf_file_changed), config);
+			priv->conf_file_monitor = monitor;
+		}
+	}
+}
+
+/*******************************************************************/
+
+/* Return to NM the full list of connections this plugin owns */
+static GSList *
+get_connections (NMSystemConfigInterface *config)
+{
+	SCPluginExamplePrivate *priv = SC_PLUGIN_EXAMPLE_GET_PRIVATE (config);
+	GHashTableIter iter;
+	NMSettingsConnection *connection;
+	GSList *list = NULL;
+
+	if (!priv->connections) {
+		/* If we haven't read connections in yet, do so now */
+		setup_monitoring (config);
+		read_connections (config);
+	}
+
+	/* Add each connection from our internal hash table to a list returned
+	 * to NetworkManager.
+	 */
+	g_hash_table_iter_init (&iter, priv->connections);
+	while (g_hash_table_iter_next (&iter, NULL, (gpointer) &connection))
+		list = g_slist_prepend (list, connection);
+	return list;
+}
+
+/* Called by NetworkManager when a user adds a new connection via D-Bus.
+ * The plugin should convert the data in 'connection' to its on-disk format
+ * write it out to disk, and return an object that's a subclass of
+ * NMSettingsConnection.  Typically plugins will subclass NMSettingsConnection
+ * and use that class to handle any plugin-specific stuff like monitoring
+ * the on-disk config files for changes, and/or parsing the file-format and
+ * converting back and forth from that to NMConnection.
+ */
+static NMSettingsConnection *
+add_connection (NMSystemConfigInterface *config,
+                NMConnection *connection,
+                GError **error)
+{
+	SCPluginExample *self = SC_PLUGIN_EXAMPLE (config);
+	NMSettingsConnection *added = NULL;
+	char *path = NULL;
+
+	/* Write it out first, then add the connection to our internal list; that
+	 * way we don't trigger the new NMSettingsConnection subclass' file watch
+	 * functions needlessly.
+	 */
+	if (write_connection (connection, NULL, &path, error)) {
+		added = _internal_new_connection (self, path, connection, error);
+		g_free (path);
+	}
+	return added;
+}
+
+/* This function returns a list of "unmanaged device specs" which represent
+ * a list of devices that NetworkManager should not manage.  Each unmanaged
+ * spec item has a specific format starting with a "tag" and followed by
+ * tag-specific data.  The only currently specified item is "mac:" followed
+ * by the MAC address of the interface NM should not manage.  This function
+ * reads the list of unmanaged devices from wherever the plugin wants to
+ * store them and returns that list to NetworkManager.
+ */
+static GSList *
+get_unmanaged_specs (NMSystemConfigInterface *config)
+{
+	SCPluginExamplePrivate *priv = SC_PLUGIN_EXAMPLE_GET_PRIVATE (config);
+	GKeyFile *key_file;
+	GSList *specs = NULL;
+	GError *error = NULL;
+	char *str, **macs;
+	int i;
+
+	if (!priv->conf_file)
+		return NULL;
+
+	key_file = g_key_file_new ();
+	if (!g_key_file_load_from_file (key_file, priv->conf_file, G_KEY_FILE_NONE, &error)) {
+		g_warning ("Error parsing file '%s': %s", priv->conf_file, error->message);
+		g_error_free (error);
+		goto out;
+	}
+
+
+	str = g_key_file_get_value (key_file, "keyfile", "unmanaged-devices", NULL);
+	if (!str)
+		goto out;
+
+	macs = g_strsplit (str, ";", -1);
+	for (i = 0; macs[i] != NULL; i++) {
+		/* Verify unmanaged specification and add it to the list */
+		if (strlen (macs[i]) > 4 && !strncmp (macs[i], "mac:", 4) && ether_aton (macs[i] + 4)) {
+			char *p = macs[i];
+
+			/* To accept uppercase MACs in configuration file, we have to
+			 * convert values to lowercase here. Unmanaged MACs in specs are
+			 * always in lowercase.
+			 */
+			while (*p) {
+				*p = g_ascii_tolower (*p);
+				p++;
+			}
+
+			specs = g_slist_append (specs, macs[i]);
+		} else {
+			g_warning ("Error in file '%s': invalid unmanaged-devices entry: '%s'", priv->conf_file, macs[i]);
+			g_free (macs[i]);
+		}
+	}
+
+	g_free (macs); /* Yes, g_free, not g_strfreev because we need the strings in the list */
+	g_free (str);
+
+out:
+	g_key_file_free (key_file);
+	return specs;
+}
+
+
+static char *
+plugin_get_hostname (SCPluginExample *plugin)
+{
+	SCPluginExamplePrivate *priv = SC_PLUGIN_EXAMPLE_GET_PRIVATE (plugin);
+	GKeyFile *key_file;
+	char *hostname = NULL;
+	GError *error = NULL;
+
+	if (!priv->conf_file)
+		return NULL;
+
+	/* Read the persistent hostname out of backing storage, which happens
+	 * to be the NM config file.  Other plugins (like distro-specific ones)
+	 * should read it from the distro-specific location like /etc/hostname.
+	 */
+	key_file = g_key_file_new ();
+	if (g_key_file_load_from_file (key_file, priv->conf_file, G_KEY_FILE_NONE, &error))
+		hostname = g_key_file_get_value (key_file, "keyfile", "hostname", NULL);
+	else {
+		g_warning ("Error parsing file '%s': %s", priv->conf_file, error->message);
+		g_error_free (error);
+	}
+
+	g_key_file_free (key_file);
+	return hostname;
+}
+
+static gboolean
+plugin_set_hostname (SCPluginExample *plugin, const char *hostname)
+{
+	SCPluginExamplePrivate *priv = SC_PLUGIN_EXAMPLE_GET_PRIVATE (plugin);
+	GKeyFile *key_file;
+	GError *error = NULL;
+	gboolean success = FALSE;
+	char *data;
+	gsize len;
+
+	if (!priv->conf_file) {
+		g_warning ("Error saving hostname: no config file");
+		return FALSE;
+	}
+
+	/* This just saves the hostname to the NM config file in a section
+	 * private to this plugin.
+	 */
+	key_file = g_key_file_new ();
+	if (!g_key_file_load_from_file (key_file, priv->conf_file, G_KEY_FILE_NONE, &error)) {
+		g_warning ("Error parsing file '%s': %s", priv->conf_file, error->message);
+		g_error_free (error);
+		goto out;
+	}
+
+	g_key_file_set_string (key_file, "example", "hostname", hostname);
+
+	data = g_key_file_to_data (key_file, &len, &error);
+	if (data) {
+		/* Save updated file to disk */
+		g_file_set_contents (priv->conf_file, data, len, &error);
+		g_free (data);
+
+		/* Update internal copy of hostname */
+		g_free (priv->hostname);
+		priv->hostname = g_strdup (hostname);
+		success = TRUE;
+	}
+
+	if (error) {
+		g_warning ("Error saving hostname: %s", error->message);
+		g_error_free (error);
+	}
+
+out:
+	g_key_file_free (key_file);
+	return success;
+}
+
+/* GObject */
+
+static void
+sc_plugin_example_init (SCPluginExample *plugin)
+{
+	/* Here we'd do any instance-specific initialization like setting
+	 * members of SCPluginExamplePrivate to default values.  But we
+	 * don't have anything to do here since most initialization is done
+	 * when NM calls the various entry points.
+	 */
+}
+
+static void
+get_property (GObject *object, guint prop_id,
+		    GValue *value, GParamSpec *pspec)
+{
+	switch (prop_id) {
+	case NM_SYSTEM_CONFIG_INTERFACE_PROP_NAME:
+		g_value_set_string (value, EXAMPLE_PLUGIN_NAME);
+		break;
+	case NM_SYSTEM_CONFIG_INTERFACE_PROP_INFO:
+		g_value_set_string (value, EXAMPLE_PLUGIN_INFO);
+		break;
+	case NM_SYSTEM_CONFIG_INTERFACE_PROP_CAPABILITIES:
+		/* Return capabilities to NM; this plugin supports changing connections
+		 * as well as being capable of saving the hostname to persistent storage.
+		 * If the plugin can't write out updated configuration, then obviously
+		 * it shouldn't advertise that capability.  If it can't save hostnames
+		 * to persistent storage, it shouldn't advertise that capability either.
+		 */
+		g_value_set_uint (value, NM_SYSTEM_CONFIG_INTERFACE_CAP_MODIFY_CONNECTIONS | 
+						  NM_SYSTEM_CONFIG_INTERFACE_CAP_MODIFY_HOSTNAME);
+		break;
+	case NM_SYSTEM_CONFIG_INTERFACE_PROP_HOSTNAME:
+		/* Return the hostname we've read from persistent storage */
+		g_value_set_string (value, SC_PLUGIN_EXAMPLE_GET_PRIVATE (object)->hostname);
+		break;
+	default:
+		G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+		break;
+	}
+}
+
+static void
+set_property (GObject *object, guint prop_id,
+			  const GValue *value, GParamSpec *pspec)
+{
+	const char *hostname;
+
+	switch (prop_id) {
+	case NM_SYSTEM_CONFIG_INTERFACE_PROP_HOSTNAME:
+		/* We'll get here when the user has changed the hostname via NM's
+		 * D-Bus interface and we're requested to save this hostname to
+		 * persistent storage.
+		 */
+		hostname = g_value_get_string (value);
+		if (hostname && strlen (hostname) < 1)
+			hostname = NULL;
+		plugin_set_hostname (SC_PLUGIN_EXAMPLE (object), hostname);
+		break;
+	default:
+		G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+		break;
+	}
+}
+
+static void
+dispose (GObject *object)
+{
+	SCPluginExamplePrivate *priv = SC_PLUGIN_EXAMPLE_GET_PRIVATE (object);
+
+	/* GObject has a two-stage object destruction process: dispose and finalize.
+	 * In dispose the object should free any references it might have on other
+	 * objects to break circular refs, then it's finally cleaned up by finalize.
+	 * We don't bother to implement a finalize, so we just make sure that we
+	 * clean everything up (including clearing pointers) in dispose so that
+	 * if GObject decides to revive this object post-dispose (yes, legal)
+	 * we don't crash on dangling pointers.
+	 */
+
+	if (priv->monitor) {
+		if (priv->monitor_id) {
+			g_signal_handler_disconnect (priv->monitor, priv->monitor_id);
+			priv->monitor_id = 0;
+		}
+
+		g_file_monitor_cancel (priv->monitor);
+		g_object_unref (priv->monitor);
+		priv->monitor = NULL;
+	}
+
+	if (priv->conf_file_monitor) {
+		if (priv->conf_file_monitor_id) {
+			g_signal_handler_disconnect (priv->conf_file_monitor, priv->conf_file_monitor_id);
+			priv->conf_file_monitor_id = 0;
+		}
+
+		g_file_monitor_cancel (priv->conf_file_monitor);
+		g_object_unref (priv->conf_file_monitor);
+		priv->conf_file_monitor = NULL;
+	}
+
+	if (priv->connections) {
+		/* Destroying the connections hash unrefs each connection in it
+		 * due to the GHashTable value_destroy_func that we passed into
+		 * g_hash_table_new_full().
+		 */
+		g_hash_table_destroy (priv->connections);
+		priv->connections = NULL;
+	}
+
+	g_free (priv->hostname);
+	priv->hostname = NULL;
+	g_free (priv->conf_file);
+	priv->conf_file = NULL;
+
+	/* Chain up to the superclass */
+	G_OBJECT_CLASS (sc_plugin_example_parent_class)->dispose (object);
+}
+
+/* This function gets called to set up any method and property overrides
+ * of superclasses, and also (if we actually had any) to set up any
+ * custom properties and signals this object might have.  This is called before
+ * the object is actually instantiated; it just sets up the generic class
+ * stuff, not anything related to a specific object instance.
+ */
+static void
+sc_plugin_example_class_init (SCPluginExampleClass *req_class)
+{
+	GObjectClass *object_class = G_OBJECT_CLASS (req_class);
+
+	/* This actually creates and zeros the object's instance data struct */
+	g_type_class_add_private (req_class, sizeof (SCPluginExamplePrivate));
+
+	/* Override GObject base class methods with our custom implementations */
+	object_class->dispose = dispose;
+	object_class->get_property = get_property;
+	object_class->set_property = set_property;
+
+	/* Override various GObject properties that we need to change.  Here we
+	 * just tell GObject that we will be handling the get/set operations for
+	 * these specific properties.  They are actually defined by the
+	 * NMSystemConfigInterface interface in nm-system-config-interface.c.
+	 * What happens here is that we tell GObject that for a given property
+	 * name (ie NM_SYSTEM_CONFIG_INTERFACE_NAME) we'll be using the enum value
+	 * NM_SYSTEM_CONFIG_INTERFACE_PROP_NAME locally in get_property() and
+	 * set_property().
+	 */
+	g_object_class_override_property (object_class,
+	                                  NM_SYSTEM_CONFIG_INTERFACE_PROP_NAME,
+	                                  NM_SYSTEM_CONFIG_INTERFACE_NAME);
+
+	g_object_class_override_property (object_class,
+	                                  NM_SYSTEM_CONFIG_INTERFACE_PROP_INFO,
+	                                  NM_SYSTEM_CONFIG_INTERFACE_INFO);
+
+	g_object_class_override_property (object_class,
+	                                  NM_SYSTEM_CONFIG_INTERFACE_PROP_CAPABILITIES,
+	                                  NM_SYSTEM_CONFIG_INTERFACE_CAPABILITIES);
+
+	g_object_class_override_property (object_class,
+	                                  NM_SYSTEM_CONFIG_INTERFACE_PROP_HOSTNAME,
+	                                  NM_SYSTEM_CONFIG_INTERFACE_HOSTNAME);
+}
+
+static void
+system_config_interface_init (NMSystemConfigInterface *sci_intf)
+{
+	/* Interface implementation for NMSystemConfigInterface.  This sets
+	 * up the GInterface vtable that lets GObject know what functions to
+	 * call for each method of the NMSystemConfigInterface interface.
+	 */
+	sci_intf->get_connections = get_connections;
+	sci_intf->add_connection = add_connection;
+	sci_intf->get_unmanaged_specs = get_unmanaged_specs;
+}
+
+/*******************************************************************/
+
+/* Factory function: this is the first entry point for NetworkManager, which
+ * gets called during NM startup to create the the instance of this plugin
+ * that NetworkManager will actually use.  Since every plugin is a singleton
+ * we just return a singleton instance.  This function should never be called
+ * twice.
+ */
+G_MODULE_EXPORT GObject *
+nm_system_config_factory (const char *config_file)
+{
+	static SCPluginExample *singleton = NULL;
+	SCPluginExamplePrivate *priv;
+
+	if (!singleton) {
+		/* Instantiate our plugin */
+		singleton = SC_PLUGIN_EXAMPLE (g_object_new (SC_TYPE_PLUGIN_EXAMPLE, NULL));
+		if (singleton) {
+			priv = SC_PLUGIN_EXAMPLE_GET_PRIVATE (singleton);
+
+			/* Cache the config file path */
+			priv->conf_file = g_strdup (config_file);
+		}
+	} else {
+		/* This function should never be called twice */
+		g_assert_not_reached ();
+	}
+
+	return G_OBJECT (singleton);
+}
+
diff --git a/src/settings/plugins/example/plugin.h b/src/settings/plugins/example/plugin.h
new file mode 100644
index 00000000..23b68e2e
--- /dev/null
+++ b/src/settings/plugins/example/plugin.h
@@ -0,0 +1,55 @@
+/* -*- Mode: C; tab-width: 4; indent-tabs-mode: t; c-basic-offset: 4 -*- */
+/* NetworkManager system settings service - example plugin
+ *
+ * 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) 2012 Red Hat, Inc.
+ */
+
+#ifndef _PLUGIN_H_
+#define _PLUGIN_H_
+
+#include <glib-object.h>
+
+/* GObject boilerplate: you usually only need to rename 'example' here to
+ * your plugin's name.  These functions get used when casting pointers
+ * to your plugin's object type.
+ */
+#define SC_TYPE_PLUGIN_EXAMPLE            (sc_plugin_example_get_type ())
+#define SC_PLUGIN_EXAMPLE(obj)            (G_TYPE_CHECK_INSTANCE_CAST ((obj), SC_TYPE_PLUGIN_EXAMPLE, SCPluginExample))
+#define SC_PLUGIN_EXAMPLE_CLASS(klass)    (G_TYPE_CHECK_CLASS_CAST ((klass), SC_TYPE_PLUGIN_EXAMPLE, SCPluginExampleClass))
+#define SC_IS_PLUGIN_EXAMPLE(obj)         (G_TYPE_CHECK_INSTANCE_TYPE ((obj), SC_TYPE_PLUGIN_EXAMPLE))
+#define SC_IS_PLUGIN_EXAMPLE_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((obj), SC_TYPE_PLUGIN_EXAMPLE))
+#define SC_PLUGIN_EXAMPLE_GET_CLASS(obj)  (G_TYPE_INSTANCE_GET_CLASS ((obj), SC_TYPE_PLUGIN_EXAMPLE, SCPluginExampleClass))
+
+typedef struct {
+	/* GObject instance structure for the plugin; we don't do anything special
+	 * here so this object's instance is exactly the same as its parent.
+	 */
+	GObject parent;
+} SCPluginExample;
+
+typedef struct {
+	/* GObject class structure; we don't do anything special here
+	 * so this object's class is exactly the same as its parent.  Typically
+	 * if the plugin implemented custom signals their prototypes would go
+	 * here, but most plugins don't need to do this.
+	 */
+	GObjectClass parent;
+} SCPluginExampleClass;
+
+GType sc_plugin_example_get_type (void);
+
+#endif	/* _PLUGIN_H_ */
diff --git a/src/settings/plugins/example/reader.c b/src/settings/plugins/example/reader.c
new file mode 100644
index 00000000..9a4cecaa
--- /dev/null
+++ b/src/settings/plugins/example/reader.c
@@ -0,0 +1,46 @@
+/* -*- Mode: C; tab-width: 4; indent-tabs-mode: t; c-basic-offset: 4 -*- */
+/* NetworkManager system settings service
+ *
+ * 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) 2012 Red Hat, Inc.
+ */
+
+#include <config.h>
+#include <glib.h>
+
+#include <nm-connection.h>
+#include <NetworkManager.h>
+
+#include "common.h"
+
+NMConnection *
+connection_from_file (const char *filename, GError **error)
+{
+	/* This function should, given a file path, read that file and convert its
+	 * data into an NMConnection.  There are two approaches to this.  First,
+	 * if the plugin data format is similar to the NMConnection internal
+	 * format, you can get away with calling nm_connection_for_each_setting_value()
+	 * to iterate through every possible setting's keys and read that value
+	 * from the plugin's format.  If the plugin's format is siginificantly
+	 * different then you may have to build up the connection manually by
+	 * determining the type of connection from the on-disk data, creating
+	 * each setting object, adding the values, then adding that setting to
+	 * the NMConnection.
+	 */
+
+	return NULL;
+}
+
diff --git a/src/settings/plugins/example/writer.c b/src/settings/plugins/example/writer.c
new file mode 100644
index 00000000..4703fa94
--- /dev/null
+++ b/src/settings/plugins/example/writer.c
@@ -0,0 +1,55 @@
+/* -*- Mode: C; tab-width: 4; indent-tabs-mode: t; c-basic-offset: 4 -*- */
+/* NetworkManager system settings service
+ *
+ * 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) 2012 Red Hat, Inc.
+ */
+
+#include <config.h>
+#include <glib.h>
+
+#include <nm-connection.h>
+
+#include "common.h"
+
+gboolean
+write_connection (NMConnection *connection,
+                  const char *existing_path,
+                  char **out_path,
+                  GError **error)
+{
+	/* This function should take the NMConnection and convert it to the format
+	 * which this plugin uses on-disk and then write out that data.  It returns
+	 * the file path of the file that represents this connection data so that
+	 * the plugin can track it for change notification and updates.  If
+	 * 'existing_path' is given we can assume that this is an update of an
+	 * existing connection and not a completely new one.
+	 */
+
+	/* There are two approaches to converting the data.  The first more manual
+	 * approach consists of grabbing each setting value from the NMConnection
+	 * and converting it into the appropriate value for the plugin's data
+	 * format.  This is usually taken by distro plugins becuase their format
+	 * is significantly different than NetworkManager's internal format.
+	 * The second uses nm_connection_for_each_setting_value() to iterate
+	 * through each value of each setting in the NMConnection, convert it to
+	 * the required format, and write it out, but this requires that the
+	 * plugin format more closely follow the NetworkManager internal format.
+	 */
+
+	return FALSE;
+}
+
diff --git a/src/settings/plugins/ifcfg-rh/Makefile.am b/src/settings/plugins/ifcfg-rh/Makefile.am
index 8b5b0f24..68225ba1 100644
--- a/src/settings/plugins/ifcfg-rh/Makefile.am
+++ b/src/settings/plugins/ifcfg-rh/Makefile.am
@@ -25,6 +25,7 @@ libifcfg_rh_io_la_SOURCES = \
 INCLUDES = \
 	-I$(top_srcdir)/src/wifi \
 	-I$(top_srcdir)/src/settings \
+	-I$(top_srcdir)/src/posix-signals \
 	-I$(top_srcdir)/include \
 	-I$(top_builddir)/include \
 	-I$(top_srcdir)/libnm-glib \
@@ -40,6 +41,7 @@ libifcfg_rh_io_la_CPPFLAGS = \
 
 libifcfg_rh_io_la_LIBADD = \
 	$(top_builddir)/src/wifi/libwifi-utils.la \
+	$(top_builddir)/src/posix-signals/libnm-posix-signals.la \
 	$(top_builddir)/libnm-util/libnm-util.la \
 	$(GLIB_LIBS) \
 	$(NSS_LIBS)
diff --git a/src/settings/plugins/ifcfg-rh/Makefile.in b/src/settings/plugins/ifcfg-rh/Makefile.in
index 3325c7e8..ba3bb528 100644
--- a/src/settings/plugins/ifcfg-rh/Makefile.in
+++ b/src/settings/plugins/ifcfg-rh/Makefile.in
@@ -48,7 +48,7 @@ am__aclocal_m4_deps = $(top_srcdir)/m4/compiler_warnings.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)/configure.ac
+	$(top_srcdir)/m4/vapigen.m4 $(top_srcdir)/configure.ac
 am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \
 	$(ACLOCAL_M4)
 mkinstalldirs = $(install_sh) -d
@@ -82,6 +82,7 @@ LTLIBRARIES = $(noinst_LTLIBRARIES) $(pkglib_LTLIBRARIES)
 am__DEPENDENCIES_1 =
 libifcfg_rh_io_la_DEPENDENCIES =  \
 	$(top_builddir)/src/wifi/libwifi-utils.la \
+	$(top_builddir)/src/posix-signals/libnm-posix-signals.la \
 	$(top_builddir)/libnm-util/libnm-util.la $(am__DEPENDENCIES_1) \
 	$(am__DEPENDENCIES_1)
 am_libifcfg_rh_io_la_OBJECTS = libifcfg_rh_io_la-shvar.lo \
@@ -249,6 +250,10 @@ INTLTOOL_EXTRACT = @INTLTOOL_EXTRACT@
 INTLTOOL_MERGE = @INTLTOOL_MERGE@
 INTLTOOL_PERL = @INTLTOOL_PERL@
 INTLTOOL_UPDATE = @INTLTOOL_UPDATE@
+INTLTOOL_V_MERGE = @INTLTOOL_V_MERGE@
+INTLTOOL_V_MERGE_OPTIONS = @INTLTOOL_V_MERGE_OPTIONS@
+INTLTOOL__v_MERGE_ = @INTLTOOL__v_MERGE_@
+INTLTOOL__v_MERGE_0 = @INTLTOOL__v_MERGE_0@
 INTL_MACOSX_LIBS = @INTL_MACOSX_LIBS@
 INTROSPECTION_CFLAGS = @INTROSPECTION_CFLAGS@
 INTROSPECTION_COMPILER = @INTROSPECTION_COMPILER@
@@ -344,6 +349,9 @@ UDEV_BASE_DIR = @UDEV_BASE_DIR@
 USE_NLS = @USE_NLS@
 UUID_CFLAGS = @UUID_CFLAGS@
 UUID_LIBS = @UUID_LIBS@
+VAPIGEN = @VAPIGEN@
+VAPIGEN_MAKEFILE = @VAPIGEN_MAKEFILE@
+VAPIGEN_VAPIDIR = @VAPIGEN_VAPIDIR@
 VERSION = @VERSION@
 XGETTEXT = @XGETTEXT@
 XGETTEXT_015 = @XGETTEXT_015@
@@ -382,6 +390,8 @@ htmldir = @htmldir@
 includedir = @includedir@
 infodir = @infodir@
 install_sh = @install_sh@
+intltool__v_merge_options_ = @intltool__v_merge_options_@
+intltool__v_merge_options_0 = @intltool__v_merge_options_0@
 libdir = @libdir@
 libexecdir = @libexecdir@
 localedir = @localedir@
@@ -423,6 +433,7 @@ libifcfg_rh_io_la_SOURCES = \
 INCLUDES = \
 	-I$(top_srcdir)/src/wifi \
 	-I$(top_srcdir)/src/settings \
+	-I$(top_srcdir)/src/posix-signals \
 	-I$(top_srcdir)/include \
 	-I$(top_builddir)/include \
 	-I$(top_srcdir)/libnm-glib \
@@ -438,6 +449,7 @@ libifcfg_rh_io_la_CPPFLAGS = \
 
 libifcfg_rh_io_la_LIBADD = \
 	$(top_builddir)/src/wifi/libwifi-utils.la \
+	$(top_builddir)/src/posix-signals/libnm-posix-signals.la \
 	$(top_builddir)/libnm-util/libnm-util.la \
 	$(GLIB_LIBS) \
 	$(NSS_LIBS)
diff --git a/src/settings/plugins/ifcfg-rh/reader.c b/src/settings/plugins/ifcfg-rh/reader.c
index 01d83c1b..a2b08e4f 100644
--- a/src/settings/plugins/ifcfg-rh/reader.c
+++ b/src/settings/plugins/ifcfg-rh/reader.c
@@ -48,6 +48,7 @@
 #include <nm-utils.h>
 
 #include "wifi-utils.h"
+#include "nm-posix-signals.h"
 
 #include "common.h"
 #include "shvar.h"
@@ -208,6 +209,12 @@ iscsiadm_child_setup (gpointer user_data G_GNUC_UNUSED)
 	 */
 	pid_t pid = getpid ();
 	setpgid (pid, pid);
+
+	/*
+	 * We blocked signals in main(). We need to restore original signal
+	 * mask for iscsiadm here so that it can receive signals.
+	 */
+	nm_unblock_posix_signals (NULL);
 }
 
 static char *
@@ -3732,8 +3739,8 @@ make_vlan_setting (shvarFile *ifcfg,
 	char *value = NULL;
 	char *iface_name = NULL;
 	char *parent = NULL;
-	const char *p = NULL, *w;
-	gboolean has_numbers = FALSE;
+	const char *p = NULL;
+	char *end = NULL;
 	gint vlan_id = -1;
 	guint32 vlan_flags = 0;
 
@@ -3773,17 +3780,12 @@ make_vlan_setting (shvarFile *ifcfg,
 				p = iface_name + 4;
 		}
 
-		w = p;
-		while (*w && !has_numbers)
-			has_numbers = g_ascii_isdigit (*w);
-
-		/* Grab VLAN ID from interface name; this takes precedence over the
-		 * separate VLAN_ID property for backwards compat.
-		 */
-		if (has_numbers) {
-			errno = 0;
-			vlan_id = (gint) g_ascii_strtoll (p, NULL, 10);
-			if (vlan_id < 0 || vlan_id > 4095 || errno) {
+		if (p) {
+			/* Grab VLAN ID from interface name; this takes precedence over the
+			 * separate VLAN_ID property for backwards compat.
+			 */
+			vlan_id = (gint) g_ascii_strtoll (p, &end, 10);
+			if (vlan_id < 0 || vlan_id > 4095 || end == p || *end) {
 				g_set_error (error, IFCFG_PLUGIN_ERROR, 0,
 				             "Failed to determine VLAN ID from DEVICE '%s'",
 				             iface_name);
diff --git a/src/settings/plugins/ifcfg-rh/tests/Makefile.in b/src/settings/plugins/ifcfg-rh/tests/Makefile.in
index 5e8abf83..dd601727 100644
--- a/src/settings/plugins/ifcfg-rh/tests/Makefile.in
+++ b/src/settings/plugins/ifcfg-rh/tests/Makefile.in
@@ -48,7 +48,7 @@ am__aclocal_m4_deps = $(top_srcdir)/m4/compiler_warnings.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)/configure.ac
+	$(top_srcdir)/m4/vapigen.m4 $(top_srcdir)/configure.ac
 am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \
 	$(ACLOCAL_M4)
 mkinstalldirs = $(install_sh) -d
@@ -211,6 +211,10 @@ INTLTOOL_EXTRACT = @INTLTOOL_EXTRACT@
 INTLTOOL_MERGE = @INTLTOOL_MERGE@
 INTLTOOL_PERL = @INTLTOOL_PERL@
 INTLTOOL_UPDATE = @INTLTOOL_UPDATE@
+INTLTOOL_V_MERGE = @INTLTOOL_V_MERGE@
+INTLTOOL_V_MERGE_OPTIONS = @INTLTOOL_V_MERGE_OPTIONS@
+INTLTOOL__v_MERGE_ = @INTLTOOL__v_MERGE_@
+INTLTOOL__v_MERGE_0 = @INTLTOOL__v_MERGE_0@
 INTL_MACOSX_LIBS = @INTL_MACOSX_LIBS@
 INTROSPECTION_CFLAGS = @INTROSPECTION_CFLAGS@
 INTROSPECTION_COMPILER = @INTROSPECTION_COMPILER@
@@ -306,6 +310,9 @@ UDEV_BASE_DIR = @UDEV_BASE_DIR@
 USE_NLS = @USE_NLS@
 UUID_CFLAGS = @UUID_CFLAGS@
 UUID_LIBS = @UUID_LIBS@
+VAPIGEN = @VAPIGEN@
+VAPIGEN_MAKEFILE = @VAPIGEN_MAKEFILE@
+VAPIGEN_VAPIDIR = @VAPIGEN_VAPIDIR@
 VERSION = @VERSION@
 XGETTEXT = @XGETTEXT@
 XGETTEXT_015 = @XGETTEXT_015@
@@ -344,6 +351,8 @@ htmldir = @htmldir@
 includedir = @includedir@
 infodir = @infodir@
 install_sh = @install_sh@
+intltool__v_merge_options_ = @intltool__v_merge_options_@
+intltool__v_merge_options_0 = @intltool__v_merge_options_0@
 libdir = @libdir@
 libexecdir = @libexecdir@
 localedir = @localedir@
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 4f34cfc3..ab8dc497 100644
--- a/src/settings/plugins/ifcfg-rh/tests/network-scripts/Makefile.in
+++ b/src/settings/plugins/ifcfg-rh/tests/network-scripts/Makefile.in
@@ -46,7 +46,7 @@ am__aclocal_m4_deps = $(top_srcdir)/m4/compiler_warnings.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)/configure.ac
+	$(top_srcdir)/m4/vapigen.m4 $(top_srcdir)/configure.ac
 am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \
 	$(ACLOCAL_M4)
 mkinstalldirs = $(install_sh) -d
@@ -134,6 +134,10 @@ INTLTOOL_EXTRACT = @INTLTOOL_EXTRACT@
 INTLTOOL_MERGE = @INTLTOOL_MERGE@
 INTLTOOL_PERL = @INTLTOOL_PERL@
 INTLTOOL_UPDATE = @INTLTOOL_UPDATE@
+INTLTOOL_V_MERGE = @INTLTOOL_V_MERGE@
+INTLTOOL_V_MERGE_OPTIONS = @INTLTOOL_V_MERGE_OPTIONS@
+INTLTOOL__v_MERGE_ = @INTLTOOL__v_MERGE_@
+INTLTOOL__v_MERGE_0 = @INTLTOOL__v_MERGE_0@
 INTL_MACOSX_LIBS = @INTL_MACOSX_LIBS@
 INTROSPECTION_CFLAGS = @INTROSPECTION_CFLAGS@
 INTROSPECTION_COMPILER = @INTROSPECTION_COMPILER@
@@ -229,6 +233,9 @@ UDEV_BASE_DIR = @UDEV_BASE_DIR@
 USE_NLS = @USE_NLS@
 UUID_CFLAGS = @UUID_CFLAGS@
 UUID_LIBS = @UUID_LIBS@
+VAPIGEN = @VAPIGEN@
+VAPIGEN_MAKEFILE = @VAPIGEN_MAKEFILE@
+VAPIGEN_VAPIDIR = @VAPIGEN_VAPIDIR@
 VERSION = @VERSION@
 XGETTEXT = @XGETTEXT@
 XGETTEXT_015 = @XGETTEXT_015@
@@ -267,6 +274,8 @@ htmldir = @htmldir@
 includedir = @includedir@
 infodir = @infodir@
 install_sh = @install_sh@
+intltool__v_merge_options_ = @intltool__v_merge_options_@
+intltool__v_merge_options_0 = @intltool__v_merge_options_0@
 libdir = @libdir@
 libexecdir = @libexecdir@
 localedir = @localedir@
diff --git a/src/settings/plugins/ifcfg-rh/tests/network-scripts/keys-test-wifi-wpa-psk-2 b/src/settings/plugins/ifcfg-rh/tests/network-scripts/keys-test-wifi-wpa-psk-2
index bf98da5a..6a63e817 100644
--- a/src/settings/plugins/ifcfg-rh/tests/network-scripts/keys-test-wifi-wpa-psk-2
+++ b/src/settings/plugins/ifcfg-rh/tests/network-scripts/keys-test-wifi-wpa-psk-2
@@ -1,2 +1,2 @@
-WPA_PSK=$'They\'re really saying I love you. >>`<<'
+WPA_PSK=$'They\'re really saying I love you. >>`<< \'
 
diff --git a/src/settings/plugins/ifcfg-rh/tests/test-ifcfg-rh.c b/src/settings/plugins/ifcfg-rh/tests/test-ifcfg-rh.c
index 62882a76..83b60d22 100644
--- a/src/settings/plugins/ifcfg-rh/tests/test-ifcfg-rh.c
+++ b/src/settings/plugins/ifcfg-rh/tests/test-ifcfg-rh.c
@@ -4927,7 +4927,7 @@ test_read_wifi_wpa_psk_2 (void)
 	GError *error = NULL;
 	const char *tmp;
 	const char *expected_id = "System ipsum (test-wifi-wpa-psk-2)";
-	const char *expected_psk = "They're really saying I love you. >>`<<";
+	const char *expected_psk = "They're really saying I love you. >>`<< \\";
 
 	connection = connection_from_file (TEST_IFCFG_WIFI_WPA_PSK_2,
                                      NULL,
@@ -12858,7 +12858,7 @@ int main (int argc, char **argv)
 	                         FALSE,
 	                         TRUE,
 	                         TRUE,
-	                         "blah`oops\"grr'$*@~!%");
+	                         "blah`oops\"grr'$*@~!%\\");
 	test_write_wifi_wpa_psk_adhoc ();
 	test_write_wifi_wpa_eap_tls ();
 	test_write_wifi_wpa_eap_ttls_tls ();
diff --git a/src/settings/plugins/ifcfg-rh/utils.c b/src/settings/plugins/ifcfg-rh/utils.c
index 0b7ddf36..908d3364 100644
--- a/src/settings/plugins/ifcfg-rh/utils.c
+++ b/src/settings/plugins/ifcfg-rh/utils.c
@@ -189,7 +189,7 @@ utils_single_unquote_string (const char *str)
 
 	i = quote + dollar;
 	while (i < slen - quote) {
-		if (str[i] == escape_char && str[i+1] == q_char)
+		if (str[i] == escape_char && str[i+1] == q_char && i+1 < slen-quote)
 			i++;
 		new_str[j++] = str[i++];
 	}
diff --git a/src/settings/plugins/ifcfg-rh/writer.c b/src/settings/plugins/ifcfg-rh/writer.c
index e2aa57dd..a431a30d 100644
--- a/src/settings/plugins/ifcfg-rh/writer.c
+++ b/src/settings/plugins/ifcfg-rh/writer.c
@@ -1030,6 +1030,7 @@ write_wired_setting (NMConnection *connection, shvarFile *ifcfg, GError **error)
 		g_free (tmp);
 	}
 
+	svSetValue (ifcfg, "MACADDR", NULL, FALSE);
 	cloned_mac = nm_setting_wired_get_cloned_mac_address (s_wired);
 	if (cloned_mac) {
 		tmp = g_strdup_printf ("%02X:%02X:%02X:%02X:%02X:%02X",
diff --git a/src/settings/plugins/ifcfg-suse/Makefile.in b/src/settings/plugins/ifcfg-suse/Makefile.in
index ac528342..25c3d345 100644
--- a/src/settings/plugins/ifcfg-suse/Makefile.in
+++ b/src/settings/plugins/ifcfg-suse/Makefile.in
@@ -47,7 +47,7 @@ am__aclocal_m4_deps = $(top_srcdir)/m4/compiler_warnings.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)/configure.ac
+	$(top_srcdir)/m4/vapigen.m4 $(top_srcdir)/configure.ac
 am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \
 	$(ACLOCAL_M4)
 mkinstalldirs = $(install_sh) -d
@@ -197,6 +197,10 @@ INTLTOOL_EXTRACT = @INTLTOOL_EXTRACT@
 INTLTOOL_MERGE = @INTLTOOL_MERGE@
 INTLTOOL_PERL = @INTLTOOL_PERL@
 INTLTOOL_UPDATE = @INTLTOOL_UPDATE@
+INTLTOOL_V_MERGE = @INTLTOOL_V_MERGE@
+INTLTOOL_V_MERGE_OPTIONS = @INTLTOOL_V_MERGE_OPTIONS@
+INTLTOOL__v_MERGE_ = @INTLTOOL__v_MERGE_@
+INTLTOOL__v_MERGE_0 = @INTLTOOL__v_MERGE_0@
 INTL_MACOSX_LIBS = @INTL_MACOSX_LIBS@
 INTROSPECTION_CFLAGS = @INTROSPECTION_CFLAGS@
 INTROSPECTION_COMPILER = @INTROSPECTION_COMPILER@
@@ -292,6 +296,9 @@ UDEV_BASE_DIR = @UDEV_BASE_DIR@
 USE_NLS = @USE_NLS@
 UUID_CFLAGS = @UUID_CFLAGS@
 UUID_LIBS = @UUID_LIBS@
+VAPIGEN = @VAPIGEN@
+VAPIGEN_MAKEFILE = @VAPIGEN_MAKEFILE@
+VAPIGEN_VAPIDIR = @VAPIGEN_VAPIDIR@
 VERSION = @VERSION@
 XGETTEXT = @XGETTEXT@
 XGETTEXT_015 = @XGETTEXT_015@
@@ -330,6 +337,8 @@ htmldir = @htmldir@
 includedir = @includedir@
 infodir = @infodir@
 install_sh = @install_sh@
+intltool__v_merge_options_ = @intltool__v_merge_options_@
+intltool__v_merge_options_0 = @intltool__v_merge_options_0@
 libdir = @libdir@
 libexecdir = @libexecdir@
 localedir = @localedir@
diff --git a/src/settings/plugins/ifnet/Makefile.am b/src/settings/plugins/ifnet/Makefile.am
index 84deda5b..07a2fc88 100644
--- a/src/settings/plugins/ifnet/Makefile.am
+++ b/src/settings/plugins/ifnet/Makefile.am
@@ -1,5 +1,6 @@
 SUBDIRS = . tests
 INCLUDES = \
+	-I$(top_srcdir)/src/wifi \
 	-I$(top_srcdir)/src/settings \
 	-I$(top_srcdir)/include \
 	-I$(top_srcdir)/libnm-glib \
@@ -52,6 +53,7 @@ lib_ifnet_io_la_CPPFLAGS = \
 	-DSBINDIR=\"$(sbindir)\"
 
 lib_ifnet_io_la_LIBADD = \
+	 $(top_builddir)/src/wifi/libwifi-utils.la \
 	 $(top_builddir)/libnm-util/libnm-util.la \
 	 $(GLIB_LIBS)\
 	 $(GIO_LIBS)
diff --git a/src/settings/plugins/ifnet/Makefile.in b/src/settings/plugins/ifnet/Makefile.in
index 322adbf8..acf4e8bc 100644
--- a/src/settings/plugins/ifnet/Makefile.in
+++ b/src/settings/plugins/ifnet/Makefile.in
@@ -47,7 +47,7 @@ am__aclocal_m4_deps = $(top_srcdir)/m4/compiler_warnings.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)/configure.ac
+	$(top_srcdir)/m4/vapigen.m4 $(top_srcdir)/configure.ac
 am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \
 	$(ACLOCAL_M4)
 mkinstalldirs = $(install_sh) -d
@@ -79,6 +79,7 @@ am__installdirs = "$(DESTDIR)$(pkglibdir)"
 LTLIBRARIES = $(noinst_LTLIBRARIES) $(pkglib_LTLIBRARIES)
 am__DEPENDENCIES_1 =
 lib_ifnet_io_la_DEPENDENCIES =  \
+	$(top_builddir)/src/wifi/libwifi-utils.la \
 	$(top_builddir)/libnm-util/libnm-util.la $(am__DEPENDENCIES_1) \
 	$(am__DEPENDENCIES_1)
 am_lib_ifnet_io_la_OBJECTS = lib_ifnet_io_la-net_parser.lo \
@@ -245,6 +246,10 @@ INTLTOOL_EXTRACT = @INTLTOOL_EXTRACT@
 INTLTOOL_MERGE = @INTLTOOL_MERGE@
 INTLTOOL_PERL = @INTLTOOL_PERL@
 INTLTOOL_UPDATE = @INTLTOOL_UPDATE@
+INTLTOOL_V_MERGE = @INTLTOOL_V_MERGE@
+INTLTOOL_V_MERGE_OPTIONS = @INTLTOOL_V_MERGE_OPTIONS@
+INTLTOOL__v_MERGE_ = @INTLTOOL__v_MERGE_@
+INTLTOOL__v_MERGE_0 = @INTLTOOL__v_MERGE_0@
 INTL_MACOSX_LIBS = @INTL_MACOSX_LIBS@
 INTROSPECTION_CFLAGS = @INTROSPECTION_CFLAGS@
 INTROSPECTION_COMPILER = @INTROSPECTION_COMPILER@
@@ -340,6 +345,9 @@ UDEV_BASE_DIR = @UDEV_BASE_DIR@
 USE_NLS = @USE_NLS@
 UUID_CFLAGS = @UUID_CFLAGS@
 UUID_LIBS = @UUID_LIBS@
+VAPIGEN = @VAPIGEN@
+VAPIGEN_MAKEFILE = @VAPIGEN_MAKEFILE@
+VAPIGEN_VAPIDIR = @VAPIGEN_VAPIDIR@
 VERSION = @VERSION@
 XGETTEXT = @XGETTEXT@
 XGETTEXT_015 = @XGETTEXT_015@
@@ -378,6 +386,8 @@ htmldir = @htmldir@
 includedir = @includedir@
 infodir = @infodir@
 install_sh = @install_sh@
+intltool__v_merge_options_ = @intltool__v_merge_options_@
+intltool__v_merge_options_0 = @intltool__v_merge_options_0@
 libdir = @libdir@
 libexecdir = @libexecdir@
 localedir = @localedir@
@@ -400,6 +410,7 @@ top_builddir = @top_builddir@
 top_srcdir = @top_srcdir@
 SUBDIRS = . tests
 INCLUDES = \
+	-I$(top_srcdir)/src/wifi \
 	-I$(top_srcdir)/src/settings \
 	-I$(top_srcdir)/include \
 	-I$(top_srcdir)/libnm-glib \
@@ -449,6 +460,7 @@ lib_ifnet_io_la_CPPFLAGS = \
 	-DSBINDIR=\"$(sbindir)\"
 
 lib_ifnet_io_la_LIBADD = \
+	 $(top_builddir)/src/wifi/libwifi-utils.la \
 	 $(top_builddir)/libnm-util/libnm-util.la \
 	 $(GLIB_LIBS)\
 	 $(GIO_LIBS)
diff --git a/src/settings/plugins/ifnet/net_parser.c b/src/settings/plugins/ifnet/net_parser.c
index 38765f5f..2562e613 100644
--- a/src/settings/plugins/ifnet/net_parser.c
+++ b/src/settings/plugins/ifnet/net_parser.c
@@ -22,7 +22,14 @@
 #include <string.h>
 #include <nm-system-config-interface.h>
 #include <stdio.h>
+
+#include <sys/ioctl.h>
+#include <net/if.h>
+#include <unistd.h>
+
 #include "plugin.h"
+#include "wifi-utils.h"
+
 #include "net_parser.h"
 #include "net_utils.h"
 
@@ -122,6 +129,24 @@ is_global_setting (char *key)
 	return 0;
 }
 
+/* Find out whether the 'iface' is an interface */
+static gboolean
+name_is_interface (const char *iface)
+{
+	int fd;
+	struct ifreq ifr;
+	gboolean is_iface = FALSE;
+
+	fd = socket (PF_INET, SOCK_DGRAM, 0);
+	if (fd >= 0) {
+		strncpy (ifr.ifr_name, iface, IFNAMSIZ);
+		if (ioctl (fd, SIOCGIFHWADDR, &ifr) == 0)
+			is_iface = TRUE;
+		close (fd);
+	}
+	return is_iface;
+}
+
 /* Parse a complete line */
 /* Connection type is determined here */
 static void
@@ -143,12 +168,13 @@ init_block_by_line (gchar * buf)
 	pos = g_strrstr (key_value[0], "_");
 	if (pos == NULL || is_global_setting (key_value[0])) {
 		/* global data */
-		PLUGIN_PRINT (IFNET_PLUGIN_NAME, "global:%s-%s\n", key_value[0],
-			      key_value[1]);
-		g_hash_table_insert (global_settings_table,
-				     g_strdup (key_value[0]),
-				     g_strdup (key_value[1]));
+		data = g_strdup (key_value[1]);
+		tmp = strip_string (data, '"');
+		strip_string (tmp, '\'');
+		PLUGIN_PRINT (IFNET_PLUGIN_NAME, "global:%s-%s\n", key_value[0], tmp);
+		g_hash_table_insert (global_settings_table, g_strdup (key_value[0]), g_strdup (tmp));
 		g_strfreev (key_value);
+		g_free (data);
 		return;
 	}
 	*pos++ = '\0';
@@ -165,8 +191,12 @@ init_block_by_line (gchar * buf)
 			/* ignored connection */
 			conn = add_new_connection_config ("ignore", pos);
 		} else
-			/* wireless connection */
-			conn = add_new_connection_config ("wireless", pos);
+			if (name_is_interface (pos) && !wifi_utils_is_wifi (pos, NULL))
+				/* wired connection */
+				conn = add_new_connection_config ("wired", pos);
+			else
+				/* wireless connection */
+				conn = add_new_connection_config ("wireless", pos);
 	}
 	data = g_strdup (key_value[1]);
 	tmp = strip_string (data, '"');
@@ -593,7 +623,7 @@ ifnet_flush_to_file (const char *config_file)
 	/* Writing global data */
 	while (g_hash_table_iter_next (&iter, &key, &value)) {
 		out_line =
-		    g_strdup_printf ("%s=%s\n", (gchar *) key, (gchar *) value);
+		    g_strdup_printf ("%s=\"%s\"\n", (gchar *) key, (gchar *) value);
 		g_io_channel_write_chars (channel, out_line, -1,
 					  &bytes_written, error);
 		if (bytes_written == 0 || (error && *error))
diff --git a/src/settings/plugins/ifnet/net_utils.c b/src/settings/plugins/ifnet/net_utils.c
index f1687479..d613db6a 100644
--- a/src/settings/plugins/ifnet/net_utils.c
+++ b/src/settings/plugins/ifnet/net_utils.c
@@ -404,7 +404,7 @@ has_ip6_address (const char *conn_name)
 
 	g_return_val_if_fail (conn_name != NULL, FALSE);
 	ipset = split_addresses (ifnet_get_data (conn_name, "config"));
-	length = g_strv_length (ipset);
+	length = ipset ? g_strv_length (ipset) : 0;
 	for (i = 0; i < length; i++) {
 		if (!is_ip6_address (ipset[i]))
 			continue;
@@ -618,7 +618,7 @@ convert_ip4_config_block (const char *conn_name)
 	g_return_val_if_fail (conn_name != NULL, NULL);
 
 	ipset = split_addresses (ifnet_get_data (conn_name, "config"));
-	length = g_strv_length (ipset);
+	length = ipset ? g_strv_length (ipset) : 0;
 
 	routes = ifnet_get_data (conn_name, "routes");
 	if (routes)
@@ -654,7 +654,7 @@ convert_ip6_config_block (const char *conn_name)
 
 	g_return_val_if_fail (conn_name != NULL, NULL);
 	ipset = split_addresses (ifnet_get_data (conn_name, "config"));
-	length = g_strv_length (ipset);
+	length = ipset ? g_strv_length (ipset) : 0;
 	for (i = 0; i < length; i++) {
 		ip = ipset[i];
 		ip = strip_string (ip, '"');
@@ -684,7 +684,7 @@ convert_ip4_routes_block (const char *conn_name)
 	g_return_val_if_fail (conn_name != NULL, NULL);
 
 	ipset = split_routes (ifnet_get_data (conn_name, "routes"));
-	length = g_strv_length (ipset);
+	length = ipset ? g_strv_length (ipset) : 0;
 	for (i = 0; i < length; i++) {
 		ip = ipset[i];
 		if (find_default_gateway_str (ip) || strstr (ip, "::")
@@ -718,7 +718,7 @@ convert_ip6_routes_block (const char *conn_name)
 
 	g_return_val_if_fail (conn_name != NULL, NULL);
 	ipset = split_routes (ifnet_get_data (conn_name, "routes"));
-	length = g_strv_length (ipset);
+	length = ipset ? g_strv_length (ipset) : 0;
 	for (i = 0; i < length; i++) {
 		ip = ipset[i];
 		ip = strip_string (ip, '"');
diff --git a/src/settings/plugins/ifnet/tests/Makefile.am b/src/settings/plugins/ifnet/tests/Makefile.am
index 20a26805..85d42388 100644
--- a/src/settings/plugins/ifnet/tests/Makefile.am
+++ b/src/settings/plugins/ifnet/tests/Makefile.am
@@ -10,7 +10,8 @@ check_ifnet_CPPFLAGS = $(CHECK_CFLAGS) $(GLIB_CFLAGS)
 check_ifnet_LDADD = $(top_builddir)/libnm-util/libnm-util.la \
 		    $(builddir)/../lib-ifnet-io.la \
 		    $(CHECK_LIBS) \
-		    $(GLIB_LIBS)
+		    $(GLIB_LIBS) \
+		    $(LIBM)
 EXTRA_DIST = hostname \
 			 net \
 			 net.all \
diff --git a/src/settings/plugins/ifnet/tests/Makefile.in b/src/settings/plugins/ifnet/tests/Makefile.in
index 02ee121f..743e547c 100644
--- a/src/settings/plugins/ifnet/tests/Makefile.in
+++ b/src/settings/plugins/ifnet/tests/Makefile.in
@@ -48,7 +48,7 @@ am__aclocal_m4_deps = $(top_srcdir)/m4/compiler_warnings.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)/configure.ac
+	$(top_srcdir)/m4/vapigen.m4 $(top_srcdir)/configure.ac
 am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \
 	$(ACLOCAL_M4)
 mkinstalldirs = $(install_sh) -d
@@ -59,7 +59,8 @@ am_check_ifnet_OBJECTS = check_ifnet-test_all.$(OBJEXT)
 check_ifnet_OBJECTS = $(am_check_ifnet_OBJECTS)
 am__DEPENDENCIES_1 =
 check_ifnet_DEPENDENCIES = $(top_builddir)/libnm-util/libnm-util.la \
-	$(builddir)/../lib-ifnet-io.la $(am__DEPENDENCIES_1)
+	$(builddir)/../lib-ifnet-io.la $(am__DEPENDENCIES_1) \
+	$(am__DEPENDENCIES_1)
 AM_V_lt = $(am__v_lt_$(V))
 am__v_lt_ = $(am__v_lt_$(AM_DEFAULT_VERBOSITY))
 am__v_lt_0 = --silent
@@ -168,6 +169,10 @@ INTLTOOL_EXTRACT = @INTLTOOL_EXTRACT@
 INTLTOOL_MERGE = @INTLTOOL_MERGE@
 INTLTOOL_PERL = @INTLTOOL_PERL@
 INTLTOOL_UPDATE = @INTLTOOL_UPDATE@
+INTLTOOL_V_MERGE = @INTLTOOL_V_MERGE@
+INTLTOOL_V_MERGE_OPTIONS = @INTLTOOL_V_MERGE_OPTIONS@
+INTLTOOL__v_MERGE_ = @INTLTOOL__v_MERGE_@
+INTLTOOL__v_MERGE_0 = @INTLTOOL__v_MERGE_0@
 INTL_MACOSX_LIBS = @INTL_MACOSX_LIBS@
 INTROSPECTION_CFLAGS = @INTROSPECTION_CFLAGS@
 INTROSPECTION_COMPILER = @INTROSPECTION_COMPILER@
@@ -263,6 +268,9 @@ UDEV_BASE_DIR = @UDEV_BASE_DIR@
 USE_NLS = @USE_NLS@
 UUID_CFLAGS = @UUID_CFLAGS@
 UUID_LIBS = @UUID_LIBS@
+VAPIGEN = @VAPIGEN@
+VAPIGEN_MAKEFILE = @VAPIGEN_MAKEFILE@
+VAPIGEN_VAPIDIR = @VAPIGEN_VAPIDIR@
 VERSION = @VERSION@
 XGETTEXT = @XGETTEXT@
 XGETTEXT_015 = @XGETTEXT_015@
@@ -301,6 +309,8 @@ htmldir = @htmldir@
 includedir = @includedir@
 infodir = @infodir@
 install_sh = @install_sh@
+intltool__v_merge_options_ = @intltool__v_merge_options_@
+intltool__v_merge_options_0 = @intltool__v_merge_options_0@
 libdir = @libdir@
 libexecdir = @libexecdir@
 localedir = @localedir@
@@ -332,7 +342,8 @@ check_ifnet_CPPFLAGS = $(CHECK_CFLAGS) $(GLIB_CFLAGS)
 check_ifnet_LDADD = $(top_builddir)/libnm-util/libnm-util.la \
 		    $(builddir)/../lib-ifnet-io.la \
 		    $(CHECK_LIBS) \
-		    $(GLIB_LIBS)
+		    $(GLIB_LIBS) \
+		    $(LIBM)
 
 EXTRA_DIST = hostname \
 			 net \
diff --git a/src/settings/plugins/ifnet/tests/net b/src/settings/plugins/ifnet/tests/net
index 27d39f44..a5ac9ca2 100644
--- a/src/settings/plugins/ifnet/tests/net
+++ b/src/settings/plugins/ifnet/tests/net
@@ -3,6 +3,8 @@
 # please review /etc/conf.d/net.example and save your configuration
 # in /etc/conf.d/net (this file :]!).
 
+modules="!wpa_supplicant"
+
 config_eth0=(
 "202.117.16.121    netmask    255.255.255.0 brd 202.117.16.255"
 "192.168.4.121/24"
diff --git a/src/settings/plugins/ifnet/tests/test_all.c b/src/settings/plugins/ifnet/tests/test_all.c
index 50441d4e..974258b9 100644
--- a/src/settings/plugins/ifnet/tests/test_all.c
+++ b/src/settings/plugins/ifnet/tests/test_all.c
@@ -56,6 +56,9 @@ test_getdata ()
 		&& strcmp (ifnet_get_data ("ppp0", "password"),
 			   "password") == 0, "get data",
 		"config_ppp0 password is not correctly read");
+	ASSERT (ifnet_get_global_data ("modules")
+		&& strcmp ("!wpa_supplicant", ifnet_get_global_data ("modules")) == 0,
+		"get data", "config_eth1 is not correct");
 }
 
 static void
diff --git a/src/settings/plugins/ifupdown/Makefile.in b/src/settings/plugins/ifupdown/Makefile.in
index f5087648..d1414ef0 100644
--- a/src/settings/plugins/ifupdown/Makefile.in
+++ b/src/settings/plugins/ifupdown/Makefile.in
@@ -47,7 +47,7 @@ am__aclocal_m4_deps = $(top_srcdir)/m4/compiler_warnings.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)/configure.ac
+	$(top_srcdir)/m4/vapigen.m4 $(top_srcdir)/configure.ac
 am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \
 	$(ACLOCAL_M4)
 mkinstalldirs = $(install_sh) -d
@@ -244,6 +244,10 @@ INTLTOOL_EXTRACT = @INTLTOOL_EXTRACT@
 INTLTOOL_MERGE = @INTLTOOL_MERGE@
 INTLTOOL_PERL = @INTLTOOL_PERL@
 INTLTOOL_UPDATE = @INTLTOOL_UPDATE@
+INTLTOOL_V_MERGE = @INTLTOOL_V_MERGE@
+INTLTOOL_V_MERGE_OPTIONS = @INTLTOOL_V_MERGE_OPTIONS@
+INTLTOOL__v_MERGE_ = @INTLTOOL__v_MERGE_@
+INTLTOOL__v_MERGE_0 = @INTLTOOL__v_MERGE_0@
 INTL_MACOSX_LIBS = @INTL_MACOSX_LIBS@
 INTROSPECTION_CFLAGS = @INTROSPECTION_CFLAGS@
 INTROSPECTION_COMPILER = @INTROSPECTION_COMPILER@
@@ -339,6 +343,9 @@ UDEV_BASE_DIR = @UDEV_BASE_DIR@
 USE_NLS = @USE_NLS@
 UUID_CFLAGS = @UUID_CFLAGS@
 UUID_LIBS = @UUID_LIBS@
+VAPIGEN = @VAPIGEN@
+VAPIGEN_MAKEFILE = @VAPIGEN_MAKEFILE@
+VAPIGEN_VAPIDIR = @VAPIGEN_VAPIDIR@
 VERSION = @VERSION@
 XGETTEXT = @XGETTEXT@
 XGETTEXT_015 = @XGETTEXT_015@
@@ -377,6 +384,8 @@ htmldir = @htmldir@
 includedir = @includedir@
 infodir = @infodir@
 install_sh = @install_sh@
+intltool__v_merge_options_ = @intltool__v_merge_options_@
+intltool__v_merge_options_0 = @intltool__v_merge_options_0@
 libdir = @libdir@
 libexecdir = @libexecdir@
 localedir = @localedir@
diff --git a/src/settings/plugins/ifupdown/tests/Makefile.am b/src/settings/plugins/ifupdown/tests/Makefile.am
index ff219d5d..9a9ea1f7 100644
--- a/src/settings/plugins/ifupdown/tests/Makefile.am
+++ b/src/settings/plugins/ifupdown/tests/Makefile.am
@@ -29,4 +29,5 @@ endif
 
 EXTRA_DIST = \
 	test1 test2 test3 test4 test5 test6 test7 test8 test9 test11 test12 \
-	test13 test14 test15 test16 test17-wired-static-verify-ip4
+	test13 test14 test15 test16 test17-wired-static-verify-ip4 \
+	test18-wired-static-verify-ip6
diff --git a/src/settings/plugins/ifupdown/tests/Makefile.in b/src/settings/plugins/ifupdown/tests/Makefile.in
index a03be1bd..68c166c0 100644
--- a/src/settings/plugins/ifupdown/tests/Makefile.in
+++ b/src/settings/plugins/ifupdown/tests/Makefile.in
@@ -48,7 +48,7 @@ am__aclocal_m4_deps = $(top_srcdir)/m4/compiler_warnings.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)/configure.ac
+	$(top_srcdir)/m4/vapigen.m4 $(top_srcdir)/configure.ac
 am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \
 	$(ACLOCAL_M4)
 mkinstalldirs = $(install_sh) -d
@@ -168,6 +168,10 @@ INTLTOOL_EXTRACT = @INTLTOOL_EXTRACT@
 INTLTOOL_MERGE = @INTLTOOL_MERGE@
 INTLTOOL_PERL = @INTLTOOL_PERL@
 INTLTOOL_UPDATE = @INTLTOOL_UPDATE@
+INTLTOOL_V_MERGE = @INTLTOOL_V_MERGE@
+INTLTOOL_V_MERGE_OPTIONS = @INTLTOOL_V_MERGE_OPTIONS@
+INTLTOOL__v_MERGE_ = @INTLTOOL__v_MERGE_@
+INTLTOOL__v_MERGE_0 = @INTLTOOL__v_MERGE_0@
 INTL_MACOSX_LIBS = @INTL_MACOSX_LIBS@
 INTROSPECTION_CFLAGS = @INTROSPECTION_CFLAGS@
 INTROSPECTION_COMPILER = @INTROSPECTION_COMPILER@
@@ -263,6 +267,9 @@ UDEV_BASE_DIR = @UDEV_BASE_DIR@
 USE_NLS = @USE_NLS@
 UUID_CFLAGS = @UUID_CFLAGS@
 UUID_LIBS = @UUID_LIBS@
+VAPIGEN = @VAPIGEN@
+VAPIGEN_MAKEFILE = @VAPIGEN_MAKEFILE@
+VAPIGEN_VAPIDIR = @VAPIGEN_VAPIDIR@
 VERSION = @VERSION@
 XGETTEXT = @XGETTEXT@
 XGETTEXT_015 = @XGETTEXT_015@
@@ -301,6 +308,8 @@ htmldir = @htmldir@
 includedir = @includedir@
 infodir = @infodir@
 install_sh = @install_sh@
+intltool__v_merge_options_ = @intltool__v_merge_options_@
+intltool__v_merge_options_0 = @intltool__v_merge_options_0@
 libdir = @libdir@
 libexecdir = @libexecdir@
 localedir = @localedir@
@@ -343,7 +352,8 @@ test_ifupdown_LDADD = \
 
 EXTRA_DIST = \
 	test1 test2 test3 test4 test5 test6 test7 test8 test9 test11 test12 \
-	test13 test14 test15 test16 test17-wired-static-verify-ip4
+	test13 test14 test15 test16 test17-wired-static-verify-ip4 \
+	test18-wired-static-verify-ip6
 
 all: all-am
 
diff --git a/src/settings/plugins/ifupdown/tests/test18-wired-static-verify-ip6 b/src/settings/plugins/ifupdown/tests/test18-wired-static-verify-ip6
new file mode 100644
index 00000000..29546a61
--- /dev/null
+++ b/src/settings/plugins/ifupdown/tests/test18-wired-static-verify-ip6
@@ -0,0 +1,6 @@
+iface myip6tunnel inet6 v4tunnel
+  address fc00::1
+  netmask 64
+  endpoint 78.35.24.124
+  dns-nameservers fc00::2 fc00::3
+  dns-search example.com foo.example.com
diff --git a/src/settings/plugins/keyfile/Makefile.in b/src/settings/plugins/keyfile/Makefile.in
index c766e794..4b9ec0dd 100644
--- a/src/settings/plugins/keyfile/Makefile.in
+++ b/src/settings/plugins/keyfile/Makefile.in
@@ -47,7 +47,7 @@ am__aclocal_m4_deps = $(top_srcdir)/m4/compiler_warnings.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)/configure.ac
+	$(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,6 +220,10 @@ INTLTOOL_EXTRACT = @INTLTOOL_EXTRACT@
 INTLTOOL_MERGE = @INTLTOOL_MERGE@
 INTLTOOL_PERL = @INTLTOOL_PERL@
 INTLTOOL_UPDATE = @INTLTOOL_UPDATE@
+INTLTOOL_V_MERGE = @INTLTOOL_V_MERGE@
+INTLTOOL_V_MERGE_OPTIONS = @INTLTOOL_V_MERGE_OPTIONS@
+INTLTOOL__v_MERGE_ = @INTLTOOL__v_MERGE_@
+INTLTOOL__v_MERGE_0 = @INTLTOOL__v_MERGE_0@
 INTL_MACOSX_LIBS = @INTL_MACOSX_LIBS@
 INTROSPECTION_CFLAGS = @INTROSPECTION_CFLAGS@
 INTROSPECTION_COMPILER = @INTROSPECTION_COMPILER@
@@ -315,6 +319,9 @@ UDEV_BASE_DIR = @UDEV_BASE_DIR@
 USE_NLS = @USE_NLS@
 UUID_CFLAGS = @UUID_CFLAGS@
 UUID_LIBS = @UUID_LIBS@
+VAPIGEN = @VAPIGEN@
+VAPIGEN_MAKEFILE = @VAPIGEN_MAKEFILE@
+VAPIGEN_VAPIDIR = @VAPIGEN_VAPIDIR@
 VERSION = @VERSION@
 XGETTEXT = @XGETTEXT@
 XGETTEXT_015 = @XGETTEXT_015@
@@ -353,6 +360,8 @@ htmldir = @htmldir@
 includedir = @includedir@
 infodir = @infodir@
 install_sh = @install_sh@
+intltool__v_merge_options_ = @intltool__v_merge_options_@
+intltool__v_merge_options_0 = @intltool__v_merge_options_0@
 libdir = @libdir@
 libexecdir = @libexecdir@
 localedir = @localedir@
diff --git a/src/settings/plugins/keyfile/reader.c b/src/settings/plugins/keyfile/reader.c
index c7889cfc..47392978 100644
--- a/src/settings/plugins/keyfile/reader.c
+++ b/src/settings/plugins/keyfile/reader.c
@@ -1351,7 +1351,8 @@ nm_keyfile_plugin_connection_from_file (const char *filename, GError **error)
 	/* Verify the connection */
 	if (!nm_connection_verify (connection, &verify_error)) {
 		g_set_error (error, KEYFILE_PLUGIN_ERROR, 0,
-			         "invalid or missing connection property '%s'",
+			         "invalid or missing connection property '%s/%s'",
+			         verify_error ? g_type_name (nm_connection_lookup_setting_type_by_quark (verify_error->domain)) : "(unknown)",
 			         (verify_error && verify_error->message) ? verify_error->message : "(unknown)");
 		g_clear_error (&verify_error);
 		g_object_unref (connection);
diff --git a/src/settings/plugins/keyfile/tests/Makefile.in b/src/settings/plugins/keyfile/tests/Makefile.in
index ff08e529..d37f2c61 100644
--- a/src/settings/plugins/keyfile/tests/Makefile.in
+++ b/src/settings/plugins/keyfile/tests/Makefile.in
@@ -48,7 +48,7 @@ am__aclocal_m4_deps = $(top_srcdir)/m4/compiler_warnings.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)/configure.ac
+	$(top_srcdir)/m4/vapigen.m4 $(top_srcdir)/configure.ac
 am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \
 	$(ACLOCAL_M4)
 mkinstalldirs = $(install_sh) -d
@@ -206,6 +206,10 @@ INTLTOOL_EXTRACT = @INTLTOOL_EXTRACT@
 INTLTOOL_MERGE = @INTLTOOL_MERGE@
 INTLTOOL_PERL = @INTLTOOL_PERL@
 INTLTOOL_UPDATE = @INTLTOOL_UPDATE@
+INTLTOOL_V_MERGE = @INTLTOOL_V_MERGE@
+INTLTOOL_V_MERGE_OPTIONS = @INTLTOOL_V_MERGE_OPTIONS@
+INTLTOOL__v_MERGE_ = @INTLTOOL__v_MERGE_@
+INTLTOOL__v_MERGE_0 = @INTLTOOL__v_MERGE_0@
 INTL_MACOSX_LIBS = @INTL_MACOSX_LIBS@
 INTROSPECTION_CFLAGS = @INTROSPECTION_CFLAGS@
 INTROSPECTION_COMPILER = @INTROSPECTION_COMPILER@
@@ -301,6 +305,9 @@ UDEV_BASE_DIR = @UDEV_BASE_DIR@
 USE_NLS = @USE_NLS@
 UUID_CFLAGS = @UUID_CFLAGS@
 UUID_LIBS = @UUID_LIBS@
+VAPIGEN = @VAPIGEN@
+VAPIGEN_MAKEFILE = @VAPIGEN_MAKEFILE@
+VAPIGEN_VAPIDIR = @VAPIGEN_VAPIDIR@
 VERSION = @VERSION@
 XGETTEXT = @XGETTEXT@
 XGETTEXT_015 = @XGETTEXT_015@
@@ -339,6 +346,8 @@ htmldir = @htmldir@
 includedir = @includedir@
 infodir = @infodir@
 install_sh = @install_sh@
+intltool__v_merge_options_ = @intltool__v_merge_options_@
+intltool__v_merge_options_0 = @intltool__v_merge_options_0@
 libdir = @libdir@
 libexecdir = @libexecdir@
 localedir = @localedir@
diff --git a/src/settings/plugins/keyfile/tests/keyfiles/Makefile.in b/src/settings/plugins/keyfile/tests/keyfiles/Makefile.in
index cf5b868f..e6cf35ad 100644
--- a/src/settings/plugins/keyfile/tests/keyfiles/Makefile.in
+++ b/src/settings/plugins/keyfile/tests/keyfiles/Makefile.in
@@ -46,7 +46,7 @@ am__aclocal_m4_deps = $(top_srcdir)/m4/compiler_warnings.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)/configure.ac
+	$(top_srcdir)/m4/vapigen.m4 $(top_srcdir)/configure.ac
 am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \
 	$(ACLOCAL_M4)
 mkinstalldirs = $(install_sh) -d
@@ -134,6 +134,10 @@ INTLTOOL_EXTRACT = @INTLTOOL_EXTRACT@
 INTLTOOL_MERGE = @INTLTOOL_MERGE@
 INTLTOOL_PERL = @INTLTOOL_PERL@
 INTLTOOL_UPDATE = @INTLTOOL_UPDATE@
+INTLTOOL_V_MERGE = @INTLTOOL_V_MERGE@
+INTLTOOL_V_MERGE_OPTIONS = @INTLTOOL_V_MERGE_OPTIONS@
+INTLTOOL__v_MERGE_ = @INTLTOOL__v_MERGE_@
+INTLTOOL__v_MERGE_0 = @INTLTOOL__v_MERGE_0@
 INTL_MACOSX_LIBS = @INTL_MACOSX_LIBS@
 INTROSPECTION_CFLAGS = @INTROSPECTION_CFLAGS@
 INTROSPECTION_COMPILER = @INTROSPECTION_COMPILER@
@@ -229,6 +233,9 @@ UDEV_BASE_DIR = @UDEV_BASE_DIR@
 USE_NLS = @USE_NLS@
 UUID_CFLAGS = @UUID_CFLAGS@
 UUID_LIBS = @UUID_LIBS@
+VAPIGEN = @VAPIGEN@
+VAPIGEN_MAKEFILE = @VAPIGEN_MAKEFILE@
+VAPIGEN_VAPIDIR = @VAPIGEN_VAPIDIR@
 VERSION = @VERSION@
 XGETTEXT = @XGETTEXT@
 XGETTEXT_015 = @XGETTEXT_015@
@@ -267,6 +274,8 @@ htmldir = @htmldir@
 includedir = @includedir@
 infodir = @infodir@
 install_sh = @install_sh@
+intltool__v_merge_options_ = @intltool__v_merge_options_@
+intltool__v_merge_options_0 = @intltool__v_merge_options_0@
 libdir = @libdir@
 libexecdir = @libexecdir@
 localedir = @localedir@
diff --git a/src/settings/tests/Makefile.in b/src/settings/tests/Makefile.in
index de5474d4..5fb95d31 100644
--- a/src/settings/tests/Makefile.in
+++ b/src/settings/tests/Makefile.in
@@ -48,7 +48,7 @@ am__aclocal_m4_deps = $(top_srcdir)/m4/compiler_warnings.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)/configure.ac
+	$(top_srcdir)/m4/vapigen.m4 $(top_srcdir)/configure.ac
 am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \
 	$(ACLOCAL_M4)
 mkinstalldirs = $(install_sh) -d
@@ -170,6 +170,10 @@ INTLTOOL_EXTRACT = @INTLTOOL_EXTRACT@
 INTLTOOL_MERGE = @INTLTOOL_MERGE@
 INTLTOOL_PERL = @INTLTOOL_PERL@
 INTLTOOL_UPDATE = @INTLTOOL_UPDATE@
+INTLTOOL_V_MERGE = @INTLTOOL_V_MERGE@
+INTLTOOL_V_MERGE_OPTIONS = @INTLTOOL_V_MERGE_OPTIONS@
+INTLTOOL__v_MERGE_ = @INTLTOOL__v_MERGE_@
+INTLTOOL__v_MERGE_0 = @INTLTOOL__v_MERGE_0@
 INTL_MACOSX_LIBS = @INTL_MACOSX_LIBS@
 INTROSPECTION_CFLAGS = @INTROSPECTION_CFLAGS@
 INTROSPECTION_COMPILER = @INTROSPECTION_COMPILER@
@@ -265,6 +269,9 @@ UDEV_BASE_DIR = @UDEV_BASE_DIR@
 USE_NLS = @USE_NLS@
 UUID_CFLAGS = @UUID_CFLAGS@
 UUID_LIBS = @UUID_LIBS@
+VAPIGEN = @VAPIGEN@
+VAPIGEN_MAKEFILE = @VAPIGEN_MAKEFILE@
+VAPIGEN_VAPIDIR = @VAPIGEN_VAPIDIR@
 VERSION = @VERSION@
 XGETTEXT = @XGETTEXT@
 XGETTEXT_015 = @XGETTEXT_015@
@@ -303,6 +310,8 @@ htmldir = @htmldir@
 includedir = @includedir@
 infodir = @infodir@
 install_sh = @install_sh@
+intltool__v_merge_options_ = @intltool__v_merge_options_@
+intltool__v_merge_options_0 = @intltool__v_merge_options_0@
 libdir = @libdir@
 libexecdir = @libexecdir@
 localedir = @localedir@
diff --git a/src/supplicant-manager/Makefile.in b/src/supplicant-manager/Makefile.in
index fbb43bde..4bde9543 100644
--- a/src/supplicant-manager/Makefile.in
+++ b/src/supplicant-manager/Makefile.in
@@ -47,7 +47,7 @@ am__aclocal_m4_deps = $(top_srcdir)/m4/compiler_warnings.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)/configure.ac
+	$(top_srcdir)/m4/vapigen.m4 $(top_srcdir)/configure.ac
 am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \
 	$(ACLOCAL_M4)
 mkinstalldirs = $(install_sh) -d
@@ -210,6 +210,10 @@ INTLTOOL_EXTRACT = @INTLTOOL_EXTRACT@
 INTLTOOL_MERGE = @INTLTOOL_MERGE@
 INTLTOOL_PERL = @INTLTOOL_PERL@
 INTLTOOL_UPDATE = @INTLTOOL_UPDATE@
+INTLTOOL_V_MERGE = @INTLTOOL_V_MERGE@
+INTLTOOL_V_MERGE_OPTIONS = @INTLTOOL_V_MERGE_OPTIONS@
+INTLTOOL__v_MERGE_ = @INTLTOOL__v_MERGE_@
+INTLTOOL__v_MERGE_0 = @INTLTOOL__v_MERGE_0@
 INTL_MACOSX_LIBS = @INTL_MACOSX_LIBS@
 INTROSPECTION_CFLAGS = @INTROSPECTION_CFLAGS@
 INTROSPECTION_COMPILER = @INTROSPECTION_COMPILER@
@@ -305,6 +309,9 @@ UDEV_BASE_DIR = @UDEV_BASE_DIR@
 USE_NLS = @USE_NLS@
 UUID_CFLAGS = @UUID_CFLAGS@
 UUID_LIBS = @UUID_LIBS@
+VAPIGEN = @VAPIGEN@
+VAPIGEN_MAKEFILE = @VAPIGEN_MAKEFILE@
+VAPIGEN_VAPIDIR = @VAPIGEN_VAPIDIR@
 VERSION = @VERSION@
 XGETTEXT = @XGETTEXT@
 XGETTEXT_015 = @XGETTEXT_015@
@@ -343,6 +350,8 @@ htmldir = @htmldir@
 includedir = @includedir@
 infodir = @infodir@
 install_sh = @install_sh@
+intltool__v_merge_options_ = @intltool__v_merge_options_@
+intltool__v_merge_options_0 = @intltool__v_merge_options_0@
 libdir = @libdir@
 libexecdir = @libexecdir@
 localedir = @localedir@
diff --git a/src/supplicant-manager/nm-supplicant-interface.c b/src/supplicant-manager/nm-supplicant-interface.c
index f8ad8f18..cbe7032f 100644
--- a/src/supplicant-manager/nm-supplicant-interface.c
+++ b/src/supplicant-manager/nm-supplicant-interface.c
@@ -50,6 +50,8 @@ static void wpas_iface_scan_done (DBusGProxy *proxy,
                                   gboolean success,
                                   gpointer user_data);
 
+static void wpas_iface_get_props (NMSupplicantInterface *self);
+
 #define NM_SUPPLICANT_INTERFACE_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), \
                                                  NM_TYPE_SUPPLICANT_INTERFACE, \
                                                  NMSupplicantInterfacePrivate))
@@ -85,6 +87,8 @@ typedef struct {
 	gboolean              is_wireless;
 	gboolean              has_credreq;  /* Whether querying 802.1x credentials is supported */
 	gboolean              fast_supported;
+	guint32               max_scan_ssids;
+	guint32               ready_count;
 
 	char *                object_path;
 	guint32               state;
@@ -100,7 +104,7 @@ typedef struct {
 	guint32               blobs_left;
 	GHashTable *          bss_proxies;
 
-	guint32               last_scan;
+	time_t                last_scan;
 
 	NMSupplicantConfig *  cfg;
 
@@ -257,6 +261,10 @@ bss_properties_changed (DBusGProxy *proxy,
                         gpointer user_data)
 {
 	NMSupplicantInterface *self = NM_SUPPLICANT_INTERFACE (user_data);
+	NMSupplicantInterfacePrivate *priv = NM_SUPPLICANT_INTERFACE_GET_PRIVATE (self);
+
+	if (priv->scanning)
+		priv->last_scan = time (NULL);
 
 	if (g_strcmp0 (interface, WPAS_DBUS_IFACE_BSS) == 0)
 		g_signal_emit (self, signals[BSS_UPDATED], 0, dbus_g_proxy_get_path (proxy), props);
@@ -268,6 +276,10 @@ old_bss_properties_changed (DBusGProxy *proxy,
                             gpointer user_data)
 {
 	NMSupplicantInterface *self = NM_SUPPLICANT_INTERFACE (user_data);
+	NMSupplicantInterfacePrivate *priv = NM_SUPPLICANT_INTERFACE_GET_PRIVATE (self);
+
+	if (priv->scanning)
+		priv->last_scan = time (NULL);
 
 	g_signal_emit (self, signals[BSS_UPDATED], 0, dbus_g_proxy_get_path (proxy), props);
 }
@@ -346,7 +358,13 @@ wpas_iface_bss_added (DBusGProxy *proxy,
                       GHashTable *props,
                       gpointer user_data)
 {
-	handle_new_bss (NM_SUPPLICANT_INTERFACE (user_data), object_path, props);
+	NMSupplicantInterface *self = NM_SUPPLICANT_INTERFACE (user_data);
+	NMSupplicantInterfacePrivate *priv = NM_SUPPLICANT_INTERFACE_GET_PRIVATE (self);
+
+	if (priv->scanning)
+		priv->last_scan = time (NULL);
+
+	handle_new_bss (self, object_path, props);
 }
 
 static void
@@ -365,7 +383,9 @@ wpas_iface_bss_removed (DBusGProxy *proxy,
 static int
 wpas_state_string_to_enum (const char *str_state)
 {
-	if (!strcmp (str_state, "disconnected"))
+	if (!strcmp (str_state, "interface_disabled"))
+		return NM_SUPPLICANT_INTERFACE_STATE_DISABLED;
+	else if (!strcmp (str_state, "disconnected"))
 		return NM_SUPPLICANT_INTERFACE_STATE_DISCONNECTED;
 	else if (!strcmp (str_state, "inactive"))
 		return NM_SUPPLICANT_INTERFACE_STATE_INACTIVE;
@@ -406,7 +426,12 @@ set_state (NMSupplicantInterface *self, guint32 new_state)
 	if (priv->state >= NM_SUPPLICANT_INTERFACE_STATE_READY)
 		g_return_if_fail (new_state > NM_SUPPLICANT_INTERFACE_STATE_READY);
 
-	if (new_state == NM_SUPPLICANT_INTERFACE_STATE_DOWN) {
+	if (new_state == NM_SUPPLICANT_INTERFACE_STATE_READY) {
+		/* Get properties again to update to the actual wpa_supplicant
+		 * interface state.
+		 */
+		wpas_iface_get_props (self);
+	} else if (new_state == NM_SUPPLICANT_INTERFACE_STATE_DOWN) {
 		/* Cancel all pending calls when going down */
 		cancel_all_callbacks (priv->other_pcalls);
 		cancel_all_callbacks (priv->assoc_pcalls);
@@ -438,6 +463,11 @@ set_state (NMSupplicantInterface *self, guint32 new_state)
 	}
 
 	priv->state = new_state;
+
+	if (   priv->state == NM_SUPPLICANT_INTERFACE_STATE_SCANNING
+	    || old_state == NM_SUPPLICANT_INTERFACE_STATE_SCANNING)
+		priv->last_scan = time (NULL);
+
 	g_signal_emit (self, signals[STATE], 0, priv->state, old_state);
 }
 
@@ -456,16 +486,13 @@ static void
 set_scanning (NMSupplicantInterface *self, gboolean new_scanning)
 {
 	NMSupplicantInterfacePrivate *priv = NM_SUPPLICANT_INTERFACE_GET_PRIVATE (self);
-	GTimeVal cur_time;
 
 	if (priv->scanning != new_scanning) {
 		priv->scanning = new_scanning;
 
 		/* Cache time of last scan completion */
-		if (priv->scanning == FALSE) {
-			g_get_current_time (&cur_time);
-			priv->last_scan = cur_time.tv_sec;
-		}
+		if (priv->scanning == FALSE)
+			priv->last_scan = time (NULL);
 
 		g_object_notify (G_OBJECT (self), "scanning");
 	}
@@ -486,6 +513,12 @@ nm_supplicant_interface_get_scanning (NMSupplicantInterface *self)
 	return FALSE;
 }
 
+time_t
+nm_supplicant_interface_get_last_scan_time (NMSupplicantInterface *self)
+{
+	return NM_SUPPLICANT_INTERFACE_GET_PRIVATE (self)->last_scan;
+}
+
 static void
 wpas_iface_scan_done (DBusGProxy *proxy,
                       gboolean success,
@@ -493,21 +526,57 @@ wpas_iface_scan_done (DBusGProxy *proxy,
 {
 	NMSupplicantInterface *self = NM_SUPPLICANT_INTERFACE (user_data);
 	NMSupplicantInterfacePrivate *priv = NM_SUPPLICANT_INTERFACE_GET_PRIVATE (self);
-	GTimeVal cur_time;
 
 	/* Cache last scan completed time */
-	g_get_current_time (&cur_time);
-	priv->last_scan = cur_time.tv_sec;
-
+	priv->last_scan = time (NULL);
 	g_signal_emit (self, signals[SCAN_DONE], 0, success);
 }
 
 static void
+parse_capabilities (NMSupplicantInterface *self, GHashTable *props)
+{
+	NMSupplicantInterfacePrivate *priv = NM_SUPPLICANT_INTERFACE_GET_PRIVATE (self);
+	GValue *value;
+	gboolean have_active = FALSE, have_ssid = FALSE;
+
+	g_return_if_fail (props != NULL);
+
+	value = g_hash_table_lookup (props, "Scan");
+	if (value && G_VALUE_HOLDS (value, G_TYPE_STRV)) {
+		const char **vals = g_value_get_boxed (value);
+		const char **iter = vals;
+
+		while (iter && *iter && (!have_active || !have_ssid)) {
+			if (g_strcmp0 (*iter, "active") == 0)
+				have_active = TRUE;
+			else if (g_strcmp0 (*iter, "ssid") == 0)
+				have_ssid = TRUE;
+			iter++;
+		}
+	}
+
+	value = g_hash_table_lookup (props, "MaxScanSSID");
+	if (value && G_VALUE_HOLDS (value, G_TYPE_INT)) {
+		/* We need active scan and SSID probe capabilities to care about MaxScanSSIDs */
+		if (have_active && have_ssid) {
+			/* wpa_supplicant's WPAS_MAX_SCAN_SSIDS value is 16, but for speed
+			 * and to ensure we don't disclose too many SSIDs from the hidden
+			 * list, we'll limit to 5.
+			 */
+			priv->max_scan_ssids = CLAMP (g_value_get_int (value), 0, 5);
+			nm_log_info (LOGD_SUPPLICANT, "(%s) supports %d scan SSIDs",
+			             priv->dev, priv->max_scan_ssids);
+		}
+	}
+}
+
+static void
 wpas_iface_properties_changed (DBusGProxy *proxy,
                                GHashTable *props,
                                gpointer user_data)
 {
 	NMSupplicantInterface *self = NM_SUPPLICANT_INTERFACE (user_data);
+	NMSupplicantInterfacePrivate *priv = NM_SUPPLICANT_INTERFACE_GET_PRIVATE (self);
 	GValue *value;
 
 	value = g_hash_table_lookup (props, "Scanning");
@@ -515,8 +584,16 @@ wpas_iface_properties_changed (DBusGProxy *proxy,
 		set_scanning (self, g_value_get_boolean (value));
 
 	value = g_hash_table_lookup (props, "State");
-	if (value && G_VALUE_HOLDS_STRING (value))
-		set_state_from_string (self, g_value_get_string (value));
+	if (value && G_VALUE_HOLDS_STRING (value)) {
+		if (priv->state >= NM_SUPPLICANT_INTERFACE_STATE_READY) {
+			/* Only transition to actual wpa_supplicant interface states (ie,
+			 * anything > READY) after the NMSupplicantInterface has had a
+			 * chance to initialize, which is signalled by entering the READY
+			 * state.
+			 */
+			set_state_from_string (self, g_value_get_string (value));
+		}
+	}
 
 	value = g_hash_table_lookup (props, "BSSs");
 	if (value && G_VALUE_HOLDS (value, DBUS_TYPE_G_ARRAY_OF_OBJECT_PATH)) {
@@ -526,6 +603,22 @@ wpas_iface_properties_changed (DBusGProxy *proxy,
 		for (i = 0; paths && (i < paths->len); i++)
 			handle_new_bss (self, g_ptr_array_index (paths, i), NULL);
 	}
+
+	value = g_hash_table_lookup (props, "Capabilities");
+	if (value && G_VALUE_HOLDS (value, DBUS_TYPE_G_MAP_OF_VARIANT))
+		parse_capabilities (self, g_value_get_boxed (value));
+}
+
+static void
+iface_check_ready (NMSupplicantInterface *self)
+{
+	NMSupplicantInterfacePrivate *priv = NM_SUPPLICANT_INTERFACE_GET_PRIVATE (self);
+
+	if (priv->ready_count && priv->state < NM_SUPPLICANT_INTERFACE_STATE_READY) {
+		priv->ready_count--;
+		if (priv->ready_count == 0)
+			set_state (self, NM_SUPPLICANT_INTERFACE_STATE_READY);
+	}
 }
 
 static void
@@ -545,6 +638,7 @@ iface_get_props_cb (DBusGProxy *proxy, DBusGProxyCall *call_id, gpointer user_da
 		             error && error->message ? error->message : "(unknown)");
 		g_clear_error (&error);
 	}
+	iface_check_ready (info->interface);
 }
 
 static void
@@ -629,6 +723,8 @@ iface_check_netreply_cb (DBusGProxy *proxy, DBusGProxyCall *call_id, gpointer us
 			        priv->has_credreq ? "supports" : "does not support");
 	}
 	g_clear_error (&error);
+
+	iface_check_ready (info->interface);
 }
 
 static void
@@ -721,13 +817,10 @@ interface_add_done (NMSupplicantInterface *self, char *path)
 	                                               WPAS_DBUS_SERVICE,
 	                                               path,
 	                                               DBUS_INTERFACE_PROPERTIES);
-	/* Get initial properties */
+	/* Get initial properties and check whether NetworkReply is supported */
 	wpas_iface_get_props (self);
-
-	/* Check whether NetworkReply is supported */
 	wpas_iface_check_network_reply (self);
-
-	set_state (self, NM_SUPPLICANT_INTERFACE_STATE_READY);
+	priv->ready_count = 2;
 }
 
 static void
@@ -1159,8 +1252,18 @@ string_to_gvalue (const char *str)
 	return val;
 }
 
+static GValue *
+byte_array_array_to_gvalue (const GPtrArray *array)
+{
+	GValue *val = g_slice_new0 (GValue);
+
+	g_value_init (val, DBUS_TYPE_G_ARRAY_OF_ARRAY_OF_UCHAR);
+	g_value_set_boxed (val, array);
+	return val;
+}
+
 gboolean
-nm_supplicant_interface_request_scan (NMSupplicantInterface * self)
+nm_supplicant_interface_request_scan (NMSupplicantInterface *self, const GPtrArray *ssids)
 {
 	NMSupplicantInterfacePrivate *priv;
 	NMSupplicantInfo *info;
@@ -1174,6 +1277,8 @@ nm_supplicant_interface_request_scan (NMSupplicantInterface * self)
 	/* Scan parameters */
 	hash = g_hash_table_new_full (g_str_hash, g_str_equal, NULL, destroy_gvalue);
 	g_hash_table_insert (hash, "Type", string_to_gvalue ("active"));
+	if (ssids)
+		g_hash_table_insert (hash, "SSIDs", byte_array_array_to_gvalue (ssids));
 
 	info = nm_supplicant_info_new (self, priv->iface_proxy, priv->other_pcalls);
 	call = dbus_g_proxy_begin_call (priv->iface_proxy, "Scan",
@@ -1206,6 +1311,8 @@ nm_supplicant_interface_state_to_string (guint32 state)
 		return "starting";
 	case NM_SUPPLICANT_INTERFACE_STATE_READY:
 		return "ready";
+	case NM_SUPPLICANT_INTERFACE_STATE_DISABLED:
+		return "disabled";
 	case NM_SUPPLICANT_INTERFACE_STATE_DISCONNECTED:
 		return "disconnected";
 	case NM_SUPPLICANT_INTERFACE_STATE_INACTIVE:
@@ -1259,6 +1366,15 @@ nm_supplicant_interface_get_ifname (NMSupplicantInterface *self)
 	return NM_SUPPLICANT_INTERFACE_GET_PRIVATE (self)->dev;
 }
 
+guint
+nm_supplicant_interface_get_max_scan_ssids (NMSupplicantInterface *self)
+{
+	g_return_val_if_fail (self != NULL, 0);
+	g_return_val_if_fail (NM_IS_SUPPLICANT_INTERFACE (self), 0);
+
+	return NM_SUPPLICANT_INTERFACE_GET_PRIVATE (self)->max_scan_ssids;
+}
+
 /*******************************************************************/
 
 NMSupplicantInterface *
diff --git a/src/supplicant-manager/nm-supplicant-interface.h b/src/supplicant-manager/nm-supplicant-interface.h
index 608ee059..b99c0f26 100644
--- a/src/supplicant-manager/nm-supplicant-interface.h
+++ b/src/supplicant-manager/nm-supplicant-interface.h
@@ -34,6 +34,7 @@ enum {
 	NM_SUPPLICANT_INTERFACE_STATE_INIT = 0,
 	NM_SUPPLICANT_INTERFACE_STATE_STARTING,
 	NM_SUPPLICANT_INTERFACE_STATE_READY,
+	NM_SUPPLICANT_INTERFACE_STATE_DISABLED,
 	NM_SUPPLICANT_INTERFACE_STATE_DISCONNECTED,
 	NM_SUPPLICANT_INTERFACE_STATE_INACTIVE,
 	NM_SUPPLICANT_INTERFACE_STATE_SCANNING,
@@ -127,7 +128,7 @@ const char * nm_supplicant_interface_get_device (NMSupplicantInterface * iface);
 
 const char *nm_supplicant_interface_get_object_path (NMSupplicantInterface * iface);
 
-gboolean nm_supplicant_interface_request_scan (NMSupplicantInterface * self);
+gboolean nm_supplicant_interface_request_scan (NMSupplicantInterface * self, const GPtrArray *ssids);
 
 guint32 nm_supplicant_interface_get_state (NMSupplicantInterface * self);
 
@@ -135,8 +136,12 @@ const char *nm_supplicant_interface_state_to_string (guint32 state);
 
 gboolean nm_supplicant_interface_get_scanning (NMSupplicantInterface *self);
 
+time_t nm_supplicant_interface_get_last_scan_time (NMSupplicantInterface *self);
+
 const char *nm_supplicant_interface_get_ifname (NMSupplicantInterface *self);
 
+guint nm_supplicant_interface_get_max_scan_ssids (NMSupplicantInterface *self);
+
 gboolean nm_supplicant_interface_get_has_credentials_request (NMSupplicantInterface *self);
 
 gboolean nm_supplicant_interface_credentials_reply (NMSupplicantInterface *self,
diff --git a/src/supplicant-manager/tests/Makefile.in b/src/supplicant-manager/tests/Makefile.in
index 65be2b39..c649a3ab 100644
--- a/src/supplicant-manager/tests/Makefile.in
+++ b/src/supplicant-manager/tests/Makefile.in
@@ -48,7 +48,7 @@ am__aclocal_m4_deps = $(top_srcdir)/m4/compiler_warnings.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)/configure.ac
+	$(top_srcdir)/m4/vapigen.m4 $(top_srcdir)/configure.ac
 am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \
 	$(ACLOCAL_M4)
 mkinstalldirs = $(install_sh) -d
@@ -170,6 +170,10 @@ INTLTOOL_EXTRACT = @INTLTOOL_EXTRACT@
 INTLTOOL_MERGE = @INTLTOOL_MERGE@
 INTLTOOL_PERL = @INTLTOOL_PERL@
 INTLTOOL_UPDATE = @INTLTOOL_UPDATE@
+INTLTOOL_V_MERGE = @INTLTOOL_V_MERGE@
+INTLTOOL_V_MERGE_OPTIONS = @INTLTOOL_V_MERGE_OPTIONS@
+INTLTOOL__v_MERGE_ = @INTLTOOL__v_MERGE_@
+INTLTOOL__v_MERGE_0 = @INTLTOOL__v_MERGE_0@
 INTL_MACOSX_LIBS = @INTL_MACOSX_LIBS@
 INTROSPECTION_CFLAGS = @INTROSPECTION_CFLAGS@
 INTROSPECTION_COMPILER = @INTROSPECTION_COMPILER@
@@ -265,6 +269,9 @@ UDEV_BASE_DIR = @UDEV_BASE_DIR@
 USE_NLS = @USE_NLS@
 UUID_CFLAGS = @UUID_CFLAGS@
 UUID_LIBS = @UUID_LIBS@
+VAPIGEN = @VAPIGEN@
+VAPIGEN_MAKEFILE = @VAPIGEN_MAKEFILE@
+VAPIGEN_VAPIDIR = @VAPIGEN_VAPIDIR@
 VERSION = @VERSION@
 XGETTEXT = @XGETTEXT@
 XGETTEXT_015 = @XGETTEXT_015@
@@ -303,6 +310,8 @@ htmldir = @htmldir@
 includedir = @includedir@
 infodir = @infodir@
 install_sh = @install_sh@
+intltool__v_merge_options_ = @intltool__v_merge_options_@
+intltool__v_merge_options_0 = @intltool__v_merge_options_0@
 libdir = @libdir@
 libexecdir = @libexecdir@
 localedir = @localedir@
diff --git a/src/tests/Makefile.in b/src/tests/Makefile.in
index 7d367415..3cc387ca 100644
--- a/src/tests/Makefile.in
+++ b/src/tests/Makefile.in
@@ -49,7 +49,7 @@ am__aclocal_m4_deps = $(top_srcdir)/m4/compiler_warnings.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)/configure.ac
+	$(top_srcdir)/m4/vapigen.m4 $(top_srcdir)/configure.ac
 am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \
 	$(ACLOCAL_M4)
 mkinstalldirs = $(install_sh) -d
@@ -187,6 +187,10 @@ INTLTOOL_EXTRACT = @INTLTOOL_EXTRACT@
 INTLTOOL_MERGE = @INTLTOOL_MERGE@
 INTLTOOL_PERL = @INTLTOOL_PERL@
 INTLTOOL_UPDATE = @INTLTOOL_UPDATE@
+INTLTOOL_V_MERGE = @INTLTOOL_V_MERGE@
+INTLTOOL_V_MERGE_OPTIONS = @INTLTOOL_V_MERGE_OPTIONS@
+INTLTOOL__v_MERGE_ = @INTLTOOL__v_MERGE_@
+INTLTOOL__v_MERGE_0 = @INTLTOOL__v_MERGE_0@
 INTL_MACOSX_LIBS = @INTL_MACOSX_LIBS@
 INTROSPECTION_CFLAGS = @INTROSPECTION_CFLAGS@
 INTROSPECTION_COMPILER = @INTROSPECTION_COMPILER@
@@ -282,6 +286,9 @@ UDEV_BASE_DIR = @UDEV_BASE_DIR@
 USE_NLS = @USE_NLS@
 UUID_CFLAGS = @UUID_CFLAGS@
 UUID_LIBS = @UUID_LIBS@
+VAPIGEN = @VAPIGEN@
+VAPIGEN_MAKEFILE = @VAPIGEN_MAKEFILE@
+VAPIGEN_VAPIDIR = @VAPIGEN_VAPIDIR@
 VERSION = @VERSION@
 XGETTEXT = @XGETTEXT@
 XGETTEXT_015 = @XGETTEXT_015@
@@ -320,6 +327,8 @@ htmldir = @htmldir@
 includedir = @includedir@
 infodir = @infodir@
 install_sh = @install_sh@
+intltool__v_merge_options_ = @intltool__v_merge_options_@
+intltool__v_merge_options_0 = @intltool__v_merge_options_0@
 libdir = @libdir@
 libexecdir = @libexecdir@
 localedir = @localedir@
diff --git a/src/vpn-manager/Makefile.am b/src/vpn-manager/Makefile.am
index c3c5b525..12e316d8 100644
--- a/src/vpn-manager/Makefile.am
+++ b/src/vpn-manager/Makefile.am
@@ -7,6 +7,7 @@ INCLUDES = \
 	-I${top_srcdir}/src/generated \
 	-I${top_builddir}/src/generated \
 	-I${top_srcdir}/src/logging \
+	-I${top_srcdir}/src/posix-signals \
 	-I${top_srcdir}/src \
 	-I${top_srcdir}/src/dns-manager \
 	-DVPN_NAME_FILES_DIR=\""$(sysconfdir)/NetworkManager/VPN"\"
@@ -31,6 +32,7 @@ libvpn_manager_la_CPPFLAGS =	\
 libvpn_manager_la_LIBADD = \
 	$(top_builddir)/src/generated/libnm-generated.la \
 	$(top_builddir)/src/logging/libnm-logging.la \
+	$(top_builddir)/src/posix-signals/libnm-posix-signals.la \
 	$(top_builddir)/libnm-util/libnm-util.la \
 	$(LIBNL_LIBS) \
 	$(DBUS_LIBS) \
diff --git a/src/vpn-manager/Makefile.in b/src/vpn-manager/Makefile.in
index 9a7e5e42..64a9c8c3 100644
--- a/src/vpn-manager/Makefile.in
+++ b/src/vpn-manager/Makefile.in
@@ -47,7 +47,7 @@ am__aclocal_m4_deps = $(top_srcdir)/m4/compiler_warnings.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)/configure.ac
+	$(top_srcdir)/m4/vapigen.m4 $(top_srcdir)/configure.ac
 am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \
 	$(ACLOCAL_M4)
 mkinstalldirs = $(install_sh) -d
@@ -59,6 +59,7 @@ am__DEPENDENCIES_1 =
 libvpn_manager_la_DEPENDENCIES =  \
 	$(top_builddir)/src/generated/libnm-generated.la \
 	$(top_builddir)/src/logging/libnm-logging.la \
+	$(top_builddir)/src/posix-signals/libnm-posix-signals.la \
 	$(top_builddir)/libnm-util/libnm-util.la $(am__DEPENDENCIES_1) \
 	$(am__DEPENDENCIES_1) $(am__DEPENDENCIES_1)
 am_libvpn_manager_la_OBJECTS = libvpn_manager_la-nm-vpn-manager.lo \
@@ -171,6 +172,10 @@ INTLTOOL_EXTRACT = @INTLTOOL_EXTRACT@
 INTLTOOL_MERGE = @INTLTOOL_MERGE@
 INTLTOOL_PERL = @INTLTOOL_PERL@
 INTLTOOL_UPDATE = @INTLTOOL_UPDATE@
+INTLTOOL_V_MERGE = @INTLTOOL_V_MERGE@
+INTLTOOL_V_MERGE_OPTIONS = @INTLTOOL_V_MERGE_OPTIONS@
+INTLTOOL__v_MERGE_ = @INTLTOOL__v_MERGE_@
+INTLTOOL__v_MERGE_0 = @INTLTOOL__v_MERGE_0@
 INTL_MACOSX_LIBS = @INTL_MACOSX_LIBS@
 INTROSPECTION_CFLAGS = @INTROSPECTION_CFLAGS@
 INTROSPECTION_COMPILER = @INTROSPECTION_COMPILER@
@@ -266,6 +271,9 @@ UDEV_BASE_DIR = @UDEV_BASE_DIR@
 USE_NLS = @USE_NLS@
 UUID_CFLAGS = @UUID_CFLAGS@
 UUID_LIBS = @UUID_LIBS@
+VAPIGEN = @VAPIGEN@
+VAPIGEN_MAKEFILE = @VAPIGEN_MAKEFILE@
+VAPIGEN_VAPIDIR = @VAPIGEN_VAPIDIR@
 VERSION = @VERSION@
 XGETTEXT = @XGETTEXT@
 XGETTEXT_015 = @XGETTEXT_015@
@@ -304,6 +312,8 @@ htmldir = @htmldir@
 includedir = @includedir@
 infodir = @infodir@
 install_sh = @install_sh@
+intltool__v_merge_options_ = @intltool__v_merge_options_@
+intltool__v_merge_options_0 = @intltool__v_merge_options_0@
 libdir = @libdir@
 libexecdir = @libexecdir@
 localedir = @localedir@
@@ -333,6 +343,7 @@ INCLUDES = \
 	-I${top_srcdir}/src/generated \
 	-I${top_builddir}/src/generated \
 	-I${top_srcdir}/src/logging \
+	-I${top_srcdir}/src/posix-signals \
 	-I${top_srcdir}/src \
 	-I${top_srcdir}/src/dns-manager \
 	-DVPN_NAME_FILES_DIR=\""$(sysconfdir)/NetworkManager/VPN"\"
@@ -355,6 +366,7 @@ libvpn_manager_la_CPPFLAGS = \
 libvpn_manager_la_LIBADD = \
 	$(top_builddir)/src/generated/libnm-generated.la \
 	$(top_builddir)/src/logging/libnm-logging.la \
+	$(top_builddir)/src/posix-signals/libnm-posix-signals.la \
 	$(top_builddir)/libnm-util/libnm-util.la \
 	$(LIBNL_LIBS) \
 	$(DBUS_LIBS) \
diff --git a/src/vpn-manager/nm-vpn-connection.c b/src/vpn-manager/nm-vpn-connection.c
index b391f1ec..5f64153b 100644
--- a/src/vpn-manager/nm-vpn-connection.c
+++ b/src/vpn-manager/nm-vpn-connection.c
@@ -43,7 +43,6 @@
 #include "nm-properties-changed-signal.h"
 #include "nm-dbus-glib-types.h"
 #include "NetworkManagerUtils.h"
-#include "nm-dns-manager.h"
 #include "nm-netlink-monitor.h"
 #include "nm-netlink-utils.h"
 #include "nm-glib-compat.h"
@@ -78,16 +77,24 @@ typedef struct {
 	NMDevice *parent_dev;
 	gulong device_monitor;
 	gulong device_ip4;
+	gulong device_ip6;
 
 	NMVPNConnectionState vpn_state;
 	NMVPNConnectionStateReason failure_reason;
 	DBusGProxy *proxy;
 	guint ipconfig_timeout;
+	gboolean has_ip4;
 	NMIP4Config *ip4_config;
 	guint32 ip4_internal_gw;
+	guint32 ip4_external_gw;
+	gboolean has_ip6;
+	NMIP6Config *ip6_config;
+	struct in6_addr *ip6_internal_gw;
+	struct in6_addr *ip6_external_gw;
 	char *ip_iface;
 	int ip_ifindex;
 	char *banner;
+	guint32 mtu;
 
 	struct rtnl_route *gw_route;
 } NMVPNConnectionPrivate;
@@ -133,13 +140,61 @@ ac_state_from_vpn_state (NMVPNConnectionState vpn_state)
 }
 
 static void
+call_plugin_disconnect (NMVPNConnection *self)
+{
+	NMVPNConnectionPrivate *priv = NM_VPN_CONNECTION_GET_PRIVATE (self);
+	GError *error = NULL;
+
+	if (priv->proxy) {
+		org_freedesktop_NetworkManager_VPN_Plugin_disconnect (priv->proxy, &error);
+		if (error)
+			nm_log_warn (LOGD_VPN, "error disconnecting VPN: %s", error->message);
+		g_clear_error (&error);
+
+		g_object_unref (priv->proxy);
+		priv->proxy = NULL;
+	}
+}
+
+static void
+vpn_cleanup (NMVPNConnection *connection)
+{
+	NMVPNConnectionPrivate *priv = NM_VPN_CONNECTION_GET_PRIVATE (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_addresses (priv->ip_ifindex, AF_UNSPEC);
+	}
+
+	if (priv->gw_route) {
+		nm_netlink_route_delete (priv->gw_route);
+		rtnl_route_put (priv->gw_route);
+		priv->gw_route = NULL;
+	}
+
+	g_free (priv->banner);
+	priv->banner = NULL;
+
+	g_free (priv->ip_iface);
+	priv->ip_iface = NULL;
+	priv->ip_ifindex = 0;
+
+	/* Clear out connection secrets to ensure that the settings service
+	 * gets asked for them next time the connection is activated.
+	 */
+	if (priv->connection)
+		nm_connection_clear_secrets (priv->connection);
+}
+
+static void
 nm_vpn_connection_set_vpn_state (NMVPNConnection *connection,
                                  NMVPNConnectionState vpn_state,
                                  NMVPNConnectionStateReason reason)
 {
 	NMVPNConnectionPrivate *priv;
 	NMVPNConnectionState old_vpn_state;
-	char *ip_iface;
 
 	g_return_if_fail (NM_IS_VPN_CONNECTION (connection));
 
@@ -155,10 +210,12 @@ nm_vpn_connection_set_vpn_state (NMVPNConnection *connection,
 	nm_active_connection_set_state (NM_ACTIVE_CONNECTION (connection),
 	                                ac_state_from_vpn_state (vpn_state));
 
-	/* Save ip_iface since when the VPN goes down it may get freed
-	 * before we're done with it.
-	 */
-	ip_iface = g_strdup (priv->ip_iface);
+	/* Clear any in-progress secrets request */
+	if (priv->secrets_id) {
+		nm_settings_connection_cancel_secrets (NM_SETTINGS_CONNECTION (priv->connection), priv->secrets_id);
+		priv->secrets_id = 0;
+	}
+	priv->secrets_idx = SECRETS_REQ_SYSTEM;
 
 	/* The connection gets destroyed by the VPN manager when it enters the
 	 * disconnected/failed state, but we need to keep it around for a bit
@@ -166,35 +223,50 @@ nm_vpn_connection_set_vpn_state (NMVPNConnection *connection,
 	 */
 	g_object_ref (connection);
 
-	g_signal_emit (connection, signals[VPN_STATE_CHANGED], 0, vpn_state, reason);
+	g_signal_emit (connection, signals[VPN_STATE_CHANGED], 0, vpn_state, old_vpn_state, reason);
 	g_object_notify (G_OBJECT (connection), NM_VPN_CONNECTION_VPN_STATE);
 
-	/* Call dispatcher after the event gets processed internally */
 	switch (vpn_state) {
+	case NM_VPN_CONNECTION_STATE_NEED_AUTH:
+		/* Kick off the secrets requests; first we get existing system secrets
+		 * and ask the plugin if these are sufficient, next we get all existing
+		 * secrets from system and from user agents and ask the plugin again,
+		 * and last we ask the user for new secrets if required.
+		 */
+		get_secrets (connection, SECRETS_REQ_SYSTEM);
+		break;
 	case NM_VPN_CONNECTION_STATE_ACTIVATED:
+		/* Secrets no longer needed now that we're connected */
+		nm_connection_clear_secrets (priv->connection);
+
+		/* Let dispatcher scripts know we're up and running */
 		nm_utils_call_dispatcher ("vpn-up",
 		                          priv->connection,
 		                          priv->parent_dev,
-		                          ip_iface,
+		                          priv->ip_iface,
 		                          priv->ip4_config,
-		                          NULL);
+		                          priv->ip6_config);
 		break;
 	case NM_VPN_CONNECTION_STATE_FAILED:
 	case NM_VPN_CONNECTION_STATE_DISCONNECTED:
 		if (old_vpn_state == NM_VPN_CONNECTION_STATE_ACTIVATED) {
+			/* Let dispatcher scripts know we're about to go down */
 			nm_utils_call_dispatcher ("vpn-down",
 			                          priv->connection,
 			                          priv->parent_dev,
-			                          ip_iface,
+			                          priv->ip_iface,
 			                          NULL,
 			                          NULL);
 		}
+
+		/* Tear down and clean up the connection */
+		call_plugin_disconnect (connection);
+		vpn_cleanup (connection);
 		break;
 	default:
 		break;
 	}
 
-	g_free (ip_iface);
 	g_object_unref (connection);
 }
 
@@ -230,11 +302,34 @@ device_ip4_config_changed (NMDevice *device,
 	    || !nm_device_get_ip4_config (device))
 		return;
 
-	if (priv->gw_route)
-		rtnl_route_put (priv->gw_route);
+	/* Re-add the VPN gateway route */
+	if (priv->ip4_external_gw) {
+		if (priv->gw_route)
+			rtnl_route_put (priv->gw_route);
+		priv->gw_route = nm_system_add_ip4_vpn_gateway_route (priv->parent_dev,
+		                                                      priv->ip4_external_gw);
+	}
+}
+
+static void
+device_ip6_config_changed (NMDevice *device,
+                           GParamSpec *pspec,
+                           gpointer user_data)
+{
+	NMVPNConnection *vpn = NM_VPN_CONNECTION (user_data);
+	NMVPNConnectionPrivate *priv = NM_VPN_CONNECTION_GET_PRIVATE (vpn);
+
+	if (   (priv->vpn_state != NM_VPN_CONNECTION_STATE_ACTIVATED)
+	    || !nm_device_get_ip6_config (device))
+		return;
 
 	/* Re-add the VPN gateway route */
-	priv->gw_route = nm_system_add_ip4_vpn_gateway_route (priv->parent_dev, priv->ip4_config);
+	if (priv->ip6_external_gw) {
+		if (priv->gw_route)
+			rtnl_route_put (priv->gw_route);
+		priv->gw_route = nm_system_add_ip6_vpn_gateway_route (priv->parent_dev,
+		                                                      priv->ip6_external_gw);
+	}
 }
 
 NMVPNConnection *
@@ -271,6 +366,9 @@ nm_vpn_connection_new (NMConnection *connection,
 	priv->device_ip4 = g_signal_connect (parent_device, "notify::" NM_DEVICE_IP4_CONFIG,
 	                                     G_CALLBACK (device_ip4_config_changed),
 	                                     self);
+	priv->device_ip6 = g_signal_connect (parent_device, "notify::" NM_DEVICE_IP6_CONFIG,
+	                                     G_CALLBACK (device_ip6_config_changed),
+	                                     self);
 
 	if (!nm_active_connection_export (NM_ACTIVE_CONNECTION (self),
 	                                  connection,
@@ -372,17 +470,18 @@ plugin_state_changed (DBusGProxy *proxy,
 	}
 }
 
+static char addr_to_string_buf[INET6_ADDRSTRLEN + 1];
+
 static const char *
 ip_address_to_string (guint32 numeric)
 {
 	struct in_addr temp_addr;
-	static char buf[INET_ADDRSTRLEN + 1];
 
-	memset (&buf, '\0', sizeof (buf));
+	memset (&addr_to_string_buf, '\0', sizeof (addr_to_string_buf));
 	temp_addr.s_addr = numeric;
 
-	if (inet_ntop (AF_INET, &temp_addr, buf, INET_ADDRSTRLEN)) {
-		return buf;
+	if (inet_ntop (AF_INET, &temp_addr, addr_to_string_buf, INET_ADDRSTRLEN)) {
+		return addr_to_string_buf;
 	} else {
 		nm_log_warn (LOGD_VPN, "error converting IP4 address 0x%X",
 		             ntohl (temp_addr.s_addr));
@@ -390,115 +489,340 @@ ip_address_to_string (guint32 numeric)
 	}
 }
 
+static const char *
+ip6_address_to_string (const struct in6_addr *addr)
+{
+	memset (addr_to_string_buf, '\0', sizeof (addr_to_string_buf));
+	if (inet_ntop (AF_INET6, addr, addr_to_string_buf, INET6_ADDRSTRLEN)) {
+		return addr_to_string_buf;
+	} else {
+		nm_log_warn (LOGD_VPN, "error converting IP6 address");
+		return NULL;
+	}
+}
+
 static void
-print_vpn_config (NMIP4Config *config,
-                  guint32 internal_gw,
-                  const char *ip_iface,
-                  const char *banner)
+print_vpn_config (NMVPNConnection *connection)
 {
+	NMVPNConnectionPrivate *priv = NM_VPN_CONNECTION_GET_PRIVATE (connection);
 	NMIP4Address *addr;
+	NMIP6Address *addr6;
 	char *dns_domain = NULL;
 	guint32 num, i;
 
-	g_return_if_fail (config != NULL);
-
-	addr = nm_ip4_config_get_address (config, 0);
-
-	nm_log_info (LOGD_VPN, "VPN Gateway: %s", ip_address_to_string (nm_ip4_address_get_gateway (addr)));
-	if (internal_gw)
-		nm_log_info (LOGD_VPN, "Internal Gateway: %s", ip_address_to_string (internal_gw));
-	nm_log_info (LOGD_VPN, "Tunnel Device: %s", ip_iface);
-	nm_log_info (LOGD_VPN, "Internal IP4 Address: %s", ip_address_to_string (nm_ip4_address_get_address (addr)));
-	nm_log_info (LOGD_VPN, "Internal IP4 Prefix: %d", nm_ip4_address_get_prefix (addr));
-	nm_log_info (LOGD_VPN, "Internal IP4 Point-to-Point Address: %s",
-	             ip_address_to_string (nm_ip4_config_get_ptp_address (config)));
-	nm_log_info (LOGD_VPN, "Maximum Segment Size (MSS): %d", nm_ip4_config_get_mss (config));
-
-	num = nm_ip4_config_get_num_routes (config);
-	for (i = 0; i < num; i++) {
-		NMIP4Route *route;
-
-		route = nm_ip4_config_get_route (config, i);
-		nm_log_info (LOGD_VPN, "Static Route: %s/%d   Next Hop: %s",
-		             ip_address_to_string (nm_ip4_route_get_dest (route)),
-		             nm_ip4_route_get_prefix (route),
-		             ip_address_to_string (nm_ip4_route_get_next_hop (route)));
-	}
+	if (priv->ip4_external_gw) {
+		nm_log_info (LOGD_VPN, "VPN Gateway: %s",
+		             ip_address_to_string (priv->ip4_external_gw));
+	} else if (priv->ip6_external_gw) {
+		nm_log_info (LOGD_VPN, "VPN Gateway: %s",
+		             ip6_address_to_string (priv->ip6_external_gw));
+	} 
 
-	nm_log_info (LOGD_VPN, "Forbid Default Route: %s",
-	             nm_ip4_config_get_never_default (config) ? "yes" : "no");
+	nm_log_info (LOGD_VPN, "Tunnel Device: %s", priv->ip_iface);
 
-	num = nm_ip4_config_get_num_nameservers (config);
-	for (i = 0; i < num; i++) {
-		nm_log_info (LOGD_VPN, "Internal IP4 DNS: %s",
-		             ip_address_to_string (nm_ip4_config_get_nameserver (config, i)));
-	}
+	if (priv->ip4_config) {
+		nm_log_info (LOGD_VPN, "IPv4 configuration:");
+
+		addr = nm_ip4_config_get_address (priv->ip4_config, 0);
+
+		if (priv->ip4_internal_gw)
+			nm_log_info (LOGD_VPN, "  Internal Gateway: %s", ip_address_to_string (priv->ip4_internal_gw));
+		nm_log_info (LOGD_VPN, "  Internal Address: %s", ip_address_to_string (nm_ip4_address_get_address (addr)));
+		nm_log_info (LOGD_VPN, "  Internal Prefix: %d", nm_ip4_address_get_prefix (addr));
+		nm_log_info (LOGD_VPN, "  Internal Point-to-Point Address: %s",
+					 ip_address_to_string (nm_ip4_config_get_ptp_address (priv->ip4_config)));
+		nm_log_info (LOGD_VPN, "  Maximum Segment Size (MSS): %d", nm_ip4_config_get_mss (priv->ip4_config));
+
+		num = nm_ip4_config_get_num_routes (priv->ip4_config);
+		for (i = 0; i < num; i++) {
+			NMIP4Route *route;
+
+			route = nm_ip4_config_get_route (priv->ip4_config, i);
+			nm_log_info (LOGD_VPN, "  Static Route: %s/%d   Next Hop: %s",
+						 ip_address_to_string (nm_ip4_route_get_dest (route)),
+						 nm_ip4_route_get_prefix (route),
+						 ip_address_to_string (nm_ip4_route_get_next_hop (route)));
+		}
+
+		nm_log_info (LOGD_VPN, "  Forbid Default Route: %s",
+					 nm_ip4_config_get_never_default (priv->ip4_config) ? "yes" : "no");
+
+		num = nm_ip4_config_get_num_nameservers (priv->ip4_config);
+		for (i = 0; i < num; i++) {
+			nm_log_info (LOGD_VPN, "  Internal DNS: %s",
+						 ip_address_to_string (nm_ip4_config_get_nameserver (priv->ip4_config, i)));
+		}
+
+		if (nm_ip4_config_get_num_domains (priv->ip4_config) > 0)
+			dns_domain = (char *) nm_ip4_config_get_domain (priv->ip4_config, 0);
+
+		nm_log_info (LOGD_VPN, "  DNS Domain: '%s'", dns_domain ? dns_domain : "(none)");
+	} else
+		nm_log_info (LOGD_VPN, "No IPv4 configuration");
+
+	if (priv->ip6_config) {
+		nm_log_info (LOGD_VPN, "IPv6 configuration:");
+
+		addr6 = nm_ip6_config_get_address (priv->ip6_config, 0);
+
+		if (priv->ip6_internal_gw)
+			nm_log_info (LOGD_VPN, "  Internal Gateway: %s", ip6_address_to_string (priv->ip6_internal_gw));
+		nm_log_info (LOGD_VPN, "  Internal Address: %s", ip6_address_to_string (nm_ip6_address_get_address (addr6)));
+		nm_log_info (LOGD_VPN, "  Internal Prefix: %d", nm_ip6_address_get_prefix (addr6));
+		nm_log_info (LOGD_VPN, "  Internal Point-to-Point Address: %s",
+					 ip6_address_to_string (nm_ip6_config_get_ptp_address (priv->ip6_config)));
+		nm_log_info (LOGD_VPN, "  Maximum Segment Size (MSS): %d", nm_ip6_config_get_mss (priv->ip6_config));
 
-	if (nm_ip4_config_get_num_domains (config) > 0)
-		dns_domain = (char *) nm_ip4_config_get_domain (config, 0);
+		num = nm_ip6_config_get_num_routes (priv->ip6_config);
+		for (i = 0; i < num; i++) {
+			NMIP6Route *route;
 
-	nm_log_info (LOGD_VPN, "DNS Domain: '%s'", dns_domain ? dns_domain : "(none)");
+			route = nm_ip6_config_get_route (priv->ip6_config, i);
+			nm_log_info (LOGD_VPN, "  Static Route: %s/%d   Next Hop: %s",
+						 ip6_address_to_string (nm_ip6_route_get_dest (route)),
+						 nm_ip6_route_get_prefix (route),
+						 ip6_address_to_string (nm_ip6_route_get_next_hop (route)));
+		}
+
+		nm_log_info (LOGD_VPN, "  Forbid Default Route: %s",
+					 nm_ip6_config_get_never_default (priv->ip6_config) ? "yes" : "no");
+
+		num = nm_ip6_config_get_num_nameservers (priv->ip6_config);
+		for (i = 0; i < num; i++) {
+			nm_log_info (LOGD_VPN, "  Internal DNS: %s",
+						 ip6_address_to_string (nm_ip6_config_get_nameserver (priv->ip6_config, i)));
+		}
 
-	if (banner && strlen (banner)) {
+		if (nm_ip6_config_get_num_domains (priv->ip6_config) > 0)
+			dns_domain = (char *) nm_ip6_config_get_domain (priv->ip6_config, 0);
+
+		nm_log_info (LOGD_VPN, "  DNS Domain: '%s'", dns_domain ? dns_domain : "(none)");
+	} else
+		nm_log_info (LOGD_VPN, "No IPv6 configuration");
+
+	if (priv->banner && strlen (priv->banner)) {
 		nm_log_info (LOGD_VPN, "Login Banner:");
 		nm_log_info (LOGD_VPN, "-----------------------------------------");
-		nm_log_info (LOGD_VPN, "%s", banner);
+		nm_log_info (LOGD_VPN, "%s", priv->banner);
 		nm_log_info (LOGD_VPN, "-----------------------------------------");
 	}
 }
 
-static void
-nm_vpn_connection_ip4_config_get (DBusGProxy *proxy,
-                                  GHashTable *config_hash,
-                                  gpointer user_data)
+static gboolean
+nm_vpn_connection_apply_config (NMVPNConnection *connection)
 {
-	NMVPNConnection *connection = NM_VPN_CONNECTION (user_data);
 	NMVPNConnectionPrivate *priv = NM_VPN_CONNECTION_GET_PRIVATE (connection);
-	NMSettingIP4Config *s_ip4;
-	NMIP4Address *addr;
-	NMIP4Config *config;
-	GValue *val;
-	int i;
-	guint32 vpn_ext_gw = 0;
 
-	nm_log_info (LOGD_VPN, "VPN connection '%s' (IP Config Get) reply received.",
+	nm_system_iface_set_up (priv->ip_ifindex, TRUE, NULL);
+
+	if (priv->ip4_config) {
+		if (!nm_system_apply_ip4_config (priv->ip_ifindex, priv->ip4_config,
+		                                 0, NM_IP4_COMPARE_FLAG_ALL))
+			return FALSE;
+	}
+
+	if (priv->ip6_config) {
+		if (!nm_system_apply_ip6_config (priv->ip_ifindex, priv->ip6_config,
+		                                 0, NM_IP6_COMPARE_FLAG_ALL))
+			/* FIXME: remove ip4 config */
+			return FALSE;
+	}
+
+	/* Add any explicit route to the VPN gateway through the parent device */
+	if (priv->ip4_external_gw) {
+		priv->gw_route = nm_system_add_ip4_vpn_gateway_route (priv->parent_dev,
+		                                                      priv->ip4_external_gw);
+	} else if (priv->ip6_external_gw) {
+		priv->gw_route = nm_system_add_ip6_vpn_gateway_route (priv->parent_dev,
+		                                                      priv->ip6_external_gw);
+	} else {
+		priv->gw_route = NULL;
+	}
+
+	nm_log_info (LOGD_VPN, "VPN connection '%s' (IP Config Get) complete.",
 	             nm_vpn_connection_get_name (connection));
+	nm_vpn_connection_set_vpn_state (connection,
+	                                 NM_VPN_CONNECTION_STATE_ACTIVATED,
+	                                 NM_VPN_CONNECTION_STATE_REASON_NONE);
+	return TRUE;
+}
+
+static void
+nm_vpn_connection_config_maybe_complete (NMVPNConnection *connection,
+                                         gboolean         success)
+{
+	NMVPNConnectionPrivate *priv = NM_VPN_CONNECTION_GET_PRIVATE (connection);
+
+	if (priv->ipconfig_timeout == 0) {
+		/* config_complete() was already called with an error;
+		 * ignore further calls.
+		 */
+		return;
+	}
+
+	if (success) {
+		if (   (priv->has_ip4 && !priv->ip4_config)
+		    || (priv->has_ip6 && !priv->ip6_config)) {
+			/* Need to wait for other config */
+			return;
+		}
+	}
 
 	g_source_remove (priv->ipconfig_timeout);
 	priv->ipconfig_timeout = 0;
 
-	config = nm_ip4_config_new ();
+	if (success) {
+		print_vpn_config (connection);
+
+		if (nm_vpn_connection_apply_config (connection))
+			return;
+	}
+
+	g_clear_object (&priv->ip4_config);
+	g_clear_object (&priv->ip6_config);
 
-	val = (GValue *) g_hash_table_lookup (config_hash, NM_VPN_PLUGIN_IP4_CONFIG_TUNDEV);
+	nm_log_warn (LOGD_VPN, "VPN connection '%s' did not receive valid IP config information.",
+	             nm_vpn_connection_get_name (connection));
+	nm_vpn_connection_set_vpn_state (connection,
+	                                 NM_VPN_CONNECTION_STATE_FAILED,
+	                                 NM_VPN_CONNECTION_STATE_REASON_IP_CONFIG_INVALID);
+}
+
+static gboolean
+process_generic_config (NMVPNConnection *connection,
+                        GHashTable *config_hash)
+{
+	NMVPNConnectionPrivate *priv = NM_VPN_CONNECTION_GET_PRIVATE (connection);
+	GValue *val;
+
+	val = (GValue *) g_hash_table_lookup (config_hash, NM_VPN_PLUGIN_CONFIG_TUNDEV);
 	if (val)
 		priv->ip_iface = g_strdup (g_value_get_string (val));
 	else {
 		nm_log_err (LOGD_VPN, "invalid or missing tunnel device received!");
-		goto error;
+		nm_vpn_connection_config_maybe_complete (connection, FALSE);
+		return FALSE;
 	}
 
 	/* Grab the interface index for address/routing operations */
 	priv->ip_ifindex = nm_netlink_iface_to_index (priv->ip_iface);
 	if (priv->ip_ifindex < 0) {
 		nm_log_err (LOGD_VPN, "(%s): failed to look up VPN interface index", priv->ip_iface);
-		goto error;
+		nm_vpn_connection_config_maybe_complete (connection, FALSE);
+		return FALSE;
+	}
+
+	val = (GValue *) g_hash_table_lookup (config_hash, NM_VPN_PLUGIN_CONFIG_BANNER);
+	if (val) {
+		g_free (priv->banner);
+		priv->banner = g_strdup (g_value_get_string (val));
+	}
+
+	/* External world-visible address of the VPN server */
+	priv->ip4_external_gw = 0;
+	priv->ip6_external_gw = NULL;
+	val = (GValue *) g_hash_table_lookup (config_hash, NM_VPN_PLUGIN_CONFIG_EXT_GATEWAY);
+	if (val) {
+		if (G_VALUE_HOLDS (val, G_TYPE_UINT)) {
+			priv->ip4_external_gw = g_value_get_uint (val);
+		} else if (G_VALUE_HOLDS (val, DBUS_TYPE_G_UCHAR_ARRAY)) {
+			GByteArray *ba = g_value_get_boxed (val);
+
+			if (ba->len == sizeof (struct in6_addr))
+				priv->ip6_external_gw = g_memdup (ba->data, ba->len);
+		} else {
+			nm_log_err (LOGD_VPN, "(%s): VPN gateway is neither IPv4 nor IPv6", priv->ip_iface);
+			nm_vpn_connection_config_maybe_complete (connection, FALSE);
+			return FALSE;
+		}
+	}
+
+	/* MTU; this is a per-connection value, though NM's API treats it
+	 * like it's IP4-specific. So we store it for now and retrieve it
+	 * later in ip4_config_get.
+	 */
+	val = (GValue *) g_hash_table_lookup (config_hash, NM_VPN_PLUGIN_CONFIG_MTU);
+	if (val)
+		priv->mtu = g_value_get_uint (val);
+	else
+		priv->mtu = 0;
+
+	return TRUE;
+}
+
+static void
+nm_vpn_connection_config_get (DBusGProxy *proxy,
+                              GHashTable *config_hash,
+                              gpointer user_data)
+{
+	NMVPNConnection *connection = NM_VPN_CONNECTION (user_data);
+	NMVPNConnectionPrivate *priv = NM_VPN_CONNECTION_GET_PRIVATE (connection);
+	GValue *val;
+
+	nm_log_info (LOGD_VPN, "VPN connection '%s' (IP Config Get) reply received.",
+	             nm_vpn_connection_get_name (connection));
+
+	if (!process_generic_config (connection, config_hash))
+		return;
+
+	/* Note whether to expect IPv4 and IPv6 configs */
+	val = g_hash_table_lookup (config_hash, NM_VPN_PLUGIN_CONFIG_HAS_IP4);
+	priv->has_ip4 = val ? g_value_get_boolean (val) : FALSE;
+	g_clear_object (&priv->ip4_config);
+
+	val = g_hash_table_lookup (config_hash, NM_VPN_PLUGIN_CONFIG_HAS_IP6);
+	priv->has_ip6 = val ? g_value_get_boolean (val) : FALSE;
+	g_clear_object (&priv->ip6_config);
+}
+
+static void
+nm_vpn_connection_ip4_config_get (DBusGProxy *proxy,
+                                  GHashTable *config_hash,
+                                  gpointer user_data)
+{
+	NMVPNConnection *connection = NM_VPN_CONNECTION (user_data);
+	NMVPNConnectionPrivate *priv = NM_VPN_CONNECTION_GET_PRIVATE (connection);
+	NMSettingIP4Config *s_ip4;
+	NMIP4Address *addr;
+	NMIP4Config *config;
+	GValue *val;
+	int i;
+
+	if (priv->has_ip4) {
+		nm_log_info (LOGD_VPN, "VPN connection '%s' (IP4 Config Get) reply received.",
+		             nm_vpn_connection_get_name (connection));
+
+		if (g_hash_table_size (config_hash) == 0) {
+			priv->has_ip4 = FALSE;
+			nm_vpn_connection_config_maybe_complete (connection, TRUE);
+			return;
+		}
+	} else {
+		nm_log_info (LOGD_VPN, "VPN connection '%s' (IP4 Config Get) reply received from old-style plugin.",
+		             nm_vpn_connection_get_name (connection));
+
+		/* In the old API, the generic and IPv4 configuration items
+		 * were mixed together.
+		 */
+		if (!process_generic_config (connection, config_hash))
+			return;
+
+		priv->has_ip4 = TRUE;
+		priv->has_ip6 = FALSE;
 	}
 
+	config = nm_ip4_config_new ();
+
 	addr = nm_ip4_address_new ();
 	nm_ip4_address_set_prefix (addr, 24); /* default to class C */
+	if (priv->ip4_external_gw)
+		nm_ip4_address_set_gateway (addr, priv->ip4_external_gw);
 
 	/* Internal address of the VPN subnet's gateway */
 	val = (GValue *) g_hash_table_lookup (config_hash, NM_VPN_PLUGIN_IP4_CONFIG_INT_GATEWAY);
 	if (val)
 		priv->ip4_internal_gw = g_value_get_uint (val);
 
-	/* External world-visible address of the VPN server */
-	val = (GValue *) g_hash_table_lookup (config_hash, NM_VPN_PLUGIN_IP4_CONFIG_EXT_GATEWAY);
-	if (val) {
-		nm_ip4_address_set_gateway (addr, g_value_get_uint (val));
-		vpn_ext_gw = g_value_get_uint (val);
-	}
-
 	val = (GValue *) g_hash_table_lookup (config_hash, NM_VPN_PLUGIN_IP4_CONFIG_ADDRESS);
 	if (val)
 		nm_ip4_address_set_address (addr, g_value_get_uint (val));
@@ -516,7 +840,9 @@ nm_vpn_connection_ip4_config_get (DBusGProxy *proxy,
 	} else {
 		nm_log_err (LOGD_VPN, "invalid IP4 config received!");
 		nm_ip4_address_unref (addr);
-		goto error;
+		g_object_unref (config);
+		nm_vpn_connection_config_maybe_complete (connection, FALSE);
+		return;
 	}
 
 	val = (GValue *) g_hash_table_lookup (config_hash, NM_VPN_PLUGIN_IP4_CONFIG_DNS);
@@ -539,9 +865,8 @@ nm_vpn_connection_ip4_config_get (DBusGProxy *proxy,
 	if (val)
 		nm_ip4_config_set_mss (config, g_value_get_uint (val));
 
-	val = (GValue *) g_hash_table_lookup (config_hash, NM_VPN_PLUGIN_IP4_CONFIG_MTU);
-	if (val)
-		nm_ip4_config_set_mtu (config, g_value_get_uint (val));
+	if (priv->mtu)
+		nm_ip4_config_set_mtu (config, priv->mtu);
 
 	val = (GValue *) g_hash_table_lookup (config_hash, NM_VPN_PLUGIN_IP4_CONFIG_DOMAIN);
 	if (val)
@@ -556,12 +881,6 @@ nm_vpn_connection_ip4_config_get (DBusGProxy *proxy,
 			nm_ip4_config_add_domain (config, *domain);
 	}
 
-	val = (GValue *) g_hash_table_lookup (config_hash, NM_VPN_PLUGIN_IP4_CONFIG_BANNER);
-	if (val) {
-		g_free (priv->banner);
-		priv->banner = g_strdup (g_value_get_string (val));
-	}
-
 	val = (GValue *) g_hash_table_lookup (config_hash, NM_VPN_PLUGIN_IP4_CONFIG_ROUTES);
 	if (val) {
 		GSList *routes;
@@ -576,10 +895,12 @@ nm_vpn_connection_ip4_config_get (DBusGProxy *proxy,
 			 * the VPN server, we want to use the NM created route instead of
 			 * whatever the server provides.
 			 */
-			if (   vpn_ext_gw
-			    && nm_ip4_route_get_dest (route) == vpn_ext_gw
-			    && nm_ip4_route_get_prefix (route) == 32)
+			if (   priv->ip4_external_gw
+			    && nm_ip4_route_get_dest (route) == priv->ip4_external_gw
+			    && nm_ip4_route_get_prefix (route) == 32) {
+				nm_ip4_route_unref (route);
 				continue;
+			}
 
 			/* Otherwise accept the VPN-provided route */
 			nm_ip4_config_take_route (config, route);
@@ -592,42 +913,149 @@ nm_vpn_connection_ip4_config_get (DBusGProxy *proxy,
 	if (val && G_VALUE_HOLDS_BOOLEAN (val))
 		nm_ip4_config_set_never_default (config, g_value_get_boolean (val));
 
-	print_vpn_config (config, priv->ip4_internal_gw, priv->ip_iface, priv->banner);
-
 	/* Merge in user overrides from the NMConnection's IPv4 setting */
 	s_ip4 = nm_connection_get_setting_ip4_config (priv->connection);
 	nm_utils_merge_ip4_config (config, s_ip4);
 
-	nm_system_iface_set_up (priv->ip_ifindex, TRUE, NULL);
+	priv->ip4_config = config;
+	nm_vpn_connection_config_maybe_complete (connection, TRUE);
+}
 
-	if (nm_system_apply_ip4_config (priv->ip_ifindex, config, 0, NM_IP4_COMPARE_FLAG_ALL)) {
-		NMDnsManager *dns_mgr;
+static void
+nm_vpn_connection_ip6_config_get (DBusGProxy *proxy,
+                                  GHashTable *config_hash,
+                                  gpointer user_data)
+{
+	NMVPNConnection *connection = NM_VPN_CONNECTION (user_data);
+	NMVPNConnectionPrivate *priv = NM_VPN_CONNECTION_GET_PRIVATE (connection);
+	NMSettingIP6Config *s_ip6;
+	NMIP6Address *addr;
+	NMIP6Config *config;
+	GValue *val;
+	int i;
 
-		/* Add any explicit route to the VPN gateway through the parent device */
-		priv->gw_route = nm_system_add_ip4_vpn_gateway_route (priv->parent_dev, config);
+	nm_log_info (LOGD_VPN, "VPN connection '%s' (IP6 Config Get) reply received.",
+	             nm_vpn_connection_get_name (connection));
 
-		/* Add the VPN to DNS */
-		dns_mgr = nm_dns_manager_get (NULL);
-		nm_dns_manager_add_ip4_config (dns_mgr, priv->ip_iface, config, NM_DNS_IP_CONFIG_TYPE_VPN);
-		g_object_unref (dns_mgr);
+	if (g_hash_table_size (config_hash) == 0) {
+		priv->has_ip6 = FALSE;
+		nm_vpn_connection_config_maybe_complete (connection, TRUE);
+		return;
+	}
 
-		priv->ip4_config = config;
+	config = nm_ip6_config_new ();
 
-		nm_log_info (LOGD_VPN, "VPN connection '%s' (IP Config Get) complete.",
-		             nm_vpn_connection_get_name (connection));
-		nm_vpn_connection_set_vpn_state (connection,
-		                                 NM_VPN_CONNECTION_STATE_ACTIVATED,
-		                                 NM_VPN_CONNECTION_STATE_REASON_NONE);
-		return;
+	addr = nm_ip6_address_new ();
+	nm_ip6_address_set_prefix (addr, 128); /* default to class C */
+	if (priv->ip6_external_gw)
+		nm_ip6_address_set_gateway (addr, priv->ip6_external_gw);
+
+	/* Internal address of the VPN subnet's gateway */
+	val = (GValue *) g_hash_table_lookup (config_hash, NM_VPN_PLUGIN_IP6_CONFIG_INT_GATEWAY);
+	if (val) {
+		GByteArray *ba = g_value_get_boxed (val);
+
+		if (ba->len == sizeof (struct in6_addr))
+			priv->ip6_internal_gw = g_memdup (ba->data, ba->len);
 	}
 
-error:
-	nm_log_warn (LOGD_VPN, "VPN connection '%s' did not receive valid IP config information.",
-	             nm_vpn_connection_get_name (connection));
-	nm_vpn_connection_set_vpn_state (connection,
-	                                 NM_VPN_CONNECTION_STATE_FAILED,
-	                                 NM_VPN_CONNECTION_STATE_REASON_IP_CONFIG_INVALID);
-	g_object_unref (config);
+	val = (GValue *) g_hash_table_lookup (config_hash, NM_VPN_PLUGIN_IP6_CONFIG_ADDRESS);
+	if (val) {
+		GByteArray *ba = g_value_get_boxed (val);
+
+		if (ba->len == sizeof (struct in6_addr))
+			nm_ip6_address_set_address (addr, (struct in6_addr *)ba->data);
+	}
+
+	val = (GValue *) g_hash_table_lookup (config_hash, NM_VPN_PLUGIN_IP6_CONFIG_PTP);
+	if (val) {
+		GByteArray *ba = g_value_get_boxed (val);
+
+		if (ba->len == sizeof (struct in6_addr))
+			nm_ip6_config_set_ptp_address (config, (struct in6_addr *)ba->data);
+	}
+
+	val = (GValue *) g_hash_table_lookup (config_hash, NM_VPN_PLUGIN_IP6_CONFIG_PREFIX);
+	if (val)
+		nm_ip6_address_set_prefix (addr, g_value_get_uint (val));
+
+	if (nm_ip6_address_get_address (addr) && nm_ip6_address_get_prefix (addr)) {
+		nm_ip6_config_take_address (config, addr);
+	} else {
+		nm_log_err (LOGD_VPN, "invalid IP6 config received!");
+		nm_ip6_address_unref (addr);
+		g_object_unref (config);
+		nm_vpn_connection_config_maybe_complete (connection, FALSE);
+	}
+
+	val = (GValue *) g_hash_table_lookup (config_hash, NM_VPN_PLUGIN_IP6_CONFIG_DNS);
+	if (val) {
+		GPtrArray *dns = (GPtrArray *) g_value_get_boxed (val);
+		GByteArray *ba;
+
+		for (i = 0; i < dns->len; i++) {
+			ba = dns->pdata[i];
+			if (ba->len == sizeof (struct in6_addr))
+				nm_ip6_config_add_nameserver (config, (struct in6_addr *)ba->data);
+		}
+	}
+
+	val = (GValue *) g_hash_table_lookup (config_hash, NM_VPN_PLUGIN_IP6_CONFIG_MSS);
+	if (val)
+		nm_ip6_config_set_mss (config, g_value_get_uint (val));
+
+	val = (GValue *) g_hash_table_lookup (config_hash, NM_VPN_PLUGIN_IP6_CONFIG_DOMAIN);
+	if (val)
+		nm_ip6_config_add_domain (config, g_value_get_string (val));
+
+	val = (GValue *) g_hash_table_lookup (config_hash, NM_VPN_PLUGIN_IP6_CONFIG_DOMAINS);
+	if (val) {
+		const char **domains = g_value_get_boxed (val);
+		const char **domain;
+
+		for (domain = domains; domain && *domain; domain++)
+			nm_ip6_config_add_domain (config, *domain);
+	}
+
+	val = (GValue *) g_hash_table_lookup (config_hash, NM_VPN_PLUGIN_IP6_CONFIG_ROUTES);
+	if (val) {
+		GSList *routes;
+		GSList *iter;
+
+		routes = nm_utils_ip6_routes_from_gvalue (val);
+		for (iter = routes; iter; iter = iter->next) {
+			NMIP6Route *route = iter->data;
+
+			/* Ignore host routes to the VPN gateway since NM adds one itself
+			 * below.  Since NM knows more about the routing situation than
+			 * the VPN server, we want to use the NM created route instead of
+			 * whatever the server provides.
+			 */
+			if (   priv->ip6_external_gw
+			    && nm_ip6_route_get_prefix (route) == 128
+				&& memcmp (nm_ip6_route_get_dest (route), priv->ip6_external_gw,
+				           sizeof (struct in6_addr)) == 0) {
+				nm_ip6_route_unref (route);
+				continue;
+			}
+
+			/* Otherwise accept the VPN-provided route */
+			nm_ip6_config_take_route (config, route);
+		}
+
+		g_slist_free (routes);
+	}
+
+	val = (GValue *) g_hash_table_lookup (config_hash, NM_VPN_PLUGIN_IP6_CONFIG_NEVER_DEFAULT);
+	if (val && G_VALUE_HOLDS_BOOLEAN (val))
+		nm_ip6_config_set_never_default (config, g_value_get_boolean (val));
+
+	/* Merge in user overrides from the NMConnection's IPv6 setting */
+	s_ip6 = nm_connection_get_setting_ip6_config (priv->connection);
+	nm_utils_merge_ip6_config (config, s_ip6);
+
+	priv->ip6_config = config;
+	nm_vpn_connection_config_maybe_complete (connection, TRUE);
 }
 
 static gboolean
@@ -716,9 +1144,18 @@ really_activate (NMVPNConnection *connection, const char *username)
 
 	priv = NM_VPN_CONNECTION_GET_PRIVATE (connection);
 
-	/* Ip4Config signal */
 	dbus_g_object_register_marshaller (g_cclosure_marshal_VOID__BOXED,
 								G_TYPE_NONE, G_TYPE_VALUE, G_TYPE_INVALID);
+
+	/* Config signal */
+	dbus_g_proxy_add_signal (priv->proxy, "Config",
+						DBUS_TYPE_G_MAP_OF_VARIANT,
+						G_TYPE_INVALID);
+	dbus_g_proxy_connect_signal (priv->proxy, "Config",
+						    G_CALLBACK (nm_vpn_connection_config_get),
+						    connection, NULL);
+
+	/* Ip4Config signal */
 	dbus_g_proxy_add_signal (priv->proxy, "Ip4Config",
 						DBUS_TYPE_G_MAP_OF_VARIANT,
 						G_TYPE_INVALID);
@@ -726,6 +1163,14 @@ really_activate (NMVPNConnection *connection, const char *username)
 						    G_CALLBACK (nm_vpn_connection_ip4_config_get),
 						    connection, NULL);
 
+	/* Ip6Config signal */
+	dbus_g_proxy_add_signal (priv->proxy, "Ip6Config",
+						DBUS_TYPE_G_MAP_OF_VARIANT,
+						G_TYPE_INVALID);
+	dbus_g_proxy_connect_signal (priv->proxy, "Ip6Config",
+						    G_CALLBACK (nm_vpn_connection_ip6_config_get),
+						    connection, NULL);
+
 	hash = _hash_with_username (priv->connection, username);
 	org_freedesktop_NetworkManager_VPN_Plugin_connect_async (priv->proxy,
 	                                                         hash,
@@ -818,6 +1263,14 @@ nm_vpn_connection_get_ip4_config (NMVPNConnection *connection)
 	return NM_VPN_CONNECTION_GET_PRIVATE (connection)->ip4_config;
 }
 
+NMIP6Config *
+nm_vpn_connection_get_ip6_config (NMVPNConnection *connection)
+{
+	g_return_val_if_fail (NM_IS_VPN_CONNECTION (connection), NULL);
+
+	return NM_VPN_CONNECTION_GET_PRIVATE (connection)->ip6_config;
+}
+
 const char *
 nm_vpn_connection_get_ip_iface (NMVPNConnection *connection)
 {
@@ -850,6 +1303,14 @@ nm_vpn_connection_get_ip4_internal_gateway (NMVPNConnection *connection)
 	return NM_VPN_CONNECTION_GET_PRIVATE (connection)->ip4_internal_gw;
 }
 
+struct in6_addr *
+nm_vpn_connection_get_ip6_internal_gateway (NMVPNConnection *connection)
+{
+	g_return_val_if_fail (NM_IS_VPN_CONNECTION (connection), 0);
+
+	return NM_VPN_CONNECTION_GET_PRIVATE (connection)->ip6_internal_gw;
+}
+
 void
 nm_vpn_connection_fail (NMVPNConnection *connection,
                         NMVPNConnectionStateReason reason)
@@ -896,11 +1357,19 @@ plugin_need_secrets_cb  (DBusGProxy *proxy,
 
 	if (setting_name && strlen (setting_name)) {
 		/* More secrets required */
-		nm_log_dbg (LOGD_VPN, "(%s/%s) service indicated additional secrets required",
-		            nm_connection_get_uuid (priv->connection),
-		            nm_connection_get_id (priv->connection));
 
-		get_secrets (self, priv->secrets_idx + 1);
+		if (priv->secrets_idx == SECRETS_REQ_NEW) {
+			nm_log_err (LOGD_VPN, "(%s/%s) final secrets request failed to provide sufficient secrets",
+			            nm_connection_get_uuid (priv->connection),
+			            nm_connection_get_id (priv->connection));
+			nm_vpn_connection_fail (self, NM_VPN_CONNECTION_STATE_REASON_NO_SECRETS);
+		} else {
+			nm_log_dbg (LOGD_VPN, "(%s/%s) service indicated additional secrets required",
+			            nm_connection_get_uuid (priv->connection),
+			            nm_connection_get_id (priv->connection));
+
+			get_secrets (self, priv->secrets_idx + 1);
+		}
 		return;
 	}
 
@@ -985,6 +1454,9 @@ get_secrets (NMVPNConnection *self, SecretsReq secrets_idx)
 		g_assert_not_reached ();
 	}
 
+	if (priv->user_requested)
+		flags |= NM_SETTINGS_GET_SECRETS_FLAG_USER_REQUESTED;
+
 	priv->secrets_id = nm_settings_connection_get_secrets (NM_SETTINGS_CONNECTION (priv->connection),
 	                                                       filter_by_uid,
 	                                                       priv->user_uid,
@@ -1004,109 +1476,7 @@ get_secrets (NMVPNConnection *self, SecretsReq secrets_idx)
 	}
 }
 
-static void
-vpn_cleanup (NMVPNConnection *connection)
-{
-	NMVPNConnectionPrivate *priv = NM_VPN_CONNECTION_GET_PRIVATE (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_addresses (priv->ip_ifindex, AF_UNSPEC);
-	}
-
-	if (priv->ip4_config) {
-		NMIP4Config *parent_config;
-		NMDnsManager *dns_mgr;
-
-		/* Remove attributes of the VPN's IP4 Config */
-		dns_mgr = nm_dns_manager_get (NULL);
-		nm_dns_manager_remove_ip4_config (dns_mgr, priv->ip_iface, priv->ip4_config);
-		g_object_unref (dns_mgr);
-
-		/* Remove any previously added VPN gateway host route */
-		if (priv->gw_route)
-			nm_netlink_route_delete (priv->gw_route);
-
-		/* Reset routes and addresses of the currently active device */
-		parent_config = nm_device_get_ip4_config (priv->parent_dev);
-		if (parent_config) {
-			if (!nm_system_apply_ip4_config (nm_device_get_ip_ifindex (priv->parent_dev),
-			                                 nm_device_get_ip4_config (priv->parent_dev),
-			                                 nm_device_get_priority (priv->parent_dev),
-			                                 NM_IP4_COMPARE_FLAG_ADDRESSES | NM_IP4_COMPARE_FLAG_ROUTES)) {
-				nm_log_err (LOGD_VPN, "failed to re-apply VPN parent device addresses and routes.");
-			}
-		}
-	}
-
-	if (priv->gw_route) {
-		rtnl_route_put (priv->gw_route);
-		priv->gw_route = NULL;
-	}
-
-	g_free (priv->banner);
-	priv->banner = NULL;
-
-	g_free (priv->ip_iface);
-	priv->ip_iface = NULL;
-	priv->ip_ifindex = 0;
-
-	/* Clear out connection secrets to ensure that the settings service
-	 * gets asked for them next time the connection is activated.
-	 */
-	if (priv->connection)
-		nm_connection_clear_secrets (priv->connection);
-}
-
-static void
-connection_state_changed (NMVPNConnection *self,
-                          NMVPNConnectionState state,
-                          NMVPNConnectionStateReason reason)
-{
-	NMVPNConnectionPrivate *priv = NM_VPN_CONNECTION_GET_PRIVATE (self);
-
-	/* Clear any in-progress secrets request */
-	if (priv->secrets_id) {
-		nm_settings_connection_cancel_secrets (NM_SETTINGS_CONNECTION (priv->connection), priv->secrets_id);
-		priv->secrets_id = 0;
-	}
-	priv->secrets_idx = SECRETS_REQ_SYSTEM;
-
-	switch (state) {
-	case NM_VPN_CONNECTION_STATE_NEED_AUTH:
-		/* Kick off the secrets requests; first we get existing system secrets
-		 * and ask the plugin if these are sufficient, next we get all existing
-		 * secrets from system and from user agents and ask the plugin again,
-		 * and last we ask the user for new secrets if required.
-		 */
-		get_secrets (self, SECRETS_REQ_SYSTEM);
-		break;
-	case NM_VPN_CONNECTION_STATE_ACTIVATED:
-		/* Secrets no longer needed now that we're connected */
-		nm_connection_clear_secrets (priv->connection);
-		break;
-	case NM_VPN_CONNECTION_STATE_DISCONNECTED:
-	case NM_VPN_CONNECTION_STATE_FAILED:
-		if (priv->proxy) {
-			GError *err = NULL;
-
-			org_freedesktop_NetworkManager_VPN_Plugin_disconnect (priv->proxy, &err);
-			if (err) {
-				nm_log_warn (LOGD_VPN, "error disconnecting VPN: %s", err->message);
-				g_error_free (err);
-			}
-
-			g_object_unref (priv->proxy);
-			priv->proxy = NULL;
-		}
-		vpn_cleanup (self);
-		break;
-	default:
-		break;
-	}
-}
+/******************************************************************************/
 
 static void
 nm_vpn_connection_init (NMVPNConnection *self)
@@ -1127,9 +1497,15 @@ dispose (GObject *object)
 
 	if (priv->gw_route)
 		rtnl_route_put (priv->gw_route);
+	if (priv->ip6_internal_gw)
+		g_free (priv->ip6_internal_gw);
+	if (priv->ip6_external_gw)
+		g_free (priv->ip6_external_gw);
 
 	if (priv->device_ip4)
 		g_signal_handler_disconnect (priv->parent_dev, priv->device_ip4);
+	if (priv->device_ip6)
+		g_signal_handler_disconnect (priv->parent_dev, priv->device_ip6);
 
 	if (priv->device_monitor)
 		g_signal_handler_disconnect (priv->parent_dev, priv->device_monitor);
@@ -1138,6 +1514,8 @@ dispose (GObject *object)
 
 	if (priv->ip4_config)
 		g_object_unref (priv->ip4_config);
+	if (priv->ip6_config)
+		g_object_unref (priv->ip6_config);
 
 	if (priv->ipconfig_timeout)
 		g_source_remove (priv->ipconfig_timeout);
@@ -1197,7 +1575,6 @@ nm_vpn_connection_class_init (NMVPNConnectionClass *connection_class)
 	g_type_class_add_private (connection_class, sizeof (NMVPNConnectionPrivate));
 
 	/* virtual methods */
-	connection_class->vpn_state_changed = connection_state_changed;
 	object_class->get_property = get_property;
 	object_class->dispose = dispose;
 	object_class->finalize = finalize;
@@ -1223,16 +1600,14 @@ nm_vpn_connection_class_init (NMVPNConnectionClass *connection_class)
 
 	/* signals */
 	signals[VPN_STATE_CHANGED] =
-		g_signal_new ("vpn-state-changed",
-				    G_OBJECT_CLASS_TYPE (object_class),
-				    G_SIGNAL_RUN_FIRST,
-				    G_STRUCT_OFFSET (NMVPNConnectionClass, vpn_state_changed),
-				    NULL, NULL,
-				    _nm_marshal_VOID__UINT_UINT,
-				    G_TYPE_NONE, 2,
-				    G_TYPE_UINT, G_TYPE_UINT);
+		g_signal_new (NM_VPN_CONNECTION_VPN_STATE_CHANGED,
+		              G_OBJECT_CLASS_TYPE (object_class),
+		              G_SIGNAL_RUN_FIRST,
+		              0, NULL, NULL,
+		              _nm_marshal_VOID__UINT_UINT_UINT,
+		              G_TYPE_NONE, 3, G_TYPE_UINT, G_TYPE_UINT, G_TYPE_UINT);
 
 	dbus_g_object_type_install_info (G_TYPE_FROM_CLASS (object_class),
-									 &dbus_glib_nm_vpn_connection_object_info);
+	                                 &dbus_glib_nm_vpn_connection_object_info);
 }
 
diff --git a/src/vpn-manager/nm-vpn-connection.h b/src/vpn-manager/nm-vpn-connection.h
index 93cc06d1..0e4f1a04 100644
--- a/src/vpn-manager/nm-vpn-connection.h
+++ b/src/vpn-manager/nm-vpn-connection.h
@@ -34,9 +34,14 @@
 #define NM_IS_VPN_CONNECTION_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((obj), NM_TYPE_VPN_CONNECTION))
 #define NM_VPN_CONNECTION_GET_CLASS(obj)  (G_TYPE_INSTANCE_GET_CLASS ((obj), NM_TYPE_VPN_CONNECTION, NMVPNConnectionClass))
 
+/* Properties */
 #define NM_VPN_CONNECTION_VPN_STATE "vpn-state"
 #define NM_VPN_CONNECTION_BANNER "banner"
 
+/* Signals */
+#define NM_VPN_CONNECTION_VPN_STATE_CHANGED "vpn-state-changed"
+
+
 typedef struct {
 	NMActiveConnection parent;
 } NMVPNConnection;
@@ -46,7 +51,8 @@ typedef struct {
 
 	/* Signals */
 	void (*vpn_state_changed) (NMVPNConnection *connection,
-	                           NMVPNConnectionState state,
+	                           NMVPNConnectionState new_state,
+	                           NMVPNConnectionState old_state,
 	                           NMVPNConnectionStateReason reason);
 } NMVPNConnectionClass;
 
@@ -68,9 +74,11 @@ void                 nm_vpn_connection_fail            (NMVPNConnection *connect
 void                 nm_vpn_connection_disconnect      (NMVPNConnection *connection,
                                                         NMVPNConnectionStateReason reason);
 NMIP4Config *        nm_vpn_connection_get_ip4_config  (NMVPNConnection *connection);
+NMIP6Config *        nm_vpn_connection_get_ip6_config  (NMVPNConnection *connection);
 const char *         nm_vpn_connection_get_ip_iface    (NMVPNConnection *connection);
 int                  nm_vpn_connection_get_ip_ifindex  (NMVPNConnection *connection);
 NMDevice *           nm_vpn_connection_get_parent_device (NMVPNConnection *connection);
 guint32              nm_vpn_connection_get_ip4_internal_gateway (NMVPNConnection *connection);
+struct in6_addr *    nm_vpn_connection_get_ip6_internal_gateway (NMVPNConnection *connection);
 
 #endif /* NM_VPN_CONNECTION_H */
diff --git a/src/vpn-manager/nm-vpn-manager.c b/src/vpn-manager/nm-vpn-manager.c
index 34131964..a462f547 100644
--- a/src/vpn-manager/nm-vpn-manager.c
+++ b/src/vpn-manager/nm-vpn-manager.c
@@ -115,19 +115,20 @@ find_active_vpn_connection_by_connection (NMVPNManager *self, NMConnection *conn
 
 static void
 connection_vpn_state_changed (NMVPNConnection *connection,
-                              NMVPNConnectionState state,
+                              NMVPNConnectionState new_state,
+                              NMVPNConnectionState old_state,
                               NMVPNConnectionStateReason reason,
                               gpointer user_data)
 {
 	NMVPNManager *manager = NM_VPN_MANAGER (user_data);
 
-	switch (state) {
+	switch (new_state) {
 	case NM_VPN_CONNECTION_STATE_ACTIVATED:
 		g_signal_emit (manager, signals[CONNECTION_ACTIVATED], 0, connection);
 		break;
 	case NM_VPN_CONNECTION_STATE_FAILED:
 	case NM_VPN_CONNECTION_STATE_DISCONNECTED:
-		g_signal_emit (manager, signals[CONNECTION_DEACTIVATED], 0, connection, state, reason);
+		g_signal_emit (manager, signals[CONNECTION_DEACTIVATED], 0, connection, new_state, old_state, reason);
 		break;
 	default:
 		break;
@@ -188,7 +189,7 @@ nm_vpn_manager_activate_connection (NMVPNManager *manager,
 
 	vpn = nm_vpn_service_activate (service, connection, device, specific_object, user_requested, user_uid, error);
 	if (vpn) {
-		g_signal_connect (vpn, "vpn-state-changed",
+		g_signal_connect (vpn, NM_VPN_CONNECTION_VPN_STATE_CHANGED,
 		                  G_CALLBACK (connection_vpn_state_changed),
 		                  manager);
 	}
@@ -518,11 +519,9 @@ nm_vpn_manager_class_init (NMVPNManagerClass *manager_class)
 		g_signal_new ("connection-deactivated",
 				    G_OBJECT_CLASS_TYPE (object_class),
 				    G_SIGNAL_RUN_FIRST,
-				    G_STRUCT_OFFSET (NMVPNManagerClass, connection_deactivated),
-				    NULL, NULL,
-				    _nm_marshal_VOID__OBJECT_UINT_UINT,
-				    G_TYPE_NONE, 3,
-				    G_TYPE_OBJECT, G_TYPE_UINT, G_TYPE_UINT);
+				    0, NULL, NULL,
+				    _nm_marshal_VOID__OBJECT_UINT_UINT_UINT,
+				    G_TYPE_NONE, 4, G_TYPE_OBJECT, G_TYPE_UINT, G_TYPE_UINT, G_TYPE_UINT);
 
 	dbus_g_error_domain_register (NM_VPN_MANAGER_ERROR, NULL, NM_TYPE_VPN_MANAGER_ERROR);
 }
diff --git a/src/vpn-manager/nm-vpn-manager.h b/src/vpn-manager/nm-vpn-manager.h
index cec370c8..17225b44 100644
--- a/src/vpn-manager/nm-vpn-manager.h
+++ b/src/vpn-manager/nm-vpn-manager.h
@@ -55,9 +55,13 @@ typedef struct {
 	GObjectClass parent;
 
 	/* Signals */
+	void (*connection_activated) (NMVPNManager *manager,
+	                              NMVPNConnection *connection);
+
 	void (*connection_deactivated) (NMVPNManager *manager,
 	                                NMVPNConnection *connection,
-	                                NMVPNConnectionState state,
+	                                NMVPNConnectionState new_state,
+	                                NMVPNConnectionState old_state,
 	                                NMVPNConnectionStateReason reason);
 } NMVPNManagerClass;
 
diff --git a/src/vpn-manager/nm-vpn-service.c b/src/vpn-manager/nm-vpn-service.c
index 95e4f2b1..a2c8b100 100644
--- a/src/vpn-manager/nm-vpn-service.c
+++ b/src/vpn-manager/nm-vpn-service.c
@@ -15,7 +15,7 @@
  * with this program; if not, write to the Free Software Foundation, Inc.,
  * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
  *
- * Copyright (C) 2005 - 2011 Red Hat, Inc.
+ * Copyright (C) 2005 - 2012 Red Hat, Inc.
  * Copyright (C) 2005 - 2008 Novell, Inc.
  */
 
@@ -31,6 +31,7 @@
 #include "nm-vpn-service.h"
 #include "nm-dbus-manager.h"
 #include "nm-logging.h"
+#include "nm-posix-signals.h"
 #include "nm-vpn-manager.h"
 #include "nm-glib-compat.h"
 
@@ -168,6 +169,12 @@ nm_vpn_service_child_setup (gpointer user_data G_GNUC_UNUSED)
 	/* We are in the child process at this point */
 	pid_t pid = getpid ();
 	setpgid (pid, pid);
+
+	/*
+	 * We blocked signals in main(). We need to restore original signal
+	 * mask for VPN service here so that it can receive signals.
+	 */
+	nm_unblock_posix_signals (NULL);
 }
 
 static void
@@ -296,13 +303,14 @@ service_quit (gpointer user_data)
 
 static void
 connection_vpn_state_changed (NMVPNConnection *connection,
-                              NMVPNConnectionState state,
+                              NMVPNConnectionState new_state,
+                              NMVPNConnectionState old_state,
                               NMVPNConnectionStateReason reason,
                               gpointer user_data)
 {
 	NMVPNServicePrivate *priv = NM_VPN_SERVICE_GET_PRIVATE (user_data);
 
-	switch (state) {
+	switch (new_state) {
 	case NM_VPN_CONNECTION_STATE_FAILED:
 	case NM_VPN_CONNECTION_STATE_DISCONNECTED:
 		/* Remove the connection from our list */
@@ -343,9 +351,9 @@ nm_vpn_service_activate (NMVPNService *service,
 	clear_quit_timeout (service);
 
 	vpn = nm_vpn_connection_new (connection, device, specific_object, user_requested, user_uid);
-	g_signal_connect (vpn, "vpn-state-changed",
-				   G_CALLBACK (connection_vpn_state_changed),
-				   service);
+	g_signal_connect (vpn, NM_VPN_CONNECTION_VPN_STATE_CHANGED,
+	                  G_CALLBACK (connection_vpn_state_changed),
+	                  service);
 
 	priv->connections = g_slist_prepend (priv->connections, vpn);
 
diff --git a/src/wifi/Makefile.in b/src/wifi/Makefile.in
index 028469bf..5e77bae3 100644
--- a/src/wifi/Makefile.in
+++ b/src/wifi/Makefile.in
@@ -48,7 +48,7 @@ am__aclocal_m4_deps = $(top_srcdir)/m4/compiler_warnings.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)/configure.ac
+	$(top_srcdir)/m4/vapigen.m4 $(top_srcdir)/configure.ac
 am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \
 	$(ACLOCAL_M4)
 mkinstalldirs = $(install_sh) -d
@@ -174,6 +174,10 @@ INTLTOOL_EXTRACT = @INTLTOOL_EXTRACT@
 INTLTOOL_MERGE = @INTLTOOL_MERGE@
 INTLTOOL_PERL = @INTLTOOL_PERL@
 INTLTOOL_UPDATE = @INTLTOOL_UPDATE@
+INTLTOOL_V_MERGE = @INTLTOOL_V_MERGE@
+INTLTOOL_V_MERGE_OPTIONS = @INTLTOOL_V_MERGE_OPTIONS@
+INTLTOOL__v_MERGE_ = @INTLTOOL__v_MERGE_@
+INTLTOOL__v_MERGE_0 = @INTLTOOL__v_MERGE_0@
 INTL_MACOSX_LIBS = @INTL_MACOSX_LIBS@
 INTROSPECTION_CFLAGS = @INTROSPECTION_CFLAGS@
 INTROSPECTION_COMPILER = @INTROSPECTION_COMPILER@
@@ -269,6 +273,9 @@ UDEV_BASE_DIR = @UDEV_BASE_DIR@
 USE_NLS = @USE_NLS@
 UUID_CFLAGS = @UUID_CFLAGS@
 UUID_LIBS = @UUID_LIBS@
+VAPIGEN = @VAPIGEN@
+VAPIGEN_MAKEFILE = @VAPIGEN_MAKEFILE@
+VAPIGEN_VAPIDIR = @VAPIGEN_VAPIDIR@
 VERSION = @VERSION@
 XGETTEXT = @XGETTEXT@
 XGETTEXT_015 = @XGETTEXT_015@
@@ -307,6 +314,8 @@ htmldir = @htmldir@
 includedir = @includedir@
 infodir = @infodir@
 install_sh = @install_sh@
+intltool__v_merge_options_ = @intltool__v_merge_options_@
+intltool__v_merge_options_0 = @intltool__v_merge_options_0@
 libdir = @libdir@
 libexecdir = @libexecdir@
 localedir = @localedir@
diff --git a/src/wifi/wifi-utils-nl80211.c b/src/wifi/wifi-utils-nl80211.c
index 4a4e661e..663cbc26 100644
--- a/src/wifi/wifi-utils-nl80211.c
+++ b/src/wifi/wifi-utils-nl80211.c
@@ -535,7 +535,9 @@ struct nl80211_device_info {
 	guint32 *freqs;
 	int num_freqs;
 	guint32 caps;
-	gboolean can_scan, can_scan_ssid;
+	gboolean can_scan;
+	gboolean can_scan_ssid;
+	gboolean supported;
 	gboolean success;
 };
 
@@ -579,11 +581,24 @@ static int nl80211_wiphy_info_handler (struct nl_msg *msg, void *arg)
 		struct nlattr *nl_cmd;
 		int i;
 
-		nla_for_each_nested (nl_cmd,
-				     tb[NL80211_ATTR_SUPPORTED_COMMANDS], i) {
-			guint32 cmd = nla_get_u32 (nl_cmd);
-			if (cmd == NL80211_CMD_TRIGGER_SCAN)
+		nla_for_each_nested (nl_cmd, tb[NL80211_ATTR_SUPPORTED_COMMANDS], i) {
+			switch (nla_get_u32 (nl_cmd)) {
+			case NL80211_CMD_TRIGGER_SCAN:
 				info->can_scan = TRUE;
+				break;
+			case NL80211_CMD_CONNECT:
+			case NL80211_CMD_AUTHENTICATE:
+				/* Only devices that support CONNECT or AUTH actually support
+				 * 802.11, unlike say ipw2x00 (up to at least kernel 3.4) which
+				 * has minimal info support, but no actual command support.
+				 * This check mirrors what wpa_supplicant does to determine
+				 * whether or not to use the nl80211 driver.
+				 */
+				info->supported = TRUE;
+				break;
+			default:
+				break;
+			}
 		}
 	}
 
@@ -650,6 +665,9 @@ static int nl80211_wiphy_info_handler (struct nl_msg *msg, void *arg)
 				info->caps |= NM_WIFI_DEVICE_CAP_CIPHER_CCMP |
 					      NM_WIFI_DEVICE_CAP_RSN;
 				break;
+			default:
+				nm_log_err (LOGD_HW | LOGD_WIFI, "Don't know the meaning of NL80211_ATTR_CIPHER_SUITES %#8.8x.", ciphers[i]);
+				break;
 			}
 		}
 	}
@@ -721,6 +739,13 @@ wifi_nl80211_init (const char *iface, int ifindex)
 		goto error;
 	}
 
+	if (!device_info.supported) {
+		nm_log_dbg (LOGD_HW | LOGD_WIFI,
+				    "(%s): driver does not fully support nl80211, falling back to WEXT",
+				    nl80211->parent.iface);
+		goto error;
+	}
+
 	if (!device_info.can_scan_ssid) {
 		nm_log_err (LOGD_HW | LOGD_WIFI,
 		            "(%s): driver does not support SSID scans",
@@ -735,6 +760,13 @@ wifi_nl80211_init (const char *iface, int ifindex)
 		goto error;
 	}
 
+	if (device_info.caps == 0) {
+		nm_log_err (LOGD_HW | LOGD_WIFI,
+		            "(%s): driver doesn't report support of any encryption",
+		            nl80211->parent.iface);
+		goto error;
+	}
+
 	nl80211->freqs = device_info.freqs;
 	nl80211->num_freqs = device_info.num_freqs;
 	nl80211->parent.can_scan_ssid = device_info.can_scan_ssid;
diff --git a/src/wimax/Makefile.in b/src/wimax/Makefile.in
index 2de52180..e463cf2d 100644
--- a/src/wimax/Makefile.in
+++ b/src/wimax/Makefile.in
@@ -47,7 +47,7 @@ am__aclocal_m4_deps = $(top_srcdir)/m4/compiler_warnings.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)/configure.ac
+	$(top_srcdir)/m4/vapigen.m4 $(top_srcdir)/configure.ac
 am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \
 	$(ACLOCAL_M4)
 mkinstalldirs = $(install_sh) -d
@@ -199,6 +199,10 @@ INTLTOOL_EXTRACT = @INTLTOOL_EXTRACT@
 INTLTOOL_MERGE = @INTLTOOL_MERGE@
 INTLTOOL_PERL = @INTLTOOL_PERL@
 INTLTOOL_UPDATE = @INTLTOOL_UPDATE@
+INTLTOOL_V_MERGE = @INTLTOOL_V_MERGE@
+INTLTOOL_V_MERGE_OPTIONS = @INTLTOOL_V_MERGE_OPTIONS@
+INTLTOOL__v_MERGE_ = @INTLTOOL__v_MERGE_@
+INTLTOOL__v_MERGE_0 = @INTLTOOL__v_MERGE_0@
 INTL_MACOSX_LIBS = @INTL_MACOSX_LIBS@
 INTROSPECTION_CFLAGS = @INTROSPECTION_CFLAGS@
 INTROSPECTION_COMPILER = @INTROSPECTION_COMPILER@
@@ -294,6 +298,9 @@ UDEV_BASE_DIR = @UDEV_BASE_DIR@
 USE_NLS = @USE_NLS@
 UUID_CFLAGS = @UUID_CFLAGS@
 UUID_LIBS = @UUID_LIBS@
+VAPIGEN = @VAPIGEN@
+VAPIGEN_MAKEFILE = @VAPIGEN_MAKEFILE@
+VAPIGEN_VAPIDIR = @VAPIGEN_VAPIDIR@
 VERSION = @VERSION@
 XGETTEXT = @XGETTEXT@
 XGETTEXT_015 = @XGETTEXT_015@
@@ -332,6 +339,8 @@ htmldir = @htmldir@
 includedir = @includedir@
 infodir = @infodir@
 install_sh = @install_sh@
+intltool__v_merge_options_ = @intltool__v_merge_options_@
+intltool__v_merge_options_0 = @intltool__v_merge_options_0@
 libdir = @libdir@
 libexecdir = @libexecdir@
 localedir = @localedir@