about summary refs log tree commit diff
path: root/src
diff options
context:
space:
mode:
authorMichael Biebl <biebl@debian.org>2011-10-28 23:04:16 +0200
committerMichael Biebl <biebl@debian.org>2011-10-28 23:04:16 +0200
commit485d149fe80915d94ed49ea6c2c0552cf7a3e79a (patch)
tree6a48492b46b8c1e3df1c58626c28f05a978c61f7 /src
parent263bf4c0c89bb88dc995acd9a6a2de9095fbd461 (diff)
Imported Upstream version 0.9.1.95 upstream/0.9.1.95
Diffstat (limited to 'src')
-rw-r--r--src/Makefile.am6
-rw-r--r--src/Makefile.in68
-rw-r--r--src/NetworkManagerUtils.c4
-rw-r--r--src/backends/Makefile.in8
-rw-r--r--src/backends/NetworkManagerGeneric.c16
-rw-r--r--src/bluez-manager/Makefile.in8
-rw-r--r--src/dhcp-manager/Makefile.in8
-rw-r--r--src/dhcp-manager/nm-dhcp-client.c2
-rw-r--r--src/dhcp-manager/tests/Makefile.in8
-rw-r--r--src/dns-manager/Makefile.in8
-rw-r--r--src/dns-manager/nm-dns-bind.c3
-rw-r--r--src/dns-manager/nm-dns-dnsmasq.c73
-rw-r--r--src/dns-manager/nm-dns-manager.c3
-rw-r--r--src/dns-manager/nm-dns-plugin.c6
-rw-r--r--src/dns-manager/nm-dns-plugin.h6
-rw-r--r--src/dnsmasq-manager/Makefile.in8
-rw-r--r--src/ip6-manager/Makefile.in8
-rw-r--r--src/ip6-manager/nm-ip6-manager.c59
-rw-r--r--src/logging/Makefile.in8
-rw-r--r--src/logging/nm-logging.c7
-rw-r--r--src/main.c185
-rw-r--r--src/modem-manager/Makefile.in8
-rw-r--r--src/modem-manager/nm-modem-manager.c29
-rw-r--r--src/modem-manager/nm-modem.c14
-rw-r--r--src/nm-config.c247
-rw-r--r--src/nm-config.h55
-rw-r--r--src/nm-crash-logger.c1
-rw-r--r--src/nm-device-ethernet.c96
-rw-r--r--src/nm-device-olpc-mesh.c12
-rw-r--r--src/nm-device-wifi.c267
-rw-r--r--src/nm-device.c54
-rw-r--r--src/nm-manager.c67
-rw-r--r--src/nm-manager.h7
-rw-r--r--src/nm-netlink-compat.c105
-rw-r--r--src/nm-netlink-compat.h207
-rw-r--r--src/nm-netlink-monitor.c98
-rw-r--r--src/nm-netlink-monitor.h4
-rw-r--r--src/nm-netlink-utils.c426
-rw-r--r--src/nm-netlink-utils.h80
-rw-r--r--src/nm-policy.c20
-rw-r--r--src/nm-system.c1014
-rw-r--r--src/nm-system.h35
-rw-r--r--src/nm-udev-manager.c76
-rw-r--r--src/nm-wifi-ap.c99
-rw-r--r--src/nm-wifi-ap.h9
-rw-r--r--src/ppp-manager/Makefile.in8
-rw-r--r--src/ppp-manager/nm-ppp-manager.c4
-rw-r--r--src/settings/Makefile.in8
-rw-r--r--src/settings/nm-settings-connection.c289
-rw-r--r--src/settings/nm-settings.c62
-rw-r--r--src/settings/nm-settings.h2
-rw-r--r--src/settings/plugins/Makefile.in8
-rw-r--r--src/settings/plugins/ifcfg-rh/Makefile.in8
-rw-r--r--src/settings/plugins/ifcfg-rh/plugin.c6
-rw-r--r--src/settings/plugins/ifcfg-rh/reader.c4
-rw-r--r--src/settings/plugins/ifcfg-rh/shvar.c20
-rw-r--r--src/settings/plugins/ifcfg-rh/tests/Makefile.in8
-rw-r--r--src/settings/plugins/ifcfg-rh/tests/network-scripts/Makefile.in8
-rw-r--r--src/settings/plugins/ifcfg-rh/tests/test-ifcfg-rh.c202
-rw-r--r--src/settings/plugins/ifcfg-rh/writer.c3
-rw-r--r--src/settings/plugins/ifcfg-suse/Makefile.in8
-rw-r--r--src/settings/plugins/ifnet/Makefile.in8
-rw-r--r--src/settings/plugins/ifnet/connection_parser.c18
-rw-r--r--src/settings/plugins/ifnet/net_utils.c2
-rw-r--r--src/settings/plugins/ifnet/tests/Makefile.in8
-rw-r--r--src/settings/plugins/ifnet/tests/net2
-rw-r--r--src/settings/plugins/ifnet/tests/test_all.c48
-rw-r--r--src/settings/plugins/ifnet/tests/wpa_supplicant.conf3
-rw-r--r--src/settings/plugins/ifupdown/Makefile.in8
-rw-r--r--src/settings/plugins/ifupdown/tests/Makefile.in8
-rw-r--r--src/settings/plugins/keyfile/Makefile.in8
-rw-r--r--src/settings/plugins/keyfile/reader.c176
-rw-r--r--src/settings/plugins/keyfile/tests/Makefile.in8
-rw-r--r--src/settings/plugins/keyfile/tests/keyfiles/Makefile.am2
-rw-r--r--src/settings/plugins/keyfile/tests/keyfiles/Makefile.in10
-rw-r--r--src/settings/plugins/keyfile/tests/keyfiles/Test_Intlike_SSID11
-rw-r--r--src/settings/plugins/keyfile/tests/keyfiles/Test_Intlike_SSID_211
-rw-r--r--src/settings/plugins/keyfile/tests/test-keyfile.c246
-rw-r--r--src/settings/plugins/keyfile/writer.c45
-rw-r--r--src/settings/tests/Makefile.in8
-rw-r--r--src/supplicant-manager/Makefile.in8
-rw-r--r--src/supplicant-manager/nm-supplicant-config.c2
-rw-r--r--src/supplicant-manager/nm-supplicant-manager.c69
-rw-r--r--src/supplicant-manager/tests/Makefile.in8
-rw-r--r--src/tests/Makefile.in8
-rw-r--r--src/vpn-manager/Makefile.in8
-rw-r--r--src/vpn-manager/nm-vpn-connection-base.c16
-rw-r--r--src/vpn-manager/nm-vpn-connection-base.h5
-rw-r--r--src/vpn-manager/nm-vpn-connection.c62
-rw-r--r--src/vpn-manager/nm-vpn-connection.h3
-rw-r--r--src/vpn-manager/nm-vpn-manager.c24
-rw-r--r--src/vpn-manager/nm-vpn-manager.h8
-rw-r--r--src/vpn-manager/nm-vpn-service.c5
-rw-r--r--src/vpn-manager/nm-vpn-service.h3
-rw-r--r--src/wimax/Makefile.in8
-rw-r--r--src/wimax/iwmxsdk.c77
-rw-r--r--src/wimax/iwmxsdk.h2
-rw-r--r--src/wimax/nm-device-wimax.c115
98 files changed, 3529 insertions, 1712 deletions
diff --git a/src/Makefile.am b/src/Makefile.am
index 94e1a8c0..cbcfdc62 100644
--- a/src/Makefile.am
+++ b/src/Makefile.am
@@ -142,6 +142,8 @@ NetworkManager_SOURCES = \
 		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 \
@@ -159,6 +161,10 @@ NetworkManager_SOURCES = \
 		nm-manager-auth.h \
 		nm-netlink-monitor.c \
 		nm-netlink-monitor.h \
+		nm-netlink-utils.c \
+		nm-netlink-utils.h \
+		nm-netlink-compat.h \
+		nm-netlink-compat.c \
 		nm-activation-request.c \
 		nm-activation-request.h \
 		nm-properties-changed-signal.c \
diff --git a/src/Makefile.in b/src/Makefile.in
index 5d9567ed..103df7fb 100644
--- a/src/Makefile.in
+++ b/src/Makefile.in
@@ -107,6 +107,7 @@ am_NetworkManager_OBJECTS = NetworkManager-nm-call-store.$(OBJEXT) \
 	NetworkManager-nm-ip4-config.$(OBJEXT) \
 	NetworkManager-nm-ip6-config.$(OBJEXT) \
 	NetworkManager-nm-active-connection.$(OBJEXT) \
+	NetworkManager-nm-config.$(OBJEXT) \
 	NetworkManager-main.$(OBJEXT) \
 	NetworkManager-nm-policy.$(OBJEXT) \
 	NetworkManager-nm-policy-hosts.$(OBJEXT) \
@@ -116,6 +117,8 @@ am_NetworkManager_OBJECTS = NetworkManager-nm-call-store.$(OBJEXT) \
 	NetworkManager-nm-manager.$(OBJEXT) \
 	NetworkManager-nm-manager-auth.$(OBJEXT) \
 	NetworkManager-nm-netlink-monitor.$(OBJEXT) \
+	NetworkManager-nm-netlink-utils.$(OBJEXT) \
+	NetworkManager-nm-netlink-compat.$(OBJEXT) \
 	NetworkManager-nm-activation-request.$(OBJEXT) \
 	NetworkManager-nm-properties-changed-signal.$(OBJEXT) \
 	NetworkManager-wpa.$(OBJEXT) \
@@ -338,8 +341,16 @@ LIBGCRYPT_LIBS = @LIBGCRYPT_LIBS@
 LIBICONV = @LIBICONV@
 LIBINTL = @LIBINTL@
 LIBM = @LIBM@
+LIBNL1_CFLAGS = @LIBNL1_CFLAGS@
+LIBNL1_LIBS = @LIBNL1_LIBS@
+LIBNL2_CFLAGS = @LIBNL2_CFLAGS@
+LIBNL2_LIBS = @LIBNL2_LIBS@
+LIBNL3_CFLAGS = @LIBNL3_CFLAGS@
+LIBNL3_LIBS = @LIBNL3_LIBS@
 LIBNL_CFLAGS = @LIBNL_CFLAGS@
 LIBNL_LIBS = @LIBNL_LIBS@
+LIBNL_ROUTE3_CFLAGS = @LIBNL_ROUTE3_CFLAGS@
+LIBNL_ROUTE3_LIBS = @LIBNL_ROUTE3_LIBS@
 LIBOBJS = @LIBOBJS@
 LIBS = @LIBS@
 LIBTOOL = @LIBTOOL@
@@ -565,6 +576,8 @@ NetworkManager_SOURCES = \
 		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 \
@@ -582,6 +595,10 @@ NetworkManager_SOURCES = \
 		nm-manager-auth.h \
 		nm-netlink-monitor.c \
 		nm-netlink-monitor.h \
+		nm-netlink-utils.c \
+		nm-netlink-utils.h \
+		nm-netlink-compat.h \
+		nm-netlink-compat.c \
 		nm-activation-request.c \
 		nm-activation-request.h \
 		nm-properties-changed-signal.c \
@@ -832,6 +849,7 @@ distclean-compile:
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/NetworkManager-nm-activation-request.Po@am__quote@
 @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-dbus-manager.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@
@@ -847,7 +865,9 @@ distclean-compile:
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/NetworkManager-nm-ip6-config.Po@am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/NetworkManager-nm-manager-auth.Po@am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/NetworkManager-nm-manager.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/NetworkManager-nm-netlink-compat.Po@am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/NetworkManager-nm-netlink-monitor.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/NetworkManager-nm-netlink-utils.Po@am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/NetworkManager-nm-policy-hostname.Po@am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/NetworkManager-nm-policy-hosts.Po@am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/NetworkManager-nm-policy.Po@am__quote@
@@ -1197,6 +1217,22 @@ NetworkManager-nm-active-connection.obj: nm-active-connection.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-active-connection.obj `if test -f 'nm-active-connection.c'; then $(CYGPATH_W) 'nm-active-connection.c'; else $(CYGPATH_W) '$(srcdir)/nm-active-connection.c'; fi`
 
+NetworkManager-nm-config.o: nm-config.c
+@am__fastdepCC_TRUE@	$(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(NetworkManager_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT NetworkManager-nm-config.o -MD -MP -MF $(DEPDIR)/NetworkManager-nm-config.Tpo -c -o NetworkManager-nm-config.o `test -f 'nm-config.c' || echo '$(srcdir)/'`nm-config.c
+@am__fastdepCC_TRUE@	$(AM_V_at)$(am__mv) $(DEPDIR)/NetworkManager-nm-config.Tpo $(DEPDIR)/NetworkManager-nm-config.Po
+@am__fastdepCC_FALSE@	$(AM_V_CC) @AM_BACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@	source='nm-config.c' object='NetworkManager-nm-config.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-config.o `test -f 'nm-config.c' || echo '$(srcdir)/'`nm-config.c
+
+NetworkManager-nm-config.obj: nm-config.c
+@am__fastdepCC_TRUE@	$(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(NetworkManager_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT NetworkManager-nm-config.obj -MD -MP -MF $(DEPDIR)/NetworkManager-nm-config.Tpo -c -o NetworkManager-nm-config.obj `if test -f 'nm-config.c'; then $(CYGPATH_W) 'nm-config.c'; else $(CYGPATH_W) '$(srcdir)/nm-config.c'; fi`
+@am__fastdepCC_TRUE@	$(AM_V_at)$(am__mv) $(DEPDIR)/NetworkManager-nm-config.Tpo $(DEPDIR)/NetworkManager-nm-config.Po
+@am__fastdepCC_FALSE@	$(AM_V_CC) @AM_BACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@	source='nm-config.c' object='NetworkManager-nm-config.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-config.obj `if test -f 'nm-config.c'; then $(CYGPATH_W) 'nm-config.c'; else $(CYGPATH_W) '$(srcdir)/nm-config.c'; fi`
+
 NetworkManager-main.o: main.c
 @am__fastdepCC_TRUE@	$(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(NetworkManager_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT NetworkManager-main.o -MD -MP -MF $(DEPDIR)/NetworkManager-main.Tpo -c -o NetworkManager-main.o `test -f 'main.c' || echo '$(srcdir)/'`main.c
 @am__fastdepCC_TRUE@	$(AM_V_at)$(am__mv) $(DEPDIR)/NetworkManager-main.Tpo $(DEPDIR)/NetworkManager-main.Po
@@ -1341,6 +1377,38 @@ NetworkManager-nm-netlink-monitor.obj: nm-netlink-monitor.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-netlink-monitor.obj `if test -f 'nm-netlink-monitor.c'; then $(CYGPATH_W) 'nm-netlink-monitor.c'; else $(CYGPATH_W) '$(srcdir)/nm-netlink-monitor.c'; fi`
 
+NetworkManager-nm-netlink-utils.o: nm-netlink-utils.c
+@am__fastdepCC_TRUE@	$(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(NetworkManager_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT NetworkManager-nm-netlink-utils.o -MD -MP -MF $(DEPDIR)/NetworkManager-nm-netlink-utils.Tpo -c -o NetworkManager-nm-netlink-utils.o `test -f 'nm-netlink-utils.c' || echo '$(srcdir)/'`nm-netlink-utils.c
+@am__fastdepCC_TRUE@	$(AM_V_at)$(am__mv) $(DEPDIR)/NetworkManager-nm-netlink-utils.Tpo $(DEPDIR)/NetworkManager-nm-netlink-utils.Po
+@am__fastdepCC_FALSE@	$(AM_V_CC) @AM_BACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@	source='nm-netlink-utils.c' object='NetworkManager-nm-netlink-utils.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-netlink-utils.o `test -f 'nm-netlink-utils.c' || echo '$(srcdir)/'`nm-netlink-utils.c
+
+NetworkManager-nm-netlink-utils.obj: nm-netlink-utils.c
+@am__fastdepCC_TRUE@	$(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(NetworkManager_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT NetworkManager-nm-netlink-utils.obj -MD -MP -MF $(DEPDIR)/NetworkManager-nm-netlink-utils.Tpo -c -o NetworkManager-nm-netlink-utils.obj `if test -f 'nm-netlink-utils.c'; then $(CYGPATH_W) 'nm-netlink-utils.c'; else $(CYGPATH_W) '$(srcdir)/nm-netlink-utils.c'; fi`
+@am__fastdepCC_TRUE@	$(AM_V_at)$(am__mv) $(DEPDIR)/NetworkManager-nm-netlink-utils.Tpo $(DEPDIR)/NetworkManager-nm-netlink-utils.Po
+@am__fastdepCC_FALSE@	$(AM_V_CC) @AM_BACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@	source='nm-netlink-utils.c' object='NetworkManager-nm-netlink-utils.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-netlink-utils.obj `if test -f 'nm-netlink-utils.c'; then $(CYGPATH_W) 'nm-netlink-utils.c'; else $(CYGPATH_W) '$(srcdir)/nm-netlink-utils.c'; fi`
+
+NetworkManager-nm-netlink-compat.o: nm-netlink-compat.c
+@am__fastdepCC_TRUE@	$(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(NetworkManager_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT NetworkManager-nm-netlink-compat.o -MD -MP -MF $(DEPDIR)/NetworkManager-nm-netlink-compat.Tpo -c -o NetworkManager-nm-netlink-compat.o `test -f 'nm-netlink-compat.c' || echo '$(srcdir)/'`nm-netlink-compat.c
+@am__fastdepCC_TRUE@	$(AM_V_at)$(am__mv) $(DEPDIR)/NetworkManager-nm-netlink-compat.Tpo $(DEPDIR)/NetworkManager-nm-netlink-compat.Po
+@am__fastdepCC_FALSE@	$(AM_V_CC) @AM_BACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@	source='nm-netlink-compat.c' object='NetworkManager-nm-netlink-compat.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-netlink-compat.o `test -f 'nm-netlink-compat.c' || echo '$(srcdir)/'`nm-netlink-compat.c
+
+NetworkManager-nm-netlink-compat.obj: nm-netlink-compat.c
+@am__fastdepCC_TRUE@	$(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(NetworkManager_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT NetworkManager-nm-netlink-compat.obj -MD -MP -MF $(DEPDIR)/NetworkManager-nm-netlink-compat.Tpo -c -o NetworkManager-nm-netlink-compat.obj `if test -f 'nm-netlink-compat.c'; then $(CYGPATH_W) 'nm-netlink-compat.c'; else $(CYGPATH_W) '$(srcdir)/nm-netlink-compat.c'; fi`
+@am__fastdepCC_TRUE@	$(AM_V_at)$(am__mv) $(DEPDIR)/NetworkManager-nm-netlink-compat.Tpo $(DEPDIR)/NetworkManager-nm-netlink-compat.Po
+@am__fastdepCC_FALSE@	$(AM_V_CC) @AM_BACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@	source='nm-netlink-compat.c' object='NetworkManager-nm-netlink-compat.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-netlink-compat.obj `if test -f 'nm-netlink-compat.c'; then $(CYGPATH_W) 'nm-netlink-compat.c'; else $(CYGPATH_W) '$(srcdir)/nm-netlink-compat.c'; fi`
+
 NetworkManager-nm-activation-request.o: nm-activation-request.c
 @am__fastdepCC_TRUE@	$(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(NetworkManager_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT NetworkManager-nm-activation-request.o -MD -MP -MF $(DEPDIR)/NetworkManager-nm-activation-request.Tpo -c -o NetworkManager-nm-activation-request.o `test -f 'nm-activation-request.c' || echo '$(srcdir)/'`nm-activation-request.c
 @am__fastdepCC_TRUE@	$(AM_V_at)$(am__mv) $(DEPDIR)/NetworkManager-nm-activation-request.Tpo $(DEPDIR)/NetworkManager-nm-activation-request.Po
diff --git a/src/NetworkManagerUtils.c b/src/NetworkManagerUtils.c
index f96f2aad..451de6d0 100644
--- a/src/NetworkManagerUtils.c
+++ b/src/NetworkManagerUtils.c
@@ -26,6 +26,7 @@
 #include <string.h>
 #include <unistd.h>
 #include <ctype.h>
+#include <stdlib.h>
 
 #include "NetworkManagerUtils.h"
 #include "nm-utils.h"
@@ -43,9 +44,6 @@
 #include "nm-setting-wireless-security.h"
 #include "nm-manager-auth.h"
 
-#include <netlink/addr.h>
-#include <netinet/in.h>
-
 /*
  * nm_ethernet_address_is_valid
  *
diff --git a/src/backends/Makefile.in b/src/backends/Makefile.in
index 2f489e75..9eb2e0ff 100644
--- a/src/backends/Makefile.in
+++ b/src/backends/Makefile.in
@@ -232,8 +232,16 @@ LIBGCRYPT_LIBS = @LIBGCRYPT_LIBS@
 LIBICONV = @LIBICONV@
 LIBINTL = @LIBINTL@
 LIBM = @LIBM@
+LIBNL1_CFLAGS = @LIBNL1_CFLAGS@
+LIBNL1_LIBS = @LIBNL1_LIBS@
+LIBNL2_CFLAGS = @LIBNL2_CFLAGS@
+LIBNL2_LIBS = @LIBNL2_LIBS@
+LIBNL3_CFLAGS = @LIBNL3_CFLAGS@
+LIBNL3_LIBS = @LIBNL3_LIBS@
 LIBNL_CFLAGS = @LIBNL_CFLAGS@
 LIBNL_LIBS = @LIBNL_LIBS@
+LIBNL_ROUTE3_CFLAGS = @LIBNL_ROUTE3_CFLAGS@
+LIBNL_ROUTE3_LIBS = @LIBNL_ROUTE3_LIBS@
 LIBOBJS = @LIBOBJS@
 LIBS = @LIBS@
 LIBTOOL = @LIBTOOL@
diff --git a/src/backends/NetworkManagerGeneric.c b/src/backends/NetworkManagerGeneric.c
index 8f16066f..89b8a46d 100644
--- a/src/backends/NetworkManagerGeneric.c
+++ b/src/backends/NetworkManagerGeneric.c
@@ -34,7 +34,9 @@
 #include "nm-system.h"
 #include "NetworkManagerUtils.h"
 #include "nm-logging.h"
+#include "nm-netlink-compat.h"
 #include "nm-netlink-monitor.h"
+#include "nm-netlink-utils.h"
 
 /* Because of a bug in libnl, rtnl.h should be included before route.h */
 #include <netlink/route/rtnl.h>
@@ -50,15 +52,13 @@
  */
 void nm_generic_enable_loopback (void)
 {
-	struct nl_handle *	nlh = NULL;
+	struct nl_sock *	nlh = NULL;
 	struct rtnl_addr *	addr = NULL;
 	struct nl_addr *	nl_addr = NULL;
 	guint32			binaddr = 0;
 	int			iface_idx = -1;
 	int			err;
 
-	nm_system_device_set_up_down_with_iface ("lo", TRUE, NULL);
-
 	nlh = nm_netlink_get_default_handle ();
 	if (!nlh)
 		return;
@@ -67,6 +67,8 @@ void nm_generic_enable_loopback (void)
 	if (iface_idx < 0)
 		return;
 
+	nm_system_iface_set_up (iface_idx, TRUE, NULL);
+
 	addr = rtnl_addr_alloc ();
 	if (!addr)
 		return;
@@ -90,10 +92,10 @@ void nm_generic_enable_loopback (void)
 	rtnl_addr_set_scope (addr, RT_SCOPE_HOST);
 	rtnl_addr_set_label (addr, "lo");
 
-	if ((err = rtnl_addr_add (nlh, addr, 0)) < 0) {
-		if (err != -EEXIST) {
-			nm_log_warn (LOGD_CORE, "error %d returned from rtnl_addr_add():\n%s", err, nl_geterror());
-		}
+	err = rtnl_addr_add (nlh, addr, 0);
+	if (err && (err != -NLE_EXIST)) {
+		nm_log_warn (LOGD_CORE, "error setting loopback address: (%d) %s",
+			         err, nl_geterror (err));
 	}
 out:
 	if (addr)
diff --git a/src/bluez-manager/Makefile.in b/src/bluez-manager/Makefile.in
index 1336b7ec..764493a4 100644
--- a/src/bluez-manager/Makefile.in
+++ b/src/bluez-manager/Makefile.in
@@ -189,8 +189,16 @@ LIBGCRYPT_LIBS = @LIBGCRYPT_LIBS@
 LIBICONV = @LIBICONV@
 LIBINTL = @LIBINTL@
 LIBM = @LIBM@
+LIBNL1_CFLAGS = @LIBNL1_CFLAGS@
+LIBNL1_LIBS = @LIBNL1_LIBS@
+LIBNL2_CFLAGS = @LIBNL2_CFLAGS@
+LIBNL2_LIBS = @LIBNL2_LIBS@
+LIBNL3_CFLAGS = @LIBNL3_CFLAGS@
+LIBNL3_LIBS = @LIBNL3_LIBS@
 LIBNL_CFLAGS = @LIBNL_CFLAGS@
 LIBNL_LIBS = @LIBNL_LIBS@
+LIBNL_ROUTE3_CFLAGS = @LIBNL_ROUTE3_CFLAGS@
+LIBNL_ROUTE3_LIBS = @LIBNL_ROUTE3_LIBS@
 LIBOBJS = @LIBOBJS@
 LIBS = @LIBS@
 LIBTOOL = @LIBTOOL@
diff --git a/src/dhcp-manager/Makefile.in b/src/dhcp-manager/Makefile.in
index dd557056..d373f7e9 100644
--- a/src/dhcp-manager/Makefile.in
+++ b/src/dhcp-manager/Makefile.in
@@ -237,8 +237,16 @@ LIBGCRYPT_LIBS = @LIBGCRYPT_LIBS@
 LIBICONV = @LIBICONV@
 LIBINTL = @LIBINTL@
 LIBM = @LIBM@
+LIBNL1_CFLAGS = @LIBNL1_CFLAGS@
+LIBNL1_LIBS = @LIBNL1_LIBS@
+LIBNL2_CFLAGS = @LIBNL2_CFLAGS@
+LIBNL2_LIBS = @LIBNL2_LIBS@
+LIBNL3_CFLAGS = @LIBNL3_CFLAGS@
+LIBNL3_LIBS = @LIBNL3_LIBS@
 LIBNL_CFLAGS = @LIBNL_CFLAGS@
 LIBNL_LIBS = @LIBNL_LIBS@
+LIBNL_ROUTE3_CFLAGS = @LIBNL_ROUTE3_CFLAGS@
+LIBNL_ROUTE3_LIBS = @LIBNL_ROUTE3_LIBS@
 LIBOBJS = @LIBOBJS@
 LIBS = @LIBS@
 LIBTOOL = @LIBTOOL@
diff --git a/src/dhcp-manager/nm-dhcp-client.c b/src/dhcp-manager/nm-dhcp-client.c
index 3418bf3b..f10f3de9 100644
--- a/src/dhcp-manager/nm-dhcp-client.c
+++ b/src/dhcp-manager/nm-dhcp-client.c
@@ -638,7 +638,7 @@ nm_dhcp_client_foreach_option (NMDHCPClient *self,
 		}
 
 		if (!ignore) {
-			const char *tmp_key = value;
+			const char *tmp_key = key;
 
 			/* Remove the "new_" prefix that dhclient passes back */
 			if (!strncmp (key, NEW_TAG, strlen (NEW_TAG)))
diff --git a/src/dhcp-manager/tests/Makefile.in b/src/dhcp-manager/tests/Makefile.in
index 7e875055..8a3c2e97 100644
--- a/src/dhcp-manager/tests/Makefile.in
+++ b/src/dhcp-manager/tests/Makefile.in
@@ -187,8 +187,16 @@ LIBGCRYPT_LIBS = @LIBGCRYPT_LIBS@
 LIBICONV = @LIBICONV@
 LIBINTL = @LIBINTL@
 LIBM = @LIBM@
+LIBNL1_CFLAGS = @LIBNL1_CFLAGS@
+LIBNL1_LIBS = @LIBNL1_LIBS@
+LIBNL2_CFLAGS = @LIBNL2_CFLAGS@
+LIBNL2_LIBS = @LIBNL2_LIBS@
+LIBNL3_CFLAGS = @LIBNL3_CFLAGS@
+LIBNL3_LIBS = @LIBNL3_LIBS@
 LIBNL_CFLAGS = @LIBNL_CFLAGS@
 LIBNL_LIBS = @LIBNL_LIBS@
+LIBNL_ROUTE3_CFLAGS = @LIBNL_ROUTE3_CFLAGS@
+LIBNL_ROUTE3_LIBS = @LIBNL_ROUTE3_LIBS@
 LIBOBJS = @LIBOBJS@
 LIBS = @LIBS@
 LIBTOOL = @LIBTOOL@
diff --git a/src/dns-manager/Makefile.in b/src/dns-manager/Makefile.in
index aad1c562..d44c3bfc 100644
--- a/src/dns-manager/Makefile.in
+++ b/src/dns-manager/Makefile.in
@@ -190,8 +190,16 @@ LIBGCRYPT_LIBS = @LIBGCRYPT_LIBS@
 LIBICONV = @LIBICONV@
 LIBINTL = @LIBINTL@
 LIBM = @LIBM@
+LIBNL1_CFLAGS = @LIBNL1_CFLAGS@
+LIBNL1_LIBS = @LIBNL1_LIBS@
+LIBNL2_CFLAGS = @LIBNL2_CFLAGS@
+LIBNL2_LIBS = @LIBNL2_LIBS@
+LIBNL3_CFLAGS = @LIBNL3_CFLAGS@
+LIBNL3_LIBS = @LIBNL3_LIBS@
 LIBNL_CFLAGS = @LIBNL_CFLAGS@
 LIBNL_LIBS = @LIBNL_LIBS@
+LIBNL_ROUTE3_CFLAGS = @LIBNL_ROUTE3_CFLAGS@
+LIBNL_ROUTE3_LIBS = @LIBNL_ROUTE3_LIBS@
 LIBOBJS = @LIBOBJS@
 LIBS = @LIBS@
 LIBTOOL = @LIBTOOL@
diff --git a/src/dns-manager/nm-dns-bind.c b/src/dns-manager/nm-dns-bind.c
index fc7af776..55fce030 100644
--- a/src/dns-manager/nm-dns-bind.c
+++ b/src/dns-manager/nm-dns-bind.c
@@ -297,7 +297,8 @@ update (NMDnsPlugin *plugin,
         const GSList *vpn_configs,
         const GSList *dev_configs,
         const GSList *other_configs,
-        const char *hostname)
+        const char *hostname,
+        const char *iface)
 {
 	NMDnsBind *self = NM_DNS_BIND (plugin);
 	NMDnsBindPrivate *priv = NM_DNS_BIND_GET_PRIVATE (self);
diff --git a/src/dns-manager/nm-dns-dnsmasq.c b/src/dns-manager/nm-dns-dnsmasq.c
index 9cc01978..a602c54f 100644
--- a/src/dns-manager/nm-dns-dnsmasq.c
+++ b/src/dns-manager/nm-dns-dnsmasq.c
@@ -133,23 +133,56 @@ add_ip4_config (GString *str, NMIP4Config *ip4, gboolean split)
 	return TRUE;
 }
 
-static gboolean
-ip6_addr_to_string (const struct in6_addr *addr, char *buf, size_t buflen)
+#define IP6_ADDR_BUFLEN (INET6_ADDRSTRLEN + 50)
+
+static char *
+ip6_addr_to_string (const struct in6_addr *addr, const char *iface)
 {
-	memset (buf, 0, buflen);
+	char *buf, *p;
+
+	/* allocate enough space for the address + interface name */
+	buf = g_malloc0 (IP6_ADDR_BUFLEN + 1);
 
 	/* inet_ntop is probably supposed to do this for us, but it doesn't */
-	if (IN6_IS_ADDR_V4MAPPED (addr))
-		return !!inet_ntop (AF_INET, &(addr->s6_addr32[3]), buf, buflen);
+	if (IN6_IS_ADDR_V4MAPPED (addr)) {
+		if (!inet_ntop (AF_INET, &(addr->s6_addr32[3]), buf, IP6_ADDR_BUFLEN))
+			goto error;
+		return buf;
+	}
 
-	return !!inet_ntop (AF_INET6, addr, buf, buflen);
+	if (!inet_ntop (AF_INET6, addr, buf, IP6_ADDR_BUFLEN))
+		goto error;
+
+	/* In the case of addr being a link-local address, inet_ntop can either
+	 * return an address with scope identifier already in place (like
+	 * fe80::202:b3ff:fe8d:7aaf%wlan0) or it returns an address without
+	 * scope identifier at all (like fe80::202:b3ff:fe8d:7aaf)
+	 */
+	p = strchr (buf, '%');
+	if (p) {
+		/* If we got a scope identifier, we need to replace the '%'
+		 * with '@', since dnsmasq supports '%' in server= addresses
+		 * only since version 2.58 and up
+		 */
+		*p = '@';
+	} else if (IN6_IS_ADDR_LINKLOCAL (addr)) {
+		/* If we got no scope identifier at all append the interface name */
+		strncat (buf, "@", IP6_ADDR_BUFLEN - strlen (buf));
+		strncat (buf, iface, IP6_ADDR_BUFLEN - strlen (buf));
+	}
+
+	return buf;
+
+error:
+	g_free (buf);
+	return NULL;
 }
 
 static gboolean
-add_ip6_config (GString *str, NMIP6Config *ip6, gboolean split)
+add_ip6_config (GString *str, NMIP6Config *ip6, gboolean split, const char *iface)
 {
-	char buf[INET6_ADDRSTRLEN + 1];
 	const struct in6_addr *addr;
+	char *buf;
 	int n, i;
 	gboolean added = FALSE;
 
@@ -159,7 +192,8 @@ add_ip6_config (GString *str, NMIP6Config *ip6, gboolean split)
 		 * the first nameserver here.
 		 */
 		addr = nm_ip6_config_get_nameserver (ip6, 0);
-		if (!ip6_addr_to_string (addr, &buf[0], sizeof (buf)))
+		buf = ip6_addr_to_string (addr, iface);
+		if (!buf)
 			return FALSE;
 
 		/* searches are preferred over domains */
@@ -181,6 +215,8 @@ add_ip6_config (GString *str, NMIP6Config *ip6, gboolean split)
 				added = TRUE;
 			}
 		}
+
+		g_free (buf);
 	}
 
 	/* If no searches or domains, just add the namservers */
@@ -188,8 +224,11 @@ add_ip6_config (GString *str, NMIP6Config *ip6, gboolean split)
 		n = nm_ip6_config_get_num_nameservers (ip6);
 		for (i = 0; i < n; i++) {
 			addr = nm_ip6_config_get_nameserver (ip6, i);
-			if (ip6_addr_to_string (addr, &buf[0], sizeof (buf)))
+			buf = ip6_addr_to_string (addr, iface);
+			if (buf) {
 				g_string_append_printf (str, "server=%s\n", buf);
+				g_free (buf);
+			}
 		}
 	}
 
@@ -201,12 +240,13 @@ update (NMDnsPlugin *plugin,
         const GSList *vpn_configs,
         const GSList *dev_configs,
         const GSList *other_configs,
-        const char *hostname)
+        const char *hostname,
+        const char *iface)
 {
 	NMDnsDnsmasq *self = NM_DNS_DNSMASQ (plugin);
 	GString *conf;
 	GSList *iter;
-	const char *argv[10];
+	const char *argv[11];
 	GError *error = NULL;
 	int ignored;
 	GPid pid = 0;
@@ -226,7 +266,7 @@ update (NMDnsPlugin *plugin,
 		if (NM_IS_IP4_CONFIG (iter->data))
 			add_ip4_config (conf, NM_IP4_CONFIG (iter->data), TRUE);
 		else if (NM_IS_IP6_CONFIG (iter->data))
-			add_ip6_config (conf, NM_IP6_CONFIG (iter->data), TRUE);
+			add_ip6_config (conf, NM_IP6_CONFIG (iter->data), TRUE, iface);
 	}
 
 	/* Now add interface configs without split DNS */
@@ -234,7 +274,7 @@ update (NMDnsPlugin *plugin,
 		if (NM_IS_IP4_CONFIG (iter->data))
 			add_ip4_config (conf, NM_IP4_CONFIG (iter->data), FALSE);
 		else if (NM_IS_IP6_CONFIG (iter->data))
-			add_ip6_config (conf, NM_IP6_CONFIG (iter->data), FALSE);
+			add_ip6_config (conf, NM_IP6_CONFIG (iter->data), FALSE, iface);
 	}
 
 	/* And any other random configs */
@@ -242,7 +282,7 @@ update (NMDnsPlugin *plugin,
 		if (NM_IS_IP4_CONFIG (iter->data))
 			add_ip4_config (conf, NM_IP4_CONFIG (iter->data), FALSE);
 		else if (NM_IS_IP6_CONFIG (iter->data))
-			add_ip6_config (conf, NM_IP6_CONFIG (iter->data), FALSE);
+			add_ip6_config (conf, NM_IP6_CONFIG (iter->data), FALSE, iface);
 	}
 
 	/* Write out the config file */
@@ -267,7 +307,8 @@ update (NMDnsPlugin *plugin,
 	argv[5] = "--pid-file=" PIDFILE;
 	argv[6] = "--listen-address=127.0.0.1"; /* Should work for both 4 and 6 */
 	argv[7] = "--conf-file=" CONFFILE;
-	argv[8] = NULL;
+	argv[8] = "--cache-size=400";
+	argv[9] = NULL;
 
 	/* And finally spawn dnsmasq */
 	pid = nm_dns_plugin_child_spawn (NM_DNS_PLUGIN (self), argv, PIDFILE, "bin/dnsmasq");
diff --git a/src/dns-manager/nm-dns-manager.c b/src/dns-manager/nm-dns-manager.c
index 49cd74e5..0203f2bb 100644
--- a/src/dns-manager/nm-dns-manager.c
+++ b/src/dns-manager/nm-dns-manager.c
@@ -711,7 +711,8 @@ update_dns (NMDnsManager *self,
 		                           vpn_configs,
 		                           dev_configs,
 		                           other_configs,
-		                           priv->hostname)) {
+		                           priv->hostname,
+					   iface)) {
 			nm_log_warn (LOGD_DNS, "DNS: plugin %s update failed", plugin_name);
 
 			/* If the plugin failed to update, we shouldn't write out a local
diff --git a/src/dns-manager/nm-dns-plugin.c b/src/dns-manager/nm-dns-plugin.c
index ae230ada..e997948e 100644
--- a/src/dns-manager/nm-dns-plugin.c
+++ b/src/dns-manager/nm-dns-plugin.c
@@ -55,7 +55,8 @@ nm_dns_plugin_update (NMDnsPlugin *self,
                       const GSList *vpn_configs,
                       const GSList *dev_configs,
                       const GSList *other_configs,
-                      const char *hostname)
+                      const char *hostname,
+                      const char *iface)
 {
 	g_return_val_if_fail (NM_DNS_PLUGIN_GET_CLASS (self)->update != NULL, FALSE);
 
@@ -63,7 +64,8 @@ nm_dns_plugin_update (NMDnsPlugin *self,
 	                                               vpn_configs,
 	                                               dev_configs,
 	                                               other_configs,
-	                                               hostname);
+	                                               hostname,
+						       iface);
 }
 
 static gboolean
diff --git a/src/dns-manager/nm-dns-plugin.h b/src/dns-manager/nm-dns-plugin.h
index d4298b86..37dd7336 100644
--- a/src/dns-manager/nm-dns-plugin.h
+++ b/src/dns-manager/nm-dns-plugin.h
@@ -53,7 +53,8 @@ typedef struct {
 	                    const GSList *vpn_configs,
 	                    const GSList *dev_configs,
 	                    const GSList *other_configs,
-	                    const char *hostname);
+	                    const char *hostname,
+	                    const char *iface);
 
 	/* Subclasses should override and return TRUE if they start a local
 	 * caching nameserver that listens on localhost and would block any
@@ -91,7 +92,8 @@ gboolean nm_dns_plugin_update (NMDnsPlugin *self,
                                const GSList *vpn_configs,
                                const GSList *dev_configs,
                                const GSList *other_configs,
-                               const char *hostname);
+                               const char *hostname,
+                               const char *iface);
 
 /* For subclasses/plugins */
 
diff --git a/src/dnsmasq-manager/Makefile.in b/src/dnsmasq-manager/Makefile.in
index 89f55e5e..de3a4478 100644
--- a/src/dnsmasq-manager/Makefile.in
+++ b/src/dnsmasq-manager/Makefile.in
@@ -186,8 +186,16 @@ LIBGCRYPT_LIBS = @LIBGCRYPT_LIBS@
 LIBICONV = @LIBICONV@
 LIBINTL = @LIBINTL@
 LIBM = @LIBM@
+LIBNL1_CFLAGS = @LIBNL1_CFLAGS@
+LIBNL1_LIBS = @LIBNL1_LIBS@
+LIBNL2_CFLAGS = @LIBNL2_CFLAGS@
+LIBNL2_LIBS = @LIBNL2_LIBS@
+LIBNL3_CFLAGS = @LIBNL3_CFLAGS@
+LIBNL3_LIBS = @LIBNL3_LIBS@
 LIBNL_CFLAGS = @LIBNL_CFLAGS@
 LIBNL_LIBS = @LIBNL_LIBS@
+LIBNL_ROUTE3_CFLAGS = @LIBNL_ROUTE3_CFLAGS@
+LIBNL_ROUTE3_LIBS = @LIBNL_ROUTE3_LIBS@
 LIBOBJS = @LIBOBJS@
 LIBS = @LIBS@
 LIBTOOL = @LIBTOOL@
diff --git a/src/ip6-manager/Makefile.in b/src/ip6-manager/Makefile.in
index 33539f51..1912bd59 100644
--- a/src/ip6-manager/Makefile.in
+++ b/src/ip6-manager/Makefile.in
@@ -187,8 +187,16 @@ LIBGCRYPT_LIBS = @LIBGCRYPT_LIBS@
 LIBICONV = @LIBICONV@
 LIBINTL = @LIBINTL@
 LIBM = @LIBM@
+LIBNL1_CFLAGS = @LIBNL1_CFLAGS@
+LIBNL1_LIBS = @LIBNL1_LIBS@
+LIBNL2_CFLAGS = @LIBNL2_CFLAGS@
+LIBNL2_LIBS = @LIBNL2_LIBS@
+LIBNL3_CFLAGS = @LIBNL3_CFLAGS@
+LIBNL3_LIBS = @LIBNL3_LIBS@
 LIBNL_CFLAGS = @LIBNL_CFLAGS@
 LIBNL_LIBS = @LIBNL_LIBS@
+LIBNL_ROUTE3_CFLAGS = @LIBNL_ROUTE3_CFLAGS@
+LIBNL_ROUTE3_LIBS = @LIBNL_ROUTE3_LIBS@
 LIBOBJS = @LIBOBJS@
 LIBS = @LIBS@
 LIBTOOL = @LIBTOOL@
diff --git a/src/ip6-manager/nm-ip6-manager.c b/src/ip6-manager/nm-ip6-manager.c
index 4a5dee58..1c761305 100644
--- a/src/ip6-manager/nm-ip6-manager.c
+++ b/src/ip6-manager/nm-ip6-manager.c
@@ -27,6 +27,8 @@
 
 #include "nm-ip6-manager.h"
 #include "nm-netlink-monitor.h"
+#include "nm-netlink-utils.h"
+#include "nm-netlink-compat.h"
 #include "NetworkManagerUtils.h"
 #include "nm-marshal.h"
 #include "nm-logging.h"
@@ -44,7 +46,7 @@ typedef struct {
 	NMNetlinkMonitor *monitor;
 	GHashTable *devices;
 
-	struct nl_handle *nlh;
+	struct nl_sock *nlh;
 	struct nl_cache *addr_cache, *route_cache;
 
 	guint netlink_id;
@@ -155,7 +157,7 @@ nm_ip6_device_new (NMIP6Manager *manager, int ifindex)
 	}
 
 	device->ifindex = ifindex;
-	device->iface = g_strdup (nm_netlink_index_to_iface (ifindex));
+	device->iface = nm_netlink_index_to_iface (ifindex);
 	if (!device->iface) {
 		nm_log_err (LOGD_IP6, "(%d): could not find interface name from index.",
 		            ifindex);
@@ -549,11 +551,12 @@ 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);
+	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
@@ -589,11 +592,12 @@ 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);
+	nl_cache_include (priv->route_cache, (struct nl_object *)rtnlroute, NULL, NULL);
 	rtnl_route_put (rtnlroute);
 
 	/* As above in process_addr */
@@ -620,6 +624,11 @@ process_prefix (NMIP6Manager *manager, struct nl_msg *msg)
 
 	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);
 
@@ -907,6 +916,13 @@ process_nduseropt (NMIP6Manager *manager, struct nl_msg *msg)
 
 	ndmsg = (struct nduseroptmsg *) NLMSG_DATA (nlmsg_hdr (msg));
 
+	if (!nlmsg_valid_hdr (nlmsg_hdr (msg), sizeof (*ndmsg)) ||
+	    nlmsg_datalen (nlmsg_hdr (msg)) <
+		(ndmsg->nduseropt_opts_len + sizeof (*ndmsg))) {
+		nm_log_dbg (LOGD_IP6, "ignoring invalid nduseropt message");
+		return NULL;
+	}
+
 	if (ndmsg->nduseropt_family != AF_INET6 ||
 		ndmsg->nduseropt_icmp_type != ND_ROUTER_ADVERT ||
 		ndmsg->nduseropt_icmp_code != 0) {
@@ -966,6 +982,19 @@ process_newlink (NMIP6Manager *manager, struct nl_msg *msg)
 	struct nlattr *pi[IFLA_INET6_MAX + 1];
 	int err;
 
+	/* 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,
+	 * we can get rid of this function and just grab IFLA_PROTINFO from
+	 * nm_ip6_device_sync_from_netlink(), then get the IFLA_INET6_FLAGS out of
+	 * the PROTINFO.
+	 */
+	err = nlmsg_parse (hdr, sizeof (*ifi), tb, IFLA_MAX, link_policy);
+	if (err < 0) {
+		nm_log_dbg (LOGD_IP6, "ignoring invalid newlink netlink message "
+				      "while parsing PROTINFO attribute");
+		return NULL;
+	}
+
 	ifi = nlmsg_data (hdr);
 	if (ifi->ifi_family != AF_INET6) {
 		nm_log_dbg (LOGD_IP6, "ignoring netlink message family %d", ifi->ifi_family);
@@ -979,18 +1008,6 @@ process_newlink (NMIP6Manager *manager, struct nl_msg *msg)
 		return 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,
-	 * we can get rid of this function and just grab IFLA_PROTINFO from
-	 * nm_ip6_device_sync_from_netlink(), then get the IFLA_INET6_FLAGS out of
-	 * the PROTINFO.
-	 */
-
-	err = nlmsg_parse (hdr, sizeof (*ifi), tb, IFLA_MAX, link_policy);
-	if (err < 0) {
-		nm_log_dbg (LOGD_IP6, "(%s): error parsing PROTINFO attribute", device->iface);
-		return NULL;
-	}
 	if (!tb[IFLA_PROTINFO]) {
 		nm_log_dbg (LOGD_IP6, "(%s): message had no PROTINFO attribute", device->iface);
 		return NULL;
@@ -1087,7 +1104,7 @@ nm_ip6_manager_prepare_interface (NMIP6Manager *manager,
 		nm_utils_do_sysctl (accept_ra_path, "0\n");
 	} else {
 		device->target_state = NM_IP6_DEVICE_GOT_ADDRESS;
-		nm_utils_do_sysctl (accept_ra_path, "1\n");
+		nm_utils_do_sysctl (accept_ra_path, "2\n");
 	}
 
 	return TRUE;
@@ -1248,7 +1265,7 @@ nm_ip6_manager_get_ip6_config (NMIP6Manager *manager, int ifindex)
 		nm_ip6_route_set_dest (ip6route, dest);
 		nm_ip6_route_set_prefix (ip6route, rtnl_route_get_dst_len (rtnlroute));
 		nm_ip6_route_set_next_hop (ip6route, gateway);
-		metric = rtnl_route_get_metric (rtnlroute, 1);
+		rtnl_route_get_metric(rtnlroute, 1, &metric);
 		if (metric != UINT_MAX)
 			nm_ip6_route_set_metric (ip6route, metric);
 		nm_ip6_config_take_route (config, ip6route);
@@ -1344,8 +1361,10 @@ nm_ip6_manager_init (NMIP6Manager *manager)
 	                                     G_CALLBACK (netlink_notification), manager);
 
 	priv->nlh = nm_netlink_get_default_handle ();
-	priv->addr_cache = rtnl_addr_alloc_cache (priv->nlh);
-	priv->route_cache = rtnl_route_alloc_cache (priv->nlh);
+	rtnl_addr_alloc_cache (priv->nlh, &priv->addr_cache);
+	g_warn_if_fail (priv->addr_cache != NULL);
+	rtnl_route_alloc_cache (priv->nlh, NETLINK_ROUTE, NL_AUTO_PROVIDE, &priv->route_cache);
+	g_warn_if_fail (priv->route_cache != NULL);
 }
 
 static void
diff --git a/src/logging/Makefile.in b/src/logging/Makefile.in
index a85578d9..4606160a 100644
--- a/src/logging/Makefile.in
+++ b/src/logging/Makefile.in
@@ -183,8 +183,16 @@ LIBGCRYPT_LIBS = @LIBGCRYPT_LIBS@
 LIBICONV = @LIBICONV@
 LIBINTL = @LIBINTL@
 LIBM = @LIBM@
+LIBNL1_CFLAGS = @LIBNL1_CFLAGS@
+LIBNL1_LIBS = @LIBNL1_LIBS@
+LIBNL2_CFLAGS = @LIBNL2_CFLAGS@
+LIBNL2_LIBS = @LIBNL2_LIBS@
+LIBNL3_CFLAGS = @LIBNL3_CFLAGS@
+LIBNL3_LIBS = @LIBNL3_LIBS@
 LIBNL_CFLAGS = @LIBNL_CFLAGS@
 LIBNL_LIBS = @LIBNL_LIBS@
+LIBNL_ROUTE3_CFLAGS = @LIBNL_ROUTE3_CFLAGS@
+LIBNL_ROUTE3_LIBS = @LIBNL_ROUTE3_LIBS@
 LIBOBJS = @LIBOBJS@
 LIBS = @LIBS@
 LIBTOOL = @LIBTOOL@
diff --git a/src/logging/nm-logging.c b/src/logging/nm-logging.c
index d8353f27..078f1527 100644
--- a/src/logging/nm-logging.c
+++ b/src/logging/nm-logging.c
@@ -30,10 +30,13 @@
 #include <errno.h>
 #include <sys/wait.h>
 #include <sys/stat.h>
-#include <execinfo.h>
 #include <strings.h>
 #include <string.h>
 
+#ifdef ENABLE_CRASHTRACE
+#include <execinfo.h>
+#endif
+
 #include <glib/gi18n.h>
 
 #include "nm-logging.h"
@@ -262,6 +265,7 @@ _nm_log (const char *loc,
 static void
 fallback_get_backtrace (void)
 {
+#ifdef ENABLE_CRASHTRACE
 	void *frames[64];
 	Dl_info info;
 	size_t size;
@@ -289,6 +293,7 @@ fallback_get_backtrace (void)
 		}
 	}
 	syslog (LOG_CRIT, "******************* END **********************************");
+#endif  /* ENABLE_CRASHTRACE */
 }
 
 
diff --git a/src/main.c b/src/main.c
index 328c253d..b7c0fd5a 100644
--- a/src/main.c
+++ b/src/main.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 - 2010 Red Hat, Inc.
+ * Copyright (C) 2004 - 2011 Red Hat, Inc.
  * Copyright (C) 2005 - 2008 Novell, Inc.
  */
 
@@ -50,14 +50,13 @@
 #include "nm-vpn-manager.h"
 #include "nm-logging.h"
 #include "nm-policy-hosts.h"
+#include "nm-config.h"
 
 #if !defined(NM_DIST_VERSION)
 # define NM_DIST_VERSION VERSION
 #endif
 
 #define NM_DEFAULT_PID_FILE          LOCALSTATEDIR"/run/NetworkManager.pid"
-#define NM_DEFAULT_SYSTEM_CONF_FILE  SYSCONFDIR"/NetworkManager/NetworkManager.conf"
-#define NM_OLD_SYSTEM_CONF_FILE      SYSCONFDIR"/NetworkManager/nm-system-settings.conf"
 #define NM_DEFAULT_SYSTEM_STATE_FILE LOCALSTATEDIR"/lib/NetworkManager/NetworkManager.state"
 
 /*
@@ -310,51 +309,11 @@ done:
 }
 
 static gboolean
-parse_config_file (const char *filename,
-                   char **plugins,
-                   char **dhcp_client,
-                   char ***dns_plugins,
-                   char **log_level,
-                   char **log_domains,
-                   GError **error)
-{
-	GKeyFile *config;
-	gboolean success = FALSE;
-
-	config = g_key_file_new ();
-	if (!config) {
-		g_set_error (error, 0, 0,
-		             "Not enough memory to load config file.");
-		return FALSE;
-	}
-
-	g_key_file_set_list_separator (config, ',');
-	if (!g_key_file_load_from_file (config, filename, G_KEY_FILE_NONE, error))
-		goto out;
-
-	*plugins = g_key_file_get_value (config, "main", "plugins", error);
-	if (*error)
-		goto out;
-
-	*dhcp_client = g_key_file_get_value (config, "main", "dhcp", NULL);
-	*dns_plugins = g_key_file_get_string_list (config, "main", "dns", NULL, NULL);
-
-	*log_level = g_key_file_get_value (config, "logging", "level", NULL);
-	*log_domains = g_key_file_get_value (config, "logging", "domains", NULL);
-
-	success = TRUE;
-
-out:
-	g_key_file_free (config);
-	return success;
-}
-
-static gboolean
 parse_state_file (const char *filename,
                   gboolean *net_enabled,
                   gboolean *wifi_enabled,
                   gboolean *wwan_enabled,
-				  gboolean *wimax_enabled,
+                  gboolean *wimax_enabled,
                   GError **error)
 {
 	GKeyFile *state_file;
@@ -368,13 +327,15 @@ parse_state_file (const char *filename,
 
 	state_file = g_key_file_new ();
 	if (!state_file) {
-		g_set_error (error, 0, 0,
-		             "Not enough memory to load state file.");
+		g_set_error (error, NM_CONFIG_ERROR, NM_CONFIG_ERROR_NO_MEMORY,
+		             "Not enough memory to load state file %s.", filename);
 		return FALSE;
 	}
 
 	g_key_file_set_list_separator (state_file, ',');
 	if (!g_key_file_load_from_file (state_file, filename, G_KEY_FILE_KEEP_COMMENTS, &tmp_error)) {
+		gboolean ret = FALSE;
+
 		/* This is kinda ugly; create the file and directory if it doesn't
 		 * exist yet.  We can't rely on distros necessarily creating the
 		 * /var/lib/NetworkManager for us since we have to ensure that
@@ -384,15 +345,16 @@ parse_state_file (const char *filename,
 		    && tmp_error->code == G_FILE_ERROR_NOENT) {
 			char *data, *dirname;
 			gsize len = 0;
-			gboolean ret = FALSE;
+
+			g_clear_error (&tmp_error);
 
 			/* try to create the directory if it doesn't exist */
 			dirname = g_path_get_dirname (filename);
 			errno = 0;
-			if (mkdir (dirname, 0755) != 0) {
+			if (g_mkdir_with_parents (dirname, 0755) != 0) {
 				if (errno != EEXIST) {
 					g_set_error (error, G_FILE_ERROR, G_FILE_ERROR_ACCES,
-					             "Error creating state directory %s: %d", dirname, errno);
+					             "Error creating state directory %s: %s", dirname, strerror(errno));
 					g_free (dirname);
 					return FALSE;
 				}
@@ -409,53 +371,38 @@ parse_state_file (const char *filename,
 			if (data)
 				ret = g_file_set_contents (filename, data, len, error);
 			g_free (data);
-
-			return ret;
 		} else {
-			g_set_error_literal (error, tmp_error->domain, tmp_error->code, tmp_error->message);
-			g_clear_error (&tmp_error);
+			/* the error is not "No such file or directory" - propagate the error */
+			g_propagate_error (error, tmp_error);
 		}
 
-		/* Otherwise, file probably corrupt or inaccessible */
-		return FALSE;
+		return ret;
 	}
 
 	/* Reading state bits of NetworkManager; an error leaves the passed-in state
 	 * value unchanged.
 	 */
 	net = g_key_file_get_boolean (state_file, "main", "NetworkingEnabled", &tmp_error);
-	if (tmp_error)
-		g_set_error_literal (error, tmp_error->domain, tmp_error->code, tmp_error->message);
-	else
+	if (tmp_error == NULL)
 		*net_enabled = net;
 	g_clear_error (&tmp_error);
 
 	wifi = g_key_file_get_boolean (state_file, "main", "WirelessEnabled", &tmp_error);
-	if (tmp_error) {
-		g_clear_error (error);
-		g_set_error_literal (error, tmp_error->domain, tmp_error->code, tmp_error->message);
-	} else
+	if (tmp_error == NULL)
 		*wifi_enabled = wifi;
 	g_clear_error (&tmp_error);
 
 	wwan = g_key_file_get_boolean (state_file, "main", "WWANEnabled", &tmp_error);
-	if (tmp_error) {
-		g_clear_error (error);
-		g_set_error_literal (error, tmp_error->domain, tmp_error->code, tmp_error->message);
-	} else
+	if (tmp_error == NULL)
 		*wwan_enabled = wwan;
 	g_clear_error (&tmp_error);
 
 	wimax = g_key_file_get_boolean (state_file, "main", "WimaxEnabled", &tmp_error);
-	if (tmp_error) {
-		g_clear_error (error);
-		g_set_error_literal (error, tmp_error->domain, tmp_error->code, tmp_error->message);
-	} else
+	if (tmp_error == NULL)
 		*wimax_enabled = wimax;
 	g_clear_error (&tmp_error);
 
 	g_key_file_free (state_file);
-
 	return TRUE;
 }
 
@@ -469,10 +416,9 @@ main (int argc, char *argv[])
 	GOptionContext *opt_ctx = NULL;
 	gboolean become_daemon = FALSE;
 	gboolean g_fatal_warnings = FALSE;
-	char *pidfile = NULL, *state_file = NULL, *dhcp = NULL;
-	char *config = NULL, *plugins = NULL, *conf_plugins = NULL;
+	char *pidfile = NULL, *state_file = NULL;
+	char *config_path = NULL, *plugins = NULL;
 	char *log_level = NULL, *log_domains = NULL;
-	char **dns = NULL;
 	gboolean wifi_enabled = TRUE, net_enabled = TRUE, wwan_enabled = TRUE, wimax_enabled = TRUE;
 	gboolean success, show_version = FALSE;
 	NMPolicy *policy = NULL;
@@ -482,9 +428,9 @@ main (int argc, char *argv[])
 	NMSupplicantManager *sup_mgr = NULL;
 	NMDHCPManager *dhcp_mgr = NULL;
 	NMSettings *settings = NULL;
+	NMConfig *config;
 	GError *error = NULL;
 	gboolean wrote_pidfile = FALSE;
-	char *cfg_log_level = NULL, *cfg_log_domains = NULL;
 
 	GOptionEntry options[] = {
 		{ "version", 0, 0, G_OPTION_ARG_NONE, &show_version, "Print NetworkManager version and exit", NULL },
@@ -492,7 +438,7 @@ main (int argc, char *argv[])
 		{ "g-fatal-warnings", 0, 0, G_OPTION_ARG_NONE, &g_fatal_warnings, "Make all warnings fatal", NULL },
 		{ "pid-file", 0, 0, G_OPTION_ARG_FILENAME, &pidfile, "Specify the location of a PID file", "filename" },
 		{ "state-file", 0, 0, G_OPTION_ARG_FILENAME, &state_file, "State file location", "/path/to/state.file" },
-		{ "config", 0, 0, G_OPTION_ARG_FILENAME, &config, "Config file location", "/path/to/config.file" },
+		{ "config", 0, 0, G_OPTION_ARG_FILENAME, &config_path, "Config file location", "/path/to/config.file" },
 		{ "plugins", 0, 0, G_OPTION_ARG_STRING, &plugins, "List of plugins separated by ','", "plugin1,plugin2" },
 		{ "log-level", 0, 0, G_OPTION_ARG_STRING, &log_level, "Log level: one of [ERR, WARN, INFO, DEBUG]", "INFO" },
 		{ "log-domains", 0, 0, G_OPTION_ARG_STRING, &log_domains,
@@ -554,58 +500,18 @@ main (int argc, char *argv[])
 	if (check_pidfile (pidfile))
 		exit (1);
 
-	/* Parse the config file */
-	if (config) {
-		if (!parse_config_file (config, &conf_plugins, &dhcp, &dns, &cfg_log_level, &cfg_log_domains, &error)) {
-			fprintf (stderr, "Config file %s invalid: (%d) %s\n",
-			         config,
-			         error ? error->code : -1,
-			         (error && error->message) ? error->message : "unknown");
-			exit (1);
-		}
-	} else {
-		gboolean parsed = FALSE;
-
-		/* Even though we prefer NetworkManager.conf, we need to check the
-		 * old nm-system-settings.conf first to preserve compat with older
-		 * setups.  In package managed systems dropping a NetworkManager.conf
-		 * onto the system would make NM use it instead of nm-system-settings.conf,
-		 * changing behavior during an upgrade.  We don't want that.
-		 */
-
-		/* Try deprecated nm-system-settings.conf first */
-		if (g_file_test (NM_OLD_SYSTEM_CONF_FILE, G_FILE_TEST_EXISTS)) {
-			config = g_strdup (NM_OLD_SYSTEM_CONF_FILE);
-			parsed = parse_config_file (config, &conf_plugins, &dhcp, &dns, &cfg_log_level, &cfg_log_domains, &error);
-			if (!parsed) {
-				fprintf (stderr, "Default config file %s invalid: (%d) %s\n",
-				         config,
-				         error ? error->code : -1,
-				         (error && error->message) ? error->message : "unknown");
-				g_free (config);
-				config = NULL;
-				g_clear_error (&error);
-			}
-		}
-
-		/* Try the preferred NetworkManager.conf last */
-		if (!parsed && g_file_test (NM_DEFAULT_SYSTEM_CONF_FILE, G_FILE_TEST_EXISTS)) {
-			config = g_strdup (NM_DEFAULT_SYSTEM_CONF_FILE);
-			parsed = parse_config_file (config, &conf_plugins, &dhcp, &dns, &cfg_log_level, &cfg_log_domains, &error);
-			if (!parsed) {
-				fprintf (stderr, "Default config file %s invalid: (%d) %s\n",
-				         config,
-				         error ? error->code : -1,
-				         (error && error->message) ? error->message : "unknown");
-				g_free (config);
-				config = NULL;
-				g_clear_error (&error);
-			}
-		}
+	/* Read the config file and CLI overrides */
+	config = nm_config_new (config_path, plugins, log_level, log_domains, &error);
+	if (config == NULL) {
+		fprintf (stderr, "Failed to read configuration: (%d) %s\n",
+		         error ? error->code : -1,
+		         (error && error->message) ? error->message : "unknown");
+		exit (1);
 	}
+
 	/* Logging setup */
-	if (!nm_logging_setup (log_level ? log_level : cfg_log_level,
-	                       log_domains ? log_domains : cfg_log_domains,
+	if (!nm_logging_setup (nm_config_get_log_level (config),
+	                       nm_config_get_log_domains (config),
 	                       &error)) {
 		fprintf (stderr,
 		         _("%s.  Please use --help to see a list of valid options.\n"),
@@ -613,10 +519,6 @@ main (int argc, char *argv[])
 		exit (1);
 	}
 
-	/* Plugins specified with '--plugins' override those of config file */
-	plugins = plugins ? plugins : g_strdup (conf_plugins);
-	g_free (conf_plugins);
-
 	/* Parse the state file */
 	if (!parse_state_file (state_file, &net_enabled, &wifi_enabled, &wwan_enabled, &wimax_enabled, &error)) {
 		fprintf (stderr, "State file %s parsing failed: (%d) %s\n",
@@ -683,8 +585,7 @@ main (int argc, char *argv[])
 	nm_log_info (LOGD_CORE, "NetworkManager (version " NM_DIST_VERSION ") is starting...");
 	success = FALSE;
 
-	if (config)
-		nm_log_info (LOGD_CORE, "Read config file %s", config);
+	nm_log_info (LOGD_CORE, "Read config file %s", nm_config_get_path (config));
 
 	main_loop = g_main_loop_new (NULL, FALSE);
 
@@ -704,22 +605,22 @@ main (int argc, char *argv[])
 		goto done;
 	}
 
-	dns_mgr = nm_dns_manager_get ((const char **) dns);
+	dns_mgr = nm_dns_manager_get (nm_config_get_dns_plugins (config));
 	if (!dns_mgr) {
 		nm_log_err (LOGD_CORE, "failed to start the DNS manager.");
 		goto done;
 	}
 
-	settings = nm_settings_new (config, plugins, &error);
+	settings = nm_settings_new (nm_config_get_path (config),
+	                            nm_config_get_plugins (config),
+	                            &error);
 	if (!settings) {
 		nm_log_err (LOGD_CORE, "failed to initialize settings storage: %s",
 		            error && error->message ? error->message : "(unknown)");
 		goto done;
 	}
 
-	manager = nm_manager_get (settings,
-	                          config,
-	                          plugins,
+	manager = nm_manager_new (settings,
 	                          state_file,
 	                          net_enabled,
 	                          wifi_enabled,
@@ -746,7 +647,7 @@ main (int argc, char *argv[])
 	}
 
 	/* Initialize DHCP manager */
-	dhcp_mgr = nm_dhcp_manager_new (dhcp, &error);
+	dhcp_mgr = nm_dhcp_manager_new (nm_config_get_dhcp_client (config), &error);
 	if (!dhcp_mgr) {
 		nm_log_err (LOGD_CORE, "failed to start the DHCP manager: %s.", error->message);
 		goto done;
@@ -806,17 +707,15 @@ done:
 	if (pidfile && wrote_pidfile)
 		unlink (pidfile);
 
+	nm_config_free (config);
+
 	/* Free options */
 	g_free (pidfile);
 	g_free (state_file);
-	g_free (config);
+	g_free (config_path);
 	g_free (plugins);
-	g_free (dhcp);
-	g_strfreev (dns);
 	g_free (log_level);
 	g_free (log_domains);
-	g_free (cfg_log_level);
-	g_free (cfg_log_domains);
 
 	nm_log_info (LOGD_CORE, "exiting (%s)", success ? "success" : "error");
 	exit (success ? 0 : 1);
diff --git a/src/modem-manager/Makefile.in b/src/modem-manager/Makefile.in
index 2a054f70..c78ed0f3 100644
--- a/src/modem-manager/Makefile.in
+++ b/src/modem-manager/Makefile.in
@@ -189,8 +189,16 @@ LIBGCRYPT_LIBS = @LIBGCRYPT_LIBS@
 LIBICONV = @LIBICONV@
 LIBINTL = @LIBINTL@
 LIBM = @LIBM@
+LIBNL1_CFLAGS = @LIBNL1_CFLAGS@
+LIBNL1_LIBS = @LIBNL1_LIBS@
+LIBNL2_CFLAGS = @LIBNL2_CFLAGS@
+LIBNL2_LIBS = @LIBNL2_LIBS@
+LIBNL3_CFLAGS = @LIBNL3_CFLAGS@
+LIBNL3_LIBS = @LIBNL3_LIBS@
 LIBNL_CFLAGS = @LIBNL_CFLAGS@
 LIBNL_LIBS = @LIBNL_LIBS@
+LIBNL_ROUTE3_CFLAGS = @LIBNL_ROUTE3_CFLAGS@
+LIBNL_ROUTE3_LIBS = @LIBNL_ROUTE3_LIBS@
 LIBOBJS = @LIBOBJS@
 LIBS = @LIBS@
 LIBTOOL = @LIBTOOL@
diff --git a/src/modem-manager/nm-modem-manager.c b/src/modem-manager/nm-modem-manager.c
index f5ade50c..3509d667 100644
--- a/src/modem-manager/nm-modem-manager.c
+++ b/src/modem-manager/nm-modem-manager.c
@@ -29,6 +29,7 @@
 #include "nm-dbus-manager.h"
 #include "nm-modem-types.h"
 #include "nm-marshal.h"
+#include "nm-dbus-glib-types.h"
 
 #define MODEM_POKE_INTERVAL 120
 
@@ -235,6 +236,23 @@ modem_removed (DBusGProxy *proxy, const char *path, gpointer user_data)
 	}
 }
 
+static void
+mm_poke_cb (DBusGProxy *proxy, DBusGProxyCall *call, gpointer user_data)
+{
+	GPtrArray *modems;
+	int i;
+
+	if (dbus_g_proxy_end_call (proxy, call, NULL,
+	                           DBUS_TYPE_G_ARRAY_OF_OBJECT_PATH, &modems,
+	                           G_TYPE_INVALID)) {
+		/* Don't care about the returned value, just free it */
+		for (i = 0; i < modems->len; i++)
+			g_free ((char *) g_ptr_array_index (modems, i));
+		g_ptr_array_free (modems, TRUE);
+	}
+	g_object_unref (proxy);
+}
+
 static gboolean
 poke_modem_cb (gpointer user_data)
 {
@@ -242,6 +260,7 @@ poke_modem_cb (gpointer user_data)
 	NMModemManagerPrivate *priv = NM_MODEM_MANAGER_GET_PRIVATE (self);
 	DBusGConnection *g_connection;
 	DBusGProxy *proxy;
+	DBusGProxyCall *call;
 
 	g_connection = nm_dbus_manager_get_connection (priv->dbus_mgr);
 	proxy = dbus_g_proxy_new_for_name (g_connection,
@@ -249,9 +268,13 @@ poke_modem_cb (gpointer user_data)
 									   MM_DBUS_PATH,
 									   MM_DBUS_INTERFACE);
 
-	dbus_g_proxy_call_no_reply (proxy, "EnumerateDevices", G_TYPE_INVALID);
-	g_object_unref (proxy);
-
+	call = dbus_g_proxy_begin_call_with_timeout (proxy,
+	                                             "EnumerateDevices",
+	                                             mm_poke_cb,
+	                                             NULL,
+	                                             NULL,
+	                                             5000,
+	                                             G_TYPE_INVALID);
 	return TRUE;
 }
 
diff --git a/src/modem-manager/nm-modem.c b/src/modem-manager/nm-modem.c
index 1823e5e6..debfbdf7 100644
--- a/src/modem-manager/nm-modem.c
+++ b/src/modem-manager/nm-modem.c
@@ -640,7 +640,7 @@ static void
 real_deactivate (NMModem *self, NMDevice *device)
 {
 	NMModemPrivate *priv;
-	const char *iface;
+	int ifindex;
 
 	g_return_if_fail (self != NULL);
 	g_return_if_fail (NM_IS_MODEM (self));
@@ -679,11 +679,11 @@ real_deactivate (NMModem *self, NMDevice *device)
 		break;
 	case MM_MODEM_IP_METHOD_STATIC:
 	case MM_MODEM_IP_METHOD_DHCP:
-		iface = nm_device_get_ip_iface (device);
+		ifindex = nm_device_get_ip_ifindex (device);
 		/* FIXME: use AF_UNSPEC here when we have IPv6 support */
-		nm_system_device_flush_routes_with_iface (iface, AF_INET);
-		nm_system_device_flush_addresses_with_iface (iface);
-		nm_system_device_set_up_down_with_iface (iface, FALSE, NULL);
+		nm_system_iface_flush_routes (ifindex, AF_INET);
+		nm_system_iface_flush_addresses (ifindex, AF_UNSPEC);
+		nm_system_iface_set_up (ifindex, FALSE, NULL);
 		break;
 	default:
 		nm_log_err (LOGD_MB, "unknown IP method %d", priv->ip_method);
@@ -775,7 +775,7 @@ nm_modem_hw_is_up (NMModem *self, NMDevice *device)
 
 		state = nm_device_interface_get_state (NM_DEVICE_INTERFACE (device));
 		if (priv->pending_ip4_config || _state_is_active (state))
-			return nm_system_device_is_up (device);
+			return nm_system_iface_is_up (nm_device_get_ip_ifindex (device));
 	}
 
 	return TRUE;
@@ -792,7 +792,7 @@ nm_modem_hw_bring_up (NMModem *self, NMDevice *device, gboolean *no_firmware)
 
 		state = nm_device_interface_get_state (NM_DEVICE_INTERFACE (device));
 		if (priv->pending_ip4_config || _state_is_active (state))
-			return nm_system_device_set_up_down (device, TRUE, no_firmware);
+			return nm_system_iface_set_up (nm_device_get_ip_ifindex (device), TRUE, no_firmware);
 	}
 
 	return TRUE;
diff --git a/src/nm-config.c b/src/nm-config.c
new file mode 100644
index 00000000..71f67d55
--- /dev/null
+++ b/src/nm-config.c
@@ -0,0 +1,247 @@
+/* -*- 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) 2011 Red Hat, Inc.
+ */
+
+#include <config.h>
+#include <string.h>
+#include <stdio.h>
+
+#include "nm-config.h"
+
+#define NM_DEFAULT_SYSTEM_CONF_FILE  SYSCONFDIR"/NetworkManager/NetworkManager.conf"
+#define NM_OLD_SYSTEM_CONF_FILE      SYSCONFDIR"/NetworkManager/nm-system-settings.conf"
+
+struct NMConfig {
+	char *path;
+	char **plugins;
+	char *dhcp_client;
+	char **dns_plugins;
+	char *log_level;
+	char *log_domains;
+};
+
+/************************************************************************/
+
+GQuark
+nm_config_error_quark (void)
+{
+	static GQuark quark = 0;
+	if (!quark)
+		quark = g_quark_from_static_string ("nm-config-error");
+	return quark;
+}
+
+/* This should really be standard. */
+#define ENUM_ENTRY(NAME, DESC) { NAME, "" #NAME "", DESC }
+
+GType
+nm_config_error_get_type (void)
+{
+	static GType etype = 0;
+
+	if (etype == 0) {
+		static const GEnumValue values[] = {
+			/* Not enough memory to parse the config file. */
+			ENUM_ENTRY (NM_CONFIG_ERROR_NO_MEMORY, "NoMemory"),
+			{ 0, 0, 0 }
+		};
+		etype = g_enum_register_static ("NMConfigError", values);
+	}
+	return etype;
+}
+
+/************************************************************************/
+
+const char *
+nm_config_get_path (NMConfig *config)
+{
+	g_return_val_if_fail (config != NULL, NULL);
+
+	return config->path;
+}
+
+const char **
+nm_config_get_plugins (NMConfig *config)
+{
+	g_return_val_if_fail (config != NULL, NULL);
+
+	return (const char **) config->plugins;
+}
+
+const char *
+nm_config_get_dhcp_client (NMConfig *config)
+{
+	g_return_val_if_fail (config != NULL, NULL);
+
+	return config->dhcp_client;
+}
+
+const char **
+nm_config_get_dns_plugins (NMConfig *config)
+{
+	g_return_val_if_fail (config != NULL, NULL);
+
+	return (const char **) config->dns_plugins;
+}
+
+const char *
+nm_config_get_log_level (NMConfig *config)
+{
+	g_return_val_if_fail (config != NULL, NULL);
+
+	return config->log_level;
+}
+
+const char *
+nm_config_get_log_domains (NMConfig *config)
+{
+	g_return_val_if_fail (config != NULL, NULL);
+
+	return config->log_domains;
+}
+
+/************************************************************************/
+
+static gboolean
+fill_from_file (NMConfig *config,
+                const char *path,
+                const char *cli_plugins,
+                const char *cli_log_level,
+                const char *cli_log_domains,
+                GError **error)
+{
+	GKeyFile *kf;
+	gboolean success = FALSE;
+
+	if (g_file_test (path, G_FILE_TEST_EXISTS) == FALSE) {
+		g_set_error (error, G_KEY_FILE_ERROR, G_KEY_FILE_ERROR_NOT_FOUND, "file %s not found", path);
+		return FALSE;
+	}
+
+	kf = g_key_file_new ();
+	if (!kf) {
+		g_set_error (error, NM_CONFIG_ERROR, NM_CONFIG_ERROR_NO_MEMORY,
+		             "Not enough memory to load config file %s", path);
+		return FALSE;
+	}
+
+	g_key_file_set_list_separator (kf, ',');
+	if (g_key_file_load_from_file (kf, path, G_KEY_FILE_NONE, error)) {
+		config->path = g_strdup (path);
+
+		/* CLI provided options override config file options */
+		if (cli_plugins && strlen (cli_plugins))
+			config->plugins = g_strsplit_set (cli_plugins, ",", 0);
+		else
+			config->plugins = g_key_file_get_string_list (kf, "main", "plugins", NULL, NULL);
+
+		config->dhcp_client = g_key_file_get_value (kf, "main", "dhcp", NULL);
+		config->dns_plugins = g_key_file_get_string_list (kf, "main", "dns", NULL, NULL);
+
+		if (cli_log_level && strlen (cli_log_level))
+			config->log_level = g_strdup (cli_log_level);
+		else
+			config->log_level = g_key_file_get_value (kf, "logging", "level", NULL);
+
+		if (cli_log_domains && strlen (cli_log_domains))
+			config->log_domains = g_strdup (cli_log_domains);
+		else
+			config->log_domains = g_key_file_get_value (kf, "logging", "domains", NULL);
+		success = TRUE;
+	}
+
+	g_key_file_free (kf);
+	return success;
+}
+
+NMConfig *
+nm_config_new (const char *cli_config_path,
+               const char *cli_plugins,
+               const char *cli_log_level,
+               const char *cli_log_domains,
+               GError **error)
+{
+	NMConfig *config;
+	GError *local = NULL;
+
+	config = g_malloc0 (sizeof (*config));
+
+	if (cli_config_path) {
+		/* Bad user-specific config file path is a hard error */
+		if (!fill_from_file (config, cli_config_path, cli_plugins, cli_log_level, cli_log_domains, error)) {
+			nm_config_free (config);
+			return NULL;
+		}
+		return config;
+	}
+
+	/* Even though we prefer NetworkManager.conf, we need to check the
+	 * old nm-system-settings.conf first to preserve compat with older
+	 * setups.  In package managed systems dropping a NetworkManager.conf
+	 * onto the system would make NM use it instead of nm-system-settings.conf,
+	 * changing behavior during an upgrade.  We don't want that.
+	 */
+
+	/* Try deprecated nm-system-settings.conf first */
+	if (fill_from_file (config, NM_OLD_SYSTEM_CONF_FILE, cli_plugins, cli_log_level, cli_log_domains, &local))
+		return config;
+
+	if (g_error_matches (local, G_KEY_FILE_ERROR, G_KEY_FILE_ERROR_NOT_FOUND) == FALSE) {
+		fprintf (stderr, "Default config file %s invalid: (%d) %s\n",
+		         NM_OLD_SYSTEM_CONF_FILE,
+		         local ? local->code : -1,
+		         (local && local->message) ? local->message : "unknown");
+	}
+	g_clear_error (&local);
+
+	/* Try the standard config file location next */
+	if (fill_from_file (config, NM_DEFAULT_SYSTEM_CONF_FILE, cli_plugins, cli_log_level, cli_log_domains, &local))
+		return config;
+
+	if (g_error_matches (local, G_KEY_FILE_ERROR, G_KEY_FILE_ERROR_NOT_FOUND) == FALSE) {
+		fprintf (stderr, "Default config file %s invalid: (%d) %s\n",
+		         NM_DEFAULT_SYSTEM_CONF_FILE,
+		         local ? local->code : -1,
+		         (local && local->message) ? local->message : "unknown");
+		g_propagate_error (error, local);
+		nm_config_free (config);
+		return NULL;
+	}
+
+	/* ignore error if config file not found */
+	g_clear_error (&local);
+	return config;
+}
+
+void
+nm_config_free (NMConfig *config)
+{
+	g_return_if_fail (config != NULL);
+
+	g_free (config->path);
+	g_strfreev (config->plugins);
+	g_free (config->dhcp_client);
+	g_strfreev (config->dns_plugins);
+	g_free (config->log_level);
+	g_free (config->log_domains);
+
+	memset (config, 0, sizeof (*config));
+	g_free (config);
+}
+
diff --git a/src/nm-config.h b/src/nm-config.h
new file mode 100644
index 00000000..fae344fb
--- /dev/null
+++ b/src/nm-config.h
@@ -0,0 +1,55 @@
+/* -*- 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) 2011 Red Hat, Inc.
+ */
+
+#ifndef NM_CONFIG_H
+#define NM_CONFIG_H
+
+#include <glib.h>
+#include <glib-object.h>
+
+typedef struct NMConfig NMConfig;
+
+typedef enum {
+	NM_CONFIG_ERROR_NO_MEMORY = 0,
+} NMConfigError;
+
+#define NM_CONFIG_ERROR (nm_config_error_quark ())
+GQuark nm_config_error_quark (void);
+#define NM_TYPE_CONFIG_ERROR (nm_config_error_get_type ())
+GType nm_config_error_get_type (void);
+
+
+NMConfig *nm_config_new (const char *cli_config_path,
+                         const char *cli_plugins,
+                         const char *cli_log_level,
+                         const char *cli_log_domains,
+                         GError **error);
+
+const char *nm_config_get_path (NMConfig *config);
+const char **nm_config_get_plugins (NMConfig *config);
+const char *nm_config_get_dhcp_client (NMConfig *config);
+const char **nm_config_get_dns_plugins (NMConfig *config);
+const char *nm_config_get_log_level (NMConfig *config);
+const char *nm_config_get_log_domains (NMConfig *config);
+
+void nm_config_free (NMConfig *config);
+
+#endif /* NM_CONFIG_H */
+
diff --git a/src/nm-crash-logger.c b/src/nm-crash-logger.c
index 9ad0412d..e0e7cbf6 100644
--- a/src/nm-crash-logger.c
+++ b/src/nm-crash-logger.c
@@ -55,6 +55,7 @@ int main (int argc, char ** argv)
 	syslog (LOG_CRIT, "******************* START **********************************");
 	while (!done)
 	{
+		line[sizeof (line) - 1] = '\0';
 		bytes_read = read (out, line, sizeof (line) - 1);
 		if (bytes_read > 0)
 		{
diff --git a/src/nm-device-ethernet.c b/src/nm-device-ethernet.c
index 35b73670..8556c5bd 100644
--- a/src/nm-device-ethernet.c
+++ b/src/nm-device-ethernet.c
@@ -59,6 +59,7 @@
 #include "nm-logging.h"
 #include "nm-properties-changed-signal.h"
 #include "nm-dhcp-manager.h"
+#include "nm-netlink-utils.h"
 
 #include "nm-device-ethernet-glue.h"
 
@@ -546,19 +547,19 @@ real_take_down (NMDevice *dev)
 static gboolean
 real_hw_is_up (NMDevice *device)
 {
-	return nm_system_device_is_up (device);
+	return nm_system_iface_is_up (nm_device_get_ip_ifindex (device));
 }
 
 static gboolean
 real_hw_bring_up (NMDevice *dev, gboolean *no_firmware)
 {
-	return nm_system_device_set_up_down (dev, TRUE, no_firmware);
+	return nm_system_iface_set_up (nm_device_get_ip_ifindex (dev), TRUE, no_firmware);
 }
 
 static void
 real_hw_take_down (NMDevice *dev)
 {
-	nm_system_device_set_up_down (dev, FALSE, NULL);
+	nm_system_iface_set_up (nm_device_get_ip_ifindex (dev), FALSE, NULL);
 }
 
 NMDevice *
@@ -677,7 +678,7 @@ _set_hw_addr (NMDeviceEthernet *self, const guint8 *addr, const char *detail)
 	/* Can't change MAC address while device is up */
 	real_hw_take_down (dev);
 
-	success = nm_system_device_set_mac (iface, (struct ether_addr *) addr);
+	success = nm_system_iface_set_mac (nm_device_get_ip_ifindex (dev), (struct ether_addr *) addr);
 	if (success) {
 		/* MAC address succesfully changed; update the current MAC to match */
 		_update_hw_addr (self, addr);
@@ -1796,73 +1797,19 @@ wired_match_config (NMDevice *self, NMConnection *connection)
 	return TRUE;
 }
 
-typedef struct {
-	int ifindex;
-	NMIP4Address *addr;
-	gboolean found;
-} AddrData;
-
-static void
-check_one_address (struct nl_object *object, void *user_data)
-{
-	AddrData *data = user_data;
-	struct rtnl_addr *addr = (struct rtnl_addr *) object;
-	struct nl_addr *local;
-	struct in_addr tmp;
-
-	if (rtnl_addr_get_ifindex (addr) != data->ifindex)
-		return;
-	if (rtnl_addr_get_family (addr) != AF_INET)
-		return;
-
-	if (nm_ip4_address_get_prefix (data->addr) != rtnl_addr_get_prefixlen (addr))
-		return;
-
-	local = rtnl_addr_get_local (addr);
-	if (nl_addr_get_family (local) != AF_INET)
-		return;
-	if (nl_addr_get_len (local) != sizeof (struct in_addr))
-		return;
-	if (!nl_addr_get_binary_addr (local))
-		return;
-
-	memcpy (&tmp, nl_addr_get_binary_addr (local), nl_addr_get_len (local));
-	if (tmp.s_addr != nm_ip4_address_get_address (data->addr))
-		return;
-
-	/* Yay, found it */
-	data->found = TRUE;
-}
-
 static gboolean
 ip4_match_config (NMDevice *self, NMConnection *connection)
 {
 	NMSettingIP4Config *s_ip4;
-	struct nl_handle *nlh = NULL;
-	struct nl_cache *addr_cache = NULL;
 	int i, num;
 	GSList *leases, *iter;
 	NMDHCPManager *dhcp_mgr;
 	const char *method;
-	int ifindex;
-	AddrData check_data;
-
-	ifindex = nm_device_get_ifindex (self);
 
-	s_ip4 = (NMSettingIP4Config *) nm_connection_get_setting (connection, NM_TYPE_SETTING_IP4_CONFIG);
+	s_ip4 = nm_connection_get_setting_ip4_config (connection);
 	if (!s_ip4)
 		return FALSE;
 
-	/* Read all the device's IP addresses */
-	nlh = nm_netlink_get_default_handle ();
-	if (!nlh)
-		return FALSE;
-
-	addr_cache = rtnl_addr_alloc_cache (nlh);
-	if (!addr_cache)
-		return FALSE;
-	nl_cache_mngt_provide (addr_cache);
-
 	/* Get any saved leases that apply to this connection */
 	dhcp_mgr = nm_dhcp_manager_get ();
 	leases = nm_dhcp_manager_get_lease_config (dhcp_mgr,
@@ -1876,15 +1823,14 @@ ip4_match_config (NMDevice *self, NMConnection *connection)
 
 		/* Find at least one lease's address on the device */
 		for (iter = leases; iter; iter = g_slist_next (iter)) {
-			NMIP4Config *addr = iter->data;
-
-			memset (&check_data, 0, sizeof (check_data));
-			check_data.ifindex = ifindex;
-			check_data.found = FALSE;
-			check_data.addr = nm_ip4_config_get_address (addr, 0);
-
-			nl_cache_foreach (addr_cache, check_one_address, &check_data);
-			if (check_data.found) {
+			NMIP4Config *ip4_config = iter->data;
+			NMIP4Address *addr = nm_ip4_config_get_address (ip4_config, 0);
+			struct in_addr tmp = { .s_addr = nm_ip4_address_get_address (addr) };
+
+			if (addr && nm_netlink_find_address (nm_device_get_ip_ifindex (self),
+			                                     AF_INET,
+			                                     &tmp,
+			                                     nm_ip4_address_get_prefix (addr))) {
 				found = TRUE; /* Yay, device has same address as a lease */
 				break;
 			}
@@ -1908,16 +1854,16 @@ ip4_match_config (NMDevice *self, NMConnection *connection)
 
 	/* Everything below for static addressing */
 
-	/* Find all IP4 addresses of this connection in the device's address list */
+	/* Find all IP4 addresses of this connection on the device */
 	num = nm_setting_ip4_config_get_num_addresses (s_ip4);
 	for (i = 0; i < num; i++) {
-		memset (&check_data, 0, sizeof (check_data));
-		check_data.ifindex = ifindex;
-		check_data.found = FALSE;
-		check_data.addr = nm_setting_ip4_config_get_address (s_ip4, i);
+		NMIP4Address *addr = nm_setting_ip4_config_get_address (s_ip4, i);
+		struct in_addr tmp = { .s_addr = nm_ip4_address_get_address (addr) };
 
-		nl_cache_foreach (addr_cache, check_one_address, &check_data);
-		if (!check_data.found)
+		if (!nm_netlink_find_address (nm_device_get_ip_ifindex (self),
+		                              AF_INET,
+		                              &tmp,
+		                              nm_ip4_address_get_prefix (addr)))
 			return FALSE;
 	}
 
diff --git a/src/nm-device-olpc-mesh.c b/src/nm-device-olpc-mesh.c
index 88322344..ddd5198e 100644
--- a/src/nm-device-olpc-mesh.c
+++ b/src/nm-device-olpc-mesh.c
@@ -271,19 +271,19 @@ error:
 static gboolean
 real_hw_is_up (NMDevice *device)
 {
-	return nm_system_device_is_up (device);
+	return nm_system_iface_is_up (nm_device_get_ip_ifindex (device));
 }
 
 static gboolean
 real_hw_bring_up (NMDevice *dev, gboolean *no_firmware)
 {
-	return nm_system_device_set_up_down (dev, TRUE, no_firmware);
+	return nm_system_iface_set_up (nm_device_get_ip_ifindex (dev), TRUE, no_firmware);
 }
 
 static void
 real_hw_take_down (NMDevice *dev)
 {
-	nm_system_device_set_up_down (dev, FALSE, NULL);
+	nm_system_iface_set_up (nm_device_get_ip_ifindex (dev), FALSE, NULL);
 }
 
 static gboolean
@@ -653,7 +653,7 @@ dispose (GObject *object)
 
 	device_cleanup (self);
 
-	manager = nm_manager_get (NULL, NULL, NULL, NULL, FALSE, FALSE, FALSE, FALSE, NULL);
+	manager = nm_manager_get ();
 	if (priv->device_added_id)
 		g_signal_handler_disconnect (manager, priv->device_added_id);
 	g_object_unref (manager);
@@ -852,7 +852,7 @@ is_companion (NMDeviceOlpcMesh *self, NMDevice *other)
 	priv->companion = other;
 
 	/* When we've found the companion, stop listening for other devices */
-	manager = nm_manager_get (NULL, NULL, NULL, NULL, FALSE, FALSE, FALSE, FALSE, NULL);
+	manager = nm_manager_get ();
 	if (priv->device_added_id) {
 		g_signal_handler_disconnect (manager, priv->device_added_id);
 		priv->device_added_id = 0;
@@ -907,7 +907,7 @@ check_companion_cb (gpointer user_data)
 	if (priv->device_added_id != 0)
 		return FALSE;
 
-	manager = nm_manager_get (NULL, NULL, NULL, NULL, FALSE, FALSE, FALSE, FALSE, NULL);
+	manager = nm_manager_get ();
 
 	priv->device_added_id = g_signal_connect (manager, "device-added",
 	                                          G_CALLBACK (device_added_cb), self);
diff --git a/src/nm-device-wifi.c b/src/nm-device-wifi.c
index 278d9a06..9695c077 100644
--- a/src/nm-device-wifi.c
+++ b/src/nm-device-wifi.c
@@ -1133,7 +1133,7 @@ out:
 static gboolean
 real_hw_is_up (NMDevice *device)
 {
-	return nm_system_device_is_up (device);
+	return nm_system_iface_is_up (nm_device_get_ip_ifindex (device));
 }
 
 static gboolean
@@ -1142,13 +1142,13 @@ real_hw_bring_up (NMDevice *device, gboolean *no_firmware)
 	if (!NM_DEVICE_WIFI_GET_PRIVATE (device)->enabled)
 		return FALSE;
 
-	return nm_system_device_set_up_down (device, TRUE, no_firmware);
+	return nm_system_iface_set_up (nm_device_get_ip_ifindex (device), TRUE, no_firmware);
 }
 
 static void
-real_hw_take_down (NMDevice *dev)
+real_hw_take_down (NMDevice *device)
 {
-	nm_system_device_set_up_down (dev, FALSE, NULL);
+	nm_system_iface_set_up (nm_device_get_ip_ifindex (device), FALSE, NULL);
 }
 
 static gboolean
@@ -1209,7 +1209,7 @@ _set_hw_addr (NMDeviceWifi *self, const guint8 *addr, const char *detail)
 	/* Can't change MAC address while device is up */
 	real_hw_take_down (dev);
 
-	success = nm_system_device_set_mac (iface, (struct ether_addr *) addr);
+	success = nm_system_iface_set_mac (nm_device_get_ip_ifindex (dev), (struct ether_addr *) addr);
 	if (success) {
 		/* MAC address succesfully changed; update the current MAC to match */
 		_update_hw_addr (self, addr);
@@ -1690,7 +1690,7 @@ nm_device_wifi_get_address (NMDeviceWifi *self,
 }
 
 static void
-nm_device_wifi_ap_list_print (NMDeviceWifi *self)
+ap_list_dump (NMDeviceWifi *self)
 {
 	NMDeviceWifiPrivate *priv = NM_DEVICE_WIFI_GET_PRIVATE (self);
 	GSList * elt;
@@ -1701,7 +1701,7 @@ nm_device_wifi_ap_list_print (NMDeviceWifi *self)
 	nm_log_dbg (LOGD_WIFI_SCAN, "Current AP list:");
 	for (elt = priv->ap_list; elt; elt = g_slist_next (elt), i++) {
 		NMAccessPoint * ap = NM_AP (elt->data);
-		nm_ap_print_self (ap, "AP: ");
+		nm_ap_dump (ap, "List AP: ");
 	}
 	nm_log_dbg (LOGD_WIFI_SCAN, "Current AP list: done");
 }
@@ -2180,91 +2180,20 @@ supplicant_iface_scan_done_cb (NMSupplicantInterface *iface,
 		 * happens when there are actual scan results to process.
 		 */
 		cull_scan_list (self);
-		nm_device_wifi_ap_list_print (self);
+		ap_list_dump (self);
 	}
 #endif
 }
 
-static gboolean
-is_encrypted (guint32 flags, guint32 wpa_flags, guint32 rsn_flags)
-{
-	if (flags & NM_802_11_AP_FLAGS_PRIVACY)
-		return TRUE;
-	if (wpa_flags & (NM_802_11_AP_SEC_KEY_MGMT_PSK | NM_802_11_AP_SEC_KEY_MGMT_802_1X))
-		return TRUE;
-	if (rsn_flags & (NM_802_11_AP_SEC_KEY_MGMT_PSK | NM_802_11_AP_SEC_KEY_MGMT_802_1X))
-		return TRUE;
-
-	return FALSE;
-}
-
-/*
- * ap_auth_enforced
- *
- * Checks whether or not there is an encryption key present for
- * this connection, and whether or not the authentication method
- * in use will result in an authentication rejection if the key
- * is wrong.  For example, Ad Hoc mode networks don't have a
- * master node and therefore nothing exists to reject the station.
- * Similarly, Open System WEP access points don't reject a station
- * when the key is wrong.  Shared Key WEP access points will.
- *
- */
-static gboolean
-ap_auth_enforced (NMConnection *connection,
-                  NMAccessPoint *ap,
-                  gboolean *encrypted)
-{
-	guint32 flags, wpa_flags, rsn_flags;
-	gboolean enforced = FALSE;
-
-	g_return_val_if_fail (NM_IS_AP (ap), FALSE);
-	g_return_val_if_fail (NM_IS_CONNECTION (connection), FALSE);
-	g_return_val_if_fail (encrypted != NULL, FALSE);
-
-	flags = nm_ap_get_flags (ap);
-	wpa_flags = nm_ap_get_wpa_flags (ap);
-	rsn_flags = nm_ap_get_rsn_flags (ap);
-
-	if (nm_ap_get_mode (ap) == NM_802_11_MODE_ADHOC)
-		goto out;
-
-	/* Static WEP */
-	if (   (flags & NM_802_11_AP_FLAGS_PRIVACY)
-        && (wpa_flags == NM_802_11_AP_SEC_NONE)
-        && (rsn_flags == NM_802_11_AP_SEC_NONE)) {
-		NMSettingWirelessSecurity *s_wireless_sec;
-		const char *auth_alg;
-
-		/* No way to tell if the key is wrong with Open System
-		 * auth mode in WEP.  Auth is not enforced like Shared Key.
-		 */
-		s_wireless_sec = (NMSettingWirelessSecurity *) nm_connection_get_setting (connection, 
-																    NM_TYPE_SETTING_WIRELESS_SECURITY);
-		if (s_wireless_sec) {
-			auth_alg = nm_setting_wireless_security_get_auth_alg (s_wireless_sec);
-			if (!auth_alg || !strcmp (auth_alg, "open"))
-				goto out;
-		}
-
-		enforced = TRUE;
-	} else if (wpa_flags != NM_802_11_AP_SEC_NONE) { /* WPA */
-		enforced = TRUE;
-	} else if (rsn_flags != NM_802_11_AP_SEC_NONE) { /* WPA2 */
-		enforced = TRUE;
-	}
-
-out:
-	*encrypted = is_encrypted (flags, wpa_flags, rsn_flags);
-	return enforced;
-}
-
 
 /****************************************************************************
  * WPA Supplicant control stuff
  *
  */
 
+#define MAC_FMT "%02x:%02x:%02x:%02x:%02x:%02x"
+#define MAC_ARG(x) ((guint8*)(x))[0],((guint8*)(x))[1],((guint8*)(x))[2],((guint8*)(x))[3],((guint8*)(x))[4],((guint8*)(x))[5]
+
 /*
  * merge_scanned_ap
  *
@@ -2284,16 +2213,33 @@ merge_scanned_ap (NMDeviceWifi *self,
 	NMDeviceWifiPrivate *priv = NM_DEVICE_WIFI_GET_PRIVATE (self);
 	NMAccessPoint *found_ap = NULL;
 	const GByteArray *ssid;
+	const struct ether_addr *bssid;
 	gboolean strict_match = TRUE;
 	NMAccessPoint *current_ap = NULL;
 
 	/* Let the manager try to fill in the SSID from seen-bssids lists
 	 * if it can
 	 */
+	bssid = nm_ap_get_address (merge_ap);
 	ssid = nm_ap_get_ssid (merge_ap);
 	if (!ssid || nm_utils_is_empty_ssid (ssid->data, ssid->len)) {
+		/* Let the manager try to fill the AP's SSID from the database */
 		g_signal_emit (self, signals[HIDDEN_AP_FOUND], 0, merge_ap);
-		nm_ap_set_broadcast (merge_ap, FALSE);
+
+		ssid = nm_ap_get_ssid (merge_ap);
+		if (ssid && (nm_utils_is_empty_ssid (ssid->data, ssid->len) == FALSE)) {
+			/* Yay, matched it, no longer treat as hidden */
+			nm_log_dbg (LOGD_WIFI_SCAN, "(%s): matched hidden AP " MAC_FMT " => '%s'",
+			            nm_device_get_iface (NM_DEVICE (self)),
+			            MAC_ARG (bssid->ether_addr_octet),
+			            nm_utils_escape_ssid (ssid->data, ssid->len));
+			nm_ap_set_broadcast (merge_ap, FALSE);
+		} else {
+			/* Didn't have an entry for this AP in the database */
+			nm_log_dbg (LOGD_WIFI_SCAN, "(%s): failed to match hidden AP " MAC_FMT,
+			            nm_device_get_iface (NM_DEVICE (self)),
+			            MAC_ARG (bssid->ether_addr_octet));
+		}
 	}
 
 	/* If the incoming scan result matches the hidden AP that NM is currently
@@ -2308,6 +2254,13 @@ merge_scanned_ap (NMDeviceWifi *self,
 
 	found_ap = nm_ap_match_in_list (merge_ap, priv->ap_list, strict_match);
 	if (found_ap) {
+		nm_log_dbg (LOGD_WIFI_SCAN, "(%s): merging AP '%s' " MAC_FMT " (%p) with existing (%p)",
+		            nm_device_get_iface (NM_DEVICE (self)),
+		            ssid ? nm_utils_escape_ssid (ssid->data, ssid->len) : "(none)",
+		            MAC_ARG (bssid->ether_addr_octet),
+		            merge_ap,
+		            found_ap);
+
 		nm_ap_set_flags (found_ap, nm_ap_get_flags (merge_ap));
 		nm_ap_set_wpa_flags (found_ap, nm_ap_get_wpa_flags (merge_ap));
 		nm_ap_set_rsn_flags (found_ap, nm_ap_get_rsn_flags (merge_ap));
@@ -2323,7 +2276,12 @@ merge_scanned_ap (NMDeviceWifi *self,
 		nm_ap_set_fake (found_ap, FALSE);
 	} else {
 		/* New entry in the list */
-		// FIXME: figure out if reference counts are correct here for AP objects
+		nm_log_dbg (LOGD_WIFI_SCAN, "(%s): adding new AP '%s' " MAC_FMT " (%p)",
+		            nm_device_get_iface (NM_DEVICE (self)),
+		            ssid ? nm_utils_escape_ssid (ssid->data, ssid->len) : "(none)",
+		            MAC_ARG (bssid->ether_addr_octet),
+		            merge_ap);
+
 		g_object_ref (merge_ap);
 		priv->ap_list = g_slist_prepend (priv->ap_list, merge_ap);
 		nm_ap_export_to_dbus (merge_ap);
@@ -2421,7 +2379,7 @@ supplicant_iface_new_bss_cb (NMSupplicantInterface *iface,
 
 	ap = nm_ap_new_from_properties (properties);
 	if (ap) {
-		nm_ap_print_self (ap, "AP: ");
+		nm_ap_dump (ap, "New AP: ");
 
 		/* Add the AP to the device's AP list */
 		merge_scanned_ap (self, ap);
@@ -2430,7 +2388,7 @@ supplicant_iface_new_bss_cb (NMSupplicantInterface *iface,
 		/* Remove outdated access points */
 		cull_scan_list (self);
 
-		nm_device_wifi_ap_list_print (self);
+		ap_list_dump (self);
 	} else {
 		nm_log_warn (LOGD_WIFI_SCAN, "(%s): invalid AP properties received",
 		             nm_device_get_iface (NM_DEVICE (self)));
@@ -2512,7 +2470,7 @@ link_timeout_cb (gpointer user_data)
 }
 
 static gboolean
-handle_authenticate_fail (NMDeviceWifi *self, guint32 new_state, guint32 old_state)
+handle_8021x_auth_fail (NMDeviceWifi *self, guint32 new_state, guint32 old_state)
 {
 	NMDevice *device = NM_DEVICE (self);
 	NMSetting8021x *s_8021x;
@@ -2643,18 +2601,21 @@ supplicant_iface_state_cb (NMSupplicantInterface *iface,
 		break;
 	case NM_SUPPLICANT_INTERFACE_STATE_DISCONNECTED:
 		if ((devstate == NM_DEVICE_STATE_ACTIVATED) || nm_device_is_activating (device)) {
-			/* Disconnect during authentication means the 802.1x password is wrong */
-			if (handle_authenticate_fail (self, new_state, old_state))
+			/* Disconnect of an 802.1x/LEAP connection during authentication
+			 * means secrets might be wrong. Not always the case, but until we
+			 * have more information from wpa_supplicant about why the
+			 * disconnect happened this is the best we can do.
+			 */
+			if (handle_8021x_auth_fail (self, new_state, old_state))
 				break;
 		}
 
+		/* Otherwise it might be a stupid driver or some transient error, so
+		 * let the supplicant try to reconnect a few more times.  Give it more
+		 * time if a scan is in progress since the link might be dropped during
+		 * the scan but will be re-established when the scan is done.
+		 */
 		if (devstate == NM_DEVICE_STATE_ACTIVATED) {
-			/* If it's a disconnect while activated then start the link timer
-			 * to let the supplicant reconnect for a bit and if that doesn't
-			 * work kill the connection and try something else.  Allow a bit
-			 * more time if the card is scanning since sometimes the link will
-			 * drop while scanning and come back when the scan is done.
-			 */
 			if (priv->link_timeout_id == 0)
 				priv->link_timeout_id = g_timeout_add_seconds (scanning ? 30 : 15, link_timeout_cb, self);
 		}
@@ -2756,7 +2717,7 @@ supplicant_iface_notify_scanning_cb (NMSupplicantInterface *iface,
 	scanning = nm_supplicant_interface_get_scanning (iface);
 	nm_log_dbg (LOGD_WIFI_SCAN, "(%s): now %s",
 	            nm_device_get_iface (NM_DEVICE (self)),
-	            scanning ? "scanning" : "not scanning");
+	            scanning ? "scanning" : "idle");
 
 	g_object_notify (G_OBJECT (self), "scanning");
 }
@@ -2826,6 +2787,29 @@ handle_auth_or_fail (NMDeviceWifi *self,
 	return ret;
 }
 
+static gboolean
+is_encrypted (NMAccessPoint *ap, NMConnection *connection)
+{
+	NM80211ApFlags flags;
+	NM80211ApSecurityFlags wpa_flags, rsn_flags;
+
+	g_return_val_if_fail (ap != NULL, FALSE);
+	g_return_val_if_fail (connection != NULL, FALSE);
+
+	flags = nm_ap_get_flags (ap);
+	wpa_flags = nm_ap_get_wpa_flags (ap);
+	rsn_flags = nm_ap_get_rsn_flags (ap);
+
+	if (flags & NM_802_11_AP_FLAGS_PRIVACY)
+		return TRUE;
+	if (wpa_flags & (NM_802_11_AP_SEC_KEY_MGMT_PSK | NM_802_11_AP_SEC_KEY_MGMT_802_1X))
+		return TRUE;
+	if (rsn_flags & (NM_802_11_AP_SEC_KEY_MGMT_PSK | NM_802_11_AP_SEC_KEY_MGMT_802_1X))
+		return TRUE;
+
+	return FALSE;
+}
+
 /*
  * supplicant_connection_timeout_cb
  *
@@ -2835,11 +2819,10 @@ handle_auth_or_fail (NMDeviceWifi *self,
 static gboolean
 supplicant_connection_timeout_cb (gpointer user_data)
 {
-	NMDevice *              dev = NM_DEVICE (user_data);
-	NMDeviceWifi * self = NM_DEVICE_WIFI (user_data);
-	NMAccessPoint *         ap;
-	NMActRequest *          req;
-	gboolean                auth_enforced = FALSE, encrypted = FALSE;
+	NMDevice *dev = NM_DEVICE (user_data);
+	NMDeviceWifi *self = NM_DEVICE_WIFI (user_data);
+	NMAccessPoint *ap;
+	NMActRequest *req;
 	NMConnection *connection;
 
 	cleanup_association_attempt (self, TRUE);
@@ -2847,10 +2830,10 @@ supplicant_connection_timeout_cb (gpointer user_data)
 	if (!nm_device_is_activating (dev))
 		return FALSE;
 
-	/* Timed out waiting for authentication success; if the security in use
-	 * does not require access point side authentication (Open System
-	 * WEP, for example) then we are likely using the wrong authentication
-	 * algorithm or key.  Request new one from the user.
+	/* Timed out waiting for a successful connection to the AP; if the AP's
+	 * security requires network-side authentication (like WPA or 802.1x)
+	 * and the connection attempt timed out then it's likely the authentication
+	 * information (passwords, pin codes, etc) are wrong.
 	 */
 
 	req = nm_device_get_act_request (dev);
@@ -2862,16 +2845,24 @@ supplicant_connection_timeout_cb (gpointer user_data)
 	ap = nm_device_wifi_get_activation_ap (self);
 	g_assert (ap);
 
-	auth_enforced = ap_auth_enforced (connection, ap, &encrypted);
-	if (!encrypted) {
+	if (nm_ap_get_mode (ap) == NM_802_11_MODE_ADHOC) {
+		/* In Ad-Hoc mode there's nothing to check the encryption key (if any)
+		 * so supplicant timeouts here are almost certainly the wifi driver
+		 * being really stupid.
+		 */
 		nm_log_warn (LOGD_DEVICE | LOGD_WIFI,
-		             "Activation (%s/wireless): association took too long, "
-		             "failing activation.",
+		             "Activation (%s/wireless): Ad-Hoc network creation took "
+		             "too long, failing activation.",
 		             nm_device_get_iface (dev));
 		nm_device_state_changed (dev, NM_DEVICE_STATE_FAILED,
 		                         NM_DEVICE_STATE_REASON_SUPPLICANT_TIMEOUT);
-	} else {
-		/* Authentication failed, encryption key is probably bad */
+		return FALSE;
+	}
+
+	if (is_encrypted (ap, connection)) {
+		/* Connection failed; either driver problems, the encryption key is
+		 * wrong, or the passwords or certificates were wrong.
+		 */
 		nm_log_warn (LOGD_DEVICE | LOGD_WIFI,
 		             "Activation (%s/wireless): association took too long.",
 		             nm_device_get_iface (dev));
@@ -2884,6 +2875,13 @@ supplicant_connection_timeout_cb (gpointer user_data)
 			nm_device_state_changed (dev, NM_DEVICE_STATE_FAILED,
 			                         NM_DEVICE_STATE_REASON_NO_SECRETS);
 		}
+	} else {
+		nm_log_warn (LOGD_DEVICE | LOGD_WIFI,
+		             "Activation (%s/wireless): association took too long, "
+		             "failing activation.",
+		             nm_device_get_iface (dev));
+		nm_device_state_changed (dev, NM_DEVICE_STATE_FAILED,
+		                         NM_DEVICE_STATE_REASON_SUPPLICANT_TIMEOUT);
 	}
 
 	return FALSE;
@@ -3323,6 +3321,34 @@ real_act_stage4_get_ip4_config (NMDevice *dev,
 	return ret;
 }
 
+static gboolean
+is_static_wep (NMAccessPoint *ap, NMConnection *connection)
+{
+	NM80211ApFlags flags;
+	NM80211ApSecurityFlags wpa_flags, rsn_flags;
+	NMSettingWirelessSecurity *s_wsec;
+	const char *key_mgmt;
+
+	g_return_val_if_fail (ap != NULL, FALSE);
+	g_return_val_if_fail (connection != NULL, FALSE);
+
+	flags = nm_ap_get_flags (ap);
+	wpa_flags = nm_ap_get_wpa_flags (ap);
+	rsn_flags = nm_ap_get_rsn_flags (ap);
+
+	if (   (flags & NM_802_11_AP_FLAGS_PRIVACY)
+	    && (wpa_flags == NM_802_11_AP_SEC_NONE)
+	    && (rsn_flags == NM_802_11_AP_SEC_NONE)) {
+		s_wsec = nm_connection_get_setting_wireless_security (connection);
+		if (s_wsec) {
+			key_mgmt = nm_setting_wireless_security_get_key_mgmt (s_wsec);
+			if (g_strcmp0 (key_mgmt, "none") == 0)
+				return TRUE;
+		}
+	}
+
+	return FALSE;
+}
 
 static NMActStageReturn
 handle_ip_config_timeout (NMDeviceWifi *self,
@@ -3333,20 +3359,20 @@ handle_ip_config_timeout (NMDeviceWifi *self,
 {
 	NMAccessPoint *ap;
 	NMActStageReturn ret = NM_ACT_STAGE_RETURN_FAILURE;
-	gboolean auth_enforced = FALSE, encrypted = FALSE;
 
 	g_return_val_if_fail (connection != NULL, NM_ACT_STAGE_RETURN_FAILURE);
 
 	ap = nm_device_wifi_get_activation_ap (self);
 	g_assert (ap);
 
-	/* If nothing checks the security authentication information (as in
-	 * Open System WEP for example), and DHCP times out, then
-	 * the encryption key is likely wrong.  Ask the user for a new one.
-	 * Otherwise the failure likely happened after a successful authentication.
+	/* If IP configuration times out and it's a static WEP connection, that
+	 * usually means the WEP key is wrong.  WEP's Open System auth mode has
+	 * no provision for figuring out if the WEP key is wrong, so you just have
+	 * to wait for DHCP to fail to figure it out.  For all other WiFi security
+	 * types (open, WPA, 802.1x, etc) if the secrets/certs were wrong the
+	 * connection would have failed before IP configuration.
 	 */
-	auth_enforced = ap_auth_enforced (connection, ap, &encrypted);
-	if (encrypted && !auth_enforced && !may_fail) {
+	if (is_static_wep (ap, connection) && (may_fail == FALSE)) {
 		/* Activation failed, we must have bad encryption key */
 		nm_log_warn (LOGD_DEVICE | LOGD_WIFI,
 		             "Activation (%s/wireless): could not get IP configuration for "
@@ -3363,10 +3389,7 @@ handle_ip_config_timeout (NMDeviceWifi *self,
 			*reason = NM_DEVICE_STATE_REASON_NO_SECRETS;
 		}
 	} else {
-		/* Non-encrypted network or authentication is enforced by some
-		 * entity (AP, RADIUS server, etc), but IP configure failed. Let the
-		 * superclass handle it.
-		 */
+		/* Not static WEP or failure allowed; let superclass handle it */
 		*chain_up = TRUE;
 	}
 
diff --git a/src/nm-device.c b/src/nm-device.c
index 1301197a..a4cd3e93 100644
--- a/src/nm-device.c
+++ b/src/nm-device.c
@@ -25,7 +25,6 @@
 #include <dbus/dbus.h>
 #include <netinet/in.h>
 #include <string.h>
-#include <net/if.h>
 #include <unistd.h>
 #include <errno.h>
 #include <sys/ioctl.h>
@@ -34,6 +33,7 @@
 #include <sys/wait.h>
 #include <arpa/inet.h>
 #include <fcntl.h>
+#include <linux/if.h>
 
 #include "nm-glib-compat.h"
 #include "nm-device-interface.h"
@@ -47,6 +47,8 @@
 #include "nm-utils.h"
 #include "nm-logging.h"
 #include "nm-netlink-monitor.h"
+#include "nm-netlink-utils.h"
+#include "nm-netlink-compat.h"
 #include "nm-setting-ip4-config.h"
 #include "nm-setting-ip6-config.h"
 #include "nm-setting-connection.h"
@@ -187,6 +189,8 @@ static void addrconf6_cleanup (NMDevice *self);
 static void dhcp6_cleanup (NMDevice *self, gboolean stop, gboolean release);
 static void dhcp4_cleanup (NMDevice *self, gboolean stop, gboolean release);
 
+static const char *reason_to_string (NMDeviceStateReason reason);
+
 
 static void
 device_interface_init (NMDeviceInterface *device_interface_class)
@@ -1569,8 +1573,11 @@ nm_device_dhcp4_renew (NMDevice *self, gboolean release)
 
 	g_return_val_if_fail (priv->dhcp4_client != NULL, FALSE);
 
+	nm_log_info (LOGD_DHCP4, "(%s): DHCPv4 lease renewal requested",
+	             nm_device_get_iface (self));
+
 	/* Terminate old DHCP instance and release the old lease */
-	dhcp4_cleanup (self, TRUE, TRUE);
+	dhcp4_cleanup (self, TRUE, release);
 
 	req = nm_device_get_act_request (self);
 	g_assert (req);
@@ -1591,16 +1598,15 @@ real_act_stage3_ip4_config_start (NMDevice *self, NMDeviceStateReason *reason)
 	NMSettingIP4Config *s_ip4;
 	NMActRequest *req;
 	NMActStageReturn ret = NM_ACT_STAGE_RETURN_SUCCESS;
-	const char *ip_iface, *method = NULL;
+	const char *method = NULL;
+	int ifindex;
 
 	g_return_val_if_fail (reason != NULL, NM_ACT_STAGE_RETURN_FAILURE);
 
-	/* Use the IP interface (not the control interface) for IP stuff */
-	ip_iface = nm_device_get_ip_iface (self);
-
 	/* Make sure the interface is up before trying to do anything with it */
-	if (!nm_system_device_is_up_with_iface (ip_iface))
-		nm_system_device_set_up_down_with_iface (ip_iface, TRUE, NULL);
+	ifindex = nm_device_get_ip_ifindex (self);
+	if (!nm_system_iface_is_up (ifindex))
+		nm_system_iface_set_up (ifindex, TRUE, NULL);
 
 	req = nm_device_get_act_request (self);
 	connection = nm_act_request_get_connection (req);
@@ -1680,10 +1686,10 @@ dhcp6_start (NMDevice *self,
 	 */
 	err = nm_system_set_ip6_route (priv->ip_iface ? priv->ip_ifindex : priv->ifindex,
 	                               &dest, 8, NULL, 256, 0, RTPROT_BOOT, RT_TABLE_LOCAL, NULL);
-	if (err && (nl_get_errno () != EEXIST)) {
+	if (err && (err != -NLE_EXIST)) {
 		nm_log_err (LOGD_DEVICE | LOGD_IP6,
 		            "(%s): failed to add IPv6 multicast route: %s",
-		            priv->ip_iface ? priv->ip_iface : priv->iface, nl_geterror ());
+		            priv->ip_iface ? priv->ip_iface : priv->iface, nl_geterror (err));
 	}
 
 	s_ip6 = (NMSettingIP6Config *) nm_connection_get_setting (connection, NM_TYPE_SETTING_IP6_CONFIG);
@@ -2522,7 +2528,7 @@ start_sharing (NMDevice *self)
 	add_share_rule (req, "filter", "FORWARD --in-interface %s --out-interface %s --jump ACCEPT", ip_iface, ip_iface);
 	add_share_rule (req, "filter", "FORWARD --source %s/%s --in-interface %s --jump ACCEPT", str_addr, str_mask, ip_iface);
 	add_share_rule (req, "filter", "FORWARD --destination %s/%s --out-interface %s --match state --state ESTABLISHED,RELATED --jump ACCEPT", str_addr, str_mask, ip_iface);
-	add_share_rule (req, "nat", "POSTROUTING --source %s/%s --destination ! %s/%s --jump MASQUERADE", str_addr, str_mask, str_addr, str_mask);
+	add_share_rule (req, "nat", "POSTROUTING --source %s/%s ! --destination %s/%s --jump MASQUERADE", str_addr, str_mask, str_addr, str_mask);
 
 	nm_act_request_set_shared (req, TRUE);
 
@@ -2820,14 +2826,15 @@ nm_device_deactivate (NMDeviceInterface *device, NMDeviceStateReason reason)
 	NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE (self);
 	NMDeviceStateReason ignored = NM_DEVICE_STATE_REASON_NONE;
 	gboolean tried_ipv6 = FALSE;
+	int ifindex, family;
 
 	g_return_if_fail (self != NULL);
 
-	nm_log_info (LOGD_DEVICE, "(%s): deactivating device (reason: %d).",
-	             nm_device_get_iface (self), reason);
+	nm_log_info (LOGD_DEVICE, "(%s): deactivating device (reason '%s') [%d]",
+	             nm_device_get_iface (self), reason_to_string (reason), reason);
 
 	/* Save whether or not we tried IPv6 for later */
-	if (NM_DEVICE_GET_PRIVATE (self)->ip6_manager)
+	if (priv->ip6_manager || priv->ip6_config)
 		tried_ipv6 = TRUE;
 
 	/* Break the activation chain */
@@ -2857,8 +2864,10 @@ nm_device_deactivate (NMDeviceInterface *device, NMDeviceStateReason reason)
 	clear_act_request (self);
 
 	/* Take out any entries in the routing table and any IP address the device had. */
-	nm_system_device_flush_routes (self, tried_ipv6 ? AF_UNSPEC : AF_INET);
-	nm_system_device_flush_addresses (self, tried_ipv6 ? AF_UNSPEC : AF_INET);
+	ifindex = nm_device_get_ip_ifindex (self);
+	family = tried_ipv6 ? AF_UNSPEC : AF_INET;
+	nm_system_iface_flush_routes (ifindex, family);
+	nm_system_iface_flush_addresses (ifindex, family);
 	nm_device_update_ip4_address (self);	
 
 	/* Clean up nameservers and addresses */
@@ -3009,6 +3018,7 @@ nm_device_set_ip4_config (NMDevice *self,
 	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);
 	g_return_val_if_fail (reason != NULL, FALSE);
@@ -3039,8 +3049,10 @@ 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)
-			success = nm_system_apply_ip4_config (ip_iface, new_config, nm_device_get_priority (self), diff);
+		if (!assumed) {
+			ip_ifindex = nm_device_get_ip_ifindex (self);
+			success = nm_system_apply_ip4_config (ip_ifindex, new_config, nm_device_get_priority (self), diff);
+		}
 
 		if (success || assumed) {
 			/* Export over D-Bus */
@@ -3112,12 +3124,14 @@ nm_device_set_ip6_config (NMDevice *self,
 	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);
 	g_return_val_if_fail (reason != NULL, FALSE);
 
 	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->ip6_config;
 
@@ -3143,7 +3157,7 @@ nm_device_set_ip6_config (NMDevice *self,
 		 * assumed when NM starts.
 		 */
 		if (!assumed)
-			success = nm_system_apply_ip6_config (ip_iface, 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) {
 			/* Export over D-Bus */
@@ -3395,7 +3409,7 @@ set_property (GObject *object, guint prop_id,
 		priv->iface = g_value_dup_string (value);
 		if (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);
 			}
 		}
diff --git a/src/nm-manager.c b/src/nm-manager.c
index f5782254..475344a5 100644
--- a/src/nm-manager.c
+++ b/src/nm-manager.c
@@ -196,7 +196,6 @@ typedef struct {
 } RadioState;
 
 typedef struct {
-	char *config_file;
 	char *state_file;
 
 	GSList *devices;
@@ -214,7 +213,8 @@ typedef struct {
 	gboolean net_enabled;
 
 	NMVPNManager *vpn_manager;
-	guint vpn_manager_id;
+	gulong vpn_manager_activated_id;
+	gulong vpn_manager_deactivated_id;
 
 	NMModemManager *modem_manager;
 	guint modem_added_id;
@@ -377,6 +377,18 @@ manager_sleeping (NMManager *self)
 }
 
 static void
+vpn_manager_connection_activated_cb (NMVPNManager *manager,
+                                     NMVPNConnection *vpn,
+                                     NMVPNConnectionState state,
+                                     NMVPNConnectionStateReason reason,
+                                     gpointer user_data)
+{
+	/* Update timestamp for the VPN connection */
+	nm_settings_connection_update_timestamp (NM_SETTINGS_CONNECTION (nm_vpn_connection_get_connection (vpn)),
+	                                         (guint64) time (NULL));
+}
+
+static void
 vpn_manager_connection_deactivated_cb (NMVPNManager *manager,
                                        NMVPNConnection *vpn,
                                        NMVPNConnectionState state,
@@ -1980,6 +1992,7 @@ nm_manager_activate_connection (NMManager *manager,
 		vpn_connection = nm_vpn_manager_activate_connection (priv->vpn_manager,
 		                                                     connection,
 		                                                     device,
+		                                                     nm_act_request_get_active_connection_path (parent_req),
 		                                                     TRUE,
 		                                                     sender_uid,
 		                                                     error);
@@ -3029,10 +3042,17 @@ out:
 	return DBUS_HANDLER_RESULT_HANDLED;
 }
 
+static NMManager *singleton = NULL;
+
+NMManager *
+nm_manager_get (void)
+{
+	g_assert (singleton);
+	return g_object_ref (singleton);
+}
+
 NMManager *
-nm_manager_get (NMSettings *settings,
-                const char *config_file,
-                const char *plugins,
+nm_manager_new (NMSettings *settings,
                 const char *state_file,
                 gboolean initial_net_enabled,
                 gboolean initial_wifi_enabled,
@@ -3040,16 +3060,14 @@ nm_manager_get (NMSettings *settings,
                 gboolean initial_wimax_enabled,
                 GError **error)
 {
-	static NMManager *singleton = NULL;
 	NMManagerPrivate *priv;
 	DBusGConnection *bus;
 	DBusConnection *dbus_connection;
 
-	if (singleton)
-		return g_object_ref (singleton);
-
 	g_assert (settings);
 
+	/* Can only be called once */
+	g_assert (singleton == NULL);
 	singleton = (NMManager *) g_object_new (NM_TYPE_MANAGER, NULL);
 	g_assert (singleton);
 
@@ -3068,7 +3086,6 @@ nm_manager_get (NMSettings *settings,
 
 	priv->settings = g_object_ref (settings);
 
-	priv->config_file = g_strdup (config_file);
 	priv->state_file = g_strdup (state_file);
 
 	priv->net_enabled = initial_net_enabled;
@@ -3155,13 +3172,16 @@ dispose (GObject *object)
 	}
 
 	g_free (priv->hostname);
-	g_free (priv->config_file);
 
 	g_object_unref (priv->settings);
 
-	if (priv->vpn_manager_id) {
-		g_source_remove (priv->vpn_manager_id);
-		priv->vpn_manager_id = 0;
+	if (priv->vpn_manager_activated_id) {
+		g_source_remove (priv->vpn_manager_activated_id);
+		priv->vpn_manager_activated_id = 0;
+	}
+	if (priv->vpn_manager_deactivated_id) {
+		g_source_remove (priv->vpn_manager_deactivated_id);
+		priv->vpn_manager_deactivated_id = 0;
 	}
 	g_object_unref (priv->vpn_manager);
 
@@ -3402,6 +3422,7 @@ static gboolean
 periodic_update_active_connection_timestamps (gpointer user_data)
 {
 	NMManager *manager = NM_MANAGER (user_data);
+	NMManagerPrivate *priv = NM_MANAGER_GET_PRIVATE (manager);
 	GPtrArray *active;
 	int i;
 
@@ -3416,6 +3437,15 @@ periodic_update_active_connection_timestamps (gpointer user_data)
 		if (device && nm_device_get_state (device) == NM_DEVICE_STATE_ACTIVATED)
 			nm_settings_connection_update_timestamp (NM_SETTINGS_CONNECTION (nm_act_request_get_connection (req)),
 			                                         (guint64) time (NULL));
+		else {
+			/* The connection is probably VPN */
+			NMVPNConnection *vpn_con;
+
+			vpn_con = nm_vpn_manager_get_vpn_connection_for_active (priv->vpn_manager, active_path);
+			if (vpn_con && nm_vpn_connection_get_vpn_state (vpn_con) == NM_VPN_CONNECTION_STATE_ACTIVATED)
+				nm_settings_connection_update_timestamp (NM_SETTINGS_CONNECTION (nm_vpn_connection_get_connection (vpn_con)),
+				                                         (guint64) time (NULL));
+		}
 	}
 
 	return TRUE;
@@ -3426,7 +3456,7 @@ nm_manager_init (NMManager *manager)
 {
 	NMManagerPrivate *priv = NM_MANAGER_GET_PRIVATE (manager);
 	DBusGConnection *g_connection;
-	guint id, i;
+	guint i;
 	GFile *file;
 
 	/* Initialize rfkill structures and states */
@@ -3471,9 +3501,10 @@ nm_manager_init (NMManager *manager)
 	                                           G_CALLBACK (modem_removed), manager);
 
 	priv->vpn_manager = nm_vpn_manager_get ();
-	id = g_signal_connect (G_OBJECT (priv->vpn_manager), "connection-deactivated",
-	                       G_CALLBACK (vpn_manager_connection_deactivated_cb), manager);
-	priv->vpn_manager_id = id;
+	priv->vpn_manager_activated_id = g_signal_connect (G_OBJECT (priv->vpn_manager), "connection-activated",
+	                                                   G_CALLBACK (vpn_manager_connection_activated_cb), manager);
+	priv->vpn_manager_deactivated_id = g_signal_connect (G_OBJECT (priv->vpn_manager), "connection-deactivated",
+	                                                   G_CALLBACK (vpn_manager_connection_deactivated_cb), manager);
 
 	g_connection = nm_dbus_manager_get_connection (priv->dbus_mgr);
 
diff --git a/src/nm-manager.h b/src/nm-manager.h
index 22bfca9e..b044971f 100644
--- a/src/nm-manager.h
+++ b/src/nm-manager.h
@@ -67,9 +67,8 @@ typedef struct {
 
 GType nm_manager_get_type (void);
 
-NMManager *nm_manager_get (NMSettings *settings,
-                           const char *config_file,
-                           const char *plugins,
+/* nm_manager_new() should only be used by main.c */
+NMManager *nm_manager_new (NMSettings *settings,
                            const char *state_file,
                            gboolean initial_net_enabled,
                            gboolean initial_wifi_enabled,
@@ -77,6 +76,8 @@ NMManager *nm_manager_get (NMSettings *settings,
 						   gboolean initial_wimax_enabled,
                            GError **error);
 
+NMManager *nm_manager_get (void);
+
 void nm_manager_start (NMManager *manager);
 
 /* Device handling */
diff --git a/src/nm-netlink-compat.c b/src/nm-netlink-compat.c
new file mode 100644
index 00000000..e91a1ff2
--- /dev/null
+++ b/src/nm-netlink-compat.c
@@ -0,0 +1,105 @@
+/* -*- 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) 2011 Caixa Magica Software.
+ */
+
+#include <config.h>
+#include <glib.h>
+
+#include "nm-netlink-compat.h"
+
+#ifndef HAVE_LIBNL1
+struct rtnl_nexthop *
+nm_netlink_get_nh (struct rtnl_route * route)
+{
+	int hops;
+
+	hops = rtnl_route_get_nnexthops (route);
+	g_return_val_if_fail(hops > 0, NULL);
+	return rtnl_route_nexthop_n (route, 0);
+}
+
+int
+rtnl_route_get_oif (struct rtnl_route * route)
+{
+	struct rtnl_nexthop * nh;
+
+	nh = nm_netlink_get_nh(route);
+	g_return_val_if_fail(nh, -NLE_OBJ_NOTFOUND);
+	return rtnl_route_nh_get_ifindex (nh);
+}
+
+int
+rtnl_route_set_oif (struct rtnl_route * route, int ifindex)
+{
+	struct rtnl_nexthop * nh;
+
+	nh = rtnl_route_nh_alloc();
+	rtnl_route_nh_set_ifindex(nh, ifindex);
+	rtnl_route_add_nexthop(route, nh);
+	return 0;
+}
+
+struct nl_addr *
+rtnl_route_get_gateway (struct rtnl_route * route)
+{
+	struct rtnl_nexthop * nh;
+
+	nh = nm_netlink_get_nh(route);
+	g_return_val_if_fail(nh, NULL);
+	return rtnl_route_nh_get_gateway(nh);
+}
+
+int
+rtnl_route_set_gateway (struct rtnl_route * route, struct nl_addr * gw_addr)
+{
+	struct rtnl_nexthop * nh;
+
+	nh = nm_netlink_get_nh(route);
+	g_return_val_if_fail(nh, -NLE_OBJ_NOTFOUND);
+
+	rtnl_route_nh_set_gateway(nh, gw_addr);
+	return 0;
+}
+
+int
+rtnl_route_get_dst_len(struct rtnl_route * rtnlroute)
+{
+	struct nl_addr * dst;
+
+	dst = rtnl_route_get_dst(rtnlroute);
+	return nl_addr_get_prefixlen(dst);
+}
+#endif
+
+#ifdef HAVE_LIBNL1
+int
+nl_compat_error (int err)
+{
+	err = abs (err);
+
+	if (err == EEXIST)
+		err = NLE_EXIST;
+	else if (err == ENOENT || err == ESRCH)
+		err = NLE_OBJ_NOTFOUND;
+	else if (err == ERANGE)
+		err = NLE_RANGE;
+
+	return -err;
+}
+#endif
diff --git a/src/nm-netlink-compat.h b/src/nm-netlink-compat.h
new file mode 100644
index 00000000..af21fb9a
--- /dev/null
+++ b/src/nm-netlink-compat.h
@@ -0,0 +1,207 @@
+/* -*- 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) 2011 Caixa Magica Software.
+ */
+
+#ifndef NM_NETLINK_COMPAT_H
+#define NM_NETLINK_COMPAT_H
+
+#include <errno.h>
+
+#include <netlink/netlink.h>
+#include <netlink/route/rtnl.h>
+#include <netlink/route/link.h>
+#include <netlink/route/route.h>
+#include <netlink/route/addr.h>
+
+
+#include <netlink/netlink.h>
+#include <netlink/cache.h>
+#include <netlink/utils.h>
+#include <netlink/data.h>
+#include <netlink/route/rtnl.h>
+#include <netlink/route/route.h>
+#include <netlink/route/link.h>
+#include <netlink/route/nexthop.h>
+
+#include <config.h>
+
+/* libnl-1 API compatibility for libnl-2/3*/
+#ifndef HAVE_LIBNL1
+
+struct rtnl_nexthop * nm_netlink_get_nh(struct rtnl_route *);
+int rtnl_route_get_oif(struct rtnl_route *);
+int rtnl_route_set_oif(struct rtnl_route *, int);
+int rtnl_route_set_gateway(struct rtnl_route *, struct nl_addr *);
+int rtnl_route_get_dst_len(struct rtnl_route *);
+struct nl_addr * rtnl_route_get_gateway(struct rtnl_route *);
+#endif
+
+/* libnl-2 API compatibility for libnl-3 */
+#ifdef HAVE_LIBNL3
+static inline int
+__rtnl_link_alloc_cache (struct nl_sock *h, struct nl_cache **cache)
+{
+       return rtnl_link_alloc_cache (h, AF_UNSPEC, cache);
+}
+#define rtnl_link_alloc_cache __rtnl_link_alloc_cache
+#endif
+
+
+/* libnl-2.0 compat functions */
+#ifdef HAVE_LIBNL2
+
+/* functions with similar prototypes */
+#define nlmsg_datalen nlmsg_len
+#endif
+
+
+/* libnl-1.0 compat functions */
+#ifdef HAVE_LIBNL1
+
+#define nl_sock nl_handle
+
+/* libnl-1.0 functions with similar prototypes */
+#define nl_socket_alloc nl_handle_alloc
+#define nl_socket_alloc_cb nl_handle_alloc_cb
+#define nl_socket_free nl_handle_destroy
+#define nl_socket_set_passcred nl_set_passcred
+#define nl_socket_disable_seq_check nl_disable_sequence_check
+#define rtnl_route_set_priority rtnl_route_set_prio
+#define nlmsg_datalen nlmsg_len
+
+/* auxiliary functions */
+int nl_compat_error (int);
+
+/* libnl-1.0 functions with modified prototypes in libnl-2/3*/
+static inline const char * 
+__nl_geterror (int err)
+{
+        /* err is set, can be parsed */
+        return nl_geterror ();
+}
+#define nl_geterror __nl_geterror
+
+static inline int
+__rtnl_addr_alloc_cache (struct nl_sock *h, struct nl_cache **cache)
+{
+	g_return_val_if_fail (cache != NULL, -EINVAL);
+
+	*cache = rtnl_addr_alloc_cache (h);
+	return *cache ? 0 : -ENOMEM;
+}
+#define rtnl_addr_alloc_cache __rtnl_addr_alloc_cache
+
+static inline int
+__rtnl_route_alloc_cache (struct nl_sock *h, int family, int flags, struct nl_cache **cache)
+{
+	g_return_val_if_fail (cache != NULL, -EINVAL);
+
+	*cache = rtnl_route_alloc_cache (h);
+	return *cache ? 0 : -ENOMEM;
+}
+#define rtnl_route_alloc_cache __rtnl_route_alloc_cache
+
+static inline int
+__rtnl_link_alloc_cache (struct nl_sock *h, struct nl_cache **cache)
+{
+	g_return_val_if_fail (cache != NULL, -EINVAL);
+
+	*cache = rtnl_link_alloc_cache (h);
+	return *cache ? 0 : -ENOMEM;
+}
+#define rtnl_link_alloc_cache __rtnl_link_alloc_cache
+
+static inline int
+__rtnl_route_get_metric (struct rtnl_route *route, int metric, unsigned int *value)
+{
+	g_return_val_if_fail (value != NULL, -EINVAL);
+
+	*value = rtnl_route_get_metric (route, metric);
+	return 0;
+}
+#define rtnl_route_get_metric __rtnl_route_get_metric
+
+static inline int
+__rtnl_addr_add (struct nl_sock *h, struct rtnl_addr *addr, int flags)
+{
+	return nl_compat_error (rtnl_addr_add (h, addr, flags));
+}
+#define rtnl_addr_add __rtnl_addr_add
+
+static inline int
+__rtnl_route_add (struct nl_sock *sk, struct rtnl_route *route, int flags)
+{
+	return nl_compat_error (rtnl_route_add (sk, route, flags));
+}
+#define rtnl_route_add __rtnl_route_add
+
+static inline int
+rtnl_route_delete (struct nl_sock *h, struct rtnl_route *route, int flags)
+{
+	return nl_compat_error (rtnl_route_del (h, route, flags));
+}
+#define rtnl_route_del rtnl_route_delete
+
+static inline int
+__rtnl_link_change (struct nl_sock *h, struct rtnl_link *old, struct rtnl_link *tmpl, int flags)
+{
+	return nl_compat_error (rtnl_link_change (h, old, tmpl,flags));
+}
+#define rtnl_link_change __rtnl_link_change
+
+static inline int
+__nl_cache_include (struct nl_cache *cache, struct nl_object *obj, change_func_t cb, void *data)
+{
+	return nl_cache_include (cache, obj, cb);
+}
+#define nl_cache_include __nl_cache_include
+
+#define NLE_SUCCESS             0
+#define NLE_FAILURE             1
+#define NLE_INTR                2
+#define NLE_BAD_SOCK            3
+#define NLE_AGAIN               4
+#define NLE_NOMEM               5
+#define NLE_EXIST               6
+#define NLE_INVAL               7
+#define NLE_RANGE               8
+#define NLE_MSGSIZE             9
+#define NLE_OPNOTSUPP           10
+#define NLE_AF_NOSUPPORT        11
+#define NLE_OBJ_NOTFOUND        12
+#define NLE_NOATTR              13
+#define NLE_MISSING_ATTR        14
+#define NLE_AF_MISMATCH         15
+#define NLE_SEQ_MISMATCH        16
+#define NLE_MSG_OVERFLOW        17
+#define NLE_MSG_TRUNC           18
+#define NLE_NOADDR              19
+#define NLE_SRCRT_NOSUPPORT     20
+#define NLE_MSG_TOOSHORT        21
+#define NLE_MSGTYPE_NOSUPPORT   22
+#define NLE_OBJ_MISMATCH        23
+#define NLE_NOCACHE             24
+#define NLE_BUSY                25
+#define NLE_PROTO_MISMATCH      26
+#define NLE_NOACCESS            27
+#define NLE_PERM                28
+#define NLE_PKTLOC_FILE         29
+#endif
+
+#endif /* NM_NETLINK_COMPAT_H */
diff --git a/src/nm-netlink-monitor.c b/src/nm-netlink-monitor.c
index 13b3ab98..9b8dac5c 100644
--- a/src/nm-netlink-monitor.c
+++ b/src/nm-netlink-monitor.c
@@ -45,6 +45,7 @@
 #include <glib.h>
 #include <glib/gi18n.h>
 
+#include "nm-netlink-compat.h"
 #include "nm-netlink-monitor.h"
 #include "nm-logging.h"
 
@@ -58,12 +59,12 @@
 
 typedef struct {
 	/* Async event listener connection */
-	struct nl_handle *nlh_event;
+	struct nl_sock *nlh_event;
 	GIOChannel *	  io_channel;
 	guint             event_id;
 
 	/* Sync/blocking request/response connection */
-	struct nl_handle *nlh_sync;
+	struct nl_sock *nlh_sync;
 	struct nl_cache * link_cache;
 
 	guint request_status_id;
@@ -98,7 +99,7 @@ link_msg_handler (struct nl_object *obj, void *arg)
 		error = g_error_new (NM_NETLINK_MONITOR_ERROR,
 		                     NM_NETLINK_MONITOR_ERROR_BAD_ALLOC,
 		                     _("error processing netlink message: %s"),
-		                     nl_geterror ());
+		                     nl_geterror (ENOMEM));
 		g_signal_emit (self, signals[ERROR], 0, error);
 		g_error_free (error);
 		return;
@@ -130,7 +131,7 @@ link_msg_handler (struct nl_object *obj, void *arg)
 static int
 event_msg_recv (struct nl_msg *msg, void *arg)
 {
-	struct nl_handle *nlh = arg;
+	struct nl_sock *nlh = arg;
 	struct nlmsghdr *hdr = nlmsg_hdr (msg);
 	struct ucred *creds = nlmsg_get_creds (msg);
 	const struct sockaddr_nl *snl;
@@ -195,6 +196,7 @@ event_handler (GIOChannel *channel,
 	NMNetlinkMonitor *self = (NMNetlinkMonitor *) user_data;
 	NMNetlinkMonitorPrivate *priv;
 	GError *error = NULL;
+	int err;
 
 	g_return_val_if_fail (NM_IS_NETLINK_MONITOR (self), TRUE);
 
@@ -225,11 +227,12 @@ event_handler (GIOChannel *channel,
 	g_return_val_if_fail (!(io_condition & ~EVENT_CONDITIONS), FALSE);
 
 	/* Process the netlink messages */
-	if (nl_recvmsgs_default (priv->nlh_event) < 0) {
+	err = nl_recvmsgs_default (priv->nlh_event);
+	if (err < 0) {
 		error = g_error_new (NM_NETLINK_MONITOR_ERROR,
 		                     NM_NETLINK_MONITOR_ERROR_PROCESSING_MESSAGE,
 		                     _("error processing netlink message: %s"),
-		                     nl_geterror ());
+		                     nl_geterror (err));
 		g_signal_emit (self, signals[ERROR], 0, error);
 		g_error_free (error);
 	}
@@ -238,32 +241,35 @@ event_handler (GIOChannel *channel,
 }
 
 static gboolean
-nlh_setup (struct nl_handle *nlh,
+nlh_setup (struct nl_sock *nlh,
            nl_recvmsg_msg_cb_t valid_func,
            gpointer cb_data,
            GError **error)
 {
+	int err;
+
 	nl_socket_modify_cb (nlh, NL_CB_MSG_IN, NL_CB_CUSTOM, event_msg_recv, cb_data);
 
 	if (valid_func)
 		nl_socket_modify_cb (nlh, NL_CB_VALID, NL_CB_CUSTOM, valid_func, cb_data);
 
-	if (nl_connect (nlh, NETLINK_ROUTE) < 0) {
+	err = nl_connect (nlh, NETLINK_ROUTE);
+	if (err < 0) {
 		g_set_error (error, NM_NETLINK_MONITOR_ERROR,
 		             NM_NETLINK_MONITOR_ERROR_NETLINK_CONNECT,
 		             _("unable to connect to netlink for monitoring link status: %s"),
-		             nl_geterror ());
+		             nl_geterror (err));
 		return FALSE;
 	}
 
 	/* Enable unix socket peer credentials which we use for verifying that the
 	 * sender of the message is actually the kernel.
 	 */
-	if (nl_set_passcred (nlh, 1) < 0) {
+	if (nl_socket_set_passcred (nlh, 1) < 0) {
 		g_set_error (error, NM_NETLINK_MONITOR_ERROR,
 		             NM_NETLINK_MONITOR_ERROR_NETLINK_CONNECT,
 		             _("unable to enable netlink handle credential passing: %s"),
-		             nl_geterror ());
+		             nl_geterror (err));
 		return FALSE;
 	}
 
@@ -276,27 +282,24 @@ event_connection_setup (NMNetlinkMonitor *self, GError **error)
 	NMNetlinkMonitorPrivate *priv = NM_NETLINK_MONITOR_GET_PRIVATE (self);
 	GError *channel_error = NULL;
 	GIOFlags channel_flags;
-	struct nl_cb *cb;
 	int fd;
 
 	g_return_val_if_fail (priv->io_channel == NULL, FALSE);
 
 	/* Set up the event listener connection */
-	cb = nl_cb_alloc (NL_CB_DEFAULT);
-	priv->nlh_event = nl_handle_alloc_cb (cb);
-	nl_cb_put (cb);
+	priv->nlh_event = nl_socket_alloc ();
 	if (!priv->nlh_event) {
 		g_set_error (error, NM_NETLINK_MONITOR_ERROR,
 		             NM_NETLINK_MONITOR_ERROR_NETLINK_ALLOC_HANDLE,
 		             _("unable to allocate netlink handle for monitoring link status: %s"),
-		             nl_geterror ());
+		             nl_geterror (ENOMEM));
 		goto error;
 	}
 
 	if (!nlh_setup (priv->nlh_event, event_msg_ready, self, error))
 		goto error;
 
-	nl_disable_sequence_check (priv->nlh_event);
+	nl_socket_disable_seq_check (priv->nlh_event);
 
 	/* Subscribe to the LINK group for internal carrier signals */
 	if (!nm_netlink_monitor_subscribe (self, RTNLGRP_LINK, error))
@@ -327,7 +330,7 @@ error:
 		nm_netlink_monitor_close_connection (self);
 
 	if (priv->nlh_event) {
-		nl_handle_destroy (priv->nlh_event);
+		nl_socket_free (priv->nlh_event);
 		priv->nlh_event = NULL;
 	}
 
@@ -338,20 +341,18 @@ static gboolean
 sync_connection_setup (NMNetlinkMonitor *self, GError **error)
 {
 	NMNetlinkMonitorPrivate *priv = NM_NETLINK_MONITOR_GET_PRIVATE (self);
-	struct nl_cb *cb;
 #ifdef LIBNL_NEEDS_ADDR_CACHING_WORKAROUND
 	struct nl_cache *addr_cache;
 #endif
+	int err;
 
 	/* Set up the event listener connection */
-	cb = nl_cb_alloc (NL_CB_DEFAULT);
-	priv->nlh_sync = nl_handle_alloc_cb (cb);
-	nl_cb_put (cb);
+	priv->nlh_sync = nl_socket_alloc ();
 	if (!priv->nlh_sync) {
 		g_set_error (error, NM_NETLINK_MONITOR_ERROR,
 		             NM_NETLINK_MONITOR_ERROR_NETLINK_ALLOC_HANDLE,
 		             _("unable to allocate netlink handle for monitoring link status: %s"),
-		             nl_geterror ());
+		             nl_geterror (ENOMEM));
 		goto error;
 	}
 
@@ -365,16 +366,18 @@ sync_connection_setup (NMNetlinkMonitor *self, GError **error)
 	 * result, most addresses will not compare as equal even to
 	 * themselves, busting caching.
 	 */
-	addr_cache = rtnl_addr_alloc_cache (priv->nlh_sync);
+	rtnl_addr_alloc_cache (priv->nlh_sync, &addr_cache);
+	g_warn_if_fail (addr_cache != NULL);
 	nl_cache_get_ops (addr_cache)->co_obj_ops->oo_id_attrs &= ~0x80;
 	nl_cache_free (addr_cache);
 #endif
 
-	if ((priv->link_cache = rtnl_link_alloc_cache (priv->nlh_sync)) == NULL) {
+	err = rtnl_link_alloc_cache (priv->nlh_sync, &priv->link_cache);
+	if (err < 0) {
 		g_set_error (error, NM_NETLINK_MONITOR_ERROR,
 		             NM_NETLINK_MONITOR_ERROR_NETLINK_ALLOC_LINK_CACHE,
 		             _("unable to allocate netlink link cache for monitoring link status: %s"),
-		             nl_geterror ());
+		             nl_geterror (err));
 		goto error;
 	}
 	nl_cache_mngt_provide (priv->link_cache);
@@ -388,7 +391,7 @@ error:
 	}
 
 	if (priv->nlh_sync) {
-		nl_handle_destroy (priv->nlh_sync);
+		nl_socket_free (priv->nlh_sync);
 		priv->nlh_sync = NULL;
 	}
 
@@ -483,7 +486,7 @@ gboolean
 nm_netlink_monitor_subscribe (NMNetlinkMonitor *self, int group, GError **error)
 {
 	NMNetlinkMonitorPrivate *priv;
-	int subs;
+	int subs, err;
 
 	g_return_val_if_fail (NM_IS_NETLINK_MONITOR (self), FALSE);
 
@@ -496,11 +499,12 @@ nm_netlink_monitor_subscribe (NMNetlinkMonitor *self, int group, GError **error)
 
 	subs = get_subs (self, group) + 1;
 	if (subs == 1) {
-		if (nl_socket_add_membership (priv->nlh_event, group) < 0) {
+		err = nl_socket_add_membership (priv->nlh_event, group);
+		if (err < 0) {
 			g_set_error (error, NM_NETLINK_MONITOR_ERROR,
 			             NM_NETLINK_MONITOR_ERROR_NETLINK_JOIN_GROUP,
 			             _("unable to join netlink group: %s"),
-			             nl_geterror ());
+			             nl_geterror (err));
 			return FALSE;
 		}
 	}
@@ -558,15 +562,17 @@ deferred_emit_carrier_state (gpointer user_data)
 {
 	NMNetlinkMonitor *self = NM_NETLINK_MONITOR (user_data);
 	NMNetlinkMonitorPrivate *priv = NM_NETLINK_MONITOR_GET_PRIVATE (self);
+	int err;
 
 	priv->request_status_id = 0;
 
 	/* Update the link cache with latest state, and if there are no errors
 	 * emit the link states for all the interfaces in the cache.
 	 */
-	if (nl_cache_refill (priv->nlh_sync, priv->link_cache)) {
-		nm_log_err (LOGD_HW, "error updating link cache: %s", nl_geterror ());
-	} else
+	err = nl_cache_refill (priv->nlh_sync, priv->link_cache);
+	if (err < 0)
+		nm_log_err (LOGD_HW, "error updating link cache: %s", nl_geterror (err));
+	else
 		nl_cache_foreach_filter (priv->link_cache, NULL, link_msg_handler, self);
 
 	return FALSE;
@@ -614,6 +620,7 @@ nm_netlink_monitor_get_flags_sync (NMNetlinkMonitor *self,
 	NMNetlinkMonitorPrivate *priv;
 	GetFlagsInfo info;
 	struct rtnl_link *filter;
+	int err;
 
 	g_return_val_if_fail (self != NULL, FALSE);
 	g_return_val_if_fail (NM_IS_NETLINK_MONITOR (self), FALSE);
@@ -622,12 +629,13 @@ nm_netlink_monitor_get_flags_sync (NMNetlinkMonitor *self,
 	priv = NM_NETLINK_MONITOR_GET_PRIVATE (self);
 
 	/* Update the link cache with the latest information */
-	if (nl_cache_refill (priv->nlh_sync, priv->link_cache)) {
+	err = nl_cache_refill (priv->nlh_sync, priv->link_cache);
+	if (err < 0) {
 		g_set_error (error,
 		             NM_NETLINK_MONITOR_ERROR,
 		             NM_NETLINK_MONITOR_ERROR_LINK_CACHE_UPDATE,
 		             _("error updating link cache: %s"),
-		             nl_geterror ());
+		             nl_geterror (err));
 		return FALSE;
 	}
 
@@ -640,7 +648,7 @@ nm_netlink_monitor_get_flags_sync (NMNetlinkMonitor *self,
 		             NM_NETLINK_MONITOR_ERROR,
 		             NM_NETLINK_MONITOR_ERROR_LINK_CACHE_UPDATE,
 		             _("error updating link cache: %s"),
-		             nl_geterror ());
+		             nl_geterror (err));
 		return FALSE;
 	}
 
@@ -651,7 +659,7 @@ nm_netlink_monitor_get_flags_sync (NMNetlinkMonitor *self,
 		             NM_NETLINK_MONITOR_ERROR,
 		             NM_NETLINK_MONITOR_ERROR_BAD_ALLOC,
 		             _("error processing netlink message: %s"),
-		             nl_geterror ());
+		             nl_geterror (err));
 		return FALSE;
 	}
 	rtnl_link_set_ifindex (filter, ifindex);
@@ -678,11 +686,11 @@ nm_netlink_monitor_get_flags_sync (NMNetlinkMonitor *self,
 
 /***************************************************************/
 
-struct nl_handle *
+struct nl_sock *
 nm_netlink_get_default_handle (void)
 {
 	NMNetlinkMonitor *self;
-	struct nl_handle *nlh;
+	struct nl_sock *nlh;
 
 	self = nm_netlink_monitor_get ();
 	nlh = NM_NETLINK_MONITOR_GET_PRIVATE (self)->nlh_sync;
@@ -710,6 +718,13 @@ nm_netlink_iface_to_index (const char *iface)
 	return idx;
 }
 
+/**
+ * nm_netlink_index_to_iface:
+ * @idx: kernel interface index
+ *
+ * Returns: the device name corresponding to the kernel interface index; caller
+ * owns returned value and must free it when it is no longer required
+ **/
 #define MAX_IFACE_LEN 33
 char *
 nm_netlink_index_to_iface (int idx)
@@ -728,6 +743,7 @@ nm_netlink_index_to_iface (int idx)
 
 	nl_cache_refill (priv->nlh_sync, priv->link_cache);
 	if (!rtnl_link_i2name (priv->link_cache, idx, buf, MAX_IFACE_LEN - 1)) {
+		nm_log_warn (LOGD_HW, "(%d) failed to find interface name for index", idx);
 		g_free (buf);
 		buf = NULL;
 	}
@@ -796,12 +812,12 @@ finalize (GObject *object)
 	}
 
 	if (priv->nlh_event) {
-		nl_handle_destroy (priv->nlh_event);
+		nl_socket_free (priv->nlh_event);
 		priv->nlh_event = NULL;
 	}
 
 	if (priv->nlh_sync) {
-		nl_handle_destroy (priv->nlh_sync);
+		nl_socket_free (priv->nlh_sync);
 		priv->nlh_sync = NULL;
 	}
 
diff --git a/src/nm-netlink-monitor.h b/src/nm-netlink-monitor.h
index 8b57a312..5c1fa339 100644
--- a/src/nm-netlink-monitor.h
+++ b/src/nm-netlink-monitor.h
@@ -90,10 +90,12 @@ gboolean          nm_netlink_monitor_get_flags_sync   (NMNetlinkMonitor *monitor
                                                        guint32 *ifflags,
                                                        GError **error);
 
+#include "nm-netlink-compat.h"
+
 /* Generic utility functions */
 int               nm_netlink_iface_to_index     (const char *iface);
 char *            nm_netlink_index_to_iface     (int idx);
 struct rtnl_link *nm_netlink_index_to_rtnl_link (int idx);
-struct nl_handle *nm_netlink_get_default_handle (void);
+struct nl_sock *  nm_netlink_get_default_handle (void);
 
 #endif  /* NM_NETLINK_MONITOR_H */
diff --git a/src/nm-netlink-utils.c b/src/nm-netlink-utils.c
new file mode 100644
index 00000000..4a62aa55
--- /dev/null
+++ b/src/nm-netlink-utils.c
@@ -0,0 +1,426 @@
+/* -*- 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) 2011 Red Hat, Inc.
+ */
+
+#include "logging/nm-logging.h"
+#include "nm-netlink-utils.h"
+#include "nm-netlink-monitor.h"
+#include "nm-netlink-compat.h"
+
+#include <arpa/inet.h>
+#include <netinet/in.h>
+#include <netlink/netlink.h>
+#include <netlink/addr.h>
+#include <netlink/route/addr.h>
+
+#include <errno.h>
+
+typedef struct {
+	int ifindex;
+	int family;
+	void *addr;
+	int addrlen;
+	int prefix;
+	gboolean found;
+} FindAddrInfo;
+
+static void
+find_one_address (struct nl_object *object, void *user_data)
+{
+	FindAddrInfo *info = user_data;
+	struct rtnl_addr *addr = (struct rtnl_addr *) object;
+	struct nl_addr *local;
+	void *binaddr;
+
+	if (info->found)
+		return;
+
+	if (rtnl_addr_get_ifindex (addr) != info->ifindex)
+		return;
+	if (rtnl_addr_get_family (addr) != info->family)
+		return;
+
+	if (rtnl_addr_get_prefixlen (addr) != info->prefix)
+		return;
+
+	local = rtnl_addr_get_local (addr);
+	if (nl_addr_get_family (local) != info->family)
+		return;
+	if (nl_addr_get_len (local) != info->addrlen)
+		return;
+	binaddr = nl_addr_get_binary_addr (local);
+	if (binaddr) {
+		if (memcmp (binaddr, info->addr, info->addrlen) == 0)
+			info->found = TRUE; /* Yay, found it */
+	}
+}
+
+/**
+ * nm_netlink_find_address:
+ * @ifindex: interface index
+ * @family: address family, either AF_INET or AF_INET6
+ * @addr: binary address, either struct in_addr* or struct in6_addr*
+ * @prefix: prefix length
+ *
+ * Searches for a matching address on the given interface.
+ *
+ * Returns: %TRUE if the given address was found on the interface, %FALSE if it
+ * was not found or an error occurred.
+ **/
+gboolean
+nm_netlink_find_address (int ifindex,
+                         int family,
+                         void *addr,  /* struct in_addr or struct in6_addr */
+                         int prefix)
+{
+	struct nl_sock *nlh = NULL;
+	struct nl_cache *cache = NULL;
+	FindAddrInfo info;
+
+	g_return_val_if_fail (ifindex > 0, FALSE);
+	g_return_val_if_fail (family == AF_INET || family == AF_INET6, FALSE);
+	g_return_val_if_fail (addr != NULL, FALSE);
+	g_return_val_if_fail (prefix >= 0, FALSE);
+
+	memset (&info, 0, sizeof (info));
+	info.ifindex = ifindex;
+	info.family = family;
+	info.prefix = prefix;
+	info.addr = addr;
+	if (family == AF_INET)
+		info.addrlen = sizeof (struct in_addr);
+	else if (family == AF_INET6)
+		info.addrlen = sizeof (struct in6_addr);
+	else
+		g_assert_not_reached ();
+
+	nlh = nm_netlink_get_default_handle ();
+	if (nlh) {
+		rtnl_addr_alloc_cache(nlh, &cache);
+		if (cache) {
+			nl_cache_mngt_provide (cache);
+			nl_cache_foreach (cache, find_one_address, &info);
+			nl_cache_free (cache);
+		}
+	}
+	return info.found;
+}
+
+struct rtnl_route *
+nm_netlink_route_new (int ifindex,
+                      int family,
+                      int mss,
+                      ...)
+{
+	va_list var_args;
+	struct rtnl_route *route;
+	NmNlProp prop = NMNL_PROP_INVALID;
+	int value;
+
+	route = rtnl_route_alloc ();
+	g_return_val_if_fail (route != NULL, NULL);
+
+	if (ifindex >= 0)
+		rtnl_route_set_oif (route, ifindex);
+	if (family != AF_UNSPEC)
+		rtnl_route_set_family (route, family);
+	if (mss > 0)
+		rtnl_route_set_metric (route, RTAX_ADVMSS, mss);
+
+	va_start (var_args, mss);
+	prop = va_arg (var_args, NmNlProp);
+	while (prop != NMNL_PROP_INVALID) {
+		value = va_arg (var_args, int);
+
+		if (prop == NMNL_PROP_PROT && value != RTPROT_UNSPEC)
+			rtnl_route_set_protocol (route, value);
+		else if (prop == NMNL_PROP_TABLE && value != RT_TABLE_UNSPEC)
+			rtnl_route_set_table (route, value);
+		else if (prop == NMNL_PROP_SCOPE && value != RT_SCOPE_NOWHERE)
+			rtnl_route_set_scope (route, value);
+		else if (prop == NMNL_PROP_PRIO && value > 0)
+			rtnl_route_set_priority (route, value);
+
+		prop = va_arg (var_args, NmNlProp);
+	}
+	va_end (var_args);
+
+	return route;
+}
+
+/**
+ * nm_netlink_route_add:
+ * @route: the route to add
+ *
+ * Returns: zero if succeeded or the netlink error otherwise.
+ **/
+int nm_netlink_route_add(struct rtnl_route * route,
+			 int family,
+			 const void * dest, /* in_addr or in6_addr */
+			 int dest_prefix,
+			 const void * gateway, /* in_addr or in6_addr */
+			 int flags)
+{
+	struct nl_sock * sk;
+	struct nl_addr * dest_addr, * gw_addr;
+	void * tmp_addr;
+	int addrlen, err, log;
+
+	if(family == AF_INET) {
+		addrlen = sizeof(struct in_addr);
+		log = LOGD_IP4;
+	}
+	else if (family == AF_INET6) {
+		addrlen = sizeof(struct in6_addr);
+		log = LOGD_IP6;
+	} else {
+		g_assert_not_reached ();
+	}
+
+
+	sk = nm_netlink_get_default_handle();
+
+	/* Build up the destination address */
+	if (dest) {
+		/* Copy to preserve const */
+		tmp_addr = g_malloc0(addrlen);
+		memcpy(tmp_addr, dest, addrlen);
+
+		dest_addr = nl_addr_build (family, tmp_addr, addrlen);
+		g_free(tmp_addr);
+
+		g_return_val_if_fail (dest_addr != NULL, -NLE_INVAL);
+		nl_addr_set_prefixlen (dest_addr, dest_prefix);
+
+		rtnl_route_set_dst (route, dest_addr);
+		nl_addr_put (dest_addr);
+	}
+
+	/* Build up the gateway address */
+	if (gateway) {
+		tmp_addr = g_malloc0(addrlen);
+		memcpy(tmp_addr, gateway, addrlen);
+
+		gw_addr = nl_addr_build (family, tmp_addr, addrlen);
+		g_free(tmp_addr);
+
+		if (gw_addr) {
+			nl_addr_set_prefixlen (gw_addr, 0);
+			rtnl_route_set_gateway (route, gw_addr);
+			rtnl_route_set_scope (route, RT_SCOPE_UNIVERSE);
+			nl_addr_put(gw_addr);
+		} else {
+			nm_log_err (LOGD_DEVICE | log, "Invalid gateway");
+		}
+	}
+
+	err = rtnl_route_add (sk, route, flags);
+
+	/* LIBNL Bug: Aliased ESRCH */
+	if (err == -NLE_FAILURE)
+		err = -NLE_OBJ_NOTFOUND;
+
+	if (err)
+		nm_log_warn (LOGD_DEVICE | log,
+                             "Failed to add route %s",
+                             nl_geterror(err));
+
+	return err;
+}
+
+/**
+ * nm_netlink_route_delete:
+ * @route: the route to delete
+ *
+ * Returns: %TRUE if the request was successful, %FALSE if it failed
+ **/
+gboolean
+nm_netlink_route_delete (struct rtnl_route *route)
+{
+	struct nl_sock *nlh;
+	int err = 0;
+
+	g_return_val_if_fail (route != NULL, FALSE);
+
+	nlh = nm_netlink_get_default_handle ();
+	err = rtnl_route_delete (nlh, route, 0);
+
+	if (err)
+		nm_log_dbg (LOGD_IP4 | LOGD_IP6, "%s (%d)", nl_geterror(err), err);
+
+	/* Workaround libnl BUG: ESRCH is aliased to generic NLE_FAILURE
+	 * See: http://git.kernel.org/?p=libs/netlink/libnl.git;a=commit;h=7e9d5f */
+	if (err == -NLE_FAILURE)
+		err = -NLE_OBJ_NOTFOUND;
+
+	return (err && (err != -NLE_OBJ_NOTFOUND) && (err != -NLE_RANGE) ) ? FALSE : TRUE;
+}
+
+
+static void
+dump_route (struct rtnl_route *route)
+{
+	char buf6[INET6_ADDRSTRLEN];
+	char buf4[INET_ADDRSTRLEN];
+	struct nl_addr *nl;
+	struct in6_addr *addr6 = NULL;
+	struct in_addr *addr4 = NULL;
+	int prefixlen = 0;
+	const char *sf = "UNSPEC";
+	int family = rtnl_route_get_family (route);
+	guint32 log_level = LOGD_IP4 | LOGD_IP6;
+
+	memset (buf6, 0, sizeof (buf6));
+	memset (buf4, 0, sizeof (buf4));
+	nl = rtnl_route_get_dst (route);
+	if (nl) {
+		if (nl_addr_get_family (nl) == AF_INET) {
+			addr4 = nl_addr_get_binary_addr (nl);
+			if (addr4)
+				inet_ntop (AF_INET, addr4, &buf4[0], sizeof (buf4));
+		} else if (nl_addr_get_family (nl) == AF_INET6) {
+			addr6 = nl_addr_get_binary_addr (nl);
+			if (addr6)
+				inet_ntop (AF_INET6, addr6, &buf6[0], sizeof (buf6));
+		}
+		prefixlen = nl_addr_get_prefixlen (nl);
+	}
+
+	if (family == AF_INET) {
+		sf = "INET";
+		log_level = LOGD_IP4;
+	} else if (family == AF_INET6) {
+		sf = "INET6";
+		log_level = LOGD_IP6;
+	}
+
+	nm_log_dbg (log_level, "  route idx %d family %s (%d) addr %s/%d",
+	            rtnl_route_get_oif (route),
+	            sf, family,
+	            strlen (buf4) ? buf4 : (strlen (buf6) ? buf6 : "<unknown>"),
+	            prefixlen);
+}
+
+
+typedef struct {
+	int ifindex;
+	int family;
+	int scope;
+	gboolean ignore_inet6_ll_mc;
+	char *iface;
+	NlRouteForeachFunc callback;
+	gpointer user_data;
+	struct rtnl_route *out_route;
+} ForeachRouteInfo;
+
+static void
+foreach_route_cb (struct nl_object *object, void *user_data)
+{
+	ForeachRouteInfo *info = user_data;
+	struct rtnl_route *route = (struct rtnl_route *) object;
+	struct nl_addr *dst;
+
+	if (info->out_route)
+		return;
+
+	if (nm_logging_level_enabled (LOGL_DEBUG))
+		dump_route (route);
+
+	if (   info->ifindex >= 0
+	    && rtnl_route_get_oif (route) != info->ifindex)
+		return;
+
+	if (   info->scope != RT_SCOPE_UNIVERSE
+	    && rtnl_route_get_scope (route) != info->scope)
+		return;
+
+	if (   info->family != AF_UNSPEC
+	    && rtnl_route_get_family (route) != info->family)
+		return;
+
+	dst = rtnl_route_get_dst (route);
+
+	/* Check for IPv6 LL and MC routes that might need to be ignored */
+	if (   (info->family == AF_INET6 || info->family == AF_UNSPEC)
+	    && (rtnl_route_get_family (route) == AF_INET6)) {
+		struct in6_addr *addr = NULL;
+
+		if (dst)
+			addr = nl_addr_get_binary_addr (dst);
+		if (addr) {
+			if (   IN6_IS_ADDR_LINKLOCAL (addr)
+			    || IN6_IS_ADDR_MC_LINKLOCAL (addr)
+			    || (IN6_IS_ADDR_MULTICAST (addr) && (nl_addr_get_prefixlen (dst) == 8)))
+				return;
+		}
+	}
+
+	info->out_route = info->callback (route, dst, info->iface, info->user_data);
+	if (info->out_route) {
+		/* Ref the route so it sticks around after the cache is cleared */
+		rtnl_route_get (info->out_route);
+	}
+}
+
+/**
+ * nm_netlink_foreach_route:
+ * @ifindex: the interface index to filter routes for
+ * @family: the address family to filter routes for
+ * @scope: route scope, eg RT_SCOPE_LINK
+ * @ignore_inet6_ll_mc: if %TRUE ignore IPv6 link-local and multi-cast routes
+ * @callback: function called when a route matches the filter
+ * @user_data: data passed to @callback
+ *
+ * Filters each route in the routing table against the given @ifindex and
+ * @family (if given) and calls @callback for each matching route.
+ *
+ * Returns: a route if @callback returned one; the caller must dispose of the
+ * route using rtnl_route_put() when it is no longer required.
+ **/
+struct rtnl_route *
+nm_netlink_foreach_route (int ifindex,
+                          int family,
+                          int scope,
+                          gboolean ignore_inet6_ll_mc,
+                          NlRouteForeachFunc callback,
+                          gpointer user_data)
+{
+	struct nl_cache *cache;
+	ForeachRouteInfo info;
+
+	memset (&info, 0, sizeof (info));
+	info.ifindex = ifindex;
+	info.family = family;
+	info.scope = scope;
+	info.ignore_inet6_ll_mc = ignore_inet6_ll_mc;
+	info.callback = callback;
+	info.user_data = user_data;
+	info.iface = nm_netlink_index_to_iface (ifindex);
+
+	rtnl_route_alloc_cache (nm_netlink_get_default_handle (), family, NL_AUTO_PROVIDE, &cache);
+	g_warn_if_fail (cache != NULL);
+	if (cache) {
+		nl_cache_foreach (cache, foreach_route_cb, &info);
+		nl_cache_free (cache);
+	}
+	g_free (info.iface);
+	return info.out_route;
+}
+
+
diff --git a/src/nm-netlink-utils.h b/src/nm-netlink-utils.h
new file mode 100644
index 00000000..c6c452a0
--- /dev/null
+++ b/src/nm-netlink-utils.h
@@ -0,0 +1,80 @@
+/* -*- 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) 2011 Red Hat, Inc.
+ */
+
+#ifndef NM_NETLINK_UTILS_H
+#define NM_NETLINK_UTILS_H
+
+#include <glib.h>
+#include <netlink/route/rtnl.h>
+#include <netlink/route/route.h>
+
+gboolean nm_netlink_find_address (int ifindex,
+                                  int family,
+                                  void *addr,  /* struct in_addr or struct in6_addr */
+                                  int prefix_);
+
+typedef enum {
+	NMNL_PROP_INVALID = 0,
+	NMNL_PROP_PROT,
+	NMNL_PROP_SCOPE,
+	NMNL_PROP_TABLE,
+	NMNL_PROP_PRIO,
+} NmNlProp;
+
+struct rtnl_route * nm_netlink_route_new (int ifindex,
+                                          int family,
+                                          int mss,
+                                          ...) __attribute__((__sentinel__));
+
+int nm_netlink_route_add (struct rtnl_route *route,
+                          int family,
+                          const void * dst, /* struct in_addr or struct in6_addr */
+                          int prefix,
+                          const void * gw, /* struct in_addr or struct in6_addr */
+                          int flags);
+
+gboolean nm_netlink_route_delete (struct rtnl_route *route);
+
+/**
+ * NlRouteForeachFunc:
+ * @route: the route being processed
+ * @dst: the route's destination address
+ * @iface: the interface name of the index passed to nm_netlink_foreach_route()
+ * @in_family: the address family passed to nm_netlink_foreach_route()
+ * @user_data: the user data pointer passed to nm_netlink_foreach_route()
+ *
+ * Returns: a route to return to the caller of nm_netlink_foreach_route() which
+ * terminates routing table iteration, or NULL to continue iterating the
+ * routing table.
+ **/
+typedef struct rtnl_route * (*NlRouteForeachFunc) (struct rtnl_route *route,
+                                                   struct nl_addr *dst,
+                                                   const char *iface,
+                                                   gpointer user_data);
+
+struct rtnl_route * nm_netlink_foreach_route (int ifindex,
+                                              int family,
+                                              int scope,
+                                              gboolean ignore_inet6_ll_mc,
+                                              NlRouteForeachFunc callback,
+                                              gpointer user_data);
+
+#endif  /* NM_NETLINK_MONITOR_H */
+
diff --git a/src/nm-policy.c b/src/nm-policy.c
index a42a0fa9..5c4059e1 100644
--- a/src/nm-policy.c
+++ b/src/nm-policy.c
@@ -322,7 +322,7 @@ update_system_hostname (NMPolicy *policy, NMDevice *best4, NMDevice *best6)
 		/* Grab a hostname out of the device's DHCP4 config */
 		dhcp4_config = nm_device_get_dhcp4_config (best4);
 		if (dhcp4_config) {
-			p = dhcp_hostname = nm_dhcp4_config_get_option (dhcp4_config, "new_host_name");
+			p = dhcp_hostname = nm_dhcp4_config_get_option (dhcp4_config, "host_name");
 			if (dhcp_hostname && strlen (dhcp_hostname)) {
 				/* Sanity check; strip leading spaces */
 				while (*p) {
@@ -341,7 +341,7 @@ update_system_hostname (NMPolicy *policy, NMDevice *best4, NMDevice *best6)
 		/* Grab a hostname out of the device's DHCP6 config */
 		dhcp6_config = nm_device_get_dhcp6_config (best6);
 		if (dhcp6_config) {
-			p = dhcp_hostname = nm_dhcp6_config_get_option (dhcp6_config, "new_host_name");
+			p = dhcp_hostname = nm_dhcp6_config_get_option (dhcp6_config, "host_name");
 			if (dhcp_hostname && strlen (dhcp_hostname)) {
 				/* Sanity check; strip leading spaces */
 				while (*p) {
@@ -425,6 +425,7 @@ update_ip4_routing_and_dns (NMPolicy *policy, gboolean force_update)
 	NMConnection *connection = NULL;
 	NMSettingConnection *s_con = NULL;
 	const char *connection_id;
+	int ip_ifindex = 0;
 
 	best = get_best_ip4_device (policy->manager, &best_req);
 	if (!best)
@@ -461,17 +462,18 @@ update_ip4_routing_and_dns (NMPolicy *policy, gboolean force_update)
 			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);
 
 			parent = nm_vpn_connection_get_parent_device (candidate);
 			parent_ip4 = nm_device_get_ip4_config (parent);
 
-			nm_system_replace_default_ip4_route_vpn (ip_iface,
+			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_iface (parent),
+			                                         nm_device_get_ip_ifindex (parent),
 			                                         nm_ip4_config_get_mss (parent_ip4));
 
 			dns_type = NM_DNS_IP_CONFIG_TYPE_VPN;
@@ -483,12 +485,14 @@ update_ip4_routing_and_dns (NMPolicy *policy, gboolean force_update)
 	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_iface, nm_ip4_address_get_gateway (addr), nm_ip4_config_get_mss (ip4_config));
-
+		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;
 	}
 
@@ -551,6 +555,7 @@ update_ip6_routing_and_dns (NMPolicy *policy, gboolean force_update)
 	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;
@@ -608,11 +613,12 @@ update_ip6_routing_and_dns (NMPolicy *policy, gboolean force_update)
 	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_iface, nm_ip6_address_get_gateway (addr));
+		nm_system_replace_default_ip6_route (ip_ifindex, nm_ip6_address_get_gateway (addr));
 
 		dns_type = NM_DNS_IP_CONFIG_TYPE_BEST_DEVICE;
 	}
diff --git a/src/nm-system.c b/src/nm-system.c
index 88db6596..62ab8b93 100644
--- a/src/nm-system.c
+++ b/src/nm-system.c
@@ -40,7 +40,7 @@
 #include <netdb.h>
 #include <glib.h>
 #include <ctype.h>
-#include <net/if.h>
+#include <linux/if.h>
 
 #include "nm-system.h"
 #include "nm-device.h"
@@ -48,9 +48,8 @@
 #include "nm-utils.h"
 #include "nm-logging.h"
 #include "nm-netlink-monitor.h"
-
-/* Because of a bug in libnl, rtnl.h should be included before route.h */
-#include <netlink/route/rtnl.h>
+#include "nm-netlink-utils.h"
+#include "nm-netlink-compat.h"
 
 #include <netlink/route/addr.h>
 #include <netlink/route/route.h>
@@ -58,9 +57,9 @@
 #include <netlink/utils.h>
 #include <netlink/route/link.h>
 
-static void nm_system_device_set_priority (const char *iface,
-								   NMIP4Config *config,
-								   int priority);
+static void nm_system_device_set_priority (int ifindex,
+                                           NMIP4Config *config,
+                                           int priority);
 
 static gboolean
 ip4_dest_in_same_subnet (NMIP4Config *config, guint32 dest, guint32 dest_prefix)
@@ -87,99 +86,54 @@ ip4_dest_in_same_subnet (NMIP4Config *config, guint32 dest, guint32 dest_prefix)
 }
 
 static struct rtnl_route *
-create_route (int iface_idx, int mss)
-{
-	struct rtnl_route *route;
-
-	route = rtnl_route_alloc ();
-	if (route) {
-		rtnl_route_set_oif (route, iface_idx);
-
-		if (mss && rtnl_route_set_metric (route, RTAX_ADVMSS, mss) < 0) {
-			nm_log_warn (LOGD_DEVICE, "could not set mss");
-		}
-	} else
-		nm_log_err (LOGD_DEVICE, "could not allocate route");
-
-	return route;
-}
-
-static struct rtnl_route *
-nm_system_device_set_ip4_route (const char *iface, 
+nm_system_device_set_ip4_route (int ifindex, 
                                 guint32 ip4_dest,
                                 guint32 ip4_prefix,
                                 guint32 ip4_gateway,
                                 guint32 metric,
                                 int mss)
 {
-	struct nl_handle *nlh;
+	struct nl_sock *nlh;
 	struct rtnl_route *route;
-	struct nl_addr *dest_addr;
-	struct nl_addr *gw_addr = NULL;
-	int err, iface_idx;
+	int err;
+
+	g_return_val_if_fail (ifindex > 0, NULL);
 
 	nlh = nm_netlink_get_default_handle ();
 	g_return_val_if_fail (nlh != NULL, NULL);
 
-	iface_idx = nm_netlink_iface_to_index (iface);
-	g_return_val_if_fail (iface_idx >= 0, NULL);
-
-	route = create_route (iface_idx, mss);
+	route = nm_netlink_route_new (ifindex, AF_INET, mss,
+	                              NMNL_PROP_PRIO, metric,
+	                              NULL);
 	g_return_val_if_fail (route != NULL, NULL);
 
-	/* Destination */
-	dest_addr = nl_addr_build (AF_INET, &ip4_dest, sizeof (ip4_dest));
-	g_return_val_if_fail (dest_addr != NULL, NULL);
-	nl_addr_set_prefixlen (dest_addr, (int) ip4_prefix);
-
-	rtnl_route_set_dst (route, dest_addr);
-	nl_addr_put (dest_addr);
-
-	/* Gateway */
-	if (ip4_gateway) {
-		gw_addr = nl_addr_build (AF_INET, &ip4_gateway, sizeof (ip4_gateway));
-		if (gw_addr) {
-			rtnl_route_set_gateway (route, gw_addr);
-			rtnl_route_set_scope (route, RT_SCOPE_UNIVERSE);
-		} else {
-			nm_log_err (LOGD_DEVICE | LOGD_IP4, "Invalid gateway 0x%X", ip4_gateway);
-			rtnl_route_put (route);
-			return NULL;
-		}
-	}
-
-	/* Metric */
-	if (metric)
-		rtnl_route_set_prio (route, metric);
-
 	/* Add the route */
-	err = rtnl_route_add (nlh, route, 0);
-	if (err == -ESRCH && ip4_gateway) {
+	err = nm_netlink_route_add(route, AF_INET, &ip4_dest, ip4_prefix, &ip4_gateway, 0);
+	if (err == -NLE_OBJ_NOTFOUND && ip4_gateway) {
 		/* Gateway might be over a bridge; try adding a route to gateway first */
 		struct rtnl_route *route2;
 
-		route2 = create_route (iface_idx, mss);
+		route2 = nm_netlink_route_new (ifindex, AF_INET, mss, NULL);
 		if (route2) {
 			/* Add route to gateway over bridge */
-			rtnl_route_set_dst (route2, gw_addr);
-			err = rtnl_route_add (nlh, route2, 0);
+			err = nm_netlink_route_add(route2, AF_INET, &ip4_gateway, 32, NULL, 0);
 			if (!err) {
-				/* Try adding the route again */
-				err = rtnl_route_add (nlh, route, 0);
+				err = nm_netlink_route_add(route, AF_INET, &ip4_dest, ip4_prefix, &ip4_gateway, 0);
 				if (err)
-					rtnl_route_del (nlh, route2, 0);
+					nm_netlink_route_delete (route2);
 			}
 			rtnl_route_put (route2);
 		}
 	}
 
-	if (gw_addr)
-		nl_addr_put (gw_addr);
-
 	if (err) {
+		char *iface = nm_netlink_index_to_iface (ifindex);
+
 		nm_log_err (LOGD_DEVICE | LOGD_IP4,
 		            "(%s): failed to set IPv4 route: %s",
-		            iface, nl_geterror ());
+		            iface ? iface : "unknown", nl_geterror (err));
+		g_free (iface);
+
 		rtnl_route_put (route);
 		route = NULL;
 	}
@@ -188,17 +142,21 @@ nm_system_device_set_ip4_route (const char *iface,
 }
 
 static gboolean
-sync_addresses (const char *iface, int ifindex, int family,
-				struct rtnl_addr **addrs, int num_addrs)
+sync_addresses (int ifindex,
+                int family,
+				struct rtnl_addr **addrs,
+				int num_addrs)
 {
-	struct nl_handle *nlh;
-	struct nl_cache *addr_cache;
-	struct rtnl_addr *filter_addr, *match_addr;
+	struct nl_sock *nlh;
+	struct nl_cache *addr_cache = NULL;
+	struct rtnl_addr *filter_addr = NULL, *match_addr;
 	struct nl_object *match;
 	struct nl_addr *nladdr;
 	int i, err;
 	guint32 log_domain = (family == AF_INET) ? LOGD_IP4 : LOGD_IP6;
 	char buf[INET6_ADDRSTRLEN + 1];
+	char *iface = NULL;
+	gboolean success = FALSE;
 
 	log_domain |= LOGD_DEVICE;
 
@@ -206,19 +164,22 @@ sync_addresses (const char *iface, int ifindex, int family,
 	if (!nlh)
 		return FALSE;
 
-	addr_cache = rtnl_addr_alloc_cache (nlh);
-	if (!addr_cache)
+	err = rtnl_addr_alloc_cache (nlh, &addr_cache);
+	if (err < 0)
 		return FALSE;
 
 	filter_addr = rtnl_addr_alloc ();
-	if (!filter_addr) {
-		nl_cache_free (addr_cache);
-		return FALSE;
-	}
+	if (!filter_addr)
+		goto out;
+
 	rtnl_addr_set_ifindex (filter_addr, ifindex);
 	if (family)
 		rtnl_addr_set_family (filter_addr, family);
 
+	iface = nm_netlink_index_to_iface (ifindex);
+	if (!iface)
+		goto out;
+
 	nm_log_dbg (log_domain, "(%s): syncing addresses (family %d)", iface, family);
 
 	/* Walk through the cache, comparing the addresses already on
@@ -279,13 +240,10 @@ sync_addresses (const char *iface, int ifindex, int family,
 		err = rtnl_addr_delete (nlh, match_addr, 0);
 		if (err < 0) {
 			nm_log_err (log_domain, "(%s): error %d returned from rtnl_addr_delete(): %s",
-						iface, err, nl_geterror ());
+						iface, err, nl_geterror (err));
 		}
 	}
 
-	rtnl_addr_put (filter_addr);
-	nl_cache_free (addr_cache);
-
 	/* Now add the remaining new addresses */
 	for (i = 0; i < num_addrs; i++) {
 		struct in6_addr *in6tmp;
@@ -312,28 +270,40 @@ sync_addresses (const char *iface, int ifindex, int family,
 		}
 
 		err = rtnl_addr_add (nlh, addrs[i], 0);
-		if (err < 0 && (nl_get_errno () != EEXIST)) {
+		if (err < 0 && (err != -NLE_EXIST)) {
 			nm_log_err (log_domain,
 			            "(%s): error %d returned from rtnl_addr_add():\n%s",
-			            iface, err, nl_geterror ());
+			            iface, err, nl_geterror (err));
 		}
 
 		rtnl_addr_put (addrs[i]);
 	}
 	g_free (addrs);
+	success = TRUE;
 
-	return TRUE;
+out:
+	if (filter_addr)
+		rtnl_addr_put (filter_addr);
+	if (addr_cache)
+		nl_cache_free (addr_cache);
+	g_free (iface);
+	return success;
 }
 
 static gboolean
-add_ip4_addresses (NMIP4Config *config, const char *iface)
+add_ip4_addresses (NMIP4Config *config, int ifindex)
 {
-	int num_addrs, i, iface_idx;
+	char *iface;
+	int num_addrs, i;
 	guint32 flags = 0;
 	gboolean did_gw = FALSE;
 	struct rtnl_addr **addrs;
 
-	iface_idx = nm_netlink_iface_to_index (iface);
+	g_return_val_if_fail (ifindex > 0, FALSE);
+
+	iface = nm_netlink_index_to_iface (ifindex);
+	if (!iface)
+		return FALSE;
 
 	num_addrs = nm_ip4_config_get_num_addresses (config);
 	addrs = g_new0 (struct rtnl_addr *, num_addrs + 1);
@@ -355,13 +325,14 @@ add_ip4_addresses (NMIP4Config *config, const char *iface)
 		if (!addrs[i]) {
 			nm_log_warn (LOGD_DEVICE | LOGD_IP4,
 			             "(%s): couldn't create rtnl address!",
-			             iface);
+			             iface ? iface : "unknown");
 			continue;
 		}
-		rtnl_addr_set_ifindex (addrs[i], iface_idx);
+		rtnl_addr_set_ifindex (addrs[i], ifindex);
 	}
+	g_free (iface);
 
-	return sync_addresses (iface, iface_idx, AF_INET, addrs, num_addrs);
+	return sync_addresses (ifindex, AF_INET, addrs, num_addrs);
 }
 
 struct rtnl_route *
@@ -406,10 +377,10 @@ nm_system_add_ip4_vpn_gateway_route (NMDevice *parent_device, NMIP4Config *vpn_c
 	 * parent device.
 	 */
 	if (ip4_dest_in_same_subnet (parent_config, vpn_gw, parent_prefix)) {
-		route = nm_system_device_set_ip4_route (nm_device_get_ip_iface (parent_device),
+		route = nm_system_device_set_ip4_route (nm_device_get_ip_ifindex (parent_device),
 		                                        vpn_gw, 32, 0, 0, nm_ip4_config_get_mss (parent_config));
 	} else {
-		route = nm_system_device_set_ip4_route (nm_device_get_ip_iface (parent_device),
+		route = nm_system_device_set_ip4_route (nm_device_get_ip_ifindex (parent_device),
 		                                        vpn_gw, 32, parent_gw, 0, nm_ip4_config_get_mss (parent_config));
 	}
 
@@ -423,18 +394,18 @@ nm_system_add_ip4_vpn_gateway_route (NMDevice *parent_device, NMIP4Config *vpn_c
  *
  */
 gboolean
-nm_system_apply_ip4_config (const char *iface,
+nm_system_apply_ip4_config (int ifindex,
                             NMIP4Config *config,
                             int priority,
                             NMIP4ConfigCompareFlags flags)
 {
 	int i;
 
-	g_return_val_if_fail (iface != NULL, FALSE);
+	g_return_val_if_fail (ifindex > 0, FALSE);
 	g_return_val_if_fail (config != NULL, FALSE);
 
 	if (flags & NM_IP4_COMPARE_FLAG_ADDRESSES) {
-		if (!add_ip4_addresses (config, iface))
+		if (!add_ip4_addresses (config, ifindex))
 			return FALSE;
 		sleep (1);
 	}
@@ -459,7 +430,7 @@ nm_system_apply_ip4_config (const char *iface,
 			    && nm_ip4_route_get_dest (route) == 0)
 				continue;
 
-			tmp = nm_system_device_set_ip4_route (iface,
+			tmp = nm_system_device_set_ip4_route (ifindex,
 			                                      nm_ip4_route_get_dest (route),
 			                                      nm_ip4_route_get_prefix (route),
 			                                      nm_ip4_route_get_next_hop (route),
@@ -471,11 +442,11 @@ nm_system_apply_ip4_config (const char *iface,
 
 	if (flags & NM_IP4_COMPARE_FLAG_MTU) {
 		if (nm_ip4_config_get_mtu (config))
-			nm_system_device_set_mtu (iface, nm_ip4_config_get_mtu (config));
+			nm_system_iface_set_mtu (ifindex, nm_ip4_config_get_mtu (config));
 	}
 
 	if (priority > 0)
-		nm_system_device_set_priority (iface, config, priority);
+		nm_system_device_set_priority (ifindex, config, priority);
 
 	return TRUE;
 }
@@ -491,10 +462,8 @@ nm_system_set_ip6_route (int ifindex,
                          int table,
                          struct rtnl_route **out_route)
 {
-	struct nl_handle *nlh;
+	struct nl_sock *nlh;
 	struct rtnl_route *route;
-	struct nl_addr *dest_addr;
-	struct nl_addr *gw_addr = NULL;
 	int err = 0;
 
 	g_return_val_if_fail (ifindex >= 0, -1);
@@ -502,64 +471,33 @@ nm_system_set_ip6_route (int ifindex,
 	nlh = nm_netlink_get_default_handle ();
 	g_return_val_if_fail (nlh != NULL, -1);
 
-	route = create_route (ifindex, mss);
+	route = nm_netlink_route_new (ifindex, AF_INET6, mss,
+	                              NMNL_PROP_PROT, protocol,
+	                              NMNL_PROP_PRIO, metric,
+	                              NMNL_PROP_TABLE, table,
+	                              NULL);
 	g_return_val_if_fail (route != NULL, -1);
 
-	/* Destination */
-	dest_addr = nl_addr_build (AF_INET6, (struct in6_addr *) ip6_dest, sizeof (*ip6_dest));
-	g_return_val_if_fail (dest_addr != NULL, -1);
-	nl_addr_set_prefixlen (dest_addr, (int) ip6_prefix);
-
-	rtnl_route_set_dst (route, dest_addr);
-	nl_addr_put (dest_addr);
-
-	/* Gateway */
-	if (ip6_gateway && !IN6_IS_ADDR_UNSPECIFIED (ip6_gateway)) {
-		gw_addr = nl_addr_build (AF_INET6, (struct in6_addr *) ip6_gateway, sizeof (*ip6_gateway));
-		if (gw_addr) {
-			rtnl_route_set_gateway (route, gw_addr);
-			rtnl_route_set_scope (route, RT_SCOPE_UNIVERSE);
-		} else {
-			nm_log_warn (LOGD_DEVICE | LOGD_IP6, "Invalid gateway");
-			rtnl_route_put (route);
-			return -1;
-		}
-	}
-
-	/* Metric */
-	if (metric)
-		rtnl_route_set_prio (route, metric);
-
-	if (protocol)
-		rtnl_route_set_protocol (route, protocol);
-
-	if (table)
-		rtnl_route_set_table (route, table);
-
 	/* Add the route */
-	err = rtnl_route_add (nlh, route, 0);
-	if (err == -ESRCH && ip6_gateway) {
+	err = nm_netlink_route_add(route, AF_INET6, &ip6_dest, ip6_prefix, &ip6_gateway, 0);
+	if (err == -NLE_OBJ_NOTFOUND && ip6_gateway) {
 		/* Gateway might be over a bridge; try adding a route to gateway first */
 		struct rtnl_route *route2;
 
-		route2 = create_route (ifindex, mss);
+		route2 = nm_netlink_route_new (ifindex, AF_INET6, mss, NULL);
 		if (route2) {
+			err = nm_netlink_route_add(route, AF_INET6, &ip6_gateway, 128, NULL, 0);
 			/* Add route to gateway over bridge */
-			rtnl_route_set_dst (route2, gw_addr);
-			err = rtnl_route_add (nlh, route2, 0);
 			if (!err) {
 				/* Try adding the route again */
-				err = rtnl_route_add (nlh, route, 0);
+				err = nm_netlink_route_add(route, AF_INET6, &ip6_dest, ip6_prefix, &ip6_gateway, 0);
 				if (err)
-					rtnl_route_del (nlh, route2, 0);
+					nm_netlink_route_delete (route2);
 			}
 			rtnl_route_put (route2);
 		}
 	}
 
-	if (gw_addr)
-		nl_addr_put (gw_addr);
-
 	if (out_route)
 		*out_route = route;
 	else
@@ -569,12 +507,17 @@ nm_system_set_ip6_route (int ifindex,
 }
 
 static gboolean
-add_ip6_addresses (NMIP6Config *config, const char *iface)
+add_ip6_addresses (NMIP6Config *config, int ifindex)
 {
-	int num_addrs, i, iface_idx;
+	char *iface;
+	int num_addrs, i;
 	struct rtnl_addr **addrs;
 
-	iface_idx = nm_netlink_iface_to_index (iface);
+	g_return_val_if_fail (ifindex > 0, FALSE);
+
+	iface = nm_netlink_index_to_iface (ifindex);
+	if (!iface)
+		return FALSE;
 
 	num_addrs = nm_ip6_config_get_num_addresses (config);
 	addrs = g_new0 (struct rtnl_addr *, num_addrs + 1);
@@ -589,13 +532,14 @@ add_ip6_addresses (NMIP6Config *config, const char *iface)
 		if (!addrs[i]) {
 			nm_log_warn (LOGD_DEVICE | LOGD_IP6,
 			             "(%s): couldn't create rtnl address!",
-			             iface);
+			             iface ? iface : "unknown");
 			continue;
 		}
-		rtnl_addr_set_ifindex (addrs[i], iface_idx);
+		rtnl_addr_set_ifindex (addrs[i], ifindex);
 	}
+	g_free (iface);
 
-	return sync_addresses (iface, iface_idx, AF_INET6, addrs, num_addrs);
+	return sync_addresses (ifindex, AF_INET6, addrs, num_addrs);
 }
 
 /*
@@ -605,24 +549,24 @@ add_ip6_addresses (NMIP6Config *config, const char *iface)
  *
  */
 gboolean
-nm_system_apply_ip6_config (const char *iface,
+nm_system_apply_ip6_config (int ifindex,
                             NMIP6Config *config,
                             int priority,
                             NMIP6ConfigCompareFlags flags)
 {
 	int i;
 
-	g_return_val_if_fail (iface != NULL, FALSE);
+	g_return_val_if_fail (ifindex > 0, FALSE);
 	g_return_val_if_fail (config != NULL, FALSE);
 
 	if (flags & NM_IP6_COMPARE_FLAG_ADDRESSES) {
-		if (!add_ip6_addresses (config, iface))
+		if (!add_ip6_addresses (config, ifindex))
 			return FALSE;
 		sleep (1); // FIXME?
 	}
 
 	if (flags & NM_IP6_COMPARE_FLAG_ROUTES) {
-		int ifindex = nm_netlink_iface_to_index (iface);
+		char *iface = nm_netlink_index_to_iface (ifindex);
 
 		for (i = 0; i < nm_ip6_config_get_num_routes (config); i++) {
 			NMIP6Route *route = nm_ip6_config_get_route (config, i);
@@ -647,9 +591,11 @@ nm_system_apply_ip6_config (const char *iface,
 			if (err) {
 				nm_log_err (LOGD_DEVICE | LOGD_IP6,
 				            "(%s): failed to set IPv6 route: %s",
-				            iface, nl_geterror ());
+				            iface ? iface : "unknown",
+				            nl_geterror (err));
 			}
 		}
+		g_free (iface);
 	}
 
 // FIXME
@@ -659,217 +605,221 @@ nm_system_apply_ip6_config (const char *iface,
 	return TRUE;
 }
 
-/*
- * nm_system_device_set_up_down
+/**
+ * nm_system_iface_set_up:
+ * @ifindex: interface index
+ * @up: %TRUE to bring interface up, or %FALSE to take it down
+ * @no_firmware: on return, %TRUE if the operation may have failed due to
+ * missing firmware
  *
- * Mark the device as up or down.
+ * Bring the interface up or take it down.
  *
- */
-gboolean
-nm_system_device_set_up_down (NMDevice *dev,
-                              gboolean up,
-                              gboolean *no_firmware)
-{
-	g_return_val_if_fail (dev != NULL, FALSE);
-
-	return nm_system_device_set_up_down_with_iface (nm_device_get_ip_iface (dev), up, no_firmware);
-}
-
+ * Returns: %TRUE on success, %FALSE on failure
+ **/
 gboolean
-nm_system_device_set_up_down_with_iface (const char *iface,
-                                         gboolean up,
-                                         gboolean *no_firmware)
+nm_system_iface_set_up (int ifindex,
+                        gboolean up,
+                        gboolean *no_firmware)
 {
 	struct rtnl_link *request = NULL, *old = NULL;
-	struct nl_handle *nlh;
+	struct nl_sock *nlh;
 	gboolean success = FALSE;
-	guint32 idx;
+	int err;
 
-	g_return_val_if_fail (iface != NULL, FALSE);
+	g_return_val_if_fail (ifindex > 0, FALSE);
 	if (no_firmware)
 		g_return_val_if_fail (*no_firmware == FALSE, FALSE);
 
 	if (!(request = rtnl_link_alloc ()))
-		goto out;
+		return FALSE;
 
 	if (up)
 		rtnl_link_set_flags (request, IFF_UP);
 	else
 		rtnl_link_unset_flags (request, IFF_UP);
 
-	idx = nm_netlink_iface_to_index (iface);
-	old = nm_netlink_index_to_rtnl_link (idx);
+	old = nm_netlink_index_to_rtnl_link (ifindex);
 	if (old) {
 		nlh = nm_netlink_get_default_handle ();
 		if (nlh) {
-			if (rtnl_link_change (nlh, old, request, 0) == 0)
+			err = rtnl_link_change (nlh, old, request, 0);
+			if (err == 0) {
 				success = TRUE;
-			else if ((nl_get_errno () == ENOENT) && no_firmware && up)
-				*no_firmware = TRUE;
+			} else {
+				if ((err == -NLE_OBJ_NOTFOUND) && no_firmware && up)
+					*no_firmware = TRUE;
+			}
 		}
 	}
 
 	rtnl_link_put (old);
 	rtnl_link_put (request);
-
-out:
 	return success;
 }
 
+/**
+ * nm_system_iface_is_up:
+ * @ifindex: interface index
+ *
+ * Returns: %TRUE if the interface is up, %FALSE if it was down or the check
+ * failed.
+ **/
 gboolean
-nm_system_device_is_up (NMDevice *device)
+nm_system_iface_is_up (int ifindex)
 {
-	g_return_val_if_fail (device != NULL, FALSE);
+	struct rtnl_link *l;
+	guint32 flags;
 
-	return nm_system_device_is_up_with_iface (nm_device_get_ip_iface (device));
-}
+	g_return_val_if_fail (ifindex > 0, FALSE);
 
-gboolean
-nm_system_device_is_up_with_iface (const char *iface)
-{
-	struct ifreq ifr;
-	int fd;
-	gboolean up = FALSE;
+	l = nm_netlink_index_to_rtnl_link (ifindex);
+	if (l == NULL) {
+		char *iface = nm_netlink_index_to_iface (ifindex);
 
-	fd = socket (PF_INET, SOCK_DGRAM, 0);
-	if (fd < 0) {
-		nm_log_err (LOGD_HW, "couldn't open control socket.");
+		g_warn_if_fail (iface != NULL);
+		nm_log_err (LOGD_HW, "(%s): failed to get interface link object",
+		            iface ? iface : "unknown");
+		g_free (iface);
 		return FALSE;
 	}
 
-	/* Get device's flags */
-	memset (&ifr, 0, sizeof (ifr));
-	strncpy (ifr.ifr_name, iface, IFNAMSIZ);
-	if (ioctl (fd, SIOCGIFFLAGS, &ifr) < 0) {
-		if (errno != ENODEV) {
-			nm_log_err (LOGD_HW, "(%s): could not get flags: errno %d",
-			            iface, errno);
-		}
-	} else {
-		up = !!(ifr.ifr_flags & IFF_UP);
-	}
-	close (fd);
+	flags = rtnl_link_get_flags (l);
+	rtnl_link_put (l);
 
-	return up;
+	return flags & IFF_UP;
 }
 
+/**
+ * nm_system_iface_set_mtu:
+ * @ifindex: interface index
+ * @mtu: the new MTU
+ *
+ * Returns: %TRUE if the request was successful, %FALSE if it failed
+ **/
 gboolean
-nm_system_device_set_mtu (const char *iface, guint32 mtu)
+nm_system_iface_set_mtu (int ifindex, guint32 mtu)
 {
 	struct rtnl_link *old;
 	struct rtnl_link *new;
 	gboolean success = FALSE;
-	struct nl_handle *nlh;
-	int iface_idx;
+	struct nl_sock *nlh;
+	int err;
 
-	g_return_val_if_fail (iface != NULL, FALSE);
+	g_return_val_if_fail (ifindex > 0, FALSE);
 	g_return_val_if_fail (mtu > 0, FALSE);
 
 	new = rtnl_link_alloc ();
 	if (!new)
 		return FALSE;
 
-	iface_idx = nm_netlink_iface_to_index (iface);
-	old = nm_netlink_index_to_rtnl_link (iface_idx);
+	old = nm_netlink_index_to_rtnl_link (ifindex);
 	if (old) {
 		rtnl_link_set_mtu (new, mtu);
 		nlh = nm_netlink_get_default_handle ();
 		if (nlh) {
-			rtnl_link_change (nlh, old, new, 0);
-			success = TRUE;
+			err = rtnl_link_change (nlh, old, new, 0);
+			if (err == 0)
+				success = TRUE;
+			else {
+				char *iface = nm_netlink_index_to_iface (ifindex);
+
+				nm_log_warn (LOGD_HW, "(%s): failed to change interface MTU",
+				             iface ? iface : "unknown");
+				g_free (iface);
+			}
 		}
 		rtnl_link_put (old);
 	}
-
 	rtnl_link_put (new);
+
 	return success;
 }
 
+/**
+ * nm_system_iface_set_mac:
+ * @ifindex: interface index
+ * @mac: new MAC address
+ *
+ * Attempts to change the interface's MAC address to the requested value,
+ * ie MAC spoofing or cloning.
+ *
+ * Returns: %TRUE if the request succeeded, %FALSE if it failed.
+ **/
 gboolean
-nm_system_device_set_mac (const char *iface, const struct ether_addr *mac)
+nm_system_iface_set_mac (int ifindex, const struct ether_addr *mac)
 {
-	struct rtnl_link *old;
-	struct rtnl_link *new;
+	struct rtnl_link *old, *new;
 	gboolean success = FALSE;
-	struct nl_handle *nlh;
-	int iface_idx;
+	struct nl_sock *nlh;
+	char *iface;
 	struct nl_addr *addr = NULL;
+	int err;
 
-	g_return_val_if_fail (iface != NULL, FALSE);
+	g_return_val_if_fail (ifindex > 0, FALSE);
 	g_return_val_if_fail (mac != NULL, FALSE);
 
 	new = rtnl_link_alloc ();
 	if (!new)
 		return FALSE;
 
-	iface_idx = nm_netlink_iface_to_index (iface);
-	old = nm_netlink_index_to_rtnl_link (iface_idx);
+	iface = nm_netlink_index_to_iface (ifindex);
+	if (!iface)
+		goto out;
+
+	old = nm_netlink_index_to_rtnl_link (ifindex);
 	if (old) {
 		addr = nl_addr_build (AF_LLC, (void *) mac, ETH_ALEN);
 		if (!addr) {
-			char *mac_str;
-			mac_str = g_strdup_printf ("%02X:%02X:%02X:%02X:%02X:%02X", mac->ether_addr_octet[0], mac->ether_addr_octet[1], mac->ether_addr_octet[2],
-			                                                            mac->ether_addr_octet[3], mac->ether_addr_octet[4], mac->ether_addr_octet[5]);
-			nm_log_err (LOGD_DEVICE, "(%s): could not allocate memory for MAC address (%s)", iface, mac_str);
-			g_free (mac_str);
+			nm_log_err (LOGD_HW, "(%s): failed to allocate memory for MAC address change", iface);
+			rtnl_link_put (old);
+			rtnl_link_put (new);
 			return FALSE;
 		}
 		rtnl_link_set_addr (new, addr);
+		nl_addr_put (addr);
 		nlh = nm_netlink_get_default_handle ();
 		if (nlh) {
-			rtnl_link_change (nlh, old, new, 0);
-			success = TRUE;
+			err = rtnl_link_change (nlh, old, new, 0);
+			if (err == 0)
+				success = TRUE;
+			else
+				nm_log_warn (LOGD_HW, "(%s): failed to change interface MAC address", iface);
 		}
 		rtnl_link_put (old);
 	}
 
+out:
 	rtnl_link_put (new);
+	g_free (iface);
 	return success;
 }
 
 static struct rtnl_route *
-add_ip4_route_to_gateway (const char *iface, guint32 gw, guint32 mss)
+add_ip4_route_to_gateway (int ifindex, guint32 gw, guint32 mss)
 {
-	struct nl_handle *nlh;
+	struct nl_sock *nlh;
 	struct rtnl_route *route = NULL;
-	struct nl_addr *gw_addr = NULL;
-	int iface_idx, err;
+	int err;
 
 	nlh = nm_netlink_get_default_handle ();
 	g_return_val_if_fail (nlh != NULL, NULL);
 
-	iface_idx = nm_netlink_iface_to_index (iface);
-	if (iface_idx < 0)
-		return NULL;
-
 	/* Gateway might be over a bridge; try adding a route to gateway first */
-	route = rtnl_route_alloc ();
-	if (route == NULL)
-		return NULL;
-
-	rtnl_route_set_family (route, AF_INET);
-	rtnl_route_set_table (route, RT_TABLE_MAIN);
-	rtnl_route_set_oif (route, iface_idx);
-	rtnl_route_set_scope (route, RT_SCOPE_LINK);
-
-	gw_addr = nl_addr_build (AF_INET, &gw, sizeof (gw));
-	if (!gw_addr)
-		goto error;
-	nl_addr_set_prefixlen (gw_addr, 32);
-	rtnl_route_set_dst (route, gw_addr);
-	nl_addr_put (gw_addr);
-
-	if (mss) {
-		if (rtnl_route_set_metric (route, RTAX_ADVMSS, mss) < 0)
-			goto error;
-	}
+	route = nm_netlink_route_new (ifindex, AF_INET, mss,
+	                              NMNL_PROP_SCOPE, RT_SCOPE_LINK,
+	                              NMNL_PROP_TABLE, RT_TABLE_MAIN,
+	                              NULL);
+	g_return_val_if_fail (route != NULL, NULL);
 
 	/* Add direct route to the gateway */
-	err = rtnl_route_add (nlh, route, 0);
+	err = nm_netlink_route_add(route, AF_INET, &gw, 32, NULL, 0);
 	if (err) {
+		char *iface = nm_netlink_index_to_iface (ifindex);
+
 		nm_log_err (LOGD_DEVICE | LOGD_IP4,
 		            "(%s): failed to add IPv4 route to gateway (%d)",
-		            iface, err);
+		            iface ? iface : "unknown", err);
+		g_free (iface);
 		goto error;
 	}
 
@@ -881,64 +831,27 @@ error:
 }
 
 static int
-replace_default_ip4_route (const char *iface, guint32 gw, guint32 mss)
+replace_default_ip4_route (int ifindex, guint32 gw, guint32 mss)
 {
 	struct rtnl_route *route = NULL;
-	struct nl_handle *nlh;
-	struct nl_addr *dst_addr = NULL;
-	guint32 dst = 0;
-	struct nl_addr *gw_addr = NULL;
-	int iface_idx, err = -1;
+	struct nl_sock *nlh;
+	int err = -1;
+	int dst=0;
 
-	g_return_val_if_fail (iface != NULL, -ENODEV);
+	g_return_val_if_fail (ifindex > 0, -ENODEV);
 
 	nlh = nm_netlink_get_default_handle ();
 	g_return_val_if_fail (nlh != NULL, -ENOMEM);
 
-	iface_idx = nm_netlink_iface_to_index (iface);
-	if (iface_idx < 0)
-		return -ENODEV;
-
-	route = rtnl_route_alloc();
+	route = nm_netlink_route_new (ifindex, AF_INET, mss,
+	                              NMNL_PROP_SCOPE, RT_SCOPE_UNIVERSE,
+	                              NMNL_PROP_TABLE, RT_TABLE_MAIN,
+	                              NULL);
 	g_return_val_if_fail (route != NULL, -ENOMEM);
 
-	rtnl_route_set_family (route, AF_INET);
-	rtnl_route_set_table (route, RT_TABLE_MAIN);
-	rtnl_route_set_scope (route, RT_SCOPE_UNIVERSE);
-	rtnl_route_set_oif (route, iface_idx);
-
-	/* Build up the destination address */
-	dst_addr = nl_addr_build (AF_INET, &dst, sizeof (dst));
-	if (!dst_addr) {
-		err = -ENOMEM;
-		goto out;
-	}
-	nl_addr_set_prefixlen (dst_addr, 0);
-	rtnl_route_set_dst (route, dst_addr);
-
-	/* Build up the gateway address */
-	gw_addr = nl_addr_build (AF_INET, &gw, sizeof (gw));
-	if (!gw_addr) {
-		err = -ENOMEM;
-		goto out;
-	}
-	nl_addr_set_prefixlen (gw_addr, 0);
-	rtnl_route_set_gateway (route, gw_addr);
-
-	if (mss > 0) {
-		err = rtnl_route_set_metric (route, RTAX_ADVMSS, mss);
-		if (err < 0)
-			goto out;
-	}
-
 	/* Add the new default route */
-	err = rtnl_route_add (nlh, route, NLM_F_REPLACE);
+	err = nm_netlink_route_add (route, AF_INET, &dst, 0, &gw, NLM_F_REPLACE);
 
-out:
-	if (dst_addr)
-		nl_addr_put (dst_addr);
-	if (gw_addr)
-		nl_addr_put (gw_addr);
 	rtnl_route_put (route);
 	return err;
 }
@@ -950,47 +863,56 @@ out:
  *
  */
 gboolean
-nm_system_replace_default_ip4_route_vpn (const char *iface,
+nm_system_replace_default_ip4_route_vpn (int ifindex,
                                          guint32 ext_gw,
                                          guint32 int_gw,
                                          guint32 mss,
-                                         const char *parent_iface,
+                                         int parent_ifindex,
                                          guint32 parent_mss)
 {
 	struct rtnl_route *gw_route = NULL;
-	struct nl_handle *nlh;
+	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_ip4_route (iface, int_gw, mss);
-	if (err == 0) {
+	err = replace_default_ip4_route (ifindex, int_gw, mss);
+	if (err == 0)
 		return TRUE;
-	} else if (err != -ESRCH) {
+
+	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_IP4,
 		            "(%s): failed to set IPv4 default route: %d",
 		            iface, err);
-		return FALSE;
+		goto out;
 	}
 
 	/* Try adding a direct route to the gateway first */
-	gw_route = add_ip4_route_to_gateway (parent_iface, ext_gw, parent_mss);
+	gw_route = add_ip4_route_to_gateway (parent_ifindex, ext_gw, parent_mss);
 	if (!gw_route)
-		return FALSE;
+		goto out;
 
 	/* Try adding the original route again */
-	err = replace_default_ip4_route (iface, int_gw, mss);
+	err = replace_default_ip4_route (ifindex, int_gw, mss);
 	if (err != 0) {
-		rtnl_route_del (nlh, gw_route, 0);
+		nm_netlink_route_delete (gw_route);
 		nm_log_err (LOGD_DEVICE | LOGD_IP4,
 		            "(%s): failed to set IPv4 default route (pass #2): %d",
 		            iface, err);
 	} else
 		success = TRUE;
 
-	rtnl_route_put (gw_route);
+out:
+	if (gw_route)
+		rtnl_route_put (gw_route);
+	g_free (iface);
 	return success;
 }
 
@@ -1001,132 +923,105 @@ nm_system_replace_default_ip4_route_vpn (const char *iface,
  *
  */
 gboolean
-nm_system_replace_default_ip4_route (const char *iface, guint32 gw, guint32 mss)
+nm_system_replace_default_ip4_route (int ifindex, guint32 gw, guint32 mss)
 {
 	struct rtnl_route *gw_route = NULL;
-	struct nl_handle *nlh;
 	gboolean success = FALSE;
+	char *iface;
 	int err;
 
-	nlh = nm_netlink_get_default_handle ();
-	g_return_val_if_fail (nlh != NULL, FALSE);
-
-	err = replace_default_ip4_route (iface, gw, mss);
-	if (err == 0) {
+	err = replace_default_ip4_route (ifindex, gw, mss);
+	if (err == 0)
 		return TRUE;
-	} else if (err != -ESRCH) {
+
+	iface = nm_netlink_index_to_iface (ifindex);
+	if (!iface)
+		goto out;
+
+	if (err != -NLE_OBJ_NOTFOUND) {
 		nm_log_err (LOGD_DEVICE | LOGD_IP4,
 		            "(%s): failed to set IPv4 default route: %d",
 		            iface, err);
-		return FALSE;
+		goto out;
 	}
 
 	/* Try adding a direct route to the gateway first */
-	gw_route = add_ip4_route_to_gateway (iface, gw, mss);
+	gw_route = add_ip4_route_to_gateway (ifindex, gw, mss);
 	if (!gw_route)
-		return FALSE;
+		goto out;
 
 	/* Try adding the original route again */
-	err = replace_default_ip4_route (iface, gw, mss);
+	err = replace_default_ip4_route (ifindex, gw, mss);
 	if (err != 0) {
-		rtnl_route_del (nlh, gw_route, 0);
+		nm_netlink_route_delete (gw_route);
 		nm_log_err (LOGD_DEVICE | LOGD_IP4,
 		            "(%s): failed to set IPv4 default route (pass #2): %d",
 		            iface, err);
 	} else
 		success = TRUE;
 
-	rtnl_route_put (gw_route);
+out:
+	if (gw_route)
+		rtnl_route_put (gw_route);
+	g_free (iface);
 	return success;
 }
 
 static struct rtnl_route *
-add_ip6_route_to_gateway (const char *iface, const struct in6_addr *gw)
+add_ip6_route_to_gateway (int ifindex, const struct in6_addr *gw)
 {
-	struct nl_handle *nlh;
+	struct nl_sock *nlh;
 	struct rtnl_route *route = NULL;
-	struct nl_addr *gw_addr = NULL;
-	int iface_idx, err;
+	int err;
 
 	nlh = nm_netlink_get_default_handle ();
 	g_return_val_if_fail (nlh != NULL, NULL);
 
-	iface_idx = nm_netlink_iface_to_index (iface);
-	if (iface_idx < 0)
-		return NULL;
-
 	/* Gateway might be over a bridge; try adding a route to gateway first */
-	route = rtnl_route_alloc ();
-	if (route == NULL)
-		return NULL;
-
-	rtnl_route_set_family (route, AF_INET6);
-	rtnl_route_set_table (route, RT_TABLE_MAIN);
-	rtnl_route_set_oif (route, iface_idx);
-	rtnl_route_set_scope (route, RT_SCOPE_LINK);
-
-	gw_addr = nl_addr_build (AF_INET, (void *) gw, sizeof (*gw));
-	if (!gw_addr)
-		goto error;
-	nl_addr_set_prefixlen (gw_addr, 128);
-	rtnl_route_set_dst (route, gw_addr);
-	nl_addr_put (gw_addr);
+	route = nm_netlink_route_new (ifindex, AF_INET6, 0,
+	                              NMNL_PROP_SCOPE, RT_SCOPE_LINK,
+	                              NMNL_PROP_TABLE, RT_TABLE_MAIN,
+	                              NULL);
+	g_return_val_if_fail (route != NULL, NULL);
 
 	/* Add direct route to the gateway */
-	err = rtnl_route_add (nlh, route, 0);
+	err = nm_netlink_route_add(route, AF_INET, gw, 128, NULL, 0);
 	if (err) {
+		char *iface = nm_netlink_index_to_iface (ifindex);
+
 		nm_log_err (LOGD_DEVICE | LOGD_IP6,
-		            "(%s): failed to add IPv4 route to gateway (%d)",
-		            iface, err);
-		goto error;
+		            "(%s): failed to add IPv6 route to gateway (%d)",
+		            iface ? iface : "unknown", err);
+		g_free (iface);
+
+		rtnl_route_put (route);
+		route = NULL;
 	}
 
 	return route;
-
-error:
-	rtnl_route_put (route);
-	return NULL;
 }
 
 static int
-replace_default_ip6_route (const char *iface, const struct in6_addr *gw)
+replace_default_ip6_route (int ifindex, const struct in6_addr *gw)
 {
 	struct rtnl_route *route = NULL;
-	struct nl_handle *nlh;
-	struct nl_addr *gw_addr = NULL;
-	int iface_idx, err = -1;
+	struct nl_sock *nlh;
+	int err = -1;
 
-	g_return_val_if_fail (iface != NULL, -ENODEV);
+	g_return_val_if_fail (ifindex > 0, FALSE);
 
 	nlh = nm_netlink_get_default_handle ();
 	g_return_val_if_fail (nlh != NULL, -ENOMEM);
 
-	iface_idx = nm_netlink_iface_to_index (iface);
-	if (iface_idx < 0)
-		return -ENODEV;
-
-	route = rtnl_route_alloc();
+	route = nm_netlink_route_new (ifindex, AF_INET6, 0,
+	                              NMNL_PROP_SCOPE, RT_SCOPE_UNIVERSE,
+	                              NMNL_PROP_TABLE, RT_TABLE_MAIN,
+	                              NULL);
 	g_return_val_if_fail (route != NULL, -ENOMEM);
 
-	rtnl_route_set_family (route, AF_INET6);
-	rtnl_route_set_table (route, RT_TABLE_MAIN);
-	rtnl_route_set_scope (route, RT_SCOPE_UNIVERSE);
-	rtnl_route_set_oif (route, iface_idx);
-
-	if (gw && !IN6_IS_ADDR_UNSPECIFIED (gw)) {
-		/* Build up the gateway address */
-		gw_addr = nl_addr_build (AF_INET6, (void *) gw, sizeof (*gw));
-		if (!gw_addr) {
-			err = -ENOMEM;
-			goto out;
-		}
-		nl_addr_set_prefixlen (gw_addr, -1);
-		rtnl_route_set_gateway (route, gw_addr);
-	}
-
 	/* Add the new default route */
-	err = rtnl_route_add (nlh, route, NLM_F_REPLACE);
-	if (err == -EEXIST) {
+	nm_netlink_route_add(route, AF_INET6, NULL, 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.  Should try to remove it first, then
 		 * add the new one again here.
@@ -1134,9 +1029,6 @@ replace_default_ip6_route (const char *iface, const struct in6_addr *gw)
 		err = 0;
 	}
 
-out:
-	if (gw_addr)
-		nl_addr_put (gw_addr);
 	rtnl_route_put (route);
 	return err;
 }
@@ -1148,208 +1040,99 @@ out:
  *
  */
 gboolean
-nm_system_replace_default_ip6_route (const char *iface, const struct in6_addr *gw)
+nm_system_replace_default_ip6_route (int ifindex, const struct in6_addr *gw)
 {
 	struct rtnl_route *gw_route = NULL;
-	struct nl_handle *nlh;
 	gboolean success = FALSE;
+	char *iface;
 	int err;
 
-	nlh = nm_netlink_get_default_handle ();
-	g_return_val_if_fail (nlh != NULL, FALSE);
-
-	err = replace_default_ip6_route (iface, gw);
-	if (err == 0) {
+	err = replace_default_ip6_route (ifindex, gw);
+	if (err == 0)
 		return TRUE;
-	} else if (err != -ESRCH) {
+
+	iface = nm_netlink_index_to_iface (ifindex);
+	if (!iface)
+		goto out;
+
+	if (err != -NLE_OBJ_NOTFOUND) {
 		nm_log_err (LOGD_DEVICE | LOGD_IP6,
 		            "(%s): failed to set IPv6 default route: %d",
 		            iface, err);
-		return FALSE;
+		goto out;
 	}
 
 	/* Try adding a direct route to the gateway first */
-	gw_route = add_ip6_route_to_gateway (iface, gw);
+	gw_route = add_ip6_route_to_gateway (ifindex, gw);
 	if (!gw_route)
-		return FALSE;
+		goto out;
 
 	/* Try adding the original route again */
-	err = replace_default_ip6_route (iface, gw);
+	err = replace_default_ip6_route (ifindex, gw);
 	if (err != 0) {
-		rtnl_route_del (nlh, gw_route, 0);
+		nm_netlink_route_delete (gw_route);
 		nm_log_err (LOGD_DEVICE | LOGD_IP6,
 		            "(%s): failed to set IPv6 default route (pass #2): %d",
 		            iface, err);
 	} else
 		success = TRUE;
 
-	rtnl_route_put (gw_route);
+out:
+	if (gw_route)
+		rtnl_route_put (gw_route);
+	g_free (iface);
 	return success;
 }
 
-static void flush_addresses (const char *iface, int family)
-{
-	int iface_idx;
-
-	g_return_if_fail (iface != NULL);
-	iface_idx = nm_netlink_iface_to_index (iface);
-	if (iface_idx >= 0)
-		sync_addresses (iface, iface_idx, family, NULL, 0);
-}
-
-/*
- * nm_system_device_flush_addresses
- *
- * Flush all network addresses associated with a network device
- *
- */
-void nm_system_device_flush_addresses (NMDevice *dev, int family)
-{
-	g_return_if_fail (dev != NULL);
-
-	flush_addresses (nm_device_get_ip_iface (dev), family);
-}
-
-
 /*
- * nm_system_device_flush_addresses_with_iface
+ * nm_system_iface_flush_addresses
  *
  * Flush all network addresses associated with a network device
  *
  */
-void nm_system_device_flush_addresses_with_iface (const char *iface)
-{
-	flush_addresses (iface, AF_UNSPEC);
-}
-
-
-static void
-foreach_route (void (*callback)(struct nl_object *, gpointer),
-			gpointer user_data)
-{
-	struct nl_handle *nlh;
-	struct nl_cache *route_cache;
-
-	nlh = nm_netlink_get_default_handle ();
-	route_cache = rtnl_route_alloc_cache (nlh);
-	g_assert (route_cache);
-	nl_cache_foreach (route_cache, callback, user_data);
-	nl_cache_free (route_cache);
-}
-
-static void
-dump_route (struct rtnl_route *route)
+gboolean
+nm_system_iface_flush_addresses (int ifindex, int family)
 {
-	char buf6[INET6_ADDRSTRLEN];
-	char buf4[INET_ADDRSTRLEN];
-	struct nl_addr *nl;
-	struct in6_addr *addr6 = NULL;
-	struct in_addr *addr4 = NULL;
-	int prefixlen = 0;
-	const char *sf = "UNSPEC";
-	int family = rtnl_route_get_family (route);
-
-	memset (buf6, 0, sizeof (buf6));
-	memset (buf4, 0, sizeof (buf4));
-	nl = rtnl_route_get_dst (route);
-	if (nl) {
-		if (nl_addr_get_family (nl) == AF_INET) {
-			addr4 = nl_addr_get_binary_addr (nl);
-			if (addr4)
-				inet_ntop (AF_INET, addr4, &buf4[0], sizeof (buf4));
-		} else if (nl_addr_get_family (nl) == AF_INET6) {
-			addr6 = nl_addr_get_binary_addr (nl);
-			if (addr6)
-				inet_ntop (AF_INET6, addr6, &buf6[0], sizeof (buf6));
-		}
-		prefixlen = nl_addr_get_prefixlen (nl);
-	}
-
-	if (family == AF_INET)
-		sf = "INET";
-	else if (family == AF_INET6)
-		sf = "INET6";
-
-	nm_log_dbg (LOGD_IP4 | LOGD_IP6, "  route idx %d family %s (%d) addr %s/%d",
-	            rtnl_route_get_oif (route),
-	            sf, family,
-	            strlen (buf4) ? buf4 : (strlen (buf6) ? buf6 : "<unknown>"),
-	            prefixlen);
+	g_return_val_if_fail (ifindex > 0, FALSE);
+	return sync_addresses (ifindex, family, NULL, 0);
 }
 
-typedef struct {
-	const char *iface;
-	int iface_idx;
-	int family;
-} RouteCheckData;
 
-static void
-check_one_route (struct nl_object *object, void *user_data)
+static struct rtnl_route *
+delete_one_route (struct rtnl_route *route,
+                  struct nl_addr *dst,
+                  const char *iface,
+                  gpointer user_data)
 {
-	RouteCheckData *data = (RouteCheckData *) user_data;
-	struct rtnl_route *route = (struct rtnl_route *) object;
-	int err;
-	guint32 log_level = LOGD_IP4 | LOGD_IP6;
-
-	if (nm_logging_level_enabled (LOGL_DEBUG))
-		dump_route (route);
-
-	/* Delete all routes from this interface */
-	if (rtnl_route_get_oif (route) != data->iface_idx)
-		return;
-	if (data->family && rtnl_route_get_family (route) != data->family)
-		return;
-
-	/* We don't want to flush IPv6 link-local routes that may exist on the
-	 * the interface since the LL address and routes should normally stay
-	 * assigned all the time.
-	 */
-	if (   (data->family == AF_INET6 || data->family == AF_UNSPEC)
-	    && (rtnl_route_get_family (route) == AF_INET6)) {
-		struct nl_addr *nl;
-		struct in6_addr *addr = NULL;
-
-		nl = rtnl_route_get_dst (route);
-		if (nl)
-			addr = nl_addr_get_binary_addr (nl);
-
-		if (addr) {
-			if (   IN6_IS_ADDR_LINKLOCAL (addr)
-			    || IN6_IS_ADDR_MC_LINKLOCAL (addr)
-			    || (IN6_IS_ADDR_MULTICAST (addr) && (nl_addr_get_prefixlen (nl) == 8)))
-				return;
-		}
-	}
+	guint32 log_level = GPOINTER_TO_UINT (user_data);
 
-	if (data->family == AF_INET)
-		log_level = LOGD_IP4;
-	else if (data->family == AF_INET6)
-		log_level = LOGD_IP6;
 	nm_log_dbg (log_level, "   deleting route");
+	if (!nm_netlink_route_delete (route))
+		nm_log_err (LOGD_DEVICE, "(%s): failed to delete route", iface);
 
-	err = rtnl_route_del (nm_netlink_get_default_handle (), route, 0);
-	if (err < 0 && (err != -ERANGE)) {
-		nm_log_err (LOGD_DEVICE,
-		            "(%s): error %d returned from rtnl_route_del(): %s",
-		            data->iface, err, nl_geterror ());
-	}
+	return NULL;
 }
 
-static void flush_routes (int ifindex, const char *iface, int family)
+/**
+ * nm_system_iface_flush_routes:
+ * @ifindex: interface index
+ * @family: address family, i.e. AF_INET, AF_INET6, or AF_UNSPEC
+ *
+ * Flush all network addresses associated with a network device.
+ *
+ * Returns: %TRUE on success, %FALSE on failure
+ **/
+gboolean
+nm_system_iface_flush_routes (int ifindex, int family)
 {
-	RouteCheckData check_data;
 	guint32 log_level = LOGD_IP4 | LOGD_IP6;
 	const char *sf = "UNSPEC";
+	char *iface;
 
-	g_return_if_fail (iface != NULL);
+	g_return_val_if_fail (ifindex > 0, FALSE);
 
-	if (ifindex < 0) {
-		ifindex = nm_netlink_iface_to_index (iface);
-		if (ifindex < 0) {
-			nm_log_dbg (LOGD_DEVICE, "(%s) failed to lookup interface index", iface);
-			return;
-		}
-	}
+	iface = nm_netlink_index_to_iface (ifindex);
+	g_return_val_if_fail (iface != NULL, FALSE);
 
 	if (family == AF_INET) {
 		log_level = LOGD_IP4;
@@ -1361,104 +1144,61 @@ static void flush_routes (int ifindex, const char *iface, int family)
 	nm_log_dbg (log_level, "(%s): flushing routes ifindex %d family %s (%d)",
 	            iface, ifindex, sf, family);
 
-	memset (&check_data, 0, sizeof (check_data));
-	check_data.iface = iface;
-	check_data.iface_idx = ifindex;
-	check_data.family = family;
-	foreach_route (check_one_route, &check_data);
-}
-
-/*
- * nm_system_device_flush_routes
- *
- * Flush all network addresses associated with a network device
- *
- */
-void nm_system_device_flush_routes (NMDevice *dev, int family)
-{
-	g_return_if_fail (dev != NULL);
-
-	flush_routes (nm_device_get_ip_ifindex (dev),
-	              nm_device_get_ip_iface (dev),
-	              family);
-}
+	/* We don't want to flush IPv6 link-local routes that may exist on the
+	 * the interface since the LL address and routes should normally stay
+	 * assigned all the time.
+	 */
+	nm_netlink_foreach_route (ifindex, family, RT_SCOPE_UNIVERSE, TRUE, delete_one_route, GUINT_TO_POINTER (log_level));
 
-/*
- * nm_system_device_flush_routes_with_iface
- *
- * Flush all routes associated with a network device.  'family' is an
- * address family, either AF_INET, AF_INET6, or AF_UNSPEC.
- *
- */
-void nm_system_device_flush_routes_with_iface (const char *iface, int family)
-{
-	flush_routes (-1, iface, family);
+	g_free (iface);
+	return TRUE;
 }
 
-typedef struct {
-	struct rtnl_route *route;
-	NMIP4Config *config;
-	int iface;
-} SetPriorityInfo;
-
-static void
-find_route (struct nl_object *object, gpointer user_data)
+static struct rtnl_route *
+find_route (struct rtnl_route *route,
+            struct nl_addr *dst,
+            const char *iface,
+            gpointer user_data)
 {
-	struct rtnl_route *route = (struct rtnl_route *) object;
-	SetPriorityInfo *info = (SetPriorityInfo *) user_data;
-	struct nl_addr *dst;
+	NMIP4Config *config = user_data;
 	struct in_addr *dst_addr;
 	int num;
 	int i;
 
-	if (info->route ||
-	    rtnl_route_get_oif (route) != info->iface ||
-	    rtnl_route_get_scope (route) != RT_SCOPE_LINK)
-		return;
-
-	dst = rtnl_route_get_dst (route);
-	if (nl_addr_get_family (dst) != AF_INET)
-		return;
+	if (dst && (nl_addr_get_family (dst) != AF_INET))
+		return NULL;
 
+	/* Find the first route that handles a subnet of at least one of the
+	 * device's IPv4 addresses.
+	 */
 	dst_addr = nl_addr_get_binary_addr (dst);
-	num = nm_ip4_config_get_num_addresses (info->config);
+	num = nm_ip4_config_get_num_addresses (config);
 	for (i = 0; i < num; i++) {
-		NMIP4Address *addr = nm_ip4_config_get_address (info->config, i);
+		NMIP4Address *addr = nm_ip4_config_get_address (config, i);
 		guint32 prefix = nm_ip4_address_get_prefix (addr);
 		guint32 address = nm_ip4_address_get_address (addr);
 
-		if (prefix == nl_addr_get_prefixlen (dst) &&
-		    (address & nm_utils_ip4_prefix_to_netmask (prefix)) == dst_addr->s_addr) {
-
-			/* Ref the route so it sticks around after the cache is cleared */
-			rtnl_route_get (route);
-			info->route = route;
-			break;
-		}
+		if (   prefix == nl_addr_get_prefixlen (dst)
+		    && (address & nm_utils_ip4_prefix_to_netmask (prefix)) == dst_addr->s_addr)
+			return route;
 	}
+	return NULL;
 }
 
 static void
-nm_system_device_set_priority (const char *iface,
-						 NMIP4Config *config,
-						 int priority)
+nm_system_device_set_priority (int ifindex,
+                               NMIP4Config *config,
+                               int priority)
 {
-	SetPriorityInfo info;
-
-	info.route = NULL;
-	info.config = config;
-	info.iface = nm_netlink_iface_to_index (iface);
-	g_return_if_fail (info.iface >= 0);
-
-	foreach_route (find_route, &info);
-	if (info.route) {
-		struct nl_handle *nlh;
+	struct nl_sock *nlh;
+	struct rtnl_route *found;
 
+	found = nm_netlink_foreach_route (ifindex, AF_INET, RT_SCOPE_LINK, FALSE,  find_route, config);
+	if (found) {
 		nlh = nm_netlink_get_default_handle ();
-		rtnl_route_del (nlh, info.route, 0);
-
-		rtnl_route_set_prio (info.route, priority);
-		rtnl_route_add (nlh, info.route, 0);
-		rtnl_route_put (info.route);
+		nm_netlink_route_delete (found);
+		rtnl_route_set_priority (found, priority);
+		rtnl_route_add (nlh, found, 0);
+		rtnl_route_put (found);
 	}
 }
diff --git a/src/nm-system.h b/src/nm-system.h
index 094f40ef..ae4e7d91 100644
--- a/src/nm-system.h
+++ b/src/nm-system.h
@@ -35,33 +35,31 @@
  * implemented in the backend files in backends/ directory
  */
 
-void			nm_system_device_flush_routes				(NMDevice *dev, int family);
-void			nm_system_device_flush_routes_with_iface	(const char *iface, int family);
+gboolean        nm_system_iface_flush_routes         (int ifindex, int family);
 
-gboolean		nm_system_replace_default_ip4_route   (const char *iface,
+gboolean		nm_system_replace_default_ip4_route   (int ifindex,
                                                        guint32 gw,
                                                        guint32 mss);
 
-gboolean		nm_system_replace_default_ip6_route   (const char *iface,
+gboolean		nm_system_replace_default_ip6_route   (int ifindex,
                                                        const struct in6_addr *gw);
 
-gboolean		nm_system_replace_default_ip4_route_vpn (const char *iface,
+gboolean		nm_system_replace_default_ip4_route_vpn (int ifindex,
                                                          guint32 ext_gw,
                                                          guint32 int_gw,
                                                          guint32 mss,
-                                                         const char *parent_iface,
+                                                         int parent_ifindex,
                                                          guint32 parent_mss);
 
 struct rtnl_route *nm_system_add_ip4_vpn_gateway_route (NMDevice *parent_device, NMIP4Config *vpn_config);
 
 
-void			nm_system_device_flush_addresses			(NMDevice *dev, int family);
-void			nm_system_device_flush_addresses_with_iface	(const char *iface);
+gboolean        nm_system_iface_flush_addresses         (int ifindex, int family);
 
 void			nm_system_enable_loopback				(void);
 void			nm_system_update_dns					(void);
 
-gboolean		nm_system_apply_ip4_config              (const char *iface,
+gboolean		nm_system_apply_ip4_config              (int ifindex,
                                                          NMIP4Config *config,
                                                          int priority,
                                                          NMIP4ConfigCompareFlags flags);
@@ -76,22 +74,19 @@ int             nm_system_set_ip6_route                 (int ifindex,
                                                          int table,
                                                          struct rtnl_route **out_route);
 
-gboolean		nm_system_apply_ip6_config              (const char *iface,
+gboolean		nm_system_apply_ip6_config              (int ifindex,
                                                          NMIP6Config *config,
                                                          int priority,
                                                          NMIP6ConfigCompareFlags flags);
 
-gboolean		nm_system_device_set_up_down				(NMDevice *dev,
-                                                             gboolean up,
-                                                             gboolean *no_firmware);
-gboolean		nm_system_device_set_up_down_with_iface		(const char *iface,
-                                                             gboolean up,
-                                                             gboolean *no_firmware);
+gboolean        nm_system_iface_set_up                  (int ifindex,
+                                                         gboolean up,
+                                                         gboolean *no_firmware);
 
-gboolean        nm_system_device_is_up (NMDevice *device);
-gboolean        nm_system_device_is_up_with_iface (const char *iface);
+gboolean        nm_system_iface_is_up                   (int ifindex);
 
-gboolean		nm_system_device_set_mtu (const char *iface, guint32 mtu);
-gboolean		nm_system_device_set_mac (const char *iface, const struct ether_addr *mac);
+gboolean		nm_system_iface_set_mtu                 (int ifindex, guint32 mtu);
+
+gboolean		nm_system_iface_set_mac                 (int ifindex, const struct ether_addr *mac);
 
 #endif
diff --git a/src/nm-udev-manager.c b/src/nm-udev-manager.c
index 72501c28..e8c6b822 100644
--- a/src/nm-udev-manager.c
+++ b/src/nm-udev-manager.c
@@ -195,78 +195,50 @@ recheck_killswitches (NMUdevManager *self)
 	NMUdevManagerPrivate *priv = NM_UDEV_MANAGER_GET_PRIVATE (self);
 	GSList *iter;
 	RfKillState poll_states[RFKILL_TYPE_MAX];
+	RfKillState platform_states[RFKILL_TYPE_MAX];
 	gboolean platform_checked[RFKILL_TYPE_MAX];
 	int i;
 
 	/* Default state is unblocked */
 	for (i = 0; i < RFKILL_TYPE_MAX; i++) {
 		poll_states[i] = RFKILL_UNBLOCKED;
+		platform_states[i] = RFKILL_UNBLOCKED;
 		platform_checked[i] = FALSE;
 	}
 
-	/* Perform two passes here; the first pass is for non-platform switches,
-	 * which typically if hardkilled cannot be changed except by a physical
-	 * hardware switch.  The second pass checks platform killswitches, which
-	 * take precedence over device killswitches, because typically platform
-	 * killswitches control device killswitches.  That is, a hardblocked device
-	 * switch can often be unblocked by a platform switch.  Thus if we have
-	 * a hardblocked device switch and a softblocked platform switch, the
-	 * combined state should be softblocked since the platform switch can be
-	 * unblocked to change the device switch.
-	 */
-
-	/* Device switches first */
+	/* Poll the states of all killswitches */
 	for (iter = priv->killswitches; iter; iter = g_slist_next (iter)) {
 		Killswitch *ks = iter->data;
 		GUdevDevice *device;
 		RfKillState dev_state;
 		int sysfs_state;
 
-		if (ks->platform == FALSE) {
-			device = g_udev_client_query_by_subsystem_and_name (priv->client, "rfkill", ks->name);
-			if (device) {
-				sysfs_state = g_udev_device_get_property_as_int (device, "RFKILL_STATE");
-				dev_state = sysfs_state_to_nm_state (sysfs_state);
+		device = g_udev_client_query_by_subsystem_and_name (priv->client, "rfkill", ks->name);
+		if (device) {
+			sysfs_state = g_udev_device_get_property_as_int (device, "RFKILL_STATE");
+			dev_state = sysfs_state_to_nm_state (sysfs_state);
+			if (ks->platform == FALSE) {
 				if (dev_state > poll_states[ks->rtype])
 					poll_states[ks->rtype] = dev_state;
-				g_object_unref (device);
-			}
-		}
-	}
-
-	/* Platform switches next; their state overwrites device state */
-	for (iter = priv->killswitches; iter; iter = g_slist_next (iter)) {
-		Killswitch *ks = iter->data;
-		GUdevDevice *device;
-		RfKillState dev_state;
-		int sysfs_state;
-
-		if (ks->platform == TRUE) {
-			device = g_udev_client_query_by_subsystem_and_name (priv->client, "rfkill", ks->name);
-			if (device) {
-				sysfs_state = g_udev_device_get_property_as_int (device, "RFKILL_STATE");
-				dev_state = sysfs_state_to_nm_state (sysfs_state);
-
-				if (platform_checked[ks->rtype] == FALSE) {
-					/* Overwrite device state with platform state for first
-					 * platform switch found.
-					 */
-					poll_states[ks->rtype] = dev_state;
-					platform_checked[ks->rtype] = TRUE;
-				} else {
-					/* If there are multiple platform switches of the same type,
-					 * take the "worst" state for all of that type.
-					 */
-					if (dev_state > poll_states[ks->rtype])
-						poll_states[ks->rtype] = dev_state;
-				}
-				g_object_unref (device);
+			} else {
+				platform_checked[ks->rtype] = TRUE;
+				if (dev_state > platform_states[ks->rtype])
+					platform_states[ks->rtype] = dev_state;
 			}
+			g_object_unref (device);
 		}
 	}
 
 	/* Log and emit change signal for final rfkill states */
 	for (i = 0; i < RFKILL_TYPE_MAX; i++) {
+		if (platform_checked[i] == TRUE) {
+			/* blocked platform switch state overrides device state, otherwise
+			 * let the device state stand. (bgo #655773)
+			 */
+			if (platform_states[i] != RFKILL_UNBLOCKED)
+				poll_states[i] = platform_states[i];
+		}
+
 		if (poll_states[i] != priv->rfkill_states[i]) {
 			nm_log_dbg (LOGD_RFKILL, "%s rfkill state now '%s'",
 			            rfkill_type_to_desc (i),
@@ -515,7 +487,7 @@ net_add (NMUdevManager *self, GUdevDevice *device)
 	 * FIXME: use something other than interface name to detect CTC here.
 	 */
 	if ((etype != 1) && (is_ctc == FALSE)) {
-		nm_log_dbg (LOGD_HW, "ignoring interface with type %d", etype);
+		nm_log_dbg (LOGD_HW, "(%s): ignoring interface with type %d", iface, etype);
 		return;
 	}
 
@@ -528,7 +500,7 @@ net_add (NMUdevManager *self, GUdevDevice *device)
 	 */
 	tmp = g_udev_device_get_property (device, "DEVTYPE");
 	if (g_strcmp0 (tmp, "wwan") == 0) {
-		nm_log_dbg (LOGD_HW, "ignoring interface with devtype '%s'", tmp);
+		nm_log_dbg (LOGD_HW, "(%s): ignoring interface with devtype '%s'", iface, tmp);
 		return;
 	}
 
@@ -539,7 +511,7 @@ net_add (NMUdevManager *self, GUdevDevice *device)
 	if (g_strcmp0 (tmp, "0421") == 0) { /* Nokia vendor ID */
 		tmp = g_udev_device_get_property (device, "ID_MODEL");
 		if (tmp && (strstr (tmp, "PC-Suite") || strstr (tmp, "PC Suite"))) {
-			nm_log_dbg (LOGD_HW, "ignoring Nokia PC-Suite ethernet interface");
+			nm_log_dbg (LOGD_HW, "(%s): ignoring Nokia PC-Suite ethernet interface", iface);
 			return;
 		}
 	}
diff --git a/src/nm-wifi-ap.c b/src/nm-wifi-ap.c
index f9c66473..be836df0 100644
--- a/src/nm-wifi-ap.c
+++ b/src/nm-wifi-ap.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 - 2010 Red Hat, Inc.
+ * Copyright (C) 2004 - 2011 Red Hat, Inc.
  * Copyright (C) 2006 - 2008 Novell, Inc.
  */
 
@@ -33,6 +33,7 @@
 #include "wpa.h"
 #include "nm-properties-changed-signal.h"
 #include "nm-setting-wireless.h"
+#include "nm-glib-compat.h"
 
 #include "nm-access-point-glue.h"
 
@@ -59,10 +60,6 @@ typedef struct
 	gboolean			fake;	/* Whether or not the AP is from a scan */
 	gboolean			broadcast;	/* Whether or not the AP is broadcasting (hidden) */
 	glong				last_seen;	/* Last time the AP was seen in a scan in seconds */
-
-	/* Things from user prefs/NetworkManagerInfo */
-	GTimeVal			timestamp;
-	GSList *			user_addresses;
 } NMAccessPointPrivate;
 
 #define NM_AP_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), NM_TYPE_AP, NMAccessPointPrivate))
@@ -112,8 +109,6 @@ finalize (GObject *object)
 	g_free (priv->dbus_path);
 	if (priv->ssid)
 		g_byte_array_free (priv->ssid, TRUE);
-	g_slist_foreach (priv->user_addresses, (GFunc)g_free, NULL);
-	g_slist_free (priv->user_addresses);
 
 	G_OBJECT_CLASS (nm_ap_parent_class)->finalize (object);
 }
@@ -147,7 +142,7 @@ set_property (GObject *object, guint prop_id,
 		nm_ap_set_max_bitrate (ap, g_value_get_uint (value));
 		break;
 	case PROP_STRENGTH:
-		nm_ap_set_strength (ap, g_value_get_char (value));
+		nm_ap_set_strength (ap, g_value_get_schar (value));
 		break;
 	case PROP_HW_ADDRESS:
 		break;
@@ -197,7 +192,7 @@ get_property (GObject *object, guint prop_id,
 		g_value_set_uint (value, priv->max_bitrate);
 		break;
 	case PROP_STRENGTH:
-		g_value_set_char (value, priv->strength);
+		g_value_set_schar (value, priv->strength);
 		break;
 	default:
 		G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
@@ -757,8 +752,7 @@ error:
 #define MAC_ARG(x) ((guint8*)(x))[0],((guint8*)(x))[1],((guint8*)(x))[2],((guint8*)(x))[3],((guint8*)(x))[4],((guint8*)(x))[5]
 
 void
-nm_ap_print_self (NMAccessPoint *ap,
-                  const char * prefix)
+nm_ap_dump (NMAccessPoint *ap, const char *prefix)
 {
 	NMAccessPointPrivate *priv;
 
@@ -773,7 +767,6 @@ nm_ap_print_self (NMAccessPoint *ap,
 	            ap);
 	nm_log_dbg (LOGD_WIFI_SCAN, "    BSSID     " MAC_FMT, MAC_ARG (priv->address.ether_addr_octet));
 	nm_log_dbg (LOGD_WIFI_SCAN, "    mode      %d", priv->mode);
-	nm_log_dbg (LOGD_WIFI_SCAN, "    timestamp %ld", priv->timestamp.tv_sec);
 	nm_log_dbg (LOGD_WIFI_SCAN, "    flags     0x%X", priv->flags);
 	nm_log_dbg (LOGD_WIFI_SCAN, "    wpa flags 0x%X", priv->wpa_flags);
 	nm_log_dbg (LOGD_WIFI_SCAN, "    rsn flags 0x%X", priv->rsn_flags);
@@ -791,37 +784,6 @@ nm_ap_get_dbus_path (NMAccessPoint *ap)
 	return NM_AP_GET_PRIVATE (ap)->dbus_path;
 }
 
-
-/*
- * Get/set functions for timestamp
- *
- */
-const GTimeVal *nm_ap_get_timestamp (const NMAccessPoint *ap)
-{
-	g_return_val_if_fail (NM_IS_AP (ap), 0);
-
-	return (&NM_AP_GET_PRIVATE (ap)->timestamp);
-}
-
-void nm_ap_set_timestamp (NMAccessPoint *ap, glong sec, glong usec)
-{
-	NMAccessPointPrivate *priv;
-
-	g_return_if_fail (NM_IS_AP (ap));
-
-	priv = NM_AP_GET_PRIVATE (ap);
-
-	priv->timestamp.tv_sec = sec;
-	priv->timestamp.tv_usec = usec;
-}
-
-void nm_ap_set_timestamp_via_timestamp (NMAccessPoint *ap, const GTimeVal *timestamp)
-{
-	g_return_if_fail (NM_IS_AP (ap));
-
-	NM_AP_GET_PRIVATE (ap)->timestamp = *timestamp;
-}
-
 /*
  * Get/set functions for ssid
  *
@@ -1151,57 +1113,6 @@ void nm_ap_set_last_seen (NMAccessPoint *ap, const glong last_seen)
 	NM_AP_GET_PRIVATE (ap)->last_seen = last_seen;
 }
 
-
-/*
- * Get/Set functions for user address list
- *
- * The internal address list is always "owned" by the AP and
- * the list returned by nm_ap_get_user_addresses() is a deep copy.
- * Likewise, when setting the list, a deep copy is made for the
- * ap's actual list.
- *
- */
-GSList *nm_ap_get_user_addresses (const NMAccessPoint *ap)
-{
-	GSList	*new = NULL;
-	GSList	*elt = NULL;
-
-	g_return_val_if_fail (NM_IS_AP (ap), NULL);
-
-	for (elt = NM_AP_GET_PRIVATE (ap)->user_addresses; elt; elt = g_slist_next (elt))
-	{
-		if (elt->data)
-			new = g_slist_append (new, g_strdup (elt->data));
-	}
-
-	/* Return a _deep__copy_ of the address list */
-	return new;
-}
-
-void nm_ap_set_user_addresses (NMAccessPoint *ap, GSList *list)
-{
-	NMAccessPointPrivate *priv;
-	GSList	*elt = NULL;
-	GSList	*new = NULL;
-
-	g_return_if_fail (NM_IS_AP (ap));
-
-	priv = NM_AP_GET_PRIVATE (ap);
-
-	/* Free existing list */
-	g_slist_foreach (priv->user_addresses, (GFunc) g_free, NULL);
-
-	/* Copy new list and set as our own */
-	for (elt = list; elt; elt = g_slist_next (elt))
-	{
-		if (elt->data)
-			new = g_slist_append (new, g_ascii_strup (elt->data, -1));
-	}
-
-	priv->user_addresses = new;
-}
-
-
 gboolean
 nm_ap_check_compatible (NMAccessPoint *self,
                         NMConnection *connection)
diff --git a/src/nm-wifi-ap.h b/src/nm-wifi-ap.h
index 95514ba6..31100d34 100644
--- a/src/nm-wifi-ap.h
+++ b/src/nm-wifi-ap.h
@@ -24,7 +24,6 @@
 
 #include <glib.h>
 #include <glib-object.h>
-#include <time.h>
 #include "NetworkManager.h"
 #include "nm-connection.h"
 
@@ -64,9 +63,6 @@ NMAccessPoint * nm_ap_new_fake_from_connection (NMConnection *connection);
 void            nm_ap_export_to_dbus    (NMAccessPoint *ap);
 
 const char *		nm_ap_get_dbus_path (NMAccessPoint *ap);
-const GTimeVal *	nm_ap_get_timestamp				(const NMAccessPoint *ap);
-void				nm_ap_set_timestamp				(NMAccessPoint *ap, glong sec, glong usec);
-void				nm_ap_set_timestamp_via_timestamp	(NMAccessPoint *ap, const GTimeVal *timestamp);
 
 const GByteArray *	nm_ap_get_ssid (const NMAccessPoint * ap);
 void				nm_ap_set_ssid (NMAccessPoint * ap, const GByteArray * ssid);
@@ -104,9 +100,6 @@ void				nm_ap_set_broadcast		(NMAccessPoint *ap, gboolean broadcast);
 glong			nm_ap_get_last_seen		(const NMAccessPoint *ap);
 void				nm_ap_set_last_seen		(NMAccessPoint *ap, const glong last_seen);
 
-GSList *			nm_ap_get_user_addresses	(const NMAccessPoint *ap);
-void				nm_ap_set_user_addresses (NMAccessPoint *ap, GSList *list);
-
 gboolean			nm_ap_check_compatible (NMAccessPoint *self,
                                             NMConnection *connection);
 
@@ -119,6 +112,6 @@ NMAccessPoint *     nm_ap_match_in_list (NMAccessPoint *find_ap,
                                          GSList *ap_list,
                                          gboolean strict_match);
 
-void				nm_ap_print_self (NMAccessPoint *ap, const char * prefix);
+void				nm_ap_dump (NMAccessPoint *ap, const char *prefix);
 
 #endif /* NM_ACCESS_POINT_H */
diff --git a/src/ppp-manager/Makefile.in b/src/ppp-manager/Makefile.in
index 13c60b41..6971408f 100644
--- a/src/ppp-manager/Makefile.in
+++ b/src/ppp-manager/Makefile.in
@@ -222,8 +222,16 @@ LIBGCRYPT_LIBS = @LIBGCRYPT_LIBS@
 LIBICONV = @LIBICONV@
 LIBINTL = @LIBINTL@
 LIBM = @LIBM@
+LIBNL1_CFLAGS = @LIBNL1_CFLAGS@
+LIBNL1_LIBS = @LIBNL1_LIBS@
+LIBNL2_CFLAGS = @LIBNL2_CFLAGS@
+LIBNL2_LIBS = @LIBNL2_LIBS@
+LIBNL3_CFLAGS = @LIBNL3_CFLAGS@
+LIBNL3_LIBS = @LIBNL3_LIBS@
 LIBNL_CFLAGS = @LIBNL_CFLAGS@
 LIBNL_LIBS = @LIBNL_LIBS@
+LIBNL_ROUTE3_CFLAGS = @LIBNL_ROUTE3_CFLAGS@
+LIBNL_ROUTE3_LIBS = @LIBNL_ROUTE3_LIBS@
 LIBOBJS = @LIBOBJS@
 LIBS = @LIBS@
 LIBTOOL = @LIBTOOL@
diff --git a/src/ppp-manager/nm-ppp-manager.c b/src/ppp-manager/nm-ppp-manager.c
index e863aaba..3546f8d7 100644
--- a/src/ppp-manager/nm-ppp-manager.c
+++ b/src/ppp-manager/nm-ppp-manager.c
@@ -32,7 +32,7 @@
 #include <sys/socket.h>
 #include <sys/ioctl.h>
 #include <asm/types.h>
-#include <net/if.h>
+#include <linux/if.h>
 #include <sys/stat.h>
 
 #include <linux/ppp_defs.h>
@@ -875,6 +875,8 @@ create_pppd_cmd_line (NMPPPManager *self,
 		nm_cmd_line_add_string (cmd, "refuse-mschap-v2");
 	if (nm_setting_ppp_get_nobsdcomp (setting))
 		nm_cmd_line_add_string (cmd, "nobsdcomp");
+	if (nm_setting_ppp_get_no_vj_comp (setting))
+		nm_cmd_line_add_string (cmd, "novj");
 	if (nm_setting_ppp_get_nodeflate (setting))
 		nm_cmd_line_add_string (cmd, "nodeflate");
 	if (nm_setting_ppp_get_require_mppe (setting))
diff --git a/src/settings/Makefile.in b/src/settings/Makefile.in
index 980f35cb..09da869d 100644
--- a/src/settings/Makefile.in
+++ b/src/settings/Makefile.in
@@ -248,8 +248,16 @@ LIBGCRYPT_LIBS = @LIBGCRYPT_LIBS@
 LIBICONV = @LIBICONV@
 LIBINTL = @LIBINTL@
 LIBM = @LIBM@
+LIBNL1_CFLAGS = @LIBNL1_CFLAGS@
+LIBNL1_LIBS = @LIBNL1_LIBS@
+LIBNL2_CFLAGS = @LIBNL2_CFLAGS@
+LIBNL2_LIBS = @LIBNL2_LIBS@
+LIBNL3_CFLAGS = @LIBNL3_CFLAGS@
+LIBNL3_LIBS = @LIBNL3_LIBS@
 LIBNL_CFLAGS = @LIBNL_CFLAGS@
 LIBNL_LIBS = @LIBNL_LIBS@
+LIBNL_ROUTE3_CFLAGS = @LIBNL_ROUTE3_CFLAGS@
+LIBNL_ROUTE3_LIBS = @LIBNL_ROUTE3_LIBS@
 LIBOBJS = @LIBOBJS@
 LIBS = @LIBS@
 LIBTOOL = @LIBTOOL@
diff --git a/src/settings/nm-settings-connection.c b/src/settings/nm-settings-connection.c
index 4b3a56cd..cdad8325 100644
--- a/src/settings/nm-settings-connection.c
+++ b/src/settings/nm-settings-connection.c
@@ -84,15 +84,27 @@ typedef struct {
 
 	NMDBusManager *dbus_mgr;
 	NMAgentManager *agent_mgr;
+	NMSessionMonitor *session_monitor;
+	guint session_changed_id;
 
 	GSList *pending_auths; /* List of pending authentication requests */
-	NMConnection *secrets;
 	gboolean visible; /* Is this connection is visible by some session? */
-
 	GSList *reqs;  /* in-progress secrets requests */
 
-	NMSessionMonitor *session_monitor;
-	guint session_changed_id;
+	/* Caches secrets from on-disk connections; were they not cached any
+	 * call to nm_connection_clear_secrets() wipes them out and we'd have
+	 * to re-read them from disk which defeats the purpose of having the
+	 * connection in-memory at all.
+	 */
+	NMConnection *system_secrets;
+
+	/* Caches secrets from agents during the activation process; if new system
+	 * secrets are returned from an agent, they get written out to disk,
+	 * triggering a re-read of the connection, which reads only system
+	 * secrets, and would wipe out any agent-owned or not-saved secrets the
+	 * agent also returned.
+	 */
+	NMConnection *agent_secrets;
 
 	guint64 timestamp;   /* Up-to-date timestamp of connection use */
 	GHashTable *seen_bssids; /* Up-to-date BSSIDs that's been seen for the connection */
@@ -294,57 +306,67 @@ nm_settings_connection_check_permission (NMSettingsConnection *self,
 
 /**************************************************************/
 
-static void
-only_system_secrets_cb (NMSetting *setting,
-                        const char *key,
-                        const GValue *value,
-                        GParamFlags flags,
-                        gpointer user_data)
+static gboolean
+secrets_filter_cb (NMSetting *setting,
+                   const char *secret,
+                   NMSettingSecretFlags flags,
+                   gpointer user_data)
 {
-	if (flags & NM_SETTING_PARAM_SECRET) {
-		NMSettingSecretFlags secret_flags = NM_SETTING_SECRET_FLAG_NONE;
+	NMSettingSecretFlags filter_flags = GPOINTER_TO_UINT (user_data);
 
-		/* VPNs are special; need to handle each secret separately */
-		if (NM_IS_SETTING_VPN (setting) && !strcmp (key, NM_SETTING_VPN_SECRETS)) {
-			GHashTableIter iter;
-			const char *secret_name = NULL;
+	/* Returns TRUE to remove the secret */
 
-			g_hash_table_iter_init (&iter, (GHashTable *) g_value_get_boxed (value));
-			while (g_hash_table_iter_next (&iter, (gpointer *) &secret_name, NULL)) {
-				secret_flags = NM_SETTING_SECRET_FLAG_NONE;
-				nm_setting_get_secret_flags (setting, secret_name, &secret_flags, NULL);
-				if (secret_flags != NM_SETTING_SECRET_FLAG_NONE)
-					nm_setting_vpn_remove_secret (NM_SETTING_VPN (setting), secret_name);
-			}
-		} else {
-			nm_setting_get_secret_flags (setting, key, &secret_flags, NULL);
-			if (secret_flags != NM_SETTING_SECRET_FLAG_NONE)
-				g_object_set (G_OBJECT (setting), key, NULL, NULL);
-		}
-	}
+	/* Can't use bitops with SECRET_FLAG_NONE so handle that specifically */
+	if (   (flags == NM_SETTING_SECRET_FLAG_NONE)
+	    && (filter_flags == NM_SETTING_SECRET_FLAG_NONE))
+		return FALSE;
+
+	/* Otherwise if the secret has at least one of the desired flags keep it */
+	return (flags & filter_flags) ? FALSE : TRUE;
 }
 
 static void
-update_secrets_cache (NMSettingsConnection *self)
+update_system_secrets_cache (NMSettingsConnection *self)
 {
 	NMSettingsConnectionPrivate *priv = NM_SETTINGS_CONNECTION_GET_PRIVATE (self);
 
-	if (priv->secrets)
-		g_object_unref (priv->secrets);
-	priv->secrets = nm_connection_duplicate (NM_CONNECTION (self));
+	if (priv->system_secrets)
+		g_object_unref (priv->system_secrets);
+	priv->system_secrets = nm_connection_duplicate (NM_CONNECTION (self));
 
 	/* Clear out non-system-owned and not-saved secrets */
-	nm_connection_for_each_setting_value (priv->secrets, only_system_secrets_cb, NULL);
+	nm_connection_clear_secrets_with_flags (priv->system_secrets,
+	                                        secrets_filter_cb,
+	                                        GUINT_TO_POINTER (NM_SETTING_SECRET_FLAG_NONE));
 }
 
-static gboolean
-clear_system_secrets (GHashTableIter *iter,
-                      NMSettingSecretFlags flags,
-                      gpointer user_data)
+static void
+update_agent_secrets_cache (NMSettingsConnection *self, NMConnection *new)
 {
-	if (flags == NM_SETTING_SECRET_FLAG_NONE)
-		g_hash_table_iter_remove (iter);
-	return TRUE;
+	NMSettingsConnectionPrivate *priv = NM_SETTINGS_CONNECTION_GET_PRIVATE (self);
+	NMSettingSecretFlags filter_flags = NM_SETTING_SECRET_FLAG_NOT_SAVED | NM_SETTING_SECRET_FLAG_AGENT_OWNED;
+
+	if (priv->agent_secrets)
+		g_object_unref (priv->agent_secrets);
+	priv->agent_secrets = nm_connection_duplicate (new ? new : NM_CONNECTION (self));
+
+	/* Clear out non-system-owned secrets */
+	nm_connection_clear_secrets_with_flags (priv->agent_secrets,
+	                                        secrets_filter_cb,
+	                                        GUINT_TO_POINTER (filter_flags));
+}
+
+static void
+secrets_cleared_cb (NMSettingsConnection *self)
+{
+	NMSettingsConnectionPrivate *priv = NM_SETTINGS_CONNECTION_GET_PRIVATE (self);
+
+	/* Clear agent secrets when connection's secrets are cleared since agent
+	 * secrets are transient.
+	 */
+	if (priv->agent_secrets)
+		g_object_unref (priv->agent_secrets);
+	priv->agent_secrets = NULL;
 }
 
 /* Update the settings of this connection to match that of 'new', taking care to
@@ -356,7 +378,7 @@ nm_settings_connection_replace_settings (NMSettingsConnection *self,
                                          GError **error)
 {
 	NMSettingsConnectionPrivate *priv;
-	GHashTable *new_settings, *transient_secrets;
+	GHashTable *new_settings, *hash = NULL;
 	gboolean success = FALSE;
 
 	g_return_val_if_fail (self != NULL, FALSE);
@@ -366,37 +388,29 @@ nm_settings_connection_replace_settings (NMSettingsConnection *self,
 
 	priv = NM_SETTINGS_CONNECTION_GET_PRIVATE (self);
 
-	/* Replacing the settings might replace transient secrets, such as when
-	 * a user agent returns secrets, which might trigger the connection to be
-	 * written out, which triggers an inotify event to re-read and update the
-	 * connection, which, if we're not careful, could wipe out the transient
-	 * secrets the user agent just sent us.  Basically, only
-	 * nm_connection_clear_secrets() should wipe out transient secrets but
-	 * re-reading a connection from on-disk and updating our in-memory copy
-	 * should not.  Thus we preserve non-system-owned secrets here.
-	 */
-	transient_secrets = nm_connection_to_hash (NM_CONNECTION (self), NM_SETTING_HASH_FLAG_ONLY_SECRETS);
-	if (transient_secrets)
-		for_each_secret (NM_CONNECTION (self), transient_secrets, clear_system_secrets, NULL);
-
 	new_settings = nm_connection_to_hash (new, NM_SETTING_HASH_FLAG_ALL);
 	g_assert (new_settings);
 	if (nm_connection_replace_settings (NM_CONNECTION (self), new_settings, error)) {
-		/* Copy the connection to keep its secrets around even if NM
-		 * calls nm_connection_clear_secrets().
+		/* Cache the just-updated system secrets in case something calls
+		 * nm_connection_clear_secrets() and clears them.
 		 */
-		update_secrets_cache (self);
+		update_system_secrets_cache (self);
+		success = TRUE;
 
-		/* And add the transient secrets back */
-		if (transient_secrets)
-			nm_connection_update_secrets (NM_CONNECTION (self), NULL, transient_secrets, NULL);
+		/* Add agent and always-ask secrets back; they won't necessarily be
+		 * in the replacement connection data if it was eg reread from disk.
+		 */
+		if (priv->agent_secrets) {
+			hash = nm_connection_to_hash (priv->agent_secrets, NM_SETTING_HASH_FLAG_ONLY_SECRETS);
+			if (hash) {
+				success = nm_connection_update_secrets (NM_CONNECTION (self), NULL, hash, error);
+				g_hash_table_destroy (hash);
+			}
+		}
 
 		nm_settings_connection_recheck_visibility (self);
-		success = TRUE;
 	}
 	g_hash_table_destroy (new_settings);
-	if (transient_secrets)
-		g_hash_table_destroy (transient_secrets);
 	return success;
 }
 
@@ -550,6 +564,7 @@ do_delete (NMSettingsConnection *connection,
 	for_agents = nm_connection_duplicate (NM_CONNECTION (connection));
 	nm_connection_clear_secrets (for_agents);
 	nm_agent_manager_delete_secrets (priv->agent_mgr, for_agents, FALSE, 0);
+	g_object_unref (for_agents);
 
 	/* Remove timestamp from timestamps database file */
 	remove_entry_from_db (connection, "timestamps");
@@ -719,7 +734,7 @@ agent_secrets_done_cb (NMAgentManager *manager,
 
 	/* Update the connection with our existing secrets from backing storage */
 	nm_connection_clear_secrets (NM_CONNECTION (self));
-	hash = nm_connection_to_hash (priv->secrets, NM_SETTING_HASH_FLAG_ONLY_SECRETS);
+	hash = nm_connection_to_hash (priv->system_secrets, NM_SETTING_HASH_FLAG_ONLY_SECRETS);
 	if (!hash || nm_connection_update_secrets (NM_CONNECTION (self), setting_name, hash, &local)) {
 		/* Update the connection with the agent's secrets; by this point if any
 		 * system-owned secrets exist in 'secrets' the agent that provided them
@@ -730,7 +745,8 @@ agent_secrets_done_cb (NMAgentManager *manager,
 			/* Now that all secrets are updated, copy and cache new secrets, 
 			 * then save them to backing storage.
 			 */
-			update_secrets_cache (self);
+			update_system_secrets_cache (self);
+			update_agent_secrets_cache (self, NULL);
 
 			/* Only save secrets to backing storage if the agent returned any
 			 * new system secrets.  If it didn't, then the secrets are agent-
@@ -807,11 +823,9 @@ nm_settings_connection_get_secrets (NMSettingsConnection *self,
 	guint32 call_id = 0;
 
 	/* Use priv->secrets to work around the fact that nm_connection_clear_secrets()
-	 * will clear secrets on this object's settings.  priv->secrets should be
-	 * a complete copy of this object and kept in sync by
-	 * nm_settings_connection_replace_settings().
+	 * will clear secrets on this object's settings.
 	 */
-	if (!priv->secrets) {
+	if (!priv->system_secrets) {
 		g_set_error (error, NM_SETTINGS_ERROR, NM_SETTINGS_ERROR_INVALID_CONNECTION,
 		             "%s.%d - Internal error; secrets cache invalid.",
 		             __FILE__, __LINE__);
@@ -826,7 +840,7 @@ nm_settings_connection_get_secrets (NMSettingsConnection *self,
 		return 0;
 	}
 
-	existing_secrets = nm_connection_to_hash (priv->secrets, NM_SETTING_HASH_FLAG_ONLY_SECRETS);
+	existing_secrets = nm_connection_to_hash (priv->system_secrets, NM_SETTING_HASH_FLAG_ONLY_SECRETS);
 	call_id = nm_agent_manager_get_secrets (priv->agent_mgr,
 	                                        NM_CONNECTION (self),
 	                                        filter_by_uid,
@@ -1084,47 +1098,40 @@ impl_settings_connection_get_settings (NMSettingsConnection *self,
 	auth_start (self, context, NULL, get_settings_auth_cb, NULL);
 }
 
+typedef struct {
+	DBusGMethodInvocation *context;
+	NMAgentManager *agent_mgr;
+	gulong sender_uid;
+} UpdateInfo;
+
 static void
-con_update_cb (NMSettingsConnection *connection,
+con_update_cb (NMSettingsConnection *self,
                GError *error,
                gpointer user_data)
 {
-	DBusGMethodInvocation *context = user_data;
+	UpdateInfo *info = user_data;
+	NMConnection *for_agent;
 
 	if (error)
-		dbus_g_method_return_error (context, error);
-	else
-		dbus_g_method_return (context);
-}
-
-static void
-secrets_filter_cb (NMSetting *setting,
-                   const char *key,
-                   const GValue *value,
-                   GParamFlags flags,
-                   gpointer user_data)
-{
-	NMSettingSecretFlags filter_flags = GPOINTER_TO_UINT (user_data);
-	NMSettingSecretFlags secret_flags = NM_SETTING_SECRET_FLAG_NONE;
-	const char *secret_name = NULL;
-	GHashTableIter iter;
+		dbus_g_method_return_error (info->context, error);
+	else {
+		/* Dupe the connection so we can clear out non-agent-owned secrets,
+		 * as agent-owned secrets are the only ones we send back be saved.
+		 * Only send secrets to agents of the same UID that called update too.
+		 */
+		for_agent = nm_connection_duplicate (NM_CONNECTION (self));
+		nm_connection_clear_secrets_with_flags (for_agent,
+		                                        secrets_filter_cb,
+		                                        GUINT_TO_POINTER (NM_SETTING_SECRET_FLAG_AGENT_OWNED));
+		nm_agent_manager_save_secrets (info->agent_mgr, for_agent, TRUE, info->sender_uid);
+		g_object_unref (for_agent);
 
-	if (flags & NM_SETTING_PARAM_SECRET) {
-		if (NM_IS_SETTING_VPN (setting) && !strcmp (key, NM_SETTING_VPN_SECRETS)) {
-			/* VPNs are special; need to handle each secret separately */
-			g_hash_table_iter_init (&iter, (GHashTable *) g_value_get_boxed (value));
-			while (g_hash_table_iter_next (&iter, (gpointer) &secret_name, NULL)) {
-				secret_flags = NM_SETTING_SECRET_FLAG_NONE;
-				nm_setting_get_secret_flags (setting, secret_name, &secret_flags, NULL);
-				if (!(secret_flags & filter_flags))
-					nm_setting_vpn_remove_secret (NM_SETTING_VPN (setting), secret_name);
-			}
-		} else {
-			nm_setting_get_secret_flags (setting, key, &secret_flags, NULL);
-			if (!(secret_flags & filter_flags))
-				g_object_set (G_OBJECT (setting), key, NULL, NULL);
-		}
+		dbus_g_method_return (info->context);
 	}
+
+	g_object_unref (info->agent_mgr);
+	memset (info, 0, sizeof (*info));
+	g_free (info);
 }
 
 static void
@@ -1136,54 +1143,27 @@ update_auth_cb (NMSettingsConnection *self,
 {
 	NMSettingsConnectionPrivate *priv = NM_SETTINGS_CONNECTION_GET_PRIVATE (self);
 	NMConnection *new_settings = data;
-	NMConnection *for_agent, *dup;
-	NMSettingSecretFlags filter_flags;
-	GHashTable *hash;
-	GError *local = NULL;
+	UpdateInfo *info;
 
 	if (error)
 		dbus_g_method_return_error (context, error);
 	else {
-		/* Cache the new secrets since they may get overwritten by the replace
-		 * when transient secrets are copied back.
+		info = g_malloc0 (sizeof (*info));
+		info->context = context;
+		info->agent_mgr = g_object_ref (priv->agent_mgr);
+		info->sender_uid = sender_uid;
+
+		/* Cache the new secrets from the agent, as stuff like inotify-triggered
+		 * changes to connection's backing config files will blow them away if
+		 * they're in the main connection.
 		 */
-		dup = nm_connection_duplicate (new_settings);
+		update_agent_secrets_cache (self, new_settings);
 
 		/* Update and commit our settings. */
 		nm_settings_connection_replace_and_commit (self,
-		                                           new_settings,
-		                                           con_update_cb,
-		                                           context);
-
-		/* Copy new agent secrets back to the connection */
-		filter_flags = NM_SETTING_SECRET_FLAG_AGENT_OWNED | NM_SETTING_SECRET_FLAG_NOT_SAVED;
-		nm_connection_for_each_setting_value (dup,
-		                                      secrets_filter_cb,
-		                                      GUINT_TO_POINTER (filter_flags));
-		hash = nm_connection_to_hash (dup, NM_SETTING_HASH_FLAG_ONLY_SECRETS);
-		g_object_unref (dup);
-
-		if (hash) {
-			if (!nm_connection_update_secrets (NM_CONNECTION (self), NULL, hash, &local)) {
-				nm_log_warn (LOGD_SETTINGS, "Failed to update connection secrets: (%d) %s",
-				             local ? local->code : -1,
-				             local && local->message ? local->message : "(unknown)");
-				g_clear_error (&local);
-			}
-			g_hash_table_destroy (hash);
-		}
-
-		/* Dupe the connection and clear out non-agent-owned secrets so we can
-		 * send the agent-owned ones to agents to be saved.  Only send them to
-		 * agents of the same UID as the Update() request sender.
-		 */
-		for_agent = nm_connection_duplicate (NM_CONNECTION (self));
-		filter_flags = NM_SETTING_SECRET_FLAG_AGENT_OWNED;
-		nm_connection_for_each_setting_value (for_agent,
-		                                      secrets_filter_cb,
-		                                      GUINT_TO_POINTER (filter_flags));
-		nm_agent_manager_save_secrets (priv->agent_mgr, for_agent, TRUE, sender_uid);
-		g_object_unref (for_agent);
+			                                       new_settings,
+			                                       con_update_cb,
+			                                       info);
 	}
 
 	g_object_unref (new_settings);
@@ -1345,16 +1325,11 @@ dbus_get_agent_secrets_cb (NMSettingsConnection *self,
 	if (error)
 		dbus_g_method_return_error (context, error);
 	else {
-		/* The connection's secrets will have been updated by the agent manager,
-		 * so we want to refresh the secrets cache.  Note that we will never save
-		 * new secrets to backing storage here because D-Bus initated requests will
-		 * never ask for completely new secrets from agents.  Thus system-owned
-		 * secrets should not have changed from backing storage.  We also don't
-		 * send agent-owned secrets back out to be saved since we assume the agent
-		 * that provided the secrets saved them itself.
+		/* Return secrets from agent and backing storage to the D-Bus caller;
+		 * nm_settings_connection_get_secrets() will have updated itself with
+		 * secrets from backing storage and those returned from the agent
+		 * by the time we get here.
 		 */
-		update_secrets_cache (self);
-
 		hash = nm_connection_to_hash (NM_CONNECTION (self), NM_SETTING_HASH_FLAG_ONLY_SECRETS);
 		if (!hash)
 			hash = g_hash_table_new (NULL, NULL);
@@ -1726,6 +1701,8 @@ nm_settings_connection_init (NMSettingsConnection *self)
 	priv->agent_mgr = nm_agent_manager_get ();
 
 	priv->seen_bssids = g_hash_table_new_full (mac_hash, mac_equal, g_free, g_free);
+
+	g_signal_connect (self, "secrets-cleared", G_CALLBACK (secrets_cleared_cb), NULL);
 }
 
 static void
@@ -1739,8 +1716,10 @@ dispose (GObject *object)
 		goto out;
 	priv->disposed = TRUE;
 
-	if (priv->secrets)
-		g_object_unref (priv->secrets);
+	if (priv->system_secrets)
+		g_object_unref (priv->system_secrets);
+	if (priv->agent_secrets)
+		g_object_unref (priv->agent_secrets);
 
 	/* Cancel PolicyKit requests */
 	for (iter = priv->pending_auths; iter; iter = g_slist_next (iter))
diff --git a/src/settings/nm-settings.c b/src/settings/nm-settings.c
index 733e9145..f0bfc162 100644
--- a/src/settings/nm-settings.c
+++ b/src/settings/nm-settings.c
@@ -27,6 +27,7 @@
 
 #include <unistd.h>
 #include <string.h>
+#include <ctype.h>
 #include <gmodule.h>
 #include <net/ethernet.h>
 #include <netinet/ether.h>
@@ -546,24 +547,23 @@ find_plugin (GSList *list, const char *pname)
 }
 
 static gboolean
-load_plugins (NMSettings *self, const char *plugins, GError **error)
+load_plugins (NMSettings *self, const char **plugins, GError **error)
 {
 	GSList *list = NULL;
-	char **plist;
-	char **iter;
+	const char **iter;
 	gboolean success = TRUE;
 
-	plist = g_strsplit (plugins, ",", 0);
-	if (!plist)
-		return FALSE;
-
-	for (iter = plist; *iter; iter++) {
+	for (iter = plugins; *iter; iter++) {
 		GModule *plugin;
 		char *full_name, *path;
-		const char *pname = g_strstrip (*iter);
+		const char *pname = *iter;
 		GObject *obj;
 		GObject * (*factory_func) (void);
 
+		/* strip leading spaces */
+		while (isblank (*pname))
+			pname++;
+
 		/* keyfile plugin built in now */
 		if (!strcmp (pname, "keyfile"))
 			continue;
@@ -616,8 +616,6 @@ load_plugins (NMSettings *self, const char *plugins, GError **error)
 		list = g_slist_append (list, obj);
 	}
 
-	g_strfreev (plist);
-
 	g_slist_foreach (list, (GFunc) g_object_unref, NULL);
 	g_slist_free (list);
 
@@ -634,6 +632,7 @@ connection_removed (NMSettingsConnection *obj, gpointer user_data)
 {
 	GObject *connection = G_OBJECT (obj);
 	guint id;
+
 	g_object_ref (connection);
 
 	/* Disconnect signal handlers, as plugins might still keep references
@@ -653,7 +652,7 @@ connection_removed (NMSettingsConnection *obj, gpointer user_data)
 	if (id)
 		g_signal_handler_disconnect (connection, id);
 
-	/* Forget about the connection internall */
+	/* Forget about the connection internally */
 	g_hash_table_remove (NM_SETTINGS_GET_PRIVATE (user_data)->connections,
 	                     (gpointer) nm_connection_get_path (NM_CONNECTION (connection)));
 
@@ -840,9 +839,6 @@ claim_connection (NMSettings *self,
 	}
 }
 
-// TODO it seems that this is only ever used to remove a
-// NMDefaultWiredConnection, and it probably needs to stay that way. So this
-// *needs* a better name!
 static void
 remove_default_wired_connection (NMSettings *self,
                                  NMSettingsConnection *connection,
@@ -852,7 +848,8 @@ remove_default_wired_connection (NMSettings *self,
 	const char *path = nm_connection_get_path (NM_CONNECTION (connection));
 
 	if (g_hash_table_lookup (priv->connections, path)) {
-		g_signal_emit_by_name (G_OBJECT (connection), NM_SETTINGS_CONNECTION_REMOVED);
+		if (do_signal)
+			g_signal_emit_by_name (G_OBJECT (connection), NM_SETTINGS_CONNECTION_REMOVED);
 		g_hash_table_remove (priv->connections, path);
 	}
 }
@@ -1378,7 +1375,7 @@ delete_cb (NMSettingsConnection *connection, GError *error, gpointer user_data)
 {
 }
 
-static gboolean
+static void
 default_wired_try_update (NMDefaultWiredConnection *wired,
                           NMSettings *self)
 {
@@ -1390,6 +1387,9 @@ default_wired_try_update (NMDefaultWiredConnection *wired,
 	 * persistent storage.
 	 */
 
+	/* Keep it alive over removal so we can re-add it if we need to */
+	g_object_ref (wired);
+
 	id = nm_connection_get_id (NM_CONNECTION (wired));
 	g_assert (id);
 
@@ -1402,21 +1402,21 @@ default_wired_try_update (NMDefaultWiredConnection *wired,
 		                   DEFAULT_WIRED_TAG,
 		                   NULL);
 		nm_log_info (LOGD_SETTINGS, "Saved default wired connection '%s' to persistent storage", id);
-		return FALSE;
+	} else {
+		nm_log_warn (LOGD_SETTINGS, "couldn't save default wired connection '%s': %d / %s",
+			         id,
+			         error ? error->code : -1,
+			         (error && error->message) ? error->message : "(unknown)");
+		g_clear_error (&error);
+
+		/* If there was an error, don't destroy the default wired connection,
+		 * but add it back to the system settings service. Connection is already
+		 * exported on the bus, don't export it again, thus do_export == FALSE.
+		 */
+		claim_connection (self, NM_SETTINGS_CONNECTION (wired), FALSE);
 	}
 
-	nm_log_warn (LOGD_SETTINGS, "couldn't save default wired connection '%s': %d / %s",
-	             id,
-	             error ? error->code : -1,
-	             (error && error->message) ? error->message : "(unknown)");
-	g_clear_error (&error);
-
-	/* If there was an error, don't destroy the default wired connection,
-	 * but add it back to the system settings service. Connection is already
-	 * exported on the bus, don't export it again, thus do_export == FALSE.
-	 */
-	claim_connection (self, NM_SETTINGS_CONNECTION (wired), FALSE);
-	return TRUE;
+	g_object_unref (wired);
 }
 
 void
@@ -1492,7 +1492,7 @@ nm_settings_device_removed (NMSettings *self, NMDevice *device)
 
 NMSettings *
 nm_settings_new (const char *config_file,
-                 const char *plugins,
+                 const char **plugins,
                  GError **error)
 {
 	NMSettings *self;
diff --git a/src/settings/nm-settings.h b/src/settings/nm-settings.h
index 66d41cce..77485e19 100644
--- a/src/settings/nm-settings.h
+++ b/src/settings/nm-settings.h
@@ -77,7 +77,7 @@ typedef struct {
 GType nm_settings_get_type (void);
 
 NMSettings *nm_settings_new (const char *config_file,
-                             const char *plugins,
+                             const char **plugins,
                              GError **error);
 
 typedef void (*NMSettingsForEachFunc) (NMSettings *settings,
diff --git a/src/settings/plugins/Makefile.in b/src/settings/plugins/Makefile.in
index 148e9620..c23e3be0 100644
--- a/src/settings/plugins/Makefile.in
+++ b/src/settings/plugins/Makefile.in
@@ -197,8 +197,16 @@ LIBGCRYPT_LIBS = @LIBGCRYPT_LIBS@
 LIBICONV = @LIBICONV@
 LIBINTL = @LIBINTL@
 LIBM = @LIBM@
+LIBNL1_CFLAGS = @LIBNL1_CFLAGS@
+LIBNL1_LIBS = @LIBNL1_LIBS@
+LIBNL2_CFLAGS = @LIBNL2_CFLAGS@
+LIBNL2_LIBS = @LIBNL2_LIBS@
+LIBNL3_CFLAGS = @LIBNL3_CFLAGS@
+LIBNL3_LIBS = @LIBNL3_LIBS@
 LIBNL_CFLAGS = @LIBNL_CFLAGS@
 LIBNL_LIBS = @LIBNL_LIBS@
+LIBNL_ROUTE3_CFLAGS = @LIBNL_ROUTE3_CFLAGS@
+LIBNL_ROUTE3_LIBS = @LIBNL_ROUTE3_LIBS@
 LIBOBJS = @LIBOBJS@
 LIBS = @LIBS@
 LIBTOOL = @LIBTOOL@
diff --git a/src/settings/plugins/ifcfg-rh/Makefile.in b/src/settings/plugins/ifcfg-rh/Makefile.in
index f02b6431..b904563a 100644
--- a/src/settings/plugins/ifcfg-rh/Makefile.in
+++ b/src/settings/plugins/ifcfg-rh/Makefile.in
@@ -267,8 +267,16 @@ LIBGCRYPT_LIBS = @LIBGCRYPT_LIBS@
 LIBICONV = @LIBICONV@
 LIBINTL = @LIBINTL@
 LIBM = @LIBM@
+LIBNL1_CFLAGS = @LIBNL1_CFLAGS@
+LIBNL1_LIBS = @LIBNL1_LIBS@
+LIBNL2_CFLAGS = @LIBNL2_CFLAGS@
+LIBNL2_LIBS = @LIBNL2_LIBS@
+LIBNL3_CFLAGS = @LIBNL3_CFLAGS@
+LIBNL3_LIBS = @LIBNL3_LIBS@
 LIBNL_CFLAGS = @LIBNL_CFLAGS@
 LIBNL_LIBS = @LIBNL_LIBS@
+LIBNL_ROUTE3_CFLAGS = @LIBNL_ROUTE3_CFLAGS@
+LIBNL_ROUTE3_LIBS = @LIBNL_ROUTE3_LIBS@
 LIBOBJS = @LIBOBJS@
 LIBS = @LIBS@
 LIBTOOL = @LIBTOOL@
diff --git a/src/settings/plugins/ifcfg-rh/plugin.c b/src/settings/plugins/ifcfg-rh/plugin.c
index ed0dceca..b4be4cba 100644
--- a/src/settings/plugins/ifcfg-rh/plugin.c
+++ b/src/settings/plugins/ifcfg-rh/plugin.c
@@ -655,8 +655,10 @@ sc_plugin_ifcfg_init (SCPluginIfcfg *plugin)
 	}
 
 	if (!success) {
-		dbus_g_connection_unref (priv->bus);
-		priv->bus = NULL;
+		if (priv->bus) {
+			dbus_g_connection_unref (priv->bus);
+			priv->bus = NULL;
+		}
 	}
 }
 
diff --git a/src/settings/plugins/ifcfg-rh/reader.c b/src/settings/plugins/ifcfg-rh/reader.c
index cdf5889e..910cca35 100644
--- a/src/settings/plugins/ifcfg-rh/reader.c
+++ b/src/settings/plugins/ifcfg-rh/reader.c
@@ -28,10 +28,10 @@
 #include <ctype.h>
 #include <sys/inotify.h>
 #include <errno.h>
-#include <net/if.h>
 #include <sys/ioctl.h>
 #include <unistd.h>
 #include <netinet/ether.h>
+#include <linux/if.h>
 
 #ifndef __user
 #define __user
@@ -3382,7 +3382,7 @@ connection_from_file (const char *filename,
 		network_file = SYSCONFDIR "/sysconfig/network";
 
 	if (!iscsiadm_path)
-		iscsiadm_path = SBINDIR "/iscsiadm";
+		iscsiadm_path = "/sbin/iscsiadm";
 
 	ifcfg_name = utils_get_ifcfg_name (filename, TRUE);
 	if (!ifcfg_name) {
diff --git a/src/settings/plugins/ifcfg-rh/shvar.c b/src/settings/plugins/ifcfg-rh/shvar.c
index db084969..0aa8efc2 100644
--- a/src/settings/plugins/ifcfg-rh/shvar.c
+++ b/src/settings/plugins/ifcfg-rh/shvar.c
@@ -142,10 +142,11 @@ svUnescape(char *s) {
  */
 static const char escapees[] = "\"'\\$~`";		/* must be escaped */
 static const char spaces[] = " \t|&;()<>";		/* only require "" */
+static const char newlines[] = "\n\r";			/* will be removed */
 char *
 svEscape(const char *s) {
     char *new;
-    int i, j, mangle = 0, space = 0;
+    int i, j, mangle = 0, space = 0, newline = 0;
     int newlen, slen;
     static int esclen, splen;
 
@@ -156,23 +157,26 @@ svEscape(const char *s) {
     for (i = 0; i < slen; i++) {
 	if (strchr(escapees, s[i])) mangle++;
 	if (strchr(spaces, s[i])) space++;
+	if (strchr(newlines, s[i])) newline++;
     }
-    if (!mangle && !space) return strdup(s);
+    if (!mangle && !space && !newline) return strdup(s);
 
-    newlen = slen + mangle + 3;	/* 3 is extra ""\0 */
+    newlen = slen + mangle - newline + 3;	/* 3 is extra ""\0 */
     new = g_malloc0(newlen);
     if (!new) return NULL;
 
     j = 0;
     new[j++] = '"';
     for (i = 0; i < slen; i++) {
+	if (strchr(newlines, s[i]))
+	    continue;
 	if (strchr(escapees, s[i])) {
 	    new[j++] = '\\';
 	}
 	new[j++] = s[i];
     }
     new[j++] = '"';
-    g_assert(j == slen + mangle + 2); /* j is the index of the '\0' */
+    g_assert(j == slen + mangle - newline + 2); /* j is the index of the '\0' */
 
     return new;
 }
@@ -332,13 +336,13 @@ svSetValue(shvarFile *s, const char *key, const char *value, gboolean verbatim)
     }
 
 end:
-    if (newval) free(newval);
-    if (val1) free(val1);
-    if (val2) free(val2);
+    g_free(newval);
+    g_free(val1);
+    g_free(val2);
     return;
 
 bail:
-    if (keyValue) free (keyValue);
+    g_free (keyValue);
     goto end;
 }
 
diff --git a/src/settings/plugins/ifcfg-rh/tests/Makefile.in b/src/settings/plugins/ifcfg-rh/tests/Makefile.in
index cd37d0a7..6c509fd0 100644
--- a/src/settings/plugins/ifcfg-rh/tests/Makefile.in
+++ b/src/settings/plugins/ifcfg-rh/tests/Makefile.in
@@ -228,8 +228,16 @@ LIBGCRYPT_LIBS = @LIBGCRYPT_LIBS@
 LIBICONV = @LIBICONV@
 LIBINTL = @LIBINTL@
 LIBM = @LIBM@
+LIBNL1_CFLAGS = @LIBNL1_CFLAGS@
+LIBNL1_LIBS = @LIBNL1_LIBS@
+LIBNL2_CFLAGS = @LIBNL2_CFLAGS@
+LIBNL2_LIBS = @LIBNL2_LIBS@
+LIBNL3_CFLAGS = @LIBNL3_CFLAGS@
+LIBNL3_LIBS = @LIBNL3_LIBS@
 LIBNL_CFLAGS = @LIBNL_CFLAGS@
 LIBNL_LIBS = @LIBNL_LIBS@
+LIBNL_ROUTE3_CFLAGS = @LIBNL_ROUTE3_CFLAGS@
+LIBNL_ROUTE3_LIBS = @LIBNL_ROUTE3_LIBS@
 LIBOBJS = @LIBOBJS@
 LIBS = @LIBS@
 LIBTOOL = @LIBTOOL@
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 a10cbb86..7a00bcfd 100644
--- a/src/settings/plugins/ifcfg-rh/tests/network-scripts/Makefile.in
+++ b/src/settings/plugins/ifcfg-rh/tests/network-scripts/Makefile.in
@@ -152,8 +152,16 @@ LIBGCRYPT_LIBS = @LIBGCRYPT_LIBS@
 LIBICONV = @LIBICONV@
 LIBINTL = @LIBINTL@
 LIBM = @LIBM@
+LIBNL1_CFLAGS = @LIBNL1_CFLAGS@
+LIBNL1_LIBS = @LIBNL1_LIBS@
+LIBNL2_CFLAGS = @LIBNL2_CFLAGS@
+LIBNL2_LIBS = @LIBNL2_LIBS@
+LIBNL3_CFLAGS = @LIBNL3_CFLAGS@
+LIBNL3_LIBS = @LIBNL3_LIBS@
 LIBNL_CFLAGS = @LIBNL_CFLAGS@
 LIBNL_LIBS = @LIBNL_LIBS@
+LIBNL_ROUTE3_CFLAGS = @LIBNL_ROUTE3_CFLAGS@
+LIBNL_ROUTE3_LIBS = @LIBNL_ROUTE3_LIBS@
 LIBOBJS = @LIBOBJS@
 LIBS = @LIBS@
 LIBTOOL = @LIBTOOL@
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 d1f08aa9..e32266cb 100644
--- a/src/settings/plugins/ifcfg-rh/tests/test-ifcfg-rh.c
+++ b/src/settings/plugins/ifcfg-rh/tests/test-ifcfg-rh.c
@@ -10141,6 +10141,207 @@ test_write_wifi_wpa_then_open (void)
 }
 
 static void
+test_write_wifi_wpa_then_wep_with_perms (void)
+{
+	NMConnection *connection;
+	NMConnection *reread;
+	NMSettingConnection *s_con;
+	NMSettingWireless *s_wifi;
+	NMSettingWirelessSecurity *s_wsec;
+	NMSettingIP4Config *s_ip4;
+	NMSettingIP6Config *s_ip6;
+	char *uuid;
+	gboolean success;
+	GError *error = NULL;
+	char *testfile = NULL;
+	char *unmanaged = NULL;
+	char *keyfile = NULL;
+	char *routefile = NULL;
+	char *route6file = NULL;
+	gboolean ignore_error = FALSE;
+	GByteArray *ssid;
+	GSList *perm_list = NULL;
+	const unsigned char ssid_data[] = "SomeSSID";
+
+	/* Test that writing out a WPA config then changing that to a WEP
+	 * config works and doesn't cause infinite loop or other issues.
+	 */
+
+	connection = nm_connection_new ();
+	g_assert (connection);
+
+	/* Connection setting */
+	s_con = (NMSettingConnection *) nm_setting_connection_new ();
+	g_assert (s_con);
+	nm_connection_add_setting (connection, NM_SETTING (s_con));
+
+	uuid = nm_utils_uuid_generate ();
+	perm_list = g_slist_append (perm_list, "user:superman:");
+	g_object_set (s_con,
+	              NM_SETTING_CONNECTION_ID, "random wifi connection 2",
+	              NM_SETTING_CONNECTION_UUID, uuid,
+	              NM_SETTING_CONNECTION_AUTOCONNECT, TRUE,
+	              NM_SETTING_CONNECTION_PERMISSIONS, perm_list,
+	              NM_SETTING_CONNECTION_TYPE, NM_SETTING_WIRELESS_SETTING_NAME,
+	              NULL);
+	g_free (uuid);
+	g_slist_free (perm_list);
+	ASSERT (nm_setting_connection_get_num_permissions (s_con) == 1,
+                "test_write_wifi_wpa_then_wep_with_perms", "unexpected failure adding valid user permisson");
+
+	/* Wifi setting */
+	s_wifi = (NMSettingWireless *) nm_setting_wireless_new ();
+	g_assert (s_wifi);
+	nm_connection_add_setting (connection, NM_SETTING (s_wifi));
+
+	ssid = g_byte_array_sized_new (sizeof (ssid_data));
+	g_byte_array_append (ssid, ssid_data, sizeof (ssid_data));
+
+	g_object_set (s_wifi,
+	              NM_SETTING_WIRELESS_SSID, ssid,
+	              NM_SETTING_WIRELESS_MODE, "infrastructure",
+	              NM_SETTING_WIRELESS_SEC, NM_SETTING_WIRELESS_SECURITY_SETTING_NAME,
+	              NULL);
+
+	g_byte_array_free (ssid, TRUE);
+
+	/* Wireless security setting */
+	s_wsec = (NMSettingWirelessSecurity *) nm_setting_wireless_security_new ();
+	g_assert (s_wsec);
+	nm_connection_add_setting (connection, NM_SETTING (s_wsec));
+
+	g_object_set (s_wsec,
+	              NM_SETTING_WIRELESS_SECURITY_KEY_MGMT, "wpa-psk",
+	              NM_SETTING_WIRELESS_SECURITY_PSK, "My cool PSK",
+	              NULL);
+
+	nm_setting_wireless_security_add_proto (s_wsec, "wpa");
+	nm_setting_wireless_security_add_pairwise (s_wsec, "tkip");
+	nm_setting_wireless_security_add_group (s_wsec, "tkip");
+
+	nm_setting_wireless_security_add_proto (s_wsec, "rsn");
+	nm_setting_wireless_security_add_pairwise (s_wsec, "ccmp");
+	nm_setting_wireless_security_add_group (s_wsec, "ccmp");
+
+	/* IP4 setting */
+	s_ip4 = (NMSettingIP4Config *) nm_setting_ip4_config_new ();
+	g_assert (s_ip4);
+	nm_connection_add_setting (connection, NM_SETTING (s_ip4));
+
+	g_object_set (s_ip4, NM_SETTING_IP4_CONFIG_METHOD, NM_SETTING_IP4_CONFIG_METHOD_AUTO, NULL);
+
+	/* IP6 setting */
+	s_ip6 = (NMSettingIP6Config *) nm_setting_ip6_config_new ();
+	g_assert (s_ip6);
+	nm_connection_add_setting (connection, NM_SETTING (s_ip6));
+
+	g_object_set (s_ip6,
+	              NM_SETTING_IP6_CONFIG_METHOD, NM_SETTING_IP6_CONFIG_METHOD_IGNORE,
+	              NM_SETTING_IP6_CONFIG_MAY_FAIL, TRUE,
+	              NULL);
+
+	success = nm_connection_verify (connection, &error);
+	g_assert_no_error (error);
+	g_assert (success);
+
+	/* Save the ifcfg */
+	success = writer_new_connection (connection,
+	                                 TEST_SCRATCH_DIR "/network-scripts/",
+	                                 &testfile,
+	                                 &error);
+	g_assert_no_error (error);
+	g_assert (success);
+	g_assert (testfile);
+
+	/* re-read the connection for comparison */
+	reread = connection_from_file (testfile,
+	                               NULL,
+	                               TYPE_WIRELESS,
+	                               NULL,
+	                               &unmanaged,
+	                               &keyfile,
+	                               &routefile,
+	                               &route6file,
+	                               &error,
+	                               &ignore_error);
+	g_assert_no_error (error);
+	g_assert (reread);
+
+	success = nm_connection_verify (reread, &error);
+	g_assert_no_error (error);
+
+	success = nm_connection_compare (connection, reread, NM_SETTING_COMPARE_FLAG_EXACT);
+	g_assert (success);
+
+	g_free (unmanaged);
+	unmanaged = NULL;
+	g_free (routefile);
+	routefile = NULL;
+	g_free (route6file);
+	route6file = NULL;
+	g_object_unref (reread);
+
+	/* Now change the connection to WEP and recheck */
+	s_wsec = (NMSettingWirelessSecurity *) nm_setting_wireless_security_new ();
+	g_assert (s_wsec);
+	nm_connection_add_setting (connection, NM_SETTING (s_wsec));
+
+	g_object_set (s_wsec,
+	              NM_SETTING_WIRELESS_SECURITY_KEY_MGMT, "none",
+	              NULL);
+	nm_setting_wireless_security_set_wep_key (s_wsec, 0, "abraka  dabra");
+
+	/* Write it back out */
+	success = writer_update_connection (connection,
+	                                    TEST_SCRATCH_DIR "/network-scripts/",
+	                                    testfile,
+	                                    keyfile,
+	                                    &error);
+	g_assert_no_error (error);
+	g_assert (success);
+
+	g_free (keyfile);
+	keyfile = NULL;
+
+	/* re-read it for comparison */
+	reread = connection_from_file (testfile,
+	                               NULL,
+	                               TYPE_WIRELESS,
+	                               NULL,
+	                               &unmanaged,
+	                               &keyfile,
+	                               &routefile,
+	                               &route6file,
+	                               &error,
+	                               &ignore_error);
+	g_assert_no_error (error);
+
+	g_assert (reread);
+
+	success = nm_connection_verify (reread, &error);
+	g_assert_no_error (error);
+
+	success = nm_connection_compare (connection, reread,
+	                                 NM_SETTING_COMPARE_FLAG_IGNORE_AGENT_OWNED_SECRETS |
+	                                 NM_SETTING_COMPARE_FLAG_IGNORE_NOT_SAVED_SECRETS);
+
+	ASSERT (success,
+	        "test_write_wifi_wpa_then_wep_with_perms", "failed to compare connections");
+
+	unlink (keyfile);
+	unlink (testfile);
+
+	g_free (testfile);
+	g_free (unmanaged);
+	g_free (keyfile);
+	g_free (routefile);
+	g_free (route6file);
+	g_object_unref (reread);
+
+	g_object_unref (connection);
+}
+
+static void
 test_write_wifi_dynamic_wep_leap (void)
 {
 	NMConnection *connection;
@@ -11713,6 +11914,7 @@ int main (int argc, char **argv)
 	test_write_wifi_wpa_eap_ttls_mschapv2 ();
 	test_write_wifi_dynamic_wep_leap ();
 	test_write_wifi_wpa_then_open ();
+	test_write_wifi_wpa_then_wep_with_perms ();
 	test_write_wired_qeth_dhcp ();
 	test_write_wired_ctc_dhcp ();
 	test_write_permissions ();
diff --git a/src/settings/plugins/ifcfg-rh/writer.c b/src/settings/plugins/ifcfg-rh/writer.c
index 192226ac..068bcda2 100644
--- a/src/settings/plugins/ifcfg-rh/writer.c
+++ b/src/settings/plugins/ifcfg-rh/writer.c
@@ -569,6 +569,7 @@ write_wireless_security_setting (NMConnection *connection,
 	svSetValue (ifcfg, "DEFAULTKEY", NULL, FALSE);
 
 	if (!strcmp (key_mgmt, "none")) {
+		svSetValue (ifcfg, "KEY_MGMT", NULL, FALSE);
 		wep = TRUE;
 		*no_8021x = TRUE;
 	} else if (!strcmp (key_mgmt, "wpa-none") || !strcmp (key_mgmt, "wpa-psk")) {
@@ -1725,7 +1726,7 @@ write_connection (NMConnection *connection,
 
 			g_free (ifcfg_name);
 			while (idx++ < 500) {
-				ifcfg_name = g_strdup_printf ("%s/ifcfg-%s %u", ifcfg_dir, escaped, idx);
+				ifcfg_name = g_strdup_printf ("%s/ifcfg-%s-%u", ifcfg_dir, escaped, idx);
 				if (g_file_test (ifcfg_name, G_FILE_TEST_EXISTS) == FALSE)
 					break;
 				g_free (ifcfg_name);
diff --git a/src/settings/plugins/ifcfg-suse/Makefile.in b/src/settings/plugins/ifcfg-suse/Makefile.in
index 02e2247a..b8017e24 100644
--- a/src/settings/plugins/ifcfg-suse/Makefile.in
+++ b/src/settings/plugins/ifcfg-suse/Makefile.in
@@ -215,8 +215,16 @@ LIBGCRYPT_LIBS = @LIBGCRYPT_LIBS@
 LIBICONV = @LIBICONV@
 LIBINTL = @LIBINTL@
 LIBM = @LIBM@
+LIBNL1_CFLAGS = @LIBNL1_CFLAGS@
+LIBNL1_LIBS = @LIBNL1_LIBS@
+LIBNL2_CFLAGS = @LIBNL2_CFLAGS@
+LIBNL2_LIBS = @LIBNL2_LIBS@
+LIBNL3_CFLAGS = @LIBNL3_CFLAGS@
+LIBNL3_LIBS = @LIBNL3_LIBS@
 LIBNL_CFLAGS = @LIBNL_CFLAGS@
 LIBNL_LIBS = @LIBNL_LIBS@
+LIBNL_ROUTE3_CFLAGS = @LIBNL_ROUTE3_CFLAGS@
+LIBNL_ROUTE3_LIBS = @LIBNL_ROUTE3_LIBS@
 LIBOBJS = @LIBOBJS@
 LIBS = @LIBS@
 LIBTOOL = @LIBTOOL@
diff --git a/src/settings/plugins/ifnet/Makefile.in b/src/settings/plugins/ifnet/Makefile.in
index 2bc7bc32..519e07c0 100644
--- a/src/settings/plugins/ifnet/Makefile.in
+++ b/src/settings/plugins/ifnet/Makefile.in
@@ -263,8 +263,16 @@ LIBGCRYPT_LIBS = @LIBGCRYPT_LIBS@
 LIBICONV = @LIBICONV@
 LIBINTL = @LIBINTL@
 LIBM = @LIBM@
+LIBNL1_CFLAGS = @LIBNL1_CFLAGS@
+LIBNL1_LIBS = @LIBNL1_LIBS@
+LIBNL2_CFLAGS = @LIBNL2_CFLAGS@
+LIBNL2_LIBS = @LIBNL2_LIBS@
+LIBNL3_CFLAGS = @LIBNL3_CFLAGS@
+LIBNL3_LIBS = @LIBNL3_LIBS@
 LIBNL_CFLAGS = @LIBNL_CFLAGS@
 LIBNL_LIBS = @LIBNL_LIBS@
+LIBNL_ROUTE3_CFLAGS = @LIBNL_ROUTE3_CFLAGS@
+LIBNL_ROUTE3_LIBS = @LIBNL_ROUTE3_LIBS@
 LIBOBJS = @LIBOBJS@
 LIBS = @LIBS@
 LIBTOOL = @LIBTOOL@
diff --git a/src/settings/plugins/ifnet/connection_parser.c b/src/settings/plugins/ifnet/connection_parser.c
index 982f94f9..b4aaa8d2 100644
--- a/src/settings/plugins/ifnet/connection_parser.c
+++ b/src/settings/plugins/ifnet/connection_parser.c
@@ -1742,27 +1742,27 @@ ifnet_update_connection_from_config_block (const char *conn_name, GError **error
 
 	/* IPv4 setting */
 	make_ip4_setting (connection, conn_name, error);
-	if (error && *error)
-		PLUGIN_WARN (IFNET_PLUGIN_NAME,
-			     "Found error: %s", (*error)->message);
+	if (error && *error) {
+		PLUGIN_WARN (IFNET_PLUGIN_NAME, "Found error: %s", (*error)->message);
+		goto error;
+	}
 
 	/* IPv6 setting */
 	make_ip6_setting (connection, conn_name, error);
-	if (error && *error)
-		PLUGIN_WARN (IFNET_PLUGIN_NAME,
-			     "Found error: %s", (*error)->message);
+	if (error && *error) {
+		PLUGIN_WARN (IFNET_PLUGIN_NAME, "Found error: %s", (*error)->message);
+		goto error;
+	}
 
 	success = nm_connection_verify (connection, error);
 	if (error && *error)
-		PLUGIN_WARN (IFNET_PLUGIN_NAME,
-			     "Found error: %s", (*error)->message);
+		PLUGIN_WARN (IFNET_PLUGIN_NAME, "Found error: %s", (*error)->message);
 	PLUGIN_PRINT (IFNET_PLUGIN_NAME, "Connection verified %s:%d", conn_name, success);
 	if (!success)
 		goto error;
 	return connection;
 
 error:
-	g_object_unref (setting);
 	g_object_unref (connection);
 	return NULL;
 }
diff --git a/src/settings/plugins/ifnet/net_utils.c b/src/settings/plugins/ifnet/net_utils.c
index 83f86ab5..b533ae3f 100644
--- a/src/settings/plugins/ifnet/net_utils.c
+++ b/src/settings/plugins/ifnet/net_utils.c
@@ -313,7 +313,7 @@ is_ip4_address (const char *in_address)
 	gboolean result = FALSE;
 	gchar *tmp;
 	GRegex *regex = g_regex_new (pattern, 0, 0, NULL);
-	GMatchInfo *match_info;
+	GMatchInfo *match_info = NULL;
 
 	if (!address)
 		goto done;
diff --git a/src/settings/plugins/ifnet/tests/Makefile.in b/src/settings/plugins/ifnet/tests/Makefile.in
index 17b80c36..d2cbb871 100644
--- a/src/settings/plugins/ifnet/tests/Makefile.in
+++ b/src/settings/plugins/ifnet/tests/Makefile.in
@@ -186,8 +186,16 @@ LIBGCRYPT_LIBS = @LIBGCRYPT_LIBS@
 LIBICONV = @LIBICONV@
 LIBINTL = @LIBINTL@
 LIBM = @LIBM@
+LIBNL1_CFLAGS = @LIBNL1_CFLAGS@
+LIBNL1_LIBS = @LIBNL1_LIBS@
+LIBNL2_CFLAGS = @LIBNL2_CFLAGS@
+LIBNL2_LIBS = @LIBNL2_LIBS@
+LIBNL3_CFLAGS = @LIBNL3_CFLAGS@
+LIBNL3_LIBS = @LIBNL3_LIBS@
 LIBNL_CFLAGS = @LIBNL_CFLAGS@
 LIBNL_LIBS = @LIBNL_LIBS@
+LIBNL_ROUTE3_CFLAGS = @LIBNL_ROUTE3_CFLAGS@
+LIBNL_ROUTE3_LIBS = @LIBNL_ROUTE3_LIBS@
 LIBOBJS = @LIBOBJS@
 LIBS = @LIBS@
 LIBTOOL = @LIBTOOL@
diff --git a/src/settings/plugins/ifnet/tests/net b/src/settings/plugins/ifnet/tests/net
index e7550002..0eef399a 100644
--- a/src/settings/plugins/ifnet/tests/net
+++ b/src/settings/plugins/ifnet/tests/net
@@ -35,6 +35,8 @@ config_eth6=("192.168.4.{1..101}/24")
 config_eth7=( "dhcp" )
 auto_eth7="true"
 
+# missing config_eth8
+auto_eth8="true"
 
 config_myxjtu2=("202.117.16.121/24 brd 202.117.16.255")
 routes_myxjtu2=("default via 202.117.16.1")
diff --git a/src/settings/plugins/ifnet/tests/test_all.c b/src/settings/plugins/ifnet/tests/test_all.c
index d114bbba..52d9ce2a 100644
--- a/src/settings/plugins/ifnet/tests/test_all.c
+++ b/src/settings/plugins/ifnet/tests/test_all.c
@@ -252,25 +252,25 @@ test_is_unmanaged ()
 static void
 test_new_connection ()
 {
-	GError **error = NULL;
+	GError *error = NULL;
 	NMConnection *connection;
 
-	connection = ifnet_update_connection_from_config_block ("eth2", error);
+	connection = ifnet_update_connection_from_config_block ("eth2", &error);
 	ASSERT (connection != NULL, "new connection",
 		"new connection failed: %s",
-		error == NULL ? "None" : (*error)->message);
+		error ? error->message : "None");
 	g_object_unref (connection);
-	connection =
-	    ifnet_update_connection_from_config_block ("qiaomuf", error);
+
+	connection = ifnet_update_connection_from_config_block ("qiaomuf", &error);
 	ASSERT (connection != NULL, "new connection",
-		"new connection failed: %s", error
-		&& (*error) ? (*error)->message : "NONE");
+		"new connection failed: %s",
+		error ? error->message : "NONE");
 	g_object_unref (connection);
-	connection =
-	    ifnet_update_connection_from_config_block ("myxjtu2", error);
+
+	connection = ifnet_update_connection_from_config_block ("myxjtu2", &error);
 	ASSERT (connection != NULL, "new connection",
-		"new connection failed: %s", error
-		&& (*error) ? (*error)->message : "NONE");
+		"new connection failed: %s",
+		error ? error->message : "NONE");
 	g_object_unref (connection);
 }
 
@@ -280,32 +280,32 @@ test_new_connection ()
 static void
 test_update_connection ()
 {
-	GError **error = NULL;
+	GError *error = NULL;
 	NMConnection *connection;
 	gboolean success;
 
-	connection = ifnet_update_connection_from_config_block ("eth0", error);
+	connection = ifnet_update_connection_from_config_block ("eth0", &error);
 	ASSERT (connection != NULL, "get connection",
 		"get connection failed: %s",
-		error == NULL ? "None" : (*error)->message);
+		error ? error->message : "None");
 
 	success = ifnet_update_parsers_by_connection (connection, "eth0",
 	                                              NET_GEN_NAME,
 	                                              SUP_GEN_NAME,
 	                                              NULL,
-	                                              error);
+	                                              &error);
 	ASSERT (success, "update connection", "update connection failed %s", "eth0");
 	g_object_unref (connection);
 
-	connection = ifnet_update_connection_from_config_block ("0xab3ace", error);
+	connection = ifnet_update_connection_from_config_block ("0xab3ace", &error);
 	ASSERT (connection != NULL, "get connection", "get connection failed: %s",
-		error == NULL ? "None" : (*error)->message);
+		error ? error->message : "None");
 
 	success = ifnet_update_parsers_by_connection (connection, "0xab3ace",
 	                                              NET_GEN_NAME,
 	                                              SUP_GEN_NAME,
 	                                              NULL,
-	                                              error);
+	                                              &error);
 	ASSERT (success, "update connection", "update connection failed %s", "0xab3ace");
 	g_object_unref (connection);
 
@@ -357,6 +357,17 @@ test_delete_connection ()
 }
 
 static void
+test_missing_config ()
+{
+	GError *error = NULL;
+	NMConnection *connection;
+
+	connection = ifnet_update_connection_from_config_block ("eth8", &error);
+	ASSERT (connection == NULL && error != NULL, "get connection",
+	        "get connection should fail with 'Unknown config for eth8'");
+}
+
+static void
 run_all (gboolean run)
 {
 	if (run) {
@@ -378,6 +389,7 @@ run_all (gboolean run)
 		test_update_connection ();
 		test_add_connection ();
 		test_delete_connection ();
+		test_missing_config ();
 	}
 }
 
diff --git a/src/settings/plugins/ifnet/tests/wpa_supplicant.conf b/src/settings/plugins/ifnet/tests/wpa_supplicant.conf
index a2595d42..4f5f68cf 100644
--- a/src/settings/plugins/ifnet/tests/wpa_supplicant.conf
+++ b/src/settings/plugins/ifnet/tests/wpa_supplicant.conf
@@ -859,6 +859,7 @@ network={
 	identity="user@example.com"
 	anonymous_identity="anonymous@example.com"
 	password="foobar"
-	ca_cert="blob://exampleblob"
+	ca_cert="test_ca_cert.pem"
+	phase2="auth=CHAP"
 	priority=20
 }
diff --git a/src/settings/plugins/ifupdown/Makefile.in b/src/settings/plugins/ifupdown/Makefile.in
index 5f5a456b..b6896b59 100644
--- a/src/settings/plugins/ifupdown/Makefile.in
+++ b/src/settings/plugins/ifupdown/Makefile.in
@@ -262,8 +262,16 @@ LIBGCRYPT_LIBS = @LIBGCRYPT_LIBS@
 LIBICONV = @LIBICONV@
 LIBINTL = @LIBINTL@
 LIBM = @LIBM@
+LIBNL1_CFLAGS = @LIBNL1_CFLAGS@
+LIBNL1_LIBS = @LIBNL1_LIBS@
+LIBNL2_CFLAGS = @LIBNL2_CFLAGS@
+LIBNL2_LIBS = @LIBNL2_LIBS@
+LIBNL3_CFLAGS = @LIBNL3_CFLAGS@
+LIBNL3_LIBS = @LIBNL3_LIBS@
 LIBNL_CFLAGS = @LIBNL_CFLAGS@
 LIBNL_LIBS = @LIBNL_LIBS@
+LIBNL_ROUTE3_CFLAGS = @LIBNL_ROUTE3_CFLAGS@
+LIBNL_ROUTE3_LIBS = @LIBNL_ROUTE3_LIBS@
 LIBOBJS = @LIBOBJS@
 LIBS = @LIBS@
 LIBTOOL = @LIBTOOL@
diff --git a/src/settings/plugins/ifupdown/tests/Makefile.in b/src/settings/plugins/ifupdown/tests/Makefile.in
index 7412e65d..3c8bf793 100644
--- a/src/settings/plugins/ifupdown/tests/Makefile.in
+++ b/src/settings/plugins/ifupdown/tests/Makefile.in
@@ -186,8 +186,16 @@ LIBGCRYPT_LIBS = @LIBGCRYPT_LIBS@
 LIBICONV = @LIBICONV@
 LIBINTL = @LIBINTL@
 LIBM = @LIBM@
+LIBNL1_CFLAGS = @LIBNL1_CFLAGS@
+LIBNL1_LIBS = @LIBNL1_LIBS@
+LIBNL2_CFLAGS = @LIBNL2_CFLAGS@
+LIBNL2_LIBS = @LIBNL2_LIBS@
+LIBNL3_CFLAGS = @LIBNL3_CFLAGS@
+LIBNL3_LIBS = @LIBNL3_LIBS@
 LIBNL_CFLAGS = @LIBNL_CFLAGS@
 LIBNL_LIBS = @LIBNL_LIBS@
+LIBNL_ROUTE3_CFLAGS = @LIBNL_ROUTE3_CFLAGS@
+LIBNL_ROUTE3_LIBS = @LIBNL_ROUTE3_LIBS@
 LIBOBJS = @LIBOBJS@
 LIBS = @LIBS@
 LIBTOOL = @LIBTOOL@
diff --git a/src/settings/plugins/keyfile/Makefile.in b/src/settings/plugins/keyfile/Makefile.in
index a2a7d231..cf821e46 100644
--- a/src/settings/plugins/keyfile/Makefile.in
+++ b/src/settings/plugins/keyfile/Makefile.in
@@ -238,8 +238,16 @@ LIBGCRYPT_LIBS = @LIBGCRYPT_LIBS@
 LIBICONV = @LIBICONV@
 LIBINTL = @LIBINTL@
 LIBM = @LIBM@
+LIBNL1_CFLAGS = @LIBNL1_CFLAGS@
+LIBNL1_LIBS = @LIBNL1_LIBS@
+LIBNL2_CFLAGS = @LIBNL2_CFLAGS@
+LIBNL2_LIBS = @LIBNL2_LIBS@
+LIBNL3_CFLAGS = @LIBNL3_CFLAGS@
+LIBNL3_LIBS = @LIBNL3_LIBS@
 LIBNL_CFLAGS = @LIBNL_CFLAGS@
 LIBNL_LIBS = @LIBNL_LIBS@
+LIBNL_ROUTE3_CFLAGS = @LIBNL_ROUTE3_CFLAGS@
+LIBNL_ROUTE3_LIBS = @LIBNL_ROUTE3_LIBS@
 LIBOBJS = @LIBOBJS@
 LIBS = @LIBS@
 LIBTOOL = @LIBTOOL@
diff --git a/src/settings/plugins/keyfile/reader.c b/src/settings/plugins/keyfile/reader.c
index c4136e05..4128b9f2 100644
--- a/src/settings/plugins/keyfile/reader.c
+++ b/src/settings/plugins/keyfile/reader.c
@@ -730,10 +730,27 @@ read_hash_of_string (GKeyFile *file, NMSetting *setting, const char *key)
 	g_strfreev (keys);
 }
 
+static void
+unescape_semicolons (char *str)
+{
+	int i;
+	gsize len = strlen (str);
+
+	for (i = 0; i < len; i++) {
+		if (str[i] == '\\' && str[i+1] == ';') {
+			memmove(str + i, str + i + 1, len - (i + 1));
+			len--;
+		}
+		str[len] = '\0';
+	}
+}
+
 static GByteArray *
 get_uchar_array (GKeyFile *keyfile,
                  const char *setting_name,
-                 const char *key)
+                 const char *key,
+                 gboolean zero_terminate,
+                 gboolean unescape_semicolon)
 {
 	GByteArray *array = NULL;
 	char *tmp_string;
@@ -742,26 +759,28 @@ get_uchar_array (GKeyFile *keyfile,
 	int i;
 
 	/* New format: just a string
-	 * Old format: integer list; e.g. 11;25;38
+	 * Old format: integer list; e.g. 11;25;38;
 	 */
 	tmp_string = g_key_file_get_string (keyfile, setting_name, key, NULL);
 	if (tmp_string) {
-		gboolean new_format = FALSE;
 		GRegex *regex;
 		GMatchInfo *match_info;
-		const char *pattern = "^[[:space:]]*[[:digit:]]{1,3}[[:space:]]*(;[[:space:]]*[[:digit:]]{1,3}[[:space:]]*)*(;[[:space:]]*)?$";
+		const char *pattern = "^[[:space:]]*[[:digit:]]{1,3}[[:space:]]*;([[:space:]]*[[:digit:]]{1,3}[[:space:]]*;)*([[:space:]]*)?$";
 
 		regex = g_regex_new (pattern, 0, 0, NULL);
 		g_regex_match (regex, tmp_string, 0, &match_info);
-		if (!g_match_info_matches (match_info))
-			new_format = TRUE;
+		if (!g_match_info_matches (match_info)) {
+			/* Handle as a simple string (ie, new format) */
+			if (unescape_semicolon)
+				unescape_semicolons (tmp_string);
+			length = strlen (tmp_string);
+			if (zero_terminate)
+				length++;
+			array = g_byte_array_sized_new (length);
+			g_byte_array_append (array, (guint8 *) tmp_string, length);
+		}
 		g_match_info_free (match_info);
 		g_regex_unref (regex);
-
-		if (new_format) {
-			array = g_byte_array_sized_new (strlen (tmp_string));
-			g_byte_array_append (array, (guint8 *) tmp_string, strlen (tmp_string));
-		}
 		g_free (tmp_string);
 	}
 
@@ -796,7 +815,7 @@ ssid_parser (NMSetting *setting, const char *key, GKeyFile *keyfile, const char
 	const char *setting_name = nm_setting_get_name (setting);
 	GByteArray *array;
 
-	array = get_uchar_array (keyfile, setting_name, key);
+	array = get_uchar_array (keyfile, setting_name, key, FALSE, TRUE);
 	if (array) {
 		g_object_set (setting, key, array, NULL);
 		g_byte_array_free (array, TRUE);
@@ -837,21 +856,79 @@ get_cert_path (const char *keyfile_path, GByteArray *cert_path)
 static const char *certext[] = { ".pem", ".cert", ".crt", ".cer", ".p12", ".der", ".key" };
 
 static gboolean
-has_cert_ext (GByteArray *array)
+has_cert_ext (const char *path)
 {
 	int i;
 
 	for (i = 0; i < G_N_ELEMENTS (certext); i++) {
-		guint32 extlen = strlen (certext[i]);
-
-		if (array->len <= extlen)
-			continue;
-		if (memcmp (&array->data[array->len - extlen], certext[i], extlen) == 0)
+		if (g_str_has_suffix (path, certext[i]))
 			return TRUE;
 	}
 	return FALSE;
 }
 
+static gboolean
+handle_as_scheme (GByteArray *array, NMSetting *setting, const char *key)
+{
+	/* It's the PATH scheme, can just set plain data */
+	if (   (array->len > strlen (SCHEME_PATH))
+	    && g_str_has_prefix ((const char *) array->data, SCHEME_PATH)
+	    && (array->data[array->len - 1] == '\0')) {
+		g_object_set (setting, key, array, NULL);
+		return TRUE;
+	}
+	return FALSE;
+}
+
+static gboolean
+handle_as_path (GByteArray *array,
+                NMSetting *setting,
+                const char *key,
+                const char *keyfile_path)
+{
+	gsize validate_len = array->len;
+	GByteArray *val;
+	char *path;
+	gboolean exists, success = FALSE;
+
+	if (array->len > 500 || array->len < 1)
+		return FALSE;
+
+	/* If there's a trailing NULL tell g_utf8_validate() to to until the NULL */
+	if (array->data[array->len - 1] == '\0')
+		validate_len = -1;
+
+	if (g_utf8_validate ((const char *) array->data, validate_len, NULL) == FALSE)
+		return FALSE;
+
+	/* Might be a bare path without the file:// prefix; in that case
+	 * if it's an absolute path, use that, otherwise treat it as a
+	 * relative path to the current directory.
+	 */
+
+	path = get_cert_path (keyfile_path, array);
+	exists = g_file_test (path, G_FILE_TEST_EXISTS);
+	if (   exists
+	    || memchr (array->data, '/', array->len)
+	    || has_cert_ext (path)) {
+		/* Construct the proper value as required for the PATH scheme */
+		val = g_byte_array_sized_new (strlen (SCHEME_PATH) + strlen (path) + 1);
+		g_byte_array_append (val, (const guint8 *) SCHEME_PATH, strlen (SCHEME_PATH));
+		g_byte_array_append (val, (const guint8 *) path, strlen (path));
+		g_byte_array_append (val, (const guint8 *) "\0", 1);
+		g_object_set (setting, key, val, NULL);
+		g_byte_array_free (val, TRUE);
+		success = TRUE;
+
+		/* Warn if the certificate didn't exist */
+		if (exists == FALSE)
+			PLUGIN_WARN (KEYFILE_PLUGIN_NAME, "   certificate or key %s does not exist", path);
+	}
+	g_free (path);
+
+	return success;
+}
+
 static void
 cert_parser (NMSetting *setting, const char *key, GKeyFile *keyfile, const char *keyfile_path)
 {
@@ -859,62 +936,25 @@ cert_parser (NMSetting *setting, const char *key, GKeyFile *keyfile, const char
 	GByteArray *array;
 	gboolean success = FALSE;
 
-	array = get_uchar_array (keyfile, setting_name, key);
-	if (array) {
-		/* Value could be either:
-		 * 1) the raw key/cert data as a blob
-		 * 2) a path scheme (ie, starts with "file://")
-		 * 3) a plain path
-		 */
-		if (   (array->len > strlen (SCHEME_PATH))
-		    && g_str_has_prefix ((const char *) array->data, SCHEME_PATH)
-		    && (array->data[array->len - 1] == '\0')) {
-			/* It's the PATH scheme, can just set plain data */
-			g_object_set (setting, key, array, NULL);
-			success = TRUE;
-		} else if (   (array->len < 500)
-		           && g_utf8_validate ((const char *) array->data, array->len, NULL)) {
-			GByteArray *val;
-			char *path;
-			gboolean exists;
-
-			/* Might be a bare path without the file:// prefix; in that case
-			 * if it's an absolute path, use that, otherwise treat it as a
-			 * relative path to the current directory.
-			 */
-
-			path = get_cert_path (keyfile_path, array);
-			exists = g_file_test (path, G_FILE_TEST_EXISTS);
-			if (   exists
-			    || memchr (array->data, '/', array->len)
-			    || has_cert_ext (array)) {
-				/* Construct the proper value as required for the PATH scheme */
-				val = g_byte_array_sized_new (strlen (SCHEME_PATH) + array->len + 1);
-				g_byte_array_append (val, (const guint8 *) SCHEME_PATH, strlen (SCHEME_PATH));
-				g_byte_array_append (val, (const guint8 *) path, strlen (path));
-				g_byte_array_append (val, (const guint8 *) "\0", 1);
-				g_object_set (setting, key, val, NULL);
-				g_byte_array_free (val, TRUE);
-				success = TRUE;
-
-				/* Warn if the certificate didn't exist */
-				if (exists == FALSE) {
-					PLUGIN_WARN (KEYFILE_PLUGIN_NAME, "   certificate or key %s does not exist", path);
-				}
-			}
-			g_free (path);
-		}
+	array = get_uchar_array (keyfile, setting_name, key, TRUE, FALSE);
+	if (array && array->len > 0) {
+		/* Try as a path + scheme (ie, starts with "file://") */
+		success = handle_as_scheme (array, setting, key);
 
-		if (!success) {
-			/* Assume it's a simple blob value of the certificate or private key's data */
-			g_object_set (setting, key, array, NULL);
-		}
+		/* If not, it might be a plain path */
+		if (success == FALSE)
+			success = handle_as_path (array, setting, key, keyfile_path);
 
-		g_byte_array_free (array, TRUE);
+		/* If neither of those two, assume blob with certificate data */
+		if (success == FALSE)
+			g_object_set (setting, key, array, NULL);
 	} else {
 		g_warning ("%s: ignoring invalid key/cert value for %s / %s",
 		           __func__, setting_name, key);
 	}
+
+	if (array)
+		g_byte_array_free (array, TRUE);
 }
 
 typedef struct {
diff --git a/src/settings/plugins/keyfile/tests/Makefile.in b/src/settings/plugins/keyfile/tests/Makefile.in
index 05ed3a61..9d4f478d 100644
--- a/src/settings/plugins/keyfile/tests/Makefile.in
+++ b/src/settings/plugins/keyfile/tests/Makefile.in
@@ -224,8 +224,16 @@ LIBGCRYPT_LIBS = @LIBGCRYPT_LIBS@
 LIBICONV = @LIBICONV@
 LIBINTL = @LIBINTL@
 LIBM = @LIBM@
+LIBNL1_CFLAGS = @LIBNL1_CFLAGS@
+LIBNL1_LIBS = @LIBNL1_LIBS@
+LIBNL2_CFLAGS = @LIBNL2_CFLAGS@
+LIBNL2_LIBS = @LIBNL2_LIBS@
+LIBNL3_CFLAGS = @LIBNL3_CFLAGS@
+LIBNL3_LIBS = @LIBNL3_LIBS@
 LIBNL_CFLAGS = @LIBNL_CFLAGS@
 LIBNL_LIBS = @LIBNL_LIBS@
+LIBNL_ROUTE3_CFLAGS = @LIBNL_ROUTE3_CFLAGS@
+LIBNL_ROUTE3_LIBS = @LIBNL_ROUTE3_LIBS@
 LIBOBJS = @LIBOBJS@
 LIBS = @LIBS@
 LIBTOOL = @LIBTOOL@
diff --git a/src/settings/plugins/keyfile/tests/keyfiles/Makefile.am b/src/settings/plugins/keyfile/tests/keyfiles/Makefile.am
index 302db866..55dda7ee 100644
--- a/src/settings/plugins/keyfile/tests/keyfiles/Makefile.am
+++ b/src/settings/plugins/keyfile/tests/keyfiles/Makefile.am
@@ -8,6 +8,8 @@ KEYFILES = \
 	ATT_Data_Connect_Plain \
 	Test_String_SSID \
 	Test_Intlist_SSID \
+	Test_Intlike_SSID \
+	Test_Intlike_SSID_2 \
 	Test_Wired_TLS_Old \
 	Test_Wired_TLS_New \
 	Test_Wired_TLS_Blob \
diff --git a/src/settings/plugins/keyfile/tests/keyfiles/Makefile.in b/src/settings/plugins/keyfile/tests/keyfiles/Makefile.in
index 083615b0..3408cb15 100644
--- a/src/settings/plugins/keyfile/tests/keyfiles/Makefile.in
+++ b/src/settings/plugins/keyfile/tests/keyfiles/Makefile.in
@@ -152,8 +152,16 @@ LIBGCRYPT_LIBS = @LIBGCRYPT_LIBS@
 LIBICONV = @LIBICONV@
 LIBINTL = @LIBINTL@
 LIBM = @LIBM@
+LIBNL1_CFLAGS = @LIBNL1_CFLAGS@
+LIBNL1_LIBS = @LIBNL1_LIBS@
+LIBNL2_CFLAGS = @LIBNL2_CFLAGS@
+LIBNL2_LIBS = @LIBNL2_LIBS@
+LIBNL3_CFLAGS = @LIBNL3_CFLAGS@
+LIBNL3_LIBS = @LIBNL3_LIBS@
 LIBNL_CFLAGS = @LIBNL_CFLAGS@
 LIBNL_LIBS = @LIBNL_LIBS@
+LIBNL_ROUTE3_CFLAGS = @LIBNL_ROUTE3_CFLAGS@
+LIBNL_ROUTE3_LIBS = @LIBNL_ROUTE3_LIBS@
 LIBOBJS = @LIBOBJS@
 LIBS = @LIBS@
 LIBTOOL = @LIBTOOL@
@@ -278,6 +286,8 @@ KEYFILES = \
 	ATT_Data_Connect_Plain \
 	Test_String_SSID \
 	Test_Intlist_SSID \
+	Test_Intlike_SSID \
+	Test_Intlike_SSID_2 \
 	Test_Wired_TLS_Old \
 	Test_Wired_TLS_New \
 	Test_Wired_TLS_Blob \
diff --git a/src/settings/plugins/keyfile/tests/keyfiles/Test_Intlike_SSID b/src/settings/plugins/keyfile/tests/keyfiles/Test_Intlike_SSID
new file mode 100644
index 00000000..2bacb725
--- /dev/null
+++ b/src/settings/plugins/keyfile/tests/keyfiles/Test_Intlike_SSID
@@ -0,0 +1,11 @@
+[connection]
+id=Test 
+uuid=2f962388-e5f3-45af-a62c-ac220b8f7baa
+type=802-11-wireless
+
+[802-11-wireless]
+ssid=101
+
+[ipv4]
+method=auto
+
diff --git a/src/settings/plugins/keyfile/tests/keyfiles/Test_Intlike_SSID_2 b/src/settings/plugins/keyfile/tests/keyfiles/Test_Intlike_SSID_2
new file mode 100644
index 00000000..20240251
--- /dev/null
+++ b/src/settings/plugins/keyfile/tests/keyfiles/Test_Intlike_SSID_2
@@ -0,0 +1,11 @@
+[connection]
+id=Test SSID - escaping semicolon in string
+uuid=2f962388-e5f3-45af-a62c-ac220b8f7baa
+type=802-11-wireless
+
+[802-11-wireless]
+ssid=11\\;12\\;13\\;
+
+[ipv4]
+method=auto
+
diff --git a/src/settings/plugins/keyfile/tests/test-keyfile.c b/src/settings/plugins/keyfile/tests/test-keyfile.c
index 3bbaaaec..2859cb3e 100644
--- a/src/settings/plugins/keyfile/tests/test-keyfile.c
+++ b/src/settings/plugins/keyfile/tests/test-keyfile.c
@@ -1563,6 +1563,246 @@ test_write_intlist_ssid (void)
 	g_object_unref (connection);
 }
 
+#define TEST_INTLIKE_SSID_FILE TEST_KEYFILES_DIR"/Test_Intlike_SSID"
+
+static void
+test_read_intlike_ssid (void)
+{
+	NMConnection *connection;
+	NMSettingWireless *s_wifi;
+	GError *error = NULL;
+	gboolean success;
+	const GByteArray *array;
+	const char *expected_ssid = "101";
+
+	connection = nm_keyfile_plugin_connection_from_file (TEST_INTLIKE_SSID_FILE, &error);
+	g_assert_no_error (error);
+	g_assert (connection);
+
+	success = nm_connection_verify (connection, &error);
+	g_assert_no_error (error);
+	g_assert (success);
+
+	/* SSID */
+	s_wifi = nm_connection_get_setting_wireless (connection);
+	g_assert (s_wifi);
+
+	array = nm_setting_wireless_get_ssid (s_wifi);
+	g_assert (array != NULL);
+	g_assert_cmpint (array->len, ==, strlen (expected_ssid));
+	g_assert_cmpint (memcmp (array->data, expected_ssid, strlen (expected_ssid)), ==, 0);
+
+	g_object_unref (connection);
+}
+
+#define TEST_INTLIKE_SSID_2_FILE TEST_KEYFILES_DIR"/Test_Intlike_SSID_2"
+
+static void
+test_read_intlike_ssid_2 (void)
+{
+	NMConnection *connection;
+	NMSettingWireless *s_wifi;
+	GError *error = NULL;
+	gboolean success;
+	const GByteArray *array;
+	const char *expected_ssid = "11;12;13;";
+
+	connection = nm_keyfile_plugin_connection_from_file (TEST_INTLIKE_SSID_2_FILE, &error);
+	g_assert_no_error (error);
+	g_assert (connection);
+
+	success = nm_connection_verify (connection, &error);
+	g_assert_no_error (error);
+	g_assert (success);
+
+	/* SSID */
+	s_wifi = nm_connection_get_setting_wireless (connection);
+	g_assert (s_wifi);
+
+	array = nm_setting_wireless_get_ssid (s_wifi);
+	g_assert (array != NULL);
+	g_assert_cmpint (array->len, ==, strlen (expected_ssid));
+	g_assert_cmpint (memcmp (array->data, expected_ssid, strlen (expected_ssid)), ==, 0);
+
+	g_object_unref (connection);
+}
+
+static void
+test_write_intlike_ssid (void)
+{
+	NMConnection *connection;
+	NMSettingConnection *s_con;
+	NMSettingWireless *s_wifi;
+	NMSettingIP4Config *s_ip4;
+	char *uuid, *testfile = NULL;
+	GByteArray *ssid;
+	unsigned char tmpssid[] = { 49, 48, 49 };
+	gboolean success;
+	NMConnection *reread;
+	GError *error = NULL;
+	pid_t owner_grp;
+	uid_t owner_uid;
+	GKeyFile *keyfile;
+	char *tmp;
+
+	connection = nm_connection_new ();
+	g_assert (connection);
+
+	/* Connection setting */
+
+	s_con = NM_SETTING_CONNECTION (nm_setting_connection_new ());
+	g_assert (s_con);
+	nm_connection_add_setting (connection, NM_SETTING (s_con));
+
+	uuid = nm_utils_uuid_generate ();
+	g_object_set (s_con,
+	              NM_SETTING_CONNECTION_ID, "Intlike SSID Test",
+	              NM_SETTING_CONNECTION_UUID, uuid,
+	              NM_SETTING_CONNECTION_TYPE, NM_SETTING_WIRELESS_SETTING_NAME,
+	              NULL);
+	g_free (uuid);
+
+	/* Wireless setting */
+	s_wifi = NM_SETTING_WIRELESS (nm_setting_wireless_new ());
+	g_assert (s_wifi);
+	nm_connection_add_setting (connection, NM_SETTING (s_wifi));
+
+	ssid = g_byte_array_sized_new (sizeof (tmpssid));
+	g_byte_array_append (ssid, &tmpssid[0], sizeof (tmpssid));
+	g_object_set (s_wifi, NM_SETTING_WIRELESS_SSID, ssid, NULL);
+	g_byte_array_free (ssid, TRUE);
+
+	/* IP4 setting */
+	s_ip4 = NM_SETTING_IP4_CONFIG (nm_setting_ip4_config_new ());
+	g_assert (s_ip4);
+	nm_connection_add_setting (connection, NM_SETTING (s_ip4));
+	g_object_set (s_ip4, NM_SETTING_IP4_CONFIG_METHOD, NM_SETTING_IP4_CONFIG_METHOD_AUTO, NULL);
+
+	/* Write out the connection */
+	owner_uid = geteuid ();
+	owner_grp = getegid ();
+	success = nm_keyfile_plugin_write_test_connection (connection, TEST_SCRATCH_DIR, owner_uid, owner_grp, &testfile, &error);
+	g_assert_no_error (error);
+	g_assert (success);
+	g_assert (testfile != NULL);
+
+	/* Ensure the SSID was written out as a plain "101" */
+	keyfile = g_key_file_new ();
+	success = g_key_file_load_from_file (keyfile, testfile, 0, &error);
+	g_assert_no_error (error);
+	g_assert (success);
+
+	tmp = g_key_file_get_string (keyfile, NM_SETTING_WIRELESS_SETTING_NAME, NM_SETTING_WIRELESS_SSID, &error);
+	g_assert_no_error (error);
+	g_assert (tmp);
+	g_assert_cmpstr (tmp, ==, "101");
+
+	g_key_file_free (keyfile);
+
+	/* Read the connection back in and compare it to the one we just wrote out */
+	reread = nm_keyfile_plugin_connection_from_file (testfile, &error);
+	g_assert_no_error (error);
+	g_assert (reread);
+
+	success = nm_connection_compare (connection, reread, NM_SETTING_COMPARE_FLAG_EXACT);
+	g_assert (success);
+
+	g_clear_error (&error);
+	unlink (testfile);
+	g_free (testfile);
+
+	g_object_unref (reread);
+	g_object_unref (connection);
+}
+
+static void
+test_write_intlike_ssid_2 (void)
+{
+	NMConnection *connection;
+	NMSettingConnection *s_con;
+	NMSettingWireless *s_wifi;
+	NMSettingIP4Config *s_ip4;
+	char *uuid, *testfile = NULL;
+	GByteArray *ssid;
+	unsigned char tmpssid[] = { 49, 49, 59, 49, 50, 59, 49, 51, 59};
+	gboolean success;
+	NMConnection *reread;
+	GError *error = NULL;
+	pid_t owner_grp;
+	uid_t owner_uid;
+	GKeyFile *keyfile;
+	char *tmp;
+
+	connection = nm_connection_new ();
+	g_assert (connection);
+
+	/* Connection setting */
+
+	s_con = NM_SETTING_CONNECTION (nm_setting_connection_new ());
+	g_assert (s_con);
+	nm_connection_add_setting (connection, NM_SETTING (s_con));
+
+	uuid = nm_utils_uuid_generate ();
+	g_object_set (s_con,
+	              NM_SETTING_CONNECTION_ID, "Intlike SSID Test 2",
+	              NM_SETTING_CONNECTION_UUID, uuid,
+	              NM_SETTING_CONNECTION_TYPE, NM_SETTING_WIRELESS_SETTING_NAME,
+	              NULL);
+	g_free (uuid);
+
+	/* Wireless setting */
+	s_wifi = NM_SETTING_WIRELESS (nm_setting_wireless_new ());
+	g_assert (s_wifi);
+	nm_connection_add_setting (connection, NM_SETTING (s_wifi));
+
+	ssid = g_byte_array_sized_new (sizeof (tmpssid));
+	g_byte_array_append (ssid, &tmpssid[0], sizeof (tmpssid));
+	g_object_set (s_wifi, NM_SETTING_WIRELESS_SSID, ssid, NULL);
+	g_byte_array_free (ssid, TRUE);
+
+	/* IP4 setting */
+	s_ip4 = NM_SETTING_IP4_CONFIG (nm_setting_ip4_config_new ());
+	g_assert (s_ip4);
+	nm_connection_add_setting (connection, NM_SETTING (s_ip4));
+	g_object_set (s_ip4, NM_SETTING_IP4_CONFIG_METHOD, NM_SETTING_IP4_CONFIG_METHOD_AUTO, NULL);
+
+	/* Write out the connection */
+	owner_uid = geteuid ();
+	owner_grp = getegid ();
+	success = nm_keyfile_plugin_write_test_connection (connection, TEST_SCRATCH_DIR, owner_uid, owner_grp, &testfile, &error);
+	g_assert_no_error (error);
+	g_assert (success);
+	g_assert (testfile != NULL);
+
+	/* Ensure the SSID was written out as a plain "11;12;13;" */
+	keyfile = g_key_file_new ();
+	success = g_key_file_load_from_file (keyfile, testfile, 0, &error);
+	g_assert_no_error (error);
+	g_assert (success);
+
+	tmp = g_key_file_get_string (keyfile, NM_SETTING_WIRELESS_SETTING_NAME, NM_SETTING_WIRELESS_SSID, &error);
+	g_assert_no_error (error);
+	g_assert (tmp);
+	g_assert_cmpstr (tmp, ==, "11\\;12\\;13\\;");
+
+	g_key_file_free (keyfile);
+
+	/* Read the connection back in and compare it to the one we just wrote out */
+	reread = nm_keyfile_plugin_connection_from_file (testfile, &error);
+	g_assert_no_error (error);
+	g_assert (reread);
+
+	success = nm_connection_compare (connection, reread, NM_SETTING_COMPARE_FLAG_EXACT);
+	g_assert (success);
+
+	g_clear_error (&error);
+	unlink (testfile);
+	g_free (testfile);
+
+	g_object_unref (reread);
+	g_object_unref (connection);
+}
+
 #define TEST_BT_DUN_FILE TEST_KEYFILES_DIR"/ATT_Data_Connect_BT"
 
 static void
@@ -2616,6 +2856,12 @@ int main (int argc, char **argv)
 	test_read_intlist_ssid ();
 	test_write_intlist_ssid ();
 
+	test_read_intlike_ssid ();
+	test_write_intlike_ssid ();
+
+	test_read_intlike_ssid_2 ();
+	test_write_intlike_ssid_2 ();
+
 	test_read_bt_dun_connection ();
 	test_write_bt_dun_connection ();
 
diff --git a/src/settings/plugins/keyfile/writer.c b/src/settings/plugins/keyfile/writer.c
index 060093ce..db43b233 100644
--- a/src/settings/plugins/keyfile/writer.c
+++ b/src/settings/plugins/keyfile/writer.c
@@ -44,6 +44,7 @@
 #include <ctype.h>
 
 #include "nm-dbus-glib-types.h"
+#include "nm-glib-compat.h"
 #include "writer.h"
 #include "common.h"
 
@@ -483,6 +484,7 @@ ssid_writer (GKeyFile *file,
 	GByteArray *array;
 	const char *setting_name = nm_setting_get_name (setting);
 	gboolean new_format = TRUE;
+	unsigned int semicolons = 0;
 	int i, *tmp_array;
 	char *ssid;
 
@@ -501,11 +503,24 @@ ssid_writer (GKeyFile *file,
 			new_format = FALSE;
 			break;
 		}
+		if (c == ';')
+			semicolons++;
 	}
 
 	if (new_format) {
-		ssid = g_malloc0 (array->len + 1);
-		memcpy (ssid, array->data, array->len);
+		ssid = g_malloc0 (array->len + semicolons + 1);
+		if (semicolons == 0)
+			memcpy (ssid, array->data, array->len);
+		else {
+			/* Escape semicolons with backslashes to make strings
+			 * containing ';', such as '16;17;' unambiguous */
+			int j = 0;
+			for (i = 0; i < array->len; i++) {
+				if (array->data[i] == ';')
+					ssid[j++] = '\\';
+				ssid[j++] = array->data[i];
+			}
+		}
 		g_key_file_set_string (file, setting_name, key, ssid);
 		g_free (ssid);
 	} else {
@@ -876,7 +891,7 @@ write_setting_value (NMSetting *setting,
 	} else if (type == G_TYPE_BOOLEAN) {
 		g_key_file_set_boolean (info->keyfile, setting_name, key, g_value_get_boolean (value));
 	} else if (type == G_TYPE_CHAR) {
-		g_key_file_set_integer (info->keyfile, setting_name, key, (int) g_value_get_char (value));
+		g_key_file_set_integer (info->keyfile, setting_name, key, (int) g_value_get_schar (value));
 	} else if (type == DBUS_TYPE_G_UCHAR_ARRAY) {
 		GByteArray *array;
 
@@ -993,15 +1008,27 @@ _internal_write_connection (NMConnection *connection,
 
 		path = g_strdup_printf ("%s/%s-%s", keyfile_dir, filename, nm_connection_get_uuid (connection));
 		if (g_file_test (path, G_FILE_TEST_EXISTS)) {
-			/* Hmm, this is odd. Give up. */
-			g_set_error (error, KEYFILE_PLUGIN_ERROR, 0,
-				         "%s.%d: could not find suitable keyfile file name (%s already used)",
-				         __FILE__, __LINE__, path);
-			g_free (path);
-			goto out;
+			if (existing_path == NULL || g_strcmp0 (path, existing_path) != 0) {
+				/* This should not happen. But, it actually occurs when
+				 * two connections have the same UUID, and one of the connections
+				 * is edited to contain the same ID as the other one.
+				 * Give up.
+				 */
+				g_set_error (error, KEYFILE_PLUGIN_ERROR, 0,
+				                    "%s.%d: could not find suitable keyfile file name (%s already used)",
+				                    __FILE__, __LINE__, path);
+				g_free (path);
+				goto out;
+			}
 		}
 	}
 
+	/* In case of updating the connection and changing the file path,
+	 * we need to remove the old one, not to end up with two connections.
+	 */
+	if (existing_path != NULL && strcmp (path, existing_path) != 0)
+		unlink (existing_path);
+
 	g_file_set_contents (path, data, len, error);
 	if (chown (path, owner_uid, owner_grp) < 0) {
 		g_set_error (error, KEYFILE_PLUGIN_ERROR, 0,
diff --git a/src/settings/tests/Makefile.in b/src/settings/tests/Makefile.in
index 33c4bd38..94ae4830 100644
--- a/src/settings/tests/Makefile.in
+++ b/src/settings/tests/Makefile.in
@@ -188,8 +188,16 @@ LIBGCRYPT_LIBS = @LIBGCRYPT_LIBS@
 LIBICONV = @LIBICONV@
 LIBINTL = @LIBINTL@
 LIBM = @LIBM@
+LIBNL1_CFLAGS = @LIBNL1_CFLAGS@
+LIBNL1_LIBS = @LIBNL1_LIBS@
+LIBNL2_CFLAGS = @LIBNL2_CFLAGS@
+LIBNL2_LIBS = @LIBNL2_LIBS@
+LIBNL3_CFLAGS = @LIBNL3_CFLAGS@
+LIBNL3_LIBS = @LIBNL3_LIBS@
 LIBNL_CFLAGS = @LIBNL_CFLAGS@
 LIBNL_LIBS = @LIBNL_LIBS@
+LIBNL_ROUTE3_CFLAGS = @LIBNL_ROUTE3_CFLAGS@
+LIBNL_ROUTE3_LIBS = @LIBNL_ROUTE3_LIBS@
 LIBOBJS = @LIBOBJS@
 LIBS = @LIBS@
 LIBTOOL = @LIBTOOL@
diff --git a/src/supplicant-manager/Makefile.in b/src/supplicant-manager/Makefile.in
index 729917d3..3a9c43f4 100644
--- a/src/supplicant-manager/Makefile.in
+++ b/src/supplicant-manager/Makefile.in
@@ -229,8 +229,16 @@ LIBGCRYPT_LIBS = @LIBGCRYPT_LIBS@
 LIBICONV = @LIBICONV@
 LIBINTL = @LIBINTL@
 LIBM = @LIBM@
+LIBNL1_CFLAGS = @LIBNL1_CFLAGS@
+LIBNL1_LIBS = @LIBNL1_LIBS@
+LIBNL2_CFLAGS = @LIBNL2_CFLAGS@
+LIBNL2_LIBS = @LIBNL2_LIBS@
+LIBNL3_CFLAGS = @LIBNL3_CFLAGS@
+LIBNL3_LIBS = @LIBNL3_LIBS@
 LIBNL_CFLAGS = @LIBNL_CFLAGS@
 LIBNL_LIBS = @LIBNL_LIBS@
+LIBNL_ROUTE3_CFLAGS = @LIBNL_ROUTE3_CFLAGS@
+LIBNL_ROUTE3_LIBS = @LIBNL_ROUTE3_LIBS@
 LIBOBJS = @LIBOBJS@
 LIBS = @LIBS@
 LIBTOOL = @LIBTOOL@
diff --git a/src/supplicant-manager/nm-supplicant-config.c b/src/supplicant-manager/nm-supplicant-config.c
index c651e0fa..4860314b 100644
--- a/src/supplicant-manager/nm-supplicant-config.c
+++ b/src/supplicant-manager/nm-supplicant-config.c
@@ -123,7 +123,7 @@ nm_supplicant_config_add_option_with_type (NMSupplicantConfig *self,
 			char buf[255];
 			memset (&buf[0], 0, sizeof (buf));
 			memcpy (&buf[0], value, len > 254 ? 254 : len);
-			nm_log_warn (LOGD_SUPPLICANT, "Key '%s' and/or value '%s' invalid.", key, buf);
+			nm_log_warn (LOGD_SUPPLICANT, "Key '%s' and/or value '%s' invalid.", key, secret ? "<omitted>" : buf);
 			return FALSE;
 		}
 	}
diff --git a/src/supplicant-manager/nm-supplicant-manager.c b/src/supplicant-manager/nm-supplicant-manager.c
index 8209da21..349f722a 100644
--- a/src/supplicant-manager/nm-supplicant-manager.c
+++ b/src/supplicant-manager/nm-supplicant-manager.c
@@ -45,8 +45,10 @@ typedef struct {
 	NMDBusManager * dbus_mgr;
 	guint           name_owner_id;
 	DBusGProxy *    proxy;
+	DBusGProxy *    props_proxy;
 	gboolean        running;
 	GHashTable *    ifaces;
+	gboolean        fast_supported;
 	guint           die_count_reset_id;
 	guint           die_count;
 	gboolean        disposed;
@@ -122,6 +124,56 @@ nm_supplicant_manager_iface_release (NMSupplicantManager *self,
 	g_hash_table_remove (priv->ifaces, ifname);
 }
 
+static void
+get_eap_methods_reply (DBusGProxy *proxy,
+                       DBusGProxyCall *call,
+                       gpointer user_data)
+{
+	NMSupplicantManager *self = NM_SUPPLICANT_MANAGER (user_data);
+	NMSupplicantManagerPrivate *priv = NM_SUPPLICANT_MANAGER_GET_PRIVATE (self);
+	GError *error = NULL;
+	GValue value = { 0 };
+	const char **iter;
+
+	if (dbus_g_proxy_end_call (proxy, call, &error,
+	                           G_TYPE_VALUE, &value,
+	                           G_TYPE_INVALID)) {
+		if (G_VALUE_HOLDS (&value, G_TYPE_STRV)) {
+			iter = g_value_get_boxed (&value);
+			while (iter && *iter) {
+				if (strcasecmp (*iter++, "FAST") == 0) {
+					priv->fast_supported = TRUE;
+					break;
+				}
+			}
+		} else {
+			nm_log_warn (LOGD_SUPPLICANT, "Unexpected EapMethods property type %s",
+			             G_VALUE_TYPE_NAME (&value));
+		}
+		g_value_unset (&value);
+	} else {
+		nm_log_warn (LOGD_SUPPLICANT, "Unexpected error requesting EapMethods: (%d) %s",
+		             error ? error->code : -1,
+		             error && error->message ? error->message : "(unknown)");
+		g_clear_error (&error);
+	}
+
+	nm_log_dbg (LOGD_SUPPLICANT, "EAP-FAST is %ssupported",
+	            priv->fast_supported ? "" : "not ");
+}
+
+static void
+check_supported_eap_methods (NMSupplicantManager *self)
+{
+	NMSupplicantManagerPrivate *priv = NM_SUPPLICANT_MANAGER_GET_PRIVATE (self);
+
+	dbus_g_proxy_begin_call (priv->props_proxy, "Get",
+	                         get_eap_methods_reply, self, NULL,
+	                         G_TYPE_STRING, WPAS_DBUS_INTERFACE,
+	                         G_TYPE_STRING, "EapMethods",
+	                         G_TYPE_INVALID);
+}
+
 gboolean
 nm_supplicant_manager_available (NMSupplicantManager *self)
 {
@@ -187,6 +239,7 @@ name_owner_changed (NMDBusManager *dbus_mgr,
 	if (!old_owner_good && new_owner_good) {
 		nm_log_info (LOGD_SUPPLICANT, "wpa_supplicant started");
 		set_running (self, TRUE);
+		check_supported_eap_methods (self);
 	} else if (old_owner_good && !new_owner_good) {
 		nm_log_info (LOGD_SUPPLICANT, "wpa_supplicant stopped");
 
@@ -207,6 +260,8 @@ name_owner_changed (NMDBusManager *dbus_mgr,
 		}
 
 		set_running (self, FALSE);
+
+		priv->fast_supported = FALSE;
 	}
 }
 
@@ -227,7 +282,7 @@ nm_supplicant_manager_get (void)
 }
 
 static void
-nm_supplicant_manager_init (NMSupplicantManager * self)
+nm_supplicant_manager_init (NMSupplicantManager *self)
 {
 	NMSupplicantManagerPrivate *priv = NM_SUPPLICANT_MANAGER_GET_PRIVATE (self);
 	DBusGConnection *bus;
@@ -245,7 +300,16 @@ nm_supplicant_manager_init (NMSupplicantManager * self)
 	                                         WPAS_DBUS_PATH,
 	                                         WPAS_DBUS_INTERFACE);
 
+	priv->props_proxy = dbus_g_proxy_new_for_name (bus,
+	                                               WPAS_DBUS_SERVICE,
+	                                               WPAS_DBUS_PATH,
+	                                               DBUS_INTERFACE_PROPERTIES);
+
 	priv->ifaces = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, g_object_unref);
+
+	/* Grab list of supported EAP methods */
+	if (priv->running)
+		check_supported_eap_methods (self);
 }
 
 static void
@@ -290,6 +354,9 @@ dispose (GObject *object)
 	if (priv->proxy)
 		g_object_unref (priv->proxy);
 
+	if (priv->props_proxy)
+		g_object_unref (priv->props_proxy);
+
 out:
 	/* Chain up to the parent class */
 	G_OBJECT_CLASS (nm_supplicant_manager_parent_class)->dispose (object);
diff --git a/src/supplicant-manager/tests/Makefile.in b/src/supplicant-manager/tests/Makefile.in
index 18288c6e..e0fa89e6 100644
--- a/src/supplicant-manager/tests/Makefile.in
+++ b/src/supplicant-manager/tests/Makefile.in
@@ -188,8 +188,16 @@ LIBGCRYPT_LIBS = @LIBGCRYPT_LIBS@
 LIBICONV = @LIBICONV@
 LIBINTL = @LIBINTL@
 LIBM = @LIBM@
+LIBNL1_CFLAGS = @LIBNL1_CFLAGS@
+LIBNL1_LIBS = @LIBNL1_LIBS@
+LIBNL2_CFLAGS = @LIBNL2_CFLAGS@
+LIBNL2_LIBS = @LIBNL2_LIBS@
+LIBNL3_CFLAGS = @LIBNL3_CFLAGS@
+LIBNL3_LIBS = @LIBNL3_LIBS@
 LIBNL_CFLAGS = @LIBNL_CFLAGS@
 LIBNL_LIBS = @LIBNL_LIBS@
+LIBNL_ROUTE3_CFLAGS = @LIBNL_ROUTE3_CFLAGS@
+LIBNL_ROUTE3_LIBS = @LIBNL_ROUTE3_LIBS@
 LIBOBJS = @LIBOBJS@
 LIBS = @LIBS@
 LIBTOOL = @LIBTOOL@
diff --git a/src/tests/Makefile.in b/src/tests/Makefile.in
index 0f19b712..a60ca43f 100644
--- a/src/tests/Makefile.in
+++ b/src/tests/Makefile.in
@@ -205,8 +205,16 @@ LIBGCRYPT_LIBS = @LIBGCRYPT_LIBS@
 LIBICONV = @LIBICONV@
 LIBINTL = @LIBINTL@
 LIBM = @LIBM@
+LIBNL1_CFLAGS = @LIBNL1_CFLAGS@
+LIBNL1_LIBS = @LIBNL1_LIBS@
+LIBNL2_CFLAGS = @LIBNL2_CFLAGS@
+LIBNL2_LIBS = @LIBNL2_LIBS@
+LIBNL3_CFLAGS = @LIBNL3_CFLAGS@
+LIBNL3_LIBS = @LIBNL3_LIBS@
 LIBNL_CFLAGS = @LIBNL_CFLAGS@
 LIBNL_LIBS = @LIBNL_LIBS@
+LIBNL_ROUTE3_CFLAGS = @LIBNL_ROUTE3_CFLAGS@
+LIBNL_ROUTE3_LIBS = @LIBNL_ROUTE3_LIBS@
 LIBOBJS = @LIBOBJS@
 LIBS = @LIBS@
 LIBTOOL = @LIBTOOL@
diff --git a/src/vpn-manager/Makefile.in b/src/vpn-manager/Makefile.in
index 3785667e..8999e831 100644
--- a/src/vpn-manager/Makefile.in
+++ b/src/vpn-manager/Makefile.in
@@ -190,8 +190,16 @@ LIBGCRYPT_LIBS = @LIBGCRYPT_LIBS@
 LIBICONV = @LIBICONV@
 LIBINTL = @LIBINTL@
 LIBM = @LIBM@
+LIBNL1_CFLAGS = @LIBNL1_CFLAGS@
+LIBNL1_LIBS = @LIBNL1_LIBS@
+LIBNL2_CFLAGS = @LIBNL2_CFLAGS@
+LIBNL2_LIBS = @LIBNL2_LIBS@
+LIBNL3_CFLAGS = @LIBNL3_CFLAGS@
+LIBNL3_LIBS = @LIBNL3_LIBS@
 LIBNL_CFLAGS = @LIBNL_CFLAGS@
 LIBNL_LIBS = @LIBNL_LIBS@
+LIBNL_ROUTE3_CFLAGS = @LIBNL_ROUTE3_CFLAGS@
+LIBNL_ROUTE3_LIBS = @LIBNL_ROUTE3_LIBS@
 LIBOBJS = @LIBOBJS@
 LIBS = @LIBS@
 LIBTOOL = @LIBTOOL@
diff --git a/src/vpn-manager/nm-vpn-connection-base.c b/src/vpn-manager/nm-vpn-connection-base.c
index c7373627..bc2cffb2 100644
--- a/src/vpn-manager/nm-vpn-connection-base.c
+++ b/src/vpn-manager/nm-vpn-connection-base.c
@@ -36,6 +36,7 @@ typedef struct {
 
 	NMConnection *connection;
 	char *ac_path;
+	char *specific_object;
 	gboolean is_default;
 	gboolean is_default6;
 	NMActiveConnectionState state;
@@ -91,9 +92,16 @@ nm_vpn_connection_base_get_ac_path (NMVpnConnectionBase *self)
 	return NM_VPN_CONNECTION_BASE_GET_PRIVATE (self)->ac_path;
 }
 
+const char *
+nm_vpn_connection_base_get_specific_object (NMVpnConnectionBase *self)
+{
+	return NM_VPN_CONNECTION_BASE_GET_PRIVATE (self)->specific_object;
+}
+
 void
 nm_vpn_connection_base_export (NMVpnConnectionBase *self,
-                               NMConnection *connection)
+                               NMConnection *connection,
+                               const char *specific_object)
 {
 	NMVpnConnectionBasePrivate *priv = NM_VPN_CONNECTION_BASE_GET_PRIVATE (self);
 	NMDBusManager *dbus_mgr;
@@ -101,6 +109,7 @@ nm_vpn_connection_base_export (NMVpnConnectionBase *self,
 	g_return_if_fail (priv->connection == NULL);
 
 	priv->connection = g_object_ref (connection);
+	priv->specific_object = g_strdup (specific_object);
 
 	dbus_mgr = nm_dbus_manager_get ();
 	dbus_g_connection_register_g_object (nm_dbus_manager_get_connection (dbus_mgr),
@@ -128,6 +137,7 @@ dispose (GObject *object)
 		priv->disposed = TRUE;
 
 		g_free (priv->ac_path);
+		g_free (priv->specific_object);
 		g_object_unref (priv->connection);
 	}
 
@@ -145,10 +155,10 @@ get_property (GObject *object, guint prop_id,
 		g_value_set_boxed (value, nm_connection_get_path (priv->connection));
 		break;
 	case PROP_UUID:
-		g_value_set_boxed (value, nm_connection_get_uuid (priv->connection));
+		g_value_set_string (value, nm_connection_get_uuid (priv->connection));
 		break;
 	case PROP_SPECIFIC_OBJECT:
-		g_value_set_boxed (value, priv->ac_path);
+		g_value_set_boxed (value, priv->specific_object);
 		break;
 	case PROP_DEVICES:
 		g_value_take_boxed (value, g_ptr_array_new ());
diff --git a/src/vpn-manager/nm-vpn-connection-base.h b/src/vpn-manager/nm-vpn-connection-base.h
index 0c17d9e8..6f19e7c5 100644
--- a/src/vpn-manager/nm-vpn-connection-base.h
+++ b/src/vpn-manager/nm-vpn-connection-base.h
@@ -44,8 +44,11 @@ GType nm_vpn_connection_base_get_type (void);
 
 const char *nm_vpn_connection_base_get_ac_path (NMVpnConnectionBase *self);
 
+const char *nm_vpn_connection_base_get_specific_object (NMVpnConnectionBase *self);
+
 void nm_vpn_connection_base_export (NMVpnConnectionBase *self,
-                                    NMConnection *connection);
+                                    NMConnection *connection,
+                                    const char *specific_object);
 
 void nm_vpn_connection_base_set_state (NMVpnConnectionBase *self,
                                        NMVPNConnectionState vpn_state);
diff --git a/src/vpn-manager/nm-vpn-connection.c b/src/vpn-manager/nm-vpn-connection.c
index 067b2dce..73f2b553 100644
--- a/src/vpn-manager/nm-vpn-connection.c
+++ b/src/vpn-manager/nm-vpn-connection.c
@@ -46,6 +46,7 @@
 #include "NetworkManagerUtils.h"
 #include "nm-dns-manager.h"
 #include "nm-netlink-monitor.h"
+#include "nm-netlink-utils.h"
 #include "nm-glib-compat.h"
 #include "settings/nm-settings-connection.h"
 
@@ -86,6 +87,7 @@ typedef struct {
 	NMIP4Config *ip4_config;
 	guint32 ip4_internal_gw;
 	char *ip_iface;
+	int ip_ifindex;
 	char *banner;
 
 	struct rtnl_route *gw_route;
@@ -219,6 +221,7 @@ device_ip4_config_changed (NMDevice *device,
 NMVPNConnection *
 nm_vpn_connection_new (NMConnection *connection,
                        NMDevice *parent_device,
+                       const char *specific_object,
                        gboolean user_requested,
                        gulong user_uid)
 {
@@ -247,7 +250,7 @@ nm_vpn_connection_new (NMConnection *connection,
 	                                     G_CALLBACK (device_ip4_config_changed),
 	                                     self);
 
-	nm_vpn_connection_base_export (NM_VPN_CONNECTION_BASE (self), connection);
+	nm_vpn_connection_base_export (NM_VPN_CONNECTION_BASE (self), connection, specific_object);
 
 	return self;
 }
@@ -283,6 +286,28 @@ plugin_failed (DBusGProxy *proxy,
 	}
 }
 
+static const char *
+vpn_state_to_string (NMVPNServiceState state)
+{
+	switch (state) {
+	case NM_VPN_SERVICE_STATE_INIT:
+		return "init";
+	case NM_VPN_SERVICE_STATE_SHUTDOWN:
+		return "shutdown";
+	case NM_VPN_SERVICE_STATE_STARTING:
+		return "starting";
+	case NM_VPN_SERVICE_STATE_STARTED:
+		return "started";
+	case NM_VPN_SERVICE_STATE_STOPPING:
+		return "stopping";
+	case NM_VPN_SERVICE_STATE_STOPPED:
+		return "stopped";
+	default:
+		break;
+	}
+	return "unknown";
+}
+
 static void
 plugin_state_changed (DBusGProxy *proxy,
                       NMVPNServiceState state,
@@ -291,7 +316,8 @@ plugin_state_changed (DBusGProxy *proxy,
 	NMVPNConnection *connection = NM_VPN_CONNECTION (user_data);
 	NMVPNConnectionPrivate *priv = NM_VPN_CONNECTION_GET_PRIVATE (connection);
 
-	nm_log_info (LOGD_VPN, "VPN plugin state changed: %d", state);
+	nm_log_info (LOGD_VPN, "VPN plugin state changed: %s (%d)",
+	             vpn_state_to_string (state), state);
 
 	if (state == NM_VPN_SERVICE_STATE_STOPPED) {
 		/* Clear connection secrets to ensure secrets get requested each time the
@@ -424,6 +450,13 @@ nm_vpn_connection_ip4_config_get (DBusGProxy *proxy,
 		goto error;
 	}
 
+	/* Grab the interface index for address/routing operations */
+	priv->ip_ifindex = nm_netlink_iface_to_index (priv->ip_iface);
+	if (!priv->ip_ifindex) {
+		nm_log_err (LOGD_VPN, "(%s): failed to look up VPN interface index", priv->ip_iface);
+		goto error;
+	}
+
 	addr = nm_ip4_address_new ();
 	nm_ip4_address_set_prefix (addr, 24); /* default to class C */
 
@@ -529,9 +562,9 @@ nm_vpn_connection_ip4_config_get (DBusGProxy *proxy,
 	s_ip4 = NM_SETTING_IP4_CONFIG (nm_connection_get_setting (priv->connection, NM_TYPE_SETTING_IP4_CONFIG));
 	nm_utils_merge_ip4_config (config, s_ip4);
 
-	nm_system_device_set_up_down_with_iface (priv->ip_iface, TRUE, NULL);
+	nm_system_iface_set_up (priv->ip_ifindex, TRUE, NULL);
 
-	if (nm_system_apply_ip4_config (priv->ip_iface, config, 0, NM_IP4_COMPARE_FLAG_ALL)) {
+	if (nm_system_apply_ip4_config (priv->ip_ifindex, config, 0, NM_IP4_COMPARE_FLAG_ALL)) {
 		NMDnsManager *dns_mgr;
 
 		/* Add any explicit route to the VPN gateway through the parent device */
@@ -765,6 +798,14 @@ nm_vpn_connection_get_ip_iface (NMVPNConnection *connection)
 	return NM_VPN_CONNECTION_GET_PRIVATE (connection)->ip_iface;
 }
 
+int
+nm_vpn_connection_get_ip_ifindex (NMVPNConnection *connection)
+{
+	g_return_val_if_fail (NM_IS_VPN_CONNECTION (connection), -1);
+
+	return NM_VPN_CONNECTION_GET_PRIVATE (connection)->ip_ifindex;
+}
+
 NMDevice *
 nm_vpn_connection_get_parent_device (NMVPNConnection *connection)
 {
@@ -940,11 +981,11 @@ vpn_cleanup (NMVPNConnection *connection)
 {
 	NMVPNConnectionPrivate *priv = NM_VPN_CONNECTION_GET_PRIVATE (connection);
 
-	if (priv->ip_iface) {
-		nm_system_device_set_up_down_with_iface (priv->ip_iface, FALSE, NULL);
+	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_device_flush_routes_with_iface (priv->ip_iface, AF_INET);
-		nm_system_device_flush_addresses_with_iface (priv->ip_iface);
+		nm_system_iface_flush_routes (priv->ip_ifindex, AF_INET);
+		nm_system_iface_flush_addresses (priv->ip_ifindex, AF_UNSPEC);
 	}
 
 	if (priv->ip4_config) {
@@ -958,12 +999,12 @@ vpn_cleanup (NMVPNConnection *connection)
 
 		/* Remove any previously added VPN gateway host route */
 		if (priv->gw_route)
-			rtnl_route_del (nm_netlink_get_default_handle (), priv->gw_route, 0);
+			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_iface (priv->parent_dev),
+			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)) {
@@ -982,6 +1023,7 @@ vpn_cleanup (NMVPNConnection *connection)
 
 	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.
diff --git a/src/vpn-manager/nm-vpn-connection.h b/src/vpn-manager/nm-vpn-connection.h
index ee8eb5b6..c0d15f8a 100644
--- a/src/vpn-manager/nm-vpn-connection.h
+++ b/src/vpn-manager/nm-vpn-connection.h
@@ -57,12 +57,14 @@ GType nm_vpn_connection_get_type (void);
 
 NMVPNConnection * nm_vpn_connection_new (NMConnection *connection,
                                          NMDevice *parent_device,
+                                         const char *specific_object,
                                          gboolean user_requested,
                                          gulong user_uid);
 
 void                 nm_vpn_connection_activate        (NMVPNConnection *connection);
 NMConnection *       nm_vpn_connection_get_connection  (NMVPNConnection *connection);
 const char *         nm_vpn_connection_get_active_connection_path (NMVPNConnection *connection);
+const char *         nm_vpn_connection_get_specific_object_path (NMVPNConnection *connection);
 const char *         nm_vpn_connection_get_name        (NMVPNConnection *connection);
 NMVPNConnectionState nm_vpn_connection_get_vpn_state   (NMVPNConnection *connection);
 const char *         nm_vpn_connection_get_banner      (NMVPNConnection *connection);
@@ -72,6 +74,7 @@ void                 nm_vpn_connection_disconnect      (NMVPNConnection *connect
                                                         NMVPNConnectionStateReason reason);
 NMIP4Config *        nm_vpn_connection_get_ip4_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);
 
diff --git a/src/vpn-manager/nm-vpn-manager.c b/src/vpn-manager/nm-vpn-manager.c
index 6772bb18..41e96c0b 100644
--- a/src/vpn-manager/nm-vpn-manager.c
+++ b/src/vpn-manager/nm-vpn-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) 2005 - 2010 Red Hat, Inc.
+ * Copyright (C) 2005 - 2011 Red Hat, Inc.
  * Copyright (C) 2006 - 2008 Novell, Inc.
  */
 
@@ -162,6 +162,7 @@ NMVPNConnection *
 nm_vpn_manager_activate_connection (NMVPNManager *manager,
                                     NMConnection *connection,
                                     NMDevice *device,
+                                    const char *specific_object,
                                     gboolean user_requested,
                                     gulong user_uid,
                                     GError **error)
@@ -209,7 +210,7 @@ nm_vpn_manager_activate_connection (NMVPNManager *manager,
 		return NULL;
 	}
 
-	vpn = nm_vpn_service_activate (service, connection, device, user_requested, user_uid, error);
+	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_CALLBACK (connection_vpn_state_changed),
@@ -306,9 +307,9 @@ nm_vpn_manager_get_active_connections (NMVPNManager *self)
 	return list;
 }
 
-NMConnection *
-nm_vpn_manager_get_connection_for_active (NMVPNManager *manager,
-                                          const char *active_path)
+NMVPNConnection *
+nm_vpn_manager_get_vpn_connection_for_active (NMVPNManager *manager,
+                                              const char *active_path)
 {
 	NMVPNManagerPrivate *priv;
 	GHashTableIter iter;
@@ -327,13 +328,24 @@ nm_vpn_manager_get_connection_for_active (NMVPNManager *manager,
 
 			ac_path = nm_vpn_connection_get_active_connection_path (vpn);
 			if (ac_path && !strcmp (ac_path, active_path))
-				return nm_vpn_connection_get_connection (vpn);
+				return vpn;
 		}
 	}
 
 	return NULL;
 }
 
+NMConnection *
+nm_vpn_manager_get_connection_for_active (NMVPNManager *manager,
+                                          const char *active_path)
+{
+	NMVPNConnection *vpn_con;
+
+	vpn_con = nm_vpn_manager_get_vpn_connection_for_active (manager, active_path);
+
+	return vpn_con ? nm_vpn_connection_get_connection (vpn_con) : NULL;
+}
+
 static char *
 service_name_from_file (const char *path)
 {
diff --git a/src/vpn-manager/nm-vpn-manager.h b/src/vpn-manager/nm-vpn-manager.h
index a899122c..78a5220b 100644
--- a/src/vpn-manager/nm-vpn-manager.h
+++ b/src/vpn-manager/nm-vpn-manager.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 - 2008 Red Hat, Inc.
+ * Copyright (C) 2005 - 2011 Red Hat, Inc.
  * Copyright (C) 2006 - 2008 Novell, Inc.
  */
 
@@ -69,6 +69,7 @@ NMVPNManager *nm_vpn_manager_get (void);
 NMVPNConnection *nm_vpn_manager_activate_connection (NMVPNManager *manager,
                                                      NMConnection *connection,
                                                      NMDevice *device,
+                                                     const char *specific_object,
                                                      gboolean user_requested,
                                                      gulong user_uid,
                                                      GError **error);
@@ -83,7 +84,10 @@ void nm_vpn_manager_add_active_connections (NMVPNManager *manager,
 
 GSList *nm_vpn_manager_get_active_connections (NMVPNManager *manager);
 
+NMVPNConnection *nm_vpn_manager_get_vpn_connection_for_active (NMVPNManager *manager,
+                                                               const char *active_path);
+
 NMConnection *nm_vpn_manager_get_connection_for_active (NMVPNManager *manager,
                                                         const char *active_path);
 
-#endif /* NM_VPN_VPN_MANAGER_H */
+#endif /* NM_VPN_MANAGER_H */
diff --git a/src/vpn-manager/nm-vpn-service.c b/src/vpn-manager/nm-vpn-service.c
index ed08a40a..95e4f2b1 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 - 2010 Red Hat, Inc.
+ * Copyright (C) 2005 - 2011 Red Hat, Inc.
  * Copyright (C) 2005 - 2008 Novell, Inc.
  */
 
@@ -324,6 +324,7 @@ NMVPNConnection *
 nm_vpn_service_activate (NMVPNService *service,
                          NMConnection *connection,
                          NMDevice *device,
+                         const char *specific_object,
                          gboolean user_requested,
                          gulong user_uid,
                          GError **error)
@@ -341,7 +342,7 @@ nm_vpn_service_activate (NMVPNService *service,
 
 	clear_quit_timeout (service);
 
-	vpn = nm_vpn_connection_new (connection, device, user_requested, user_uid);
+	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);
diff --git a/src/vpn-manager/nm-vpn-service.h b/src/vpn-manager/nm-vpn-service.h
index cbe394ca..e8b1cfc4 100644
--- a/src/vpn-manager/nm-vpn-service.h
+++ b/src/vpn-manager/nm-vpn-service.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 - 2008 Red Hat, Inc.
+ * Copyright (C) 2005 - 2011 Red Hat, Inc.
  * Copyright (C) 2005 - 2008 Novell, Inc.
  */
 
@@ -57,6 +57,7 @@ const char *nm_vpn_service_get_name_file (NMVPNService *service);
 NMVPNConnection * nm_vpn_service_activate (NMVPNService *service,
                                            NMConnection *connection,
                                            NMDevice *device,
+                                           const char *specific_object,
                                            gboolean user_requested,
                                            gulong user_uid,
                                            GError **error);
diff --git a/src/wimax/Makefile.in b/src/wimax/Makefile.in
index e6064bc6..1be78482 100644
--- a/src/wimax/Makefile.in
+++ b/src/wimax/Makefile.in
@@ -186,8 +186,16 @@ LIBGCRYPT_LIBS = @LIBGCRYPT_LIBS@
 LIBICONV = @LIBICONV@
 LIBINTL = @LIBINTL@
 LIBM = @LIBM@
+LIBNL1_CFLAGS = @LIBNL1_CFLAGS@
+LIBNL1_LIBS = @LIBNL1_LIBS@
+LIBNL2_CFLAGS = @LIBNL2_CFLAGS@
+LIBNL2_LIBS = @LIBNL2_LIBS@
+LIBNL3_CFLAGS = @LIBNL3_CFLAGS@
+LIBNL3_LIBS = @LIBNL3_LIBS@
 LIBNL_CFLAGS = @LIBNL_CFLAGS@
 LIBNL_LIBS = @LIBNL_LIBS@
+LIBNL_ROUTE3_CFLAGS = @LIBNL_ROUTE3_CFLAGS@
+LIBNL_ROUTE3_LIBS = @LIBNL_ROUTE3_LIBS@
 LIBOBJS = @LIBOBJS@
 LIBS = @LIBS@
 LIBTOOL = @LIBTOOL@
diff --git a/src/wimax/iwmxsdk.c b/src/wimax/iwmxsdk.c
index dd78d5a4..9c3a78bb 100644
--- a/src/wimax/iwmxsdk.c
+++ b/src/wimax/iwmxsdk.c
@@ -27,7 +27,8 @@
 #include <stdlib.h>
 #include <errno.h>
 #include <string.h>
-#include <net/if.h>
+#include <sys/socket.h>
+#include <linux/if.h>
 
 #include <glib.h>
 
@@ -190,6 +191,7 @@ typedef struct {
 	WIMAX_API_DEVICE_STATUS new_status;
 	WIMAX_API_DEVICE_STATUS old_status;
 	WIMAX_API_STATUS_REASON reason;
+	WIMAX_API_CONNECTION_PROGRESS_INFO progress;
 } StateChangeInfo;
 
 static gboolean
@@ -202,6 +204,7 @@ state_change_handler(gpointer user_data)
 		                              info->new_status,
 		                              info->old_status,
 		                              info->reason,
+		                              info->progress,
 		                              info->wmxsdk->callback_data);
 	}
 	wmxsdk_unref(info->wmxsdk);
@@ -214,7 +217,8 @@ static void
 _schedule_state_change(struct wmxsdk *wmxsdk,
                        WIMAX_API_DEVICE_STATUS new_status,
                        WIMAX_API_DEVICE_STATUS old_status,
-                       WIMAX_API_STATUS_REASON reason)
+                       WIMAX_API_STATUS_REASON reason,
+                       WIMAX_API_CONNECTION_PROGRESS_INFO progress)
 {
 	StateChangeInfo *info;
 
@@ -227,6 +231,7 @@ _schedule_state_change(struct wmxsdk *wmxsdk,
 	info->new_status = new_status;
 	info->old_status = old_status;
 	info->reason = reason;
+	info->progress = progress;
 
 	wmxsdk_ref(wmxsdk);
 	g_idle_add(state_change_handler, info);
@@ -476,6 +481,48 @@ const char *iwmx_sdk_media_status_to_str(WIMAX_API_MEDIA_STATUS status)
 	}
 }
 
+const char *
+iwmx_sdk_con_progress_to_str(WIMAX_API_CONNECTION_PROGRESS_INFO progress)
+{
+	switch (progress) {
+
+	/**< Device is in Ranging */
+	case WIMAX_API_DEVICE_CONNECTION_PROGRESS_Ranging:
+		return "ranging";
+
+	/**< Device is in SBC */
+	case WIMAX_API_DEVICE_CONNECTION_PROGRESS_SBC:
+		return "sbc";
+
+	/**< Device is in EAP authentication Device */
+	case WIMAX_API_DEVICE_CONNECTION_PROGRESS_EAP_authentication_Device:
+		return "eap-auth-device";
+
+	/**< Device is in EAP authentication User */
+	case WIMAX_API_DEVICE_CONNECTION_PROGRESS_EAP_authentication_User:
+		return "eap-auth-user";
+
+	/**< Device is in 3-way-handshake */
+	case WIMAX_API_DEVICE_CONNECTION_PROGRESS_3_way_handshake:
+		return "3way-handshake";
+
+	/**< Device is in Registration */
+	case WIMAX_API_DEVICE_CONNECTION_PROGRESS_Registration:
+		return "registration";
+
+	/**< Device is in De-registration */
+	case WIMAX_API_DEVICE_CONNECTION_PROGRESS_De_registration:
+		return "deregistration";
+
+	/**< Device is registered (operational) */
+	case WIMAX_API_DEVICE_CONNECTION_PROGRESS_Registered:
+		return "registered";
+
+	default:
+		return "unknown";
+	}
+}
+
 /*
  * Get the device's status from the device
  *
@@ -982,7 +1029,7 @@ static void __iwmx_sdk_state_change_cb(WIMAX_API_DEVICE_ID *device_id,
 	wmxsdk->status = status;
 	g_mutex_unlock(wmxsdk->status_mutex);
 
-	_schedule_state_change(wmxsdk, status, old_status, reason);
+	_schedule_state_change(wmxsdk, status, old_status, reason, pi);
 }
 
 /*
@@ -1170,7 +1217,8 @@ static int iwmx_sdk_setup(struct wmxsdk *wmxsdk)
 	_schedule_state_change(wmxsdk,
 	                       status,
 	                       WIMAX_API_DEVICE_STATUS_UnInitialized,
-	                       WIMAX_API_STATUS_REASON_Normal);
+	                       WIMAX_API_STATUS_REASON_Normal,
+	                       WIMAX_API_DEVICE_CONNECTION_PROGRESS_Ranging);
 
 	return 0;
 
@@ -1268,23 +1316,22 @@ void wmxsdk_unref(struct wmxsdk *wmxsdk)
 
 static void iwmx_sdk_dev_add(unsigned idx, unsigned api_idx, const char *name)
 {
-	int ifindex;
 	struct wmxsdk *wmxsdk;
 	const char *s;
 
 	if (idx >= IWMX_SDK_DEV_MAX) {
 		nm_log_err(LOGD_WIMAX, "BUG! idx (%u) >= IWMX_SDK_DEV_MAX (%u)", idx, IWMX_SDK_DEV_MAX);
-		goto error_bug;
+		return;
 	}
 	if (g_iwmx_sdk_devs[idx] != NULL) {
 		nm_log_err(LOGD_WIMAX, "BUG! device index %u already enumerated?", idx);
-		goto error_bug;
+		return;
 	}
 
 	wmxsdk = wmxsdk_new();
 	if (wmxsdk == NULL) {
 		nm_log_err(LOGD_WIMAX, "Can't allocate %zu bytes", sizeof(*wmxsdk));
-		goto error_bug;
+		return;
 	}
 
 	/*
@@ -1297,23 +1344,17 @@ static void iwmx_sdk_dev_add(unsigned idx, unsigned api_idx, const char *name)
 	    || sscanf(s, "if:%15[^ \f\n\r\t\v]", wmxsdk->ifname) != 1) {
 		nm_log_err(LOGD_WIMAX, "Cannot extract network interface name off '%s'",
 			      name);
-		goto error_noifname;
+		goto error;
 	}
 	nm_log_dbg(LOGD_WIMAX, "network interface name: '%s'", wmxsdk->ifname);
 
-	ifindex = if_nametoindex(wmxsdk->ifname);
-	if (ifindex <= 0) {
-		nm_log_err(LOGD_WIMAX, "wxmsdk: %s: cannot find interface index", wmxsdk->ifname);
-		goto error_noifname;
-	}
-
 	strncpy(wmxsdk->name, name, sizeof(wmxsdk->name));
 	wmxsdk->device_id.privilege = WIMAX_API_PRIVILEGE_READ_WRITE;
 	wmxsdk->device_id.deviceIndex = api_idx;
 
 	if (iwmx_sdk_setup(wmxsdk) != 0) {
 		nm_log_err(LOGD_WIMAX, "wxmsdk: %s: cannot set up interface", wmxsdk->ifname);
-		goto error_setup;
+		goto error;
 	}
 
 	g_iwmx_sdk_devs[idx] = wmxsdk;
@@ -1322,10 +1363,8 @@ static void iwmx_sdk_dev_add(unsigned idx, unsigned api_idx, const char *name)
 	iwmx_sdk_call_new_callbacks (wmxsdk);
 	return;
 
-error_setup:
-error_noifname:
+error:
 	wmxsdk_unref(wmxsdk);
-error_bug:
 	return;
 }
 
diff --git a/src/wimax/iwmxsdk.h b/src/wimax/iwmxsdk.h
index bd55679a..1888b709 100644
--- a/src/wimax/iwmxsdk.h
+++ b/src/wimax/iwmxsdk.h
@@ -34,6 +34,7 @@ typedef void (*WimaxStateChangeFunc) (struct wmxsdk *wmxsdk,
                                       WIMAX_API_DEVICE_STATUS new_status,
                                       WIMAX_API_DEVICE_STATUS old_status,
                                       WIMAX_API_STATUS_REASON reason,
+                                      WIMAX_API_CONNECTION_PROGRESS_INFO info,
                                       void *user_data);
 
 typedef void (*WimaxMediaStatusFunc) (struct wmxsdk *wmxsdk,
@@ -101,6 +102,7 @@ WIMAX_API_LINK_STATUS_INFO_EX *iwmx_sdk_get_link_status_info(struct wmxsdk *wmxs
 const char *iwmx_sdk_dev_status_to_str(WIMAX_API_DEVICE_STATUS status);
 const char *iwmx_sdk_reason_to_str(WIMAX_API_STATUS_REASON reason);
 const char *iwmx_sdk_media_status_to_str(WIMAX_API_MEDIA_STATUS status);
+const char *iwmx_sdk_con_progress_to_str(WIMAX_API_CONNECTION_PROGRESS_INFO progress);
 int iwmx_sdk_rf_state_set(struct wmxsdk *wmxsdk, WIMAX_API_RF_STATE rf_state);
 int iwmx_sdk_get_networks(struct wmxsdk *wmxsdk);
 int iwmx_sdk_api_init(void);
diff --git a/src/wimax/nm-device-wimax.c b/src/wimax/nm-device-wimax.c
index 9dff503d..2d8553a0 100644
--- a/src/wimax/nm-device-wimax.c
+++ b/src/wimax/nm-device-wimax.c
@@ -23,7 +23,8 @@
 #include <unistd.h>
 #include <sys/ioctl.h>
 #include <net/ethernet.h>
-#include <net/if.h>
+#include <sys/socket.h>
+#include <linux/if.h>
 
 #include <WiMaxAPI.h>
 #include <WiMaxAPIEx.h>
@@ -91,6 +92,9 @@ typedef struct {
 	struct ether_addr hw_addr;
 	guint activation_timeout_id;
 
+	/* Track whether stage1 (Prepare) is completed yet or not */
+	gboolean prepare_done;
+
 	guint sdk_action_defer_id;
 
 	guint link_timeout_id;
@@ -231,27 +235,25 @@ set_current_nsp (NMDeviceWimax *self, NMWimaxNsp *new_nsp)
 {
 	NMDeviceWimaxPrivate *priv = NM_DEVICE_WIMAX_GET_PRIVATE (self);
 	NMWimaxNsp *old_nsp;
-	char *old_path = NULL;
+	gboolean path_changed = FALSE;
 
 	old_nsp = priv->current_nsp;
-	if (old_nsp) {
-		old_path = g_strdup (nm_wimax_nsp_get_dbus_path (old_nsp));
-		priv->current_nsp = NULL;
-	}
+	priv->current_nsp = NULL;
 
 	if (new_nsp)
 		priv->current_nsp = g_object_ref (new_nsp);
 
-	if (old_nsp)
-		g_object_unref (old_nsp);
+	if (old_nsp && new_nsp) {
+		path_changed = (g_strcmp0 (nm_wimax_nsp_get_dbus_path (old_nsp),
+		                           nm_wimax_nsp_get_dbus_path (new_nsp)) != 0);
+	}
 
 	/* Only notify if it's really changed */
-	if (   (!old_path && new_nsp)
-		|| (old_path && !new_nsp)
-	    || (old_path && new_nsp && strcmp (old_path, nm_wimax_nsp_get_dbus_path (new_nsp))))
+	if (old_nsp != new_nsp || path_changed)
 		g_object_notify (G_OBJECT (self), NM_DEVICE_WIMAX_ACTIVE_NSP);
 
-	g_free (old_path);
+	if (old_nsp)
+		g_object_unref (old_nsp);
 }
 
 NMWimaxNsp *
@@ -390,7 +392,7 @@ real_take_down (NMDevice *device)
 static gboolean
 real_hw_is_up (NMDevice *device)
 {
-	return nm_system_device_is_up (device);
+	return nm_system_iface_is_up (nm_device_get_ip_ifindex (device));
 }
 
 static gboolean
@@ -401,13 +403,13 @@ real_hw_bring_up (NMDevice *dev, gboolean *no_firmware)
 	if (!priv->enabled || !priv->wimaxd_enabled)
 		return FALSE;
 
-	return nm_system_device_set_up_down (dev, TRUE, no_firmware);
+	return nm_system_iface_set_up (nm_device_get_ip_ifindex (dev), TRUE, no_firmware);
 }
 
 static void
 real_hw_take_down (NMDevice *dev)
 {
-	nm_system_device_set_up_down (dev, FALSE, NULL);
+	nm_system_iface_set_up (nm_device_get_ip_ifindex (dev), FALSE, NULL);
 }
 
 static void
@@ -749,6 +751,8 @@ real_act_stage1_prepare (NMDevice *device, NMDeviceStateReason *reason)
 
 	set_current_nsp (NM_DEVICE_WIMAX (device), nsp);
 
+	priv->prepare_done = TRUE;
+
 	/* If the device is scanning, it won't connect, so we have to wait until
 	 * it's not scanning to proceed to stage 2.
 	 */
@@ -853,6 +857,7 @@ wmx_state_change_cb (struct wmxsdk *wmxsdk,
                      WIMAX_API_DEVICE_STATUS new_status,
                      WIMAX_API_DEVICE_STATUS old_status,
                      WIMAX_API_STATUS_REASON reason,
+                     WIMAX_API_CONNECTION_PROGRESS_INFO progress,
                      void *user_data)
 {
 	NMDeviceWimax *self = NM_DEVICE_WIMAX (user_data);
@@ -862,10 +867,17 @@ wmx_state_change_cb (struct wmxsdk *wmxsdk,
 	gboolean old_available = FALSE;
 	const char *nsp_name = NULL;
 
+	iface = nm_device_get_iface (NM_DEVICE (self));
+	nm_log_info (LOGD_WIMAX, "(%s): wimax state change %s -> %s (%s (%d))",
+	             iface,
+	             iwmx_sdk_dev_status_to_str (old_status),
+	             iwmx_sdk_dev_status_to_str (new_status),
+	             iwmx_sdk_con_progress_to_str (progress),
+	             progress);
+
 	if (new_status == old_status)
 		return;
 
-	iface = nm_device_get_iface (NM_DEVICE (self));
 	state = nm_device_interface_get_state (NM_DEVICE_INTERFACE (self));
 	old_available = nm_device_is_available (NM_DEVICE (self));
 
@@ -873,12 +885,6 @@ wmx_state_change_cb (struct wmxsdk *wmxsdk,
 	if (priv->current_nsp)
 		nsp_name = nm_wimax_nsp_get_name (priv->current_nsp);
 
-	nm_log_info (LOGD_WIMAX, "(%s): wimax state change %s -> %s (reason %d)",
-	             iface,
-	             iwmx_sdk_dev_status_to_str (old_status),
-	             iwmx_sdk_dev_status_to_str (new_status),
-	             reason);
-
 	switch (new_status) {
 	case WIMAX_API_DEVICE_STATUS_UnInitialized:
 	case WIMAX_API_DEVICE_STATUS_RF_OFF_HW_SW:
@@ -936,7 +942,7 @@ wmx_state_change_cb (struct wmxsdk *wmxsdk,
 		 * then check if we need to move to stage2 now that the device might be
 		 * ready.
 		 */
-		if (state == NM_DEVICE_STATE_PREPARE) {
+		if (state == NM_DEVICE_STATE_PREPARE && priv->prepare_done) {
 			if (   new_status == WIMAX_API_DEVICE_STATUS_Ready
 			    || new_status == WIMAX_API_DEVICE_STATUS_Connecting) {
 				nm_device_activate_schedule_stage2_device_config (NM_DEVICE (self));
@@ -1003,7 +1009,7 @@ wmx_media_status_cb (struct wmxsdk *wmxsdk,
 		break;
 	case WIMAX_API_MEDIA_STATUS_LINK_DOWN:
 		nm_log_dbg (LOGD_WIMAX, "(%s): starting link timeout", iface);
-		priv->link_timeout_id = g_timeout_add (15, link_timeout_cb, self);
+		priv->link_timeout_id = g_timeout_add_seconds (15, link_timeout_cb, self);
 		break;
 	case WIMAX_API_MEDIA_STATUS_LINK_RENEW:
 		nm_log_dbg (LOGD_WIMAX, "(%s): renewing DHCP lease", iface);
@@ -1130,18 +1136,22 @@ wmx_removed_cb (struct wmxsdk *wmxsdk, void *user_data)
 	NMDeviceWimax *self = NM_DEVICE_WIMAX (user_data);
 	NMDeviceWimaxPrivate *priv = NM_DEVICE_WIMAX_GET_PRIVATE (self);
 
-	if (priv->sdk) {
-		/* Clear callbacks just in case we don't hold the last reference */
-		iwmx_sdk_set_callbacks (priv->sdk, NULL, NULL, NULL, NULL, NULL, NULL);
+	if (!priv->sdk) {
+		nm_log_dbg (LOGD_WIMAX, "(%s): removed unhandled WiMAX interface", wmxsdk->ifname);
+		return;
+	}
 
-		wmxsdk_unref (priv->sdk);
-		priv->sdk = NULL;
+	nm_log_dbg (LOGD_WIMAX, "(%s): removed WiMAX interface", wmxsdk->ifname);
 
-		priv->status = WIMAX_API_DEVICE_STATUS_UnInitialized;
-		nm_device_state_changed (NM_DEVICE (self),
-								 NM_DEVICE_STATE_UNAVAILABLE,
-								 NM_DEVICE_STATE_REASON_NONE);
-	}
+	/* Clear callbacks just in case we don't hold the last reference */
+	iwmx_sdk_set_callbacks (priv->sdk, NULL, NULL, NULL, NULL, NULL, NULL);
+	wmxsdk_unref (priv->sdk);
+	priv->sdk = NULL;
+
+	priv->status = WIMAX_API_DEVICE_STATUS_UnInitialized;
+	nm_device_state_changed (NM_DEVICE (self),
+							 NM_DEVICE_STATE_UNAVAILABLE,
+							 NM_DEVICE_STATE_REASON_NONE);
 }
 
 /*************************************************************************/
@@ -1277,6 +1287,9 @@ device_state_changed (NMDevice *device,
 	NMDeviceWimax *self = NM_DEVICE_WIMAX (device);
 	NMDeviceWimaxPrivate *priv = NM_DEVICE_WIMAX_GET_PRIVATE (self);
 
+	/* Reset our stage1 (Prepare) done marker since it's only valid while in stage1 */
+	priv->prepare_done = FALSE;
+
 	if (new_state < NM_DEVICE_STATE_DISCONNECTED)
 		remove_all_nsps (self);
 
@@ -1323,21 +1336,27 @@ wmx_new_sdk_cb (struct wmxsdk *sdk, void *user_data)
 	NMDeviceWimax *self = NM_DEVICE_WIMAX (user_data);
 	NMDeviceWimaxPrivate *priv = NM_DEVICE_WIMAX_GET_PRIVATE (self);
 
-	/* If we now have the SDK, schedule an idle handler to start the device up */
-	if (!priv->sdk) {
-		priv->sdk = wmxsdk_ref (sdk);
-		iwmx_sdk_set_callbacks(priv->sdk,
-		                       wmx_state_change_cb,
-		                       wmx_media_status_cb,
-		                       wmx_connect_result_cb,
-		                       wmx_scan_result_cb,
-		                       wmx_removed_cb,
-		                       self);
-		iwmx_sdk_set_fast_reconnect_enabled (priv->sdk, 0);
-
-		if (!priv->sdk_action_defer_id)
-			priv->sdk_action_defer_id = g_idle_add (sdk_action_defer_cb, self);
+	/* We only track one wmxsdk at a time because the WiMAX SDK is pretty stupid */
+	if (priv->sdk) {
+		nm_log_dbg (LOGD_WIMAX, "(%s): WiMAX interface already known", sdk->ifname);
+		return;
 	}
+
+	nm_log_dbg (LOGD_WIMAX, "(%s): new WiMAX interface (%s)", sdk->ifname, sdk->name);
+
+	/* Now that we have an SDK, schedule an idle handler to start the device up */
+	priv->sdk = wmxsdk_ref (sdk);
+	iwmx_sdk_set_callbacks(priv->sdk,
+	                       wmx_state_change_cb,
+	                       wmx_media_status_cb,
+	                       wmx_connect_result_cb,
+	                       wmx_scan_result_cb,
+	                       wmx_removed_cb,
+	                       self);
+	iwmx_sdk_set_fast_reconnect_enabled (priv->sdk, 0);
+
+	if (!priv->sdk_action_defer_id)
+		priv->sdk_action_defer_id = g_idle_add (sdk_action_defer_cb, self);
 }
 
 /*************************************************************************/