summary refs log tree commit diff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/Makefile.am80
-rw-r--r--src/Makefile.in481
-rw-r--r--src/NetworkManagerUtils.c82
-rw-r--r--src/NetworkManagerUtils.h16
-rw-r--r--src/backends/Makefile.am7
-rw-r--r--src/backends/Makefile.in22
-rw-r--r--src/backends/NetworkManagerArch.c34
-rw-r--r--src/backends/NetworkManagerDebian.c30
-rw-r--r--src/backends/NetworkManagerExherbo.c32
-rw-r--r--src/backends/NetworkManagerFrugalware.c29
-rw-r--r--src/backends/NetworkManagerGeneric.c64
-rw-r--r--src/backends/NetworkManagerGeneric.h15
-rw-r--r--src/backends/NetworkManagerGentoo.c38
-rw-r--r--src/backends/NetworkManagerLinexa.c29
-rw-r--r--src/backends/NetworkManagerMandriva.c30
-rw-r--r--src/backends/NetworkManagerPaldo.c36
-rw-r--r--src/backends/NetworkManagerPardus.c29
-rw-r--r--src/backends/NetworkManagerRedHat.c30
-rw-r--r--src/backends/NetworkManagerSlackware.c29
-rw-r--r--src/backends/NetworkManagerSuSE.c36
-rw-r--r--src/backends/nm-backend.h30
-rw-r--r--src/bluez-manager/Makefile.am9
-rw-r--r--src/bluez-manager/Makefile.in20
-rw-r--r--src/bluez-manager/nm-bluez-manager.c7
-rw-r--r--src/dhcp-manager/Makefile.am7
-rw-r--r--src/dhcp-manager/Makefile.in18
-rw-r--r--src/dhcp-manager/nm-dhcp-dhclient-utils.c4
-rw-r--r--src/dhcp-manager/nm-dhcp-manager.c18
-rw-r--r--src/dhcp-manager/nm-dhcp-manager.h10
-rw-r--r--src/dhcp-manager/tests/Makefile.am2
-rw-r--r--src/dhcp-manager/tests/Makefile.in11
-rw-r--r--src/dns-manager/Makefile.am4
-rw-r--r--src/dns-manager/Makefile.in13
-rw-r--r--src/dns-manager/nm-dns-bind.c2
-rw-r--r--src/dns-manager/nm-dns-dnsmasq.c7
-rw-r--r--src/dns-manager/nm-dns-manager.c4
-rw-r--r--src/dnsmasq-manager/Makefile.in9
-rw-r--r--src/firewall-manager/Makefile.am23
-rw-r--r--src/firewall-manager/Makefile.in641
-rw-r--r--src/firewall-manager/nm-firewall-manager.c327
-rw-r--r--src/firewall-manager/nm-firewall-manager.h73
-rw-r--r--src/generated/Makefile.am77
-rw-r--r--src/generated/Makefile.in697
-rw-r--r--src/generated/nm-enum-types.c913
-rw-r--r--src/generated/nm-enum-types.h89
-rw-r--r--src/generated/nm-marshal.c705
-rw-r--r--src/generated/nm-marshal.h151
-rw-r--r--src/ip6-manager/Makefile.am7
-rw-r--r--src/ip6-manager/Makefile.in18
-rw-r--r--src/ip6-manager/nm-ip6-manager.c63
-rw-r--r--src/logging/Makefile.in9
-rw-r--r--src/logging/nm-logging.c28
-rw-r--r--src/logging/nm-logging.h9
-rw-r--r--src/main.c175
-rw-r--r--src/modem-manager/Makefile.am9
-rw-r--r--src/modem-manager/Makefile.in19
-rw-r--r--src/modem-manager/nm-modem-cdma.c55
-rw-r--r--src/modem-manager/nm-modem-cdma.h6
-rw-r--r--src/modem-manager/nm-modem-gsm.c167
-rw-r--r--src/modem-manager/nm-modem-gsm.h6
-rw-r--r--src/modem-manager/nm-modem-manager.c106
-rw-r--r--src/modem-manager/nm-modem.c189
-rw-r--r--src/modem-manager/nm-modem.h10
-rw-r--r--src/nm-activation-request.c318
-rw-r--r--src/nm-activation-request.h32
-rw-r--r--src/nm-active-connection.c320
-rw-r--r--src/nm-active-connection.h78
-rw-r--r--src/nm-config.c93
-rw-r--r--src/nm-config.h10
-rw-r--r--src/nm-connectivity.c368
-rw-r--r--src/nm-connectivity.h66
-rw-r--r--src/nm-device-bond.c569
-rw-r--r--src/nm-device-bond.h65
-rw-r--r--src/nm-device-bt.c157
-rw-r--r--src/nm-device-bt.h8
-rw-r--r--src/nm-device-ethernet.c970
-rw-r--r--src/nm-device-ethernet.h17
-rw-r--r--src/nm-device-factory.h91
-rw-r--r--src/nm-device-infiniband.c517
-rw-r--r--src/nm-device-infiniband.h66
-rw-r--r--src/nm-device-interface.c433
-rw-r--r--src/nm-device-interface.h158
-rw-r--r--src/nm-device-modem.c78
-rw-r--r--src/nm-device-olpc-mesh.c308
-rw-r--r--src/nm-device-olpc-mesh.h7
-rw-r--r--src/nm-device-private.h41
-rw-r--r--src/nm-device-vlan.c803
-rw-r--r--src/nm-device-vlan.h67
-rw-r--r--src/nm-device-wifi.c1205
-rw-r--r--src/nm-device-wifi.h14
-rw-r--r--src/nm-device-wired.c595
-rw-r--r--src/nm-device-wired.h59
-rw-r--r--src/nm-device.c3159
-rw-r--r--src/nm-device.h137
-rw-r--r--src/nm-ip6-config.c19
-rw-r--r--src/nm-manager-auth.c2
-rw-r--r--src/nm-manager.c1387
-rw-r--r--src/nm-manager.h35
-rw-r--r--src/nm-netlink-compat.c137
-rw-r--r--src/nm-netlink-compat.h78
-rw-r--r--src/nm-netlink-monitor.c122
-rw-r--r--src/nm-netlink-monitor.h5
-rw-r--r--src/nm-netlink-utils.c109
-rw-r--r--src/nm-netlink-utils.h16
-rw-r--r--src/nm-policy.c215
-rw-r--r--src/nm-properties-changed-signal.c5
-rw-r--r--src/nm-session-monitor-ck.c (renamed from src/nm-session-monitor.c)137
-rw-r--r--src/nm-session-monitor-null.c171
-rw-r--r--src/nm-session-monitor-systemd.c251
-rw-r--r--src/nm-session-utils.c79
-rw-r--r--src/nm-session-utils.h41
-rw-r--r--src/nm-system.c832
-rw-r--r--src/nm-system.h37
-rw-r--r--src/nm-udev-manager.c209
-rw-r--r--src/nm-udev-manager.h7
-rw-r--r--src/nm-wifi-ap.c53
-rw-r--r--src/nm-wifi-ap.h8
-rw-r--r--src/org.freedesktop.NetworkManager.conf (renamed from src/NetworkManager.conf)0
-rw-r--r--src/ppp-manager/Makefile.am9
-rw-r--r--src/ppp-manager/Makefile.in20
-rw-r--r--src/ppp-manager/nm-ppp-manager.c16
-rw-r--r--src/settings/Makefile.am9
-rw-r--r--src/settings/Makefile.in20
-rw-r--r--src/settings/nm-agent-manager.c45
-rw-r--r--src/settings/nm-agent-manager.h10
-rw-r--r--src/settings/nm-settings-connection.c20
-rw-r--r--src/settings/nm-settings-connection.h4
-rw-r--r--src/settings/nm-settings-error.c50
-rw-r--r--src/settings/nm-settings-error.h36
-rw-r--r--src/settings/nm-settings.c229
-rw-r--r--src/settings/nm-settings.h3
-rw-r--r--src/settings/nm-system-config-interface.h2
-rw-r--r--src/settings/plugins/Makefile.in9
-rw-r--r--src/settings/plugins/ifcfg-rh/Makefile.am7
-rw-r--r--src/settings/plugins/ifcfg-rh/Makefile.in22
-rw-r--r--src/settings/plugins/ifcfg-rh/common.h11
-rw-r--r--src/settings/plugins/ifcfg-rh/plugin.c4
-rw-r--r--src/settings/plugins/ifcfg-rh/reader.c834
-rw-r--r--src/settings/plugins/ifcfg-rh/reader.h2
-rw-r--r--src/settings/plugins/ifcfg-rh/tests/Makefile.am3
-rw-r--r--src/settings/plugins/ifcfg-rh/tests/Makefile.in15
-rw-r--r--src/settings/plugins/ifcfg-rh/tests/network-scripts/Makefile.am9
-rw-r--r--src/settings/plugins/ifcfg-rh/tests/network-scripts/Makefile.in18
-rw-r--r--src/settings/plugins/ifcfg-rh/tests/network-scripts/ifcfg-test-bond-main5
-rw-r--r--src/settings/plugins/ifcfg-rh/tests/network-scripts/ifcfg-test-bond-slave4
-rw-r--r--src/settings/plugins/ifcfg-rh/tests/network-scripts/ifcfg-test-infiniband8
-rw-r--r--src/settings/plugins/ifcfg-rh/tests/network-scripts/ifcfg-test-vlan-interface11
-rw-r--r--src/settings/plugins/ifcfg-rh/tests/network-scripts/ifcfg-test-vlan-only-device4
-rw-r--r--src/settings/plugins/ifcfg-rh/tests/network-scripts/ifcfg-test-vlan-only-vlanid6
-rw-r--r--src/settings/plugins/ifcfg-rh/tests/network-scripts/ifcfg-test-wifi-wpa-psk-219
-rw-r--r--src/settings/plugins/ifcfg-rh/tests/network-scripts/keys-test-wifi-wpa-psk-22
-rw-r--r--src/settings/plugins/ifcfg-rh/tests/test-ifcfg-rh.c1245
-rw-r--r--src/settings/plugins/ifcfg-rh/utils.c99
-rw-r--r--src/settings/plugins/ifcfg-rh/utils.h9
-rw-r--r--src/settings/plugins/ifcfg-rh/writer.c276
-rw-r--r--src/settings/plugins/ifcfg-suse/Makefile.in9
-rw-r--r--src/settings/plugins/ifcfg-suse/plugin.c4
-rw-r--r--src/settings/plugins/ifnet/Makefile.am16
-rw-r--r--src/settings/plugins/ifnet/Makefile.in25
-rw-r--r--src/settings/plugins/ifnet/connection_parser.c89
-rw-r--r--src/settings/plugins/ifnet/net_parser.c169
-rw-r--r--src/settings/plugins/ifnet/net_parser.h4
-rw-r--r--src/settings/plugins/ifnet/net_utils.c169
-rw-r--r--src/settings/plugins/ifnet/net_utils.h1
-rw-r--r--src/settings/plugins/ifnet/plugin.c85
-rw-r--r--src/settings/plugins/ifnet/plugin.h2
-rw-r--r--src/settings/plugins/ifnet/tests/Makefile.in9
-rw-r--r--src/settings/plugins/ifnet/tests/net11
-rw-r--r--src/settings/plugins/ifnet/tests/test_all.c43
-rw-r--r--src/settings/plugins/ifnet/tests/wpa_supplicant.conf7
-rw-r--r--src/settings/plugins/ifnet/wpa_parser.c19
-rw-r--r--src/settings/plugins/ifnet/wpa_parser.h5
-rw-r--r--src/settings/plugins/ifupdown/Makefile.in9
-rw-r--r--src/settings/plugins/ifupdown/interface_parser.c13
-rw-r--r--src/settings/plugins/ifupdown/interface_parser.h3
-rw-r--r--src/settings/plugins/ifupdown/parser.c315
-rw-r--r--src/settings/plugins/ifupdown/plugin.c49
-rw-r--r--src/settings/plugins/ifupdown/tests/Makefile.am2
-rw-r--r--src/settings/plugins/ifupdown/tests/Makefile.in11
-rw-r--r--src/settings/plugins/ifupdown/tests/test-ifupdown.c391
-rw-r--r--src/settings/plugins/ifupdown/tests/test17-wired-static-verify-ip45
-rw-r--r--src/settings/plugins/keyfile/Makefile.am4
-rw-r--r--src/settings/plugins/keyfile/Makefile.in13
-rw-r--r--src/settings/plugins/keyfile/plugin.c54
-rw-r--r--src/settings/plugins/keyfile/plugin.h4
-rw-r--r--src/settings/plugins/keyfile/reader.c89
-rw-r--r--src/settings/plugins/keyfile/tests/Makefile.am2
-rw-r--r--src/settings/plugins/keyfile/tests/Makefile.in11
-rw-r--r--src/settings/plugins/keyfile/tests/keyfiles/Makefile.am3
-rw-r--r--src/settings/plugins/keyfile/tests/keyfiles/Makefile.in12
-rw-r--r--src/settings/plugins/keyfile/tests/keyfiles/Test_InfiniBand_Connection13
-rw-r--r--src/settings/plugins/keyfile/tests/test-keyfile.c207
-rw-r--r--src/settings/plugins/keyfile/writer.c40
-rw-r--r--src/settings/tests/Makefile.am1
-rw-r--r--src/settings/tests/Makefile.in10
-rw-r--r--src/supplicant-manager/Makefile.am6
-rw-r--r--src/supplicant-manager/Makefile.in16
-rw-r--r--src/supplicant-manager/nm-supplicant-config.c105
-rw-r--r--src/supplicant-manager/nm-supplicant-config.h8
-rw-r--r--src/supplicant-manager/nm-supplicant-interface.c353
-rw-r--r--src/supplicant-manager/nm-supplicant-interface.h26
-rw-r--r--src/supplicant-manager/nm-supplicant-manager.c2
-rw-r--r--src/supplicant-manager/nm-supplicant-settings-verify.c34
-rw-r--r--src/supplicant-manager/nm-supplicant-settings-verify.h3
-rw-r--r--src/supplicant-manager/tests/Makefile.am2
-rw-r--r--src/supplicant-manager/tests/Makefile.in11
-rw-r--r--src/tests/Makefile.am2
-rw-r--r--src/tests/Makefile.in11
-rw-r--r--src/tests/test-wifi-ap-utils.c8
-rw-r--r--src/vpn-manager/Makefile.am13
-rw-r--r--src/vpn-manager/Makefile.in34
-rw-r--r--src/vpn-manager/nm-vpn-connection-base.c209
-rw-r--r--src/vpn-manager/nm-vpn-connection-base.h57
-rw-r--r--src/vpn-manager/nm-vpn-connection.c91
-rw-r--r--src/vpn-manager/nm-vpn-connection.h9
-rw-r--r--src/vpn-manager/nm-vpn-manager.c38
-rw-r--r--src/vpn-manager/nm-vpn-manager.h23
-rw-r--r--src/wifi/Makefile.am31
-rw-r--r--src/wifi/Makefile.in665
-rw-r--r--src/wifi/wifi-utils-nl80211.c819
-rw-r--r--src/wifi/wifi-utils-nl80211.h30
-rw-r--r--src/wifi/wifi-utils-private.h74
-rw-r--r--src/wifi/wifi-utils-wext.c663
-rw-r--r--src/wifi/wifi-utils-wext.h30
-rw-r--r--src/wifi/wifi-utils.c213
-rw-r--r--src/wifi/wifi-utils.h72
-rw-r--r--src/wimax/Makefile.am21
-rw-r--r--src/wimax/Makefile.in190
-rw-r--r--src/wimax/nm-device-wimax.c111
-rw-r--r--src/wimax/nm-device-wimax.h8
-rw-r--r--src/wimax/nm-wimax-factory.c58
-rw-r--r--src/wimax/nm-wimax-nsp.c2
-rw-r--r--src/wpa.c455
-rw-r--r--src/wpa.h38
234 files changed, 22296 insertions, 7928 deletions
diff --git a/src/Makefile.am b/src/Makefile.am
index cbcfdc62..f46fbab3 100644
--- a/src/Makefile.am
+++ b/src/Makefile.am
@@ -1,4 +1,5 @@
 SUBDIRS= \
+	generated \
 	logging \
 	dns-manager \
 	vpn-manager \
@@ -10,6 +11,8 @@ SUBDIRS= \
 	dnsmasq-manager \
 	modem-manager \
 	bluez-manager \
+	firewall-manager \
+	wifi \
 	settings
 
 if WITH_WIMAX
@@ -20,7 +23,9 @@ SUBDIRS += . tests
 
 INCLUDES = -I${top_srcdir} \
            -I${top_srcdir}/include \
-           -I${top_builddir}/marshallers \
+           -I${top_builddir}/include \
+           -I${top_srcdir}/src/generated \
+           -I${top_builddir}/src/generated \
            -I${top_srcdir}/src/logging \
            -I${top_srcdir}/src/dns-manager \
            -I${top_srcdir}/src/vpn-manager \
@@ -30,14 +35,13 @@ INCLUDES = -I${top_srcdir} \
            -I${top_srcdir}/src/dnsmasq-manager \
            -I${top_srcdir}/src/modem-manager \
            -I$(top_srcdir)/src/bluez-manager \
+           -I$(top_srcdir)/src/firewall-manager \
            -I$(top_srcdir)/src/settings \
+           -I$(top_srcdir)/src/wifi \
            -I${top_srcdir}/libnm-util \
+           -I${top_builddir}/libnm-util \
            -I${top_srcdir}/callouts
 
-if WITH_WIMAX
-INCLUDES += -I$(top_srcdir)/src/wimax
-endif
-
 ###########################################
 # Test libraries
 ###########################################
@@ -63,7 +67,7 @@ libtest_dhcp_la_CPPFLAGS = \
 	$(LIBNL_CFLAGS)
 
 libtest_dhcp_la_LIBADD = \
-	$(top_builddir)/marshallers/libmarshallers.la \
+	$(top_builddir)/src/generated/libnm-generated.la \
 	$(top_builddir)/libnm-util/libnm-util.la \
 	$(GLIB_LIBS) \
 	$(DBUS_LIBS) \
@@ -113,19 +117,25 @@ NetworkManager_SOURCES = \
 		nm-call-store.h \
 		nm-device.c \
 		nm-device.h \
-		nm-device-interface.c \
-		nm-device-interface.h \
 		nm-device-private.h \
 		nm-device-ethernet.c \
 		nm-device-ethernet.h \
 		nm-device-wifi.c \
 		nm-device-wifi.h \
+		nm-device-wired.c \
+		nm-device-wired.h \
 		nm-device-olpc-mesh.c	\
 		nm-device-olpc-mesh.h	\
 		nm-device-bt.c \
 		nm-device-bt.h \
 		nm-device-modem.h \
 		nm-device-modem.c \
+		nm-device-infiniband.c \
+		nm-device-infiniband.h \
+		nm-device-bond.c \
+		nm-device-bond.h \
+		nm-device-vlan.c \
+		nm-device-vlan.h \
 		nm-wifi-ap.c \
 		nm-wifi-ap.h \
 		nm-wifi-ap-utils.c \
@@ -134,6 +144,7 @@ NetworkManager_SOURCES = \
 		nm-dbus-manager.c \
 		nm-udev-manager.c \
 		nm-udev-manager.h \
+		nm-device-factory.h \
 		nm-hostname-provider.c \
 		nm-hostname-provider.h \
 		nm-ip4-config.c \
@@ -169,15 +180,28 @@ NetworkManager_SOURCES = \
 		nm-activation-request.h \
 		nm-properties-changed-signal.c \
 		nm-properties-changed-signal.h \
-		wpa.c \
-		wpa.h \
 		nm-dhcp4-config.c \
 		nm-dhcp4-config.h \
 		nm-dhcp6-config.c \
 		nm-dhcp6-config.h \
 		nm-rfkill.h \
-		nm-session-monitor.c \
-		nm-session-monitor.h
+		nm-session-monitor.h \
+		nm-session-utils.c \
+		nm-session-utils.h
+
+if WITH_CONCHECK
+NetworkManager_SOURCES += nm-connectivity.c nm-connectivity.h
+endif
+
+if SESSION_TRACKING_SYSTEMD
+NetworkManager_SOURCES += nm-session-monitor-systemd.c
+else
+if SESSION_TRACKING_CK
+NetworkManager_SOURCES += nm-session-monitor-ck.c
+else
+NetworkManager_SOURCES += nm-session-monitor-null.c
+endif
+endif
 
 nm-access-point-glue.h: $(top_srcdir)/introspection/nm-access-point.xml
 	$(AM_V_GEN) dbus-binding-tool --prefix=nm_access_point --mode=glib-server --output=$@ $<
@@ -191,6 +215,9 @@ nm-device-interface-glue.h: $(top_srcdir)/introspection/nm-device.xml
 nm-device-ethernet-glue.h: $(top_srcdir)/introspection/nm-device-ethernet.xml
 	$(AM_V_GEN) dbus-binding-tool --prefix=nm_device_ethernet --mode=glib-server --output=$@ $<
 
+nm-device-infiniband-glue.h: $(top_srcdir)/introspection/nm-device-infiniband.xml
+	$(AM_V_GEN) dbus-binding-tool --prefix=nm_device_infiniband --mode=glib-server --output=$@ $<
+
 nm-device-wifi-glue.h: $(top_srcdir)/introspection/nm-device-wifi.xml
 	$(AM_V_GEN) dbus-binding-tool --prefix=nm_device_wifi --mode=glib-server --output=$@ $<
 
@@ -200,6 +227,12 @@ nm-device-bt-glue.h: $(top_srcdir)/introspection/nm-device-bt.xml
 nm-device-olpc-mesh-glue.h: $(top_srcdir)/introspection/nm-device-olpc-mesh.xml
 	$(AM_V_GEN) dbus-binding-tool --prefix=nm_device_olpc_mesh --mode=glib-server --output=$@ $<
 
+nm-device-bond-glue.h: $(top_srcdir)/introspection/nm-device-bond.xml
+	$(AM_V_GEN) dbus-binding-tool --prefix=nm_device_bond --mode=glib-server --output=$@ $<
+
+nm-device-vlan-glue.h: $(top_srcdir)/introspection/nm-device-vlan.xml
+	$(AM_V_GEN) dbus-binding-tool --prefix=nm_device_vlan --mode=glib-server --output=$@ $<
+
 nm-ip4-config-glue.h: $(top_srcdir)/introspection/nm-ip4-config.xml
 	$(AM_V_GEN) dbus-binding-tool --prefix=nm_ip4_config --mode=glib-server --output=$@ $<
 
@@ -223,6 +256,9 @@ BUILT_SOURCES = \
 	nm-manager-glue.h \
 	nm-device-interface-glue.h \
 	nm-device-ethernet-glue.h \
+	nm-device-infiniband-glue.h \
+	nm-device-bond-glue.h \
+	nm-device-vlan-glue.h \
 	nm-device-wifi-glue.h \
 	nm-device-olpc-mesh-glue.h \
 	nm-device-bt-glue.h \
@@ -240,6 +276,7 @@ NetworkManager_CPPFLAGS = \
 	$(LIBNL_CFLAGS) \
 	$(GMODULE_CFLAGS) \
 	$(POLKIT_CFLAGS) \
+	$(SYSTEMD_CFLAGS) \
 	-DG_DISABLE_DEPRECATED \
 	-DBINDIR=\"$(bindir)\" \
 	-DSBINDIR=\"$(sbindir)\" \
@@ -249,16 +286,15 @@ NetworkManager_CPPFLAGS = \
 	-DLOCALSTATEDIR=\"$(localstatedir)\" \
 	-DNM_RUN_DIR=\"$(rundir)\" \
 	-DNMLOCALEDIR=\"$(datadir)/locale\" \
+	-DNMPLUGINDIR=\"$(pkglibdir)\"
 	-DARP_DEBUG
 
-
-WIMAX_LIBS=
-if WITH_WIMAX
-WIMAX_LIBS += ./wimax/libwimax.la
+if WITH_CONCHECK
+NetworkManager_CPPFLAGS += $(LIBSOUP_CFLAGS)
 endif
 
 NetworkManager_LDADD = \
-	$(top_builddir)/marshallers/libmarshallers.la \
+	./generated/libnm-generated.la \
 	./logging/libnm-logging.la \
 	./dns-manager/libdns-manager.la \
 	./vpn-manager/libvpn-manager.la \
@@ -269,8 +305,9 @@ NetworkManager_LDADD = \
 	./ppp-manager/libppp-manager.la \
 	./modem-manager/libmodem-manager.la \
 	./bluez-manager/libbluez-manager.la \
+	./wifi/libwifi-utils.la \
+	./firewall-manager/libfirewall-manager.la \
 	./settings/libsettings.la \
-	$(WIMAX_LIBS) \
 	./backends/libnmbackend.la \
 	$(top_builddir)/libnm-util/libnm-util.la \
 	$(DBUS_LIBS) \
@@ -279,9 +316,14 @@ NetworkManager_LDADD = \
 	$(LIBNL_LIBS) \
 	$(GMODULE_LIBS) \
 	$(POLKIT_LIBS) \
+	$(SYSTEMD_LIBS) \
 	$(LIBM) \
 	$(LIBDL)
 
+if WITH_CONCHECK
+NetworkManager_LDADD += $(LIBSOUP_LIBS)
+endif
+
 NetworkManager_LDFLAGS = -rdynamic
 
 libexec_PROGRAMS = nm-crash-logger
@@ -301,7 +343,7 @@ NetworkManagerdir = $(datadir)/NetworkManager
 NetworkManager_DATA = gdb-cmd
 
 dbusservicedir = $(DBUS_SYS_DIR)
-dbusservice_DATA = NetworkManager.conf
+dbusservice_DATA = org.freedesktop.NetworkManager.conf
 
 EXTRA_DIST = \
 	$(dbusservice_DATA) \
diff --git a/src/Makefile.in b/src/Makefile.in
index 5a388235..715658e8 100644
--- a/src/Makefile.in
+++ b/src/Makefile.in
@@ -37,9 +37,13 @@ POST_UNINSTALL = :
 build_triplet = @build@
 host_triplet = @host@
 @WITH_WIMAX_TRUE@am__append_1 = wimax
-@WITH_WIMAX_TRUE@am__append_2 = -I$(top_srcdir)/src/wimax
 sbin_PROGRAMS = NetworkManager$(EXEEXT)
-@WITH_WIMAX_TRUE@am__append_3 = ./wimax/libwimax.la
+@WITH_CONCHECK_TRUE@am__append_2 = nm-connectivity.c nm-connectivity.h
+@SESSION_TRACKING_SYSTEMD_TRUE@am__append_3 = nm-session-monitor-systemd.c
+@SESSION_TRACKING_CK_TRUE@@SESSION_TRACKING_SYSTEMD_FALSE@am__append_4 = nm-session-monitor-ck.c
+@SESSION_TRACKING_CK_FALSE@@SESSION_TRACKING_SYSTEMD_FALSE@am__append_5 = nm-session-monitor-null.c
+@WITH_CONCHECK_TRUE@am__append_6 = $(LIBSOUP_CFLAGS)
+@WITH_CONCHECK_TRUE@am__append_7 = $(LIBSOUP_LIBS)
 libexec_PROGRAMS = nm-crash-logger$(EXEEXT)
 subdir = src
 DIST_COMMON = $(srcdir)/Makefile.am $(srcdir)/Makefile.in
@@ -64,7 +68,7 @@ CONFIG_CLEAN_VPATH_FILES =
 LTLIBRARIES = $(noinst_LTLIBRARIES)
 am__DEPENDENCIES_1 =
 libtest_dhcp_la_DEPENDENCIES =  \
-	$(top_builddir)/marshallers/libmarshallers.la \
+	$(top_builddir)/src/generated/libnm-generated.la \
 	$(top_builddir)/libnm-util/libnm-util.la $(am__DEPENDENCIES_1) \
 	$(am__DEPENDENCIES_1) $(am__DEPENDENCIES_1)
 am_libtest_dhcp_la_OBJECTS = libtest_dhcp_la-nm-ip4-config.lo \
@@ -91,14 +95,50 @@ libtest_wifi_ap_utils_la_OBJECTS =  \
 am__installdirs = "$(DESTDIR)$(libexecdir)" "$(DESTDIR)$(sbindir)" \
 	"$(DESTDIR)$(NetworkManagerdir)" "$(DESTDIR)$(dbusservicedir)"
 PROGRAMS = $(libexec_PROGRAMS) $(sbin_PROGRAMS)
+am__NetworkManager_SOURCES_DIST = nm-call-store.c nm-call-store.h \
+	nm-device.c nm-device.h nm-device-private.h \
+	nm-device-ethernet.c nm-device-ethernet.h nm-device-wifi.c \
+	nm-device-wifi.h nm-device-wired.c nm-device-wired.h \
+	nm-device-olpc-mesh.c nm-device-olpc-mesh.h nm-device-bt.c \
+	nm-device-bt.h nm-device-modem.h nm-device-modem.c \
+	nm-device-infiniband.c nm-device-infiniband.h nm-device-bond.c \
+	nm-device-bond.h nm-device-vlan.c nm-device-vlan.h \
+	nm-wifi-ap.c nm-wifi-ap.h nm-wifi-ap-utils.c \
+	nm-wifi-ap-utils.h nm-dbus-manager.h nm-dbus-manager.c \
+	nm-udev-manager.c nm-udev-manager.h nm-device-factory.h \
+	nm-hostname-provider.c nm-hostname-provider.h nm-ip4-config.c \
+	nm-ip4-config.h nm-ip6-config.c nm-ip6-config.h \
+	nm-active-connection.h nm-active-connection.c nm-config.h \
+	nm-config.c main.c nm-policy.c nm-policy.h nm-policy-hosts.c \
+	nm-policy-hosts.h nm-policy-hostname.c nm-policy-hostname.h \
+	NetworkManagerUtils.c NetworkManagerUtils.h nm-system.c \
+	nm-system.h nm-manager.c nm-manager.h nm-manager-auth.c \
+	nm-manager-auth.h nm-netlink-monitor.c nm-netlink-monitor.h \
+	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 \
+	nm-properties-changed-signal.h nm-dhcp4-config.c \
+	nm-dhcp4-config.h nm-dhcp6-config.c nm-dhcp6-config.h \
+	nm-rfkill.h nm-session-monitor.h nm-session-utils.c \
+	nm-session-utils.h nm-connectivity.c nm-connectivity.h \
+	nm-session-monitor-systemd.c nm-session-monitor-ck.c \
+	nm-session-monitor-null.c
+@WITH_CONCHECK_TRUE@am__objects_1 =  \
+@WITH_CONCHECK_TRUE@	NetworkManager-nm-connectivity.$(OBJEXT)
+@SESSION_TRACKING_SYSTEMD_TRUE@am__objects_2 = NetworkManager-nm-session-monitor-systemd.$(OBJEXT)
+@SESSION_TRACKING_CK_TRUE@@SESSION_TRACKING_SYSTEMD_FALSE@am__objects_3 = NetworkManager-nm-session-monitor-ck.$(OBJEXT)
+@SESSION_TRACKING_CK_FALSE@@SESSION_TRACKING_SYSTEMD_FALSE@am__objects_4 = NetworkManager-nm-session-monitor-null.$(OBJEXT)
 am_NetworkManager_OBJECTS = NetworkManager-nm-call-store.$(OBJEXT) \
 	NetworkManager-nm-device.$(OBJEXT) \
-	NetworkManager-nm-device-interface.$(OBJEXT) \
 	NetworkManager-nm-device-ethernet.$(OBJEXT) \
 	NetworkManager-nm-device-wifi.$(OBJEXT) \
+	NetworkManager-nm-device-wired.$(OBJEXT) \
 	NetworkManager-nm-device-olpc-mesh.$(OBJEXT) \
 	NetworkManager-nm-device-bt.$(OBJEXT) \
 	NetworkManager-nm-device-modem.$(OBJEXT) \
+	NetworkManager-nm-device-infiniband.$(OBJEXT) \
+	NetworkManager-nm-device-bond.$(OBJEXT) \
+	NetworkManager-nm-device-vlan.$(OBJEXT) \
 	NetworkManager-nm-wifi-ap.$(OBJEXT) \
 	NetworkManager-nm-wifi-ap-utils.$(OBJEXT) \
 	NetworkManager-nm-dbus-manager.$(OBJEXT) \
@@ -121,13 +161,13 @@ am_NetworkManager_OBJECTS = NetworkManager-nm-call-store.$(OBJEXT) \
 	NetworkManager-nm-netlink-compat.$(OBJEXT) \
 	NetworkManager-nm-activation-request.$(OBJEXT) \
 	NetworkManager-nm-properties-changed-signal.$(OBJEXT) \
-	NetworkManager-wpa.$(OBJEXT) \
 	NetworkManager-nm-dhcp4-config.$(OBJEXT) \
 	NetworkManager-nm-dhcp6-config.$(OBJEXT) \
-	NetworkManager-nm-session-monitor.$(OBJEXT)
+	NetworkManager-nm-session-utils.$(OBJEXT) $(am__objects_1) \
+	$(am__objects_2) $(am__objects_3) $(am__objects_4)
 NetworkManager_OBJECTS = $(am_NetworkManager_OBJECTS)
-NetworkManager_DEPENDENCIES =  \
-	$(top_builddir)/marshallers/libmarshallers.la \
+@WITH_CONCHECK_TRUE@am__DEPENDENCIES_2 = $(am__DEPENDENCIES_1)
+NetworkManager_DEPENDENCIES = ./generated/libnm-generated.la \
 	./logging/libnm-logging.la ./dns-manager/libdns-manager.la \
 	./vpn-manager/libvpn-manager.la \
 	./dhcp-manager/libdhcp-manager.la \
@@ -136,13 +176,15 @@ NetworkManager_DEPENDENCIES =  \
 	./dnsmasq-manager/libdnsmasq-manager.la \
 	./ppp-manager/libppp-manager.la \
 	./modem-manager/libmodem-manager.la \
-	./bluez-manager/libbluez-manager.la ./settings/libsettings.la \
-	$(WIMAX_LIBS) ./backends/libnmbackend.la \
+	./bluez-manager/libbluez-manager.la ./wifi/libwifi-utils.la \
+	./firewall-manager/libfirewall-manager.la \
+	./settings/libsettings.la ./backends/libnmbackend.la \
 	$(top_builddir)/libnm-util/libnm-util.la $(am__DEPENDENCIES_1) \
 	$(am__DEPENDENCIES_1) $(am__DEPENDENCIES_1) \
 	$(am__DEPENDENCIES_1) $(am__DEPENDENCIES_1) \
 	$(am__DEPENDENCIES_1) $(am__DEPENDENCIES_1) \
-	$(am__DEPENDENCIES_1)
+	$(am__DEPENDENCIES_1) $(am__DEPENDENCIES_1) \
+	$(am__DEPENDENCIES_2)
 NetworkManager_LINK = $(LIBTOOL) $(AM_V_lt) --tag=CC \
 	$(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=link $(CCLD) \
 	$(AM_CFLAGS) $(CFLAGS) $(NetworkManager_LDFLAGS) $(LDFLAGS) -o \
@@ -183,8 +225,8 @@ SOURCES = $(libtest_dhcp_la_SOURCES) \
 	$(nm_crash_logger_SOURCES)
 DIST_SOURCES = $(libtest_dhcp_la_SOURCES) \
 	$(libtest_policy_hosts_la_SOURCES) \
-	$(libtest_wifi_ap_utils_la_SOURCES) $(NetworkManager_SOURCES) \
-	$(nm_crash_logger_SOURCES)
+	$(libtest_wifi_ap_utils_la_SOURCES) \
+	$(am__NetworkManager_SOURCES_DIST) $(nm_crash_logger_SOURCES)
 RECURSIVE_TARGETS = all-recursive check-recursive dvi-recursive \
 	html-recursive info-recursive install-data-recursive \
 	install-dvi-recursive install-exec-recursive \
@@ -221,10 +263,10 @@ AM_RECURSIVE_TARGETS = $(RECURSIVE_TARGETS:-recursive=) \
 	distdir
 ETAGS = etags
 CTAGS = ctags
-DIST_SUBDIRS = logging dns-manager vpn-manager dhcp-manager \
+DIST_SUBDIRS = generated logging dns-manager vpn-manager dhcp-manager \
 	ip6-manager supplicant-manager ppp-manager backends \
-	dnsmasq-manager modem-manager bluez-manager settings wimax . \
-	tests
+	dnsmasq-manager modem-manager bluez-manager firewall-manager \
+	wifi settings wimax . tests
 DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST)
 am__relativize = \
   dir0=`pwd`; \
@@ -296,6 +338,8 @@ GIO_LIBS = @GIO_LIBS@
 GLIB_CFLAGS = @GLIB_CFLAGS@
 GLIB_GENMARSHAL = @GLIB_GENMARSHAL@
 GLIB_LIBS = @GLIB_LIBS@
+GLIB_MAKEFILE = @GLIB_MAKEFILE@
+GLIB_MKENUMS = @GLIB_MKENUMS@
 GMODULE_CFLAGS = @GMODULE_CFLAGS@
 GMODULE_LIBS = @GMODULE_LIBS@
 GMSGFMT = @GMSGFMT@
@@ -350,11 +394,15 @@ LIBNL2_LIBS = @LIBNL2_LIBS@
 LIBNL3_CFLAGS = @LIBNL3_CFLAGS@
 LIBNL3_LIBS = @LIBNL3_LIBS@
 LIBNL_CFLAGS = @LIBNL_CFLAGS@
+LIBNL_GENL3_CFLAGS = @LIBNL_GENL3_CFLAGS@
+LIBNL_GENL3_LIBS = @LIBNL_GENL3_LIBS@
 LIBNL_LIBS = @LIBNL_LIBS@
 LIBNL_ROUTE3_CFLAGS = @LIBNL_ROUTE3_CFLAGS@
 LIBNL_ROUTE3_LIBS = @LIBNL_ROUTE3_LIBS@
 LIBOBJS = @LIBOBJS@
 LIBS = @LIBS@
+LIBSOUP_CFLAGS = @LIBSOUP_CFLAGS@
+LIBSOUP_LIBS = @LIBSOUP_LIBS@
 LIBTOOL = @LIBTOOL@
 LIPO = @LIPO@
 LN_S = @LN_S@
@@ -365,6 +413,7 @@ MAINT = @MAINT@
 MAKEINFO = @MAKEINFO@
 MANIFEST_TOOL = @MANIFEST_TOOL@
 MKDIR_P = @MKDIR_P@
+MOC = @MOC@
 MSGFMT = @MSGFMT@
 MSGFMT_015 = @MSGFMT_015@
 MSGMERGE = @MSGMERGE@
@@ -404,6 +453,8 @@ SED = @SED@
 SET_MAKE = @SET_MAKE@
 SHELL = @SHELL@
 STRIP = @STRIP@
+SYSTEMD_CFLAGS = @SYSTEMD_CFLAGS@
+SYSTEMD_LIBS = @SYSTEMD_LIBS@
 SYSTEM_CA_PATH = @SYSTEM_CA_PATH@
 UDEV_BASE_DIR = @UDEV_BASE_DIR@
 USE_NLS = @USE_NLS@
@@ -467,21 +518,31 @@ target_alias = @target_alias@
 top_build_prefix = @top_build_prefix@
 top_builddir = @top_builddir@
 top_srcdir = @top_srcdir@
-SUBDIRS = logging dns-manager vpn-manager dhcp-manager ip6-manager \
-	supplicant-manager ppp-manager backends dnsmasq-manager \
-	modem-manager bluez-manager settings $(am__append_1) . tests
-INCLUDES = -I${top_srcdir} -I${top_srcdir}/include \
-	-I${top_builddir}/marshallers -I${top_srcdir}/src/logging \
-	-I${top_srcdir}/src/dns-manager \
-	-I${top_srcdir}/src/vpn-manager \
-	-I${top_srcdir}/src/dhcp-manager \
-	-I${top_srcdir}/src/ip6-manager \
-	-I${top_srcdir}/src/supplicant-manager \
-	-I${top_srcdir}/src/dnsmasq-manager \
-	-I${top_srcdir}/src/modem-manager \
-	-I$(top_srcdir)/src/bluez-manager -I$(top_srcdir)/src/settings \
-	-I${top_srcdir}/libnm-util -I${top_srcdir}/callouts \
-	$(am__append_2)
+SUBDIRS = generated logging dns-manager vpn-manager dhcp-manager \
+	ip6-manager supplicant-manager ppp-manager backends \
+	dnsmasq-manager modem-manager bluez-manager firewall-manager \
+	wifi settings $(am__append_1) . tests
+INCLUDES = -I${top_srcdir} \
+           -I${top_srcdir}/include \
+           -I${top_builddir}/include \
+           -I${top_srcdir}/src/generated \
+           -I${top_builddir}/src/generated \
+           -I${top_srcdir}/src/logging \
+           -I${top_srcdir}/src/dns-manager \
+           -I${top_srcdir}/src/vpn-manager \
+           -I${top_srcdir}/src/dhcp-manager \
+           -I${top_srcdir}/src/ip6-manager \
+           -I${top_srcdir}/src/supplicant-manager \
+           -I${top_srcdir}/src/dnsmasq-manager \
+           -I${top_srcdir}/src/modem-manager \
+           -I$(top_srcdir)/src/bluez-manager \
+           -I$(top_srcdir)/src/firewall-manager \
+           -I$(top_srcdir)/src/settings \
+           -I$(top_srcdir)/src/wifi \
+           -I${top_srcdir}/libnm-util \
+           -I${top_builddir}/libnm-util \
+           -I${top_srcdir}/callouts
+
 
 ###########################################
 # Test libraries
@@ -507,7 +568,7 @@ libtest_dhcp_la_CPPFLAGS = \
 	$(LIBNL_CFLAGS)
 
 libtest_dhcp_la_LIBADD = \
-	$(top_builddir)/marshallers/libmarshallers.la \
+	$(top_builddir)/src/generated/libnm-generated.la \
 	$(top_builddir)/libnm-util/libnm-util.la \
 	$(GLIB_LIBS) \
 	$(DBUS_LIBS) \
@@ -544,82 +605,41 @@ libtest_wifi_ap_utils_la_LIBADD = \
 	${top_builddir}/libnm-util/libnm-util.la \
 	$(GLIB_LIBS)
 
-NetworkManager_SOURCES = \
-		nm-call-store.c \
-		nm-call-store.h \
-		nm-device.c \
-		nm-device.h \
-		nm-device-interface.c \
-		nm-device-interface.h \
-		nm-device-private.h \
-		nm-device-ethernet.c \
-		nm-device-ethernet.h \
-		nm-device-wifi.c \
-		nm-device-wifi.h \
-		nm-device-olpc-mesh.c	\
-		nm-device-olpc-mesh.h	\
-		nm-device-bt.c \
-		nm-device-bt.h \
-		nm-device-modem.h \
-		nm-device-modem.c \
-		nm-wifi-ap.c \
-		nm-wifi-ap.h \
-		nm-wifi-ap-utils.c \
-		nm-wifi-ap-utils.h \
-		nm-dbus-manager.h \
-		nm-dbus-manager.c \
-		nm-udev-manager.c \
-		nm-udev-manager.h \
-		nm-hostname-provider.c \
-		nm-hostname-provider.h \
-		nm-ip4-config.c \
-		nm-ip4-config.h \
-		nm-ip6-config.c \
-		nm-ip6-config.h \
-		nm-active-connection.h \
-		nm-active-connection.c \
-		nm-config.h \
-		nm-config.c \
-		main.c \
-		nm-policy.c \
-		nm-policy.h \
-		nm-policy-hosts.c \
-		nm-policy-hosts.h \
-		nm-policy-hostname.c \
-		nm-policy-hostname.h \
-		NetworkManagerUtils.c \
-		NetworkManagerUtils.h \
-		nm-system.c \
-		nm-system.h \
-		nm-manager.c \
-		nm-manager.h \
-		nm-manager-auth.c \
-		nm-manager-auth.h \
-		nm-netlink-monitor.c \
-		nm-netlink-monitor.h \
-		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 \
-		nm-properties-changed-signal.h \
-		wpa.c \
-		wpa.h \
-		nm-dhcp4-config.c \
-		nm-dhcp4-config.h \
-		nm-dhcp6-config.c \
-		nm-dhcp6-config.h \
-		nm-rfkill.h \
-		nm-session-monitor.c \
-		nm-session-monitor.h
-
+NetworkManager_SOURCES = nm-call-store.c nm-call-store.h nm-device.c \
+	nm-device.h nm-device-private.h nm-device-ethernet.c \
+	nm-device-ethernet.h nm-device-wifi.c nm-device-wifi.h \
+	nm-device-wired.c nm-device-wired.h nm-device-olpc-mesh.c \
+	nm-device-olpc-mesh.h nm-device-bt.c nm-device-bt.h \
+	nm-device-modem.h nm-device-modem.c nm-device-infiniband.c \
+	nm-device-infiniband.h nm-device-bond.c nm-device-bond.h \
+	nm-device-vlan.c nm-device-vlan.h nm-wifi-ap.c nm-wifi-ap.h \
+	nm-wifi-ap-utils.c nm-wifi-ap-utils.h nm-dbus-manager.h \
+	nm-dbus-manager.c nm-udev-manager.c nm-udev-manager.h \
+	nm-device-factory.h nm-hostname-provider.c \
+	nm-hostname-provider.h nm-ip4-config.c nm-ip4-config.h \
+	nm-ip6-config.c nm-ip6-config.h nm-active-connection.h \
+	nm-active-connection.c nm-config.h nm-config.c main.c \
+	nm-policy.c nm-policy.h nm-policy-hosts.c nm-policy-hosts.h \
+	nm-policy-hostname.c nm-policy-hostname.h \
+	NetworkManagerUtils.c NetworkManagerUtils.h nm-system.c \
+	nm-system.h nm-manager.c nm-manager.h nm-manager-auth.c \
+	nm-manager-auth.h nm-netlink-monitor.c nm-netlink-monitor.h \
+	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 \
+	nm-properties-changed-signal.h nm-dhcp4-config.c \
+	nm-dhcp4-config.h nm-dhcp6-config.c nm-dhcp6-config.h \
+	nm-rfkill.h nm-session-monitor.h nm-session-utils.c \
+	nm-session-utils.h $(am__append_2) $(am__append_3) \
+	$(am__append_4) $(am__append_5)
 BUILT_SOURCES = \
 	nm-access-point-glue.h \
 	nm-manager-glue.h \
 	nm-device-interface-glue.h \
 	nm-device-ethernet-glue.h \
+	nm-device-infiniband-glue.h \
+	nm-device-bond-glue.h \
+	nm-device-vlan-glue.h \
 	nm-device-wifi-glue.h \
 	nm-device-olpc-mesh-glue.h \
 	nm-device-bt-glue.h \
@@ -630,29 +650,17 @@ BUILT_SOURCES = \
 	nm-dhcp4-config-glue.h \
 	nm-dhcp6-config-glue.h
 
-NetworkManager_CPPFLAGS = \
-	$(DBUS_CFLAGS) \
-	$(GLIB_CFLAGS) \
-	$(GUDEV_CFLAGS) \
-	$(LIBNL_CFLAGS) \
-	$(GMODULE_CFLAGS) \
-	$(POLKIT_CFLAGS) \
-	-DG_DISABLE_DEPRECATED \
-	-DBINDIR=\"$(bindir)\" \
-	-DSBINDIR=\"$(sbindir)\" \
-	-DLIBEXECDIR=\"$(libexecdir)\" \
-	-DDATADIR=\"$(datadir)\" \
+NetworkManager_CPPFLAGS = $(DBUS_CFLAGS) $(GLIB_CFLAGS) \
+	$(GUDEV_CFLAGS) $(LIBNL_CFLAGS) $(GMODULE_CFLAGS) \
+	$(POLKIT_CFLAGS) $(SYSTEMD_CFLAGS) -DG_DISABLE_DEPRECATED \
+	-DBINDIR=\"$(bindir)\" -DSBINDIR=\"$(sbindir)\" \
+	-DLIBEXECDIR=\"$(libexecdir)\" -DDATADIR=\"$(datadir)\" \
 	-DSYSCONFDIR=\"$(sysconfdir)\" \
 	-DLOCALSTATEDIR=\"$(localstatedir)\" \
-	-DNM_RUN_DIR=\"$(rundir)\" \
-	-DNMLOCALEDIR=\"$(datadir)/locale\" \
-	-DARP_DEBUG
-
-WIMAX_LIBS = $(am__append_3)
-NetworkManager_LDADD = \
-	$(top_builddir)/marshallers/libmarshallers.la \
-	./logging/libnm-logging.la \
-	./dns-manager/libdns-manager.la \
+	-DNM_RUN_DIR=\"$(rundir)\" -DNMLOCALEDIR=\"$(datadir)/locale\" \
+	-DNMPLUGINDIR=\"$(pkglibdir)\" $(am__append_6)
+NetworkManager_LDADD = ./generated/libnm-generated.la \
+	./logging/libnm-logging.la ./dns-manager/libdns-manager.la \
 	./vpn-manager/libvpn-manager.la \
 	./dhcp-manager/libdhcp-manager.la \
 	./ip6-manager/libip6-manager.la \
@@ -660,20 +668,13 @@ NetworkManager_LDADD = \
 	./dnsmasq-manager/libdnsmasq-manager.la \
 	./ppp-manager/libppp-manager.la \
 	./modem-manager/libmodem-manager.la \
-	./bluez-manager/libbluez-manager.la \
-	./settings/libsettings.la \
-	$(WIMAX_LIBS) \
-	./backends/libnmbackend.la \
-	$(top_builddir)/libnm-util/libnm-util.la \
-	$(DBUS_LIBS) \
-	$(GLIB_LIBS) \
-	$(GUDEV_LIBS) \
-	$(LIBNL_LIBS) \
-	$(GMODULE_LIBS) \
-	$(POLKIT_LIBS) \
-	$(LIBM) \
-	$(LIBDL)
-
+	./bluez-manager/libbluez-manager.la ./wifi/libwifi-utils.la \
+	./firewall-manager/libfirewall-manager.la \
+	./settings/libsettings.la ./backends/libnmbackend.la \
+	$(top_builddir)/libnm-util/libnm-util.la $(DBUS_LIBS) \
+	$(GLIB_LIBS) $(GUDEV_LIBS) $(LIBNL_LIBS) $(GMODULE_LIBS) \
+	$(POLKIT_LIBS) $(SYSTEMD_LIBS) $(LIBM) $(LIBDL) \
+	$(am__append_7)
 NetworkManager_LDFLAGS = -rdynamic
 nm_crash_logger_SOURCES = nm-crash-logger.c
 nm_crash_logger_CPPFLAGS = \
@@ -689,7 +690,7 @@ nm_crash_logger_LDADD = $(GLIB_LIBS)
 NetworkManagerdir = $(datadir)/NetworkManager
 NetworkManager_DATA = gdb-cmd
 dbusservicedir = $(DBUS_SYS_DIR)
-dbusservice_DATA = NetworkManager.conf
+dbusservice_DATA = org.freedesktop.NetworkManager.conf
 EXTRA_DIST = \
 	$(dbusservice_DATA) \
 	$(NetworkManager_DATA)
@@ -852,13 +853,17 @@ distclean-compile:
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/NetworkManager-nm-active-connection.Po@am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/NetworkManager-nm-call-store.Po@am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/NetworkManager-nm-config.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/NetworkManager-nm-connectivity.Po@am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/NetworkManager-nm-dbus-manager.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/NetworkManager-nm-device-bond.Po@am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/NetworkManager-nm-device-bt.Po@am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/NetworkManager-nm-device-ethernet.Po@am__quote@
-@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/NetworkManager-nm-device-interface.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/NetworkManager-nm-device-infiniband.Po@am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/NetworkManager-nm-device-modem.Po@am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/NetworkManager-nm-device-olpc-mesh.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/NetworkManager-nm-device-vlan.Po@am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/NetworkManager-nm-device-wifi.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/NetworkManager-nm-device-wired.Po@am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/NetworkManager-nm-device.Po@am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/NetworkManager-nm-dhcp4-config.Po@am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/NetworkManager-nm-dhcp6-config.Po@am__quote@
@@ -874,12 +879,14 @@ distclean-compile:
 @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@
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/NetworkManager-nm-properties-changed-signal.Po@am__quote@
-@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/NetworkManager-nm-session-monitor.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/NetworkManager-nm-session-monitor-ck.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/NetworkManager-nm-session-monitor-null.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/NetworkManager-nm-session-monitor-systemd.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/NetworkManager-nm-session-utils.Po@am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/NetworkManager-nm-system.Po@am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/NetworkManager-nm-udev-manager.Po@am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/NetworkManager-nm-wifi-ap-utils.Po@am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/NetworkManager-nm-wifi-ap.Po@am__quote@
-@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/NetworkManager-wpa.Po@am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libtest_dhcp_la-nm-dbus-manager.Plo@am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libtest_dhcp_la-nm-hostname-provider.Plo@am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libtest_dhcp_la-nm-ip4-config.Plo@am__quote@
@@ -995,22 +1002,6 @@ NetworkManager-nm-device.obj: nm-device.c
 @AMDEP_TRUE@@am__fastdepCC_FALSE@	DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
 @am__fastdepCC_FALSE@	$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(NetworkManager_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o NetworkManager-nm-device.obj `if test -f 'nm-device.c'; then $(CYGPATH_W) 'nm-device.c'; else $(CYGPATH_W) '$(srcdir)/nm-device.c'; fi`
 
-NetworkManager-nm-device-interface.o: nm-device-interface.c
-@am__fastdepCC_TRUE@	$(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(NetworkManager_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT NetworkManager-nm-device-interface.o -MD -MP -MF $(DEPDIR)/NetworkManager-nm-device-interface.Tpo -c -o NetworkManager-nm-device-interface.o `test -f 'nm-device-interface.c' || echo '$(srcdir)/'`nm-device-interface.c
-@am__fastdepCC_TRUE@	$(AM_V_at)$(am__mv) $(DEPDIR)/NetworkManager-nm-device-interface.Tpo $(DEPDIR)/NetworkManager-nm-device-interface.Po
-@am__fastdepCC_FALSE@	$(AM_V_CC) @AM_BACKSLASH@
-@AMDEP_TRUE@@am__fastdepCC_FALSE@	source='nm-device-interface.c' object='NetworkManager-nm-device-interface.o' libtool=no @AMDEPBACKSLASH@
-@AMDEP_TRUE@@am__fastdepCC_FALSE@	DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
-@am__fastdepCC_FALSE@	$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(NetworkManager_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o NetworkManager-nm-device-interface.o `test -f 'nm-device-interface.c' || echo '$(srcdir)/'`nm-device-interface.c
-
-NetworkManager-nm-device-interface.obj: nm-device-interface.c
-@am__fastdepCC_TRUE@	$(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(NetworkManager_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT NetworkManager-nm-device-interface.obj -MD -MP -MF $(DEPDIR)/NetworkManager-nm-device-interface.Tpo -c -o NetworkManager-nm-device-interface.obj `if test -f 'nm-device-interface.c'; then $(CYGPATH_W) 'nm-device-interface.c'; else $(CYGPATH_W) '$(srcdir)/nm-device-interface.c'; fi`
-@am__fastdepCC_TRUE@	$(AM_V_at)$(am__mv) $(DEPDIR)/NetworkManager-nm-device-interface.Tpo $(DEPDIR)/NetworkManager-nm-device-interface.Po
-@am__fastdepCC_FALSE@	$(AM_V_CC) @AM_BACKSLASH@
-@AMDEP_TRUE@@am__fastdepCC_FALSE@	source='nm-device-interface.c' object='NetworkManager-nm-device-interface.obj' libtool=no @AMDEPBACKSLASH@
-@AMDEP_TRUE@@am__fastdepCC_FALSE@	DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
-@am__fastdepCC_FALSE@	$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(NetworkManager_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o NetworkManager-nm-device-interface.obj `if test -f 'nm-device-interface.c'; then $(CYGPATH_W) 'nm-device-interface.c'; else $(CYGPATH_W) '$(srcdir)/nm-device-interface.c'; fi`
-
 NetworkManager-nm-device-ethernet.o: nm-device-ethernet.c
 @am__fastdepCC_TRUE@	$(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(NetworkManager_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT NetworkManager-nm-device-ethernet.o -MD -MP -MF $(DEPDIR)/NetworkManager-nm-device-ethernet.Tpo -c -o NetworkManager-nm-device-ethernet.o `test -f 'nm-device-ethernet.c' || echo '$(srcdir)/'`nm-device-ethernet.c
 @am__fastdepCC_TRUE@	$(AM_V_at)$(am__mv) $(DEPDIR)/NetworkManager-nm-device-ethernet.Tpo $(DEPDIR)/NetworkManager-nm-device-ethernet.Po
@@ -1043,6 +1034,22 @@ NetworkManager-nm-device-wifi.obj: nm-device-wifi.c
 @AMDEP_TRUE@@am__fastdepCC_FALSE@	DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
 @am__fastdepCC_FALSE@	$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(NetworkManager_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o NetworkManager-nm-device-wifi.obj `if test -f 'nm-device-wifi.c'; then $(CYGPATH_W) 'nm-device-wifi.c'; else $(CYGPATH_W) '$(srcdir)/nm-device-wifi.c'; fi`
 
+NetworkManager-nm-device-wired.o: nm-device-wired.c
+@am__fastdepCC_TRUE@	$(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(NetworkManager_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT NetworkManager-nm-device-wired.o -MD -MP -MF $(DEPDIR)/NetworkManager-nm-device-wired.Tpo -c -o NetworkManager-nm-device-wired.o `test -f 'nm-device-wired.c' || echo '$(srcdir)/'`nm-device-wired.c
+@am__fastdepCC_TRUE@	$(AM_V_at)$(am__mv) $(DEPDIR)/NetworkManager-nm-device-wired.Tpo $(DEPDIR)/NetworkManager-nm-device-wired.Po
+@am__fastdepCC_FALSE@	$(AM_V_CC) @AM_BACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@	source='nm-device-wired.c' object='NetworkManager-nm-device-wired.o' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@	DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@	$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(NetworkManager_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o NetworkManager-nm-device-wired.o `test -f 'nm-device-wired.c' || echo '$(srcdir)/'`nm-device-wired.c
+
+NetworkManager-nm-device-wired.obj: nm-device-wired.c
+@am__fastdepCC_TRUE@	$(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(NetworkManager_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT NetworkManager-nm-device-wired.obj -MD -MP -MF $(DEPDIR)/NetworkManager-nm-device-wired.Tpo -c -o NetworkManager-nm-device-wired.obj `if test -f 'nm-device-wired.c'; then $(CYGPATH_W) 'nm-device-wired.c'; else $(CYGPATH_W) '$(srcdir)/nm-device-wired.c'; fi`
+@am__fastdepCC_TRUE@	$(AM_V_at)$(am__mv) $(DEPDIR)/NetworkManager-nm-device-wired.Tpo $(DEPDIR)/NetworkManager-nm-device-wired.Po
+@am__fastdepCC_FALSE@	$(AM_V_CC) @AM_BACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@	source='nm-device-wired.c' object='NetworkManager-nm-device-wired.obj' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@	DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@	$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(NetworkManager_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o NetworkManager-nm-device-wired.obj `if test -f 'nm-device-wired.c'; then $(CYGPATH_W) 'nm-device-wired.c'; else $(CYGPATH_W) '$(srcdir)/nm-device-wired.c'; fi`
+
 NetworkManager-nm-device-olpc-mesh.o: nm-device-olpc-mesh.c
 @am__fastdepCC_TRUE@	$(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(NetworkManager_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT NetworkManager-nm-device-olpc-mesh.o -MD -MP -MF $(DEPDIR)/NetworkManager-nm-device-olpc-mesh.Tpo -c -o NetworkManager-nm-device-olpc-mesh.o `test -f 'nm-device-olpc-mesh.c' || echo '$(srcdir)/'`nm-device-olpc-mesh.c
 @am__fastdepCC_TRUE@	$(AM_V_at)$(am__mv) $(DEPDIR)/NetworkManager-nm-device-olpc-mesh.Tpo $(DEPDIR)/NetworkManager-nm-device-olpc-mesh.Po
@@ -1091,6 +1098,54 @@ NetworkManager-nm-device-modem.obj: nm-device-modem.c
 @AMDEP_TRUE@@am__fastdepCC_FALSE@	DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
 @am__fastdepCC_FALSE@	$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(NetworkManager_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o NetworkManager-nm-device-modem.obj `if test -f 'nm-device-modem.c'; then $(CYGPATH_W) 'nm-device-modem.c'; else $(CYGPATH_W) '$(srcdir)/nm-device-modem.c'; fi`
 
+NetworkManager-nm-device-infiniband.o: nm-device-infiniband.c
+@am__fastdepCC_TRUE@	$(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(NetworkManager_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT NetworkManager-nm-device-infiniband.o -MD -MP -MF $(DEPDIR)/NetworkManager-nm-device-infiniband.Tpo -c -o NetworkManager-nm-device-infiniband.o `test -f 'nm-device-infiniband.c' || echo '$(srcdir)/'`nm-device-infiniband.c
+@am__fastdepCC_TRUE@	$(AM_V_at)$(am__mv) $(DEPDIR)/NetworkManager-nm-device-infiniband.Tpo $(DEPDIR)/NetworkManager-nm-device-infiniband.Po
+@am__fastdepCC_FALSE@	$(AM_V_CC) @AM_BACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@	source='nm-device-infiniband.c' object='NetworkManager-nm-device-infiniband.o' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@	DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@	$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(NetworkManager_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o NetworkManager-nm-device-infiniband.o `test -f 'nm-device-infiniband.c' || echo '$(srcdir)/'`nm-device-infiniband.c
+
+NetworkManager-nm-device-infiniband.obj: nm-device-infiniband.c
+@am__fastdepCC_TRUE@	$(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(NetworkManager_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT NetworkManager-nm-device-infiniband.obj -MD -MP -MF $(DEPDIR)/NetworkManager-nm-device-infiniband.Tpo -c -o NetworkManager-nm-device-infiniband.obj `if test -f 'nm-device-infiniband.c'; then $(CYGPATH_W) 'nm-device-infiniband.c'; else $(CYGPATH_W) '$(srcdir)/nm-device-infiniband.c'; fi`
+@am__fastdepCC_TRUE@	$(AM_V_at)$(am__mv) $(DEPDIR)/NetworkManager-nm-device-infiniband.Tpo $(DEPDIR)/NetworkManager-nm-device-infiniband.Po
+@am__fastdepCC_FALSE@	$(AM_V_CC) @AM_BACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@	source='nm-device-infiniband.c' object='NetworkManager-nm-device-infiniband.obj' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@	DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@	$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(NetworkManager_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o NetworkManager-nm-device-infiniband.obj `if test -f 'nm-device-infiniband.c'; then $(CYGPATH_W) 'nm-device-infiniband.c'; else $(CYGPATH_W) '$(srcdir)/nm-device-infiniband.c'; fi`
+
+NetworkManager-nm-device-bond.o: nm-device-bond.c
+@am__fastdepCC_TRUE@	$(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(NetworkManager_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT NetworkManager-nm-device-bond.o -MD -MP -MF $(DEPDIR)/NetworkManager-nm-device-bond.Tpo -c -o NetworkManager-nm-device-bond.o `test -f 'nm-device-bond.c' || echo '$(srcdir)/'`nm-device-bond.c
+@am__fastdepCC_TRUE@	$(AM_V_at)$(am__mv) $(DEPDIR)/NetworkManager-nm-device-bond.Tpo $(DEPDIR)/NetworkManager-nm-device-bond.Po
+@am__fastdepCC_FALSE@	$(AM_V_CC) @AM_BACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@	source='nm-device-bond.c' object='NetworkManager-nm-device-bond.o' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@	DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@	$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(NetworkManager_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o NetworkManager-nm-device-bond.o `test -f 'nm-device-bond.c' || echo '$(srcdir)/'`nm-device-bond.c
+
+NetworkManager-nm-device-bond.obj: nm-device-bond.c
+@am__fastdepCC_TRUE@	$(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(NetworkManager_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT NetworkManager-nm-device-bond.obj -MD -MP -MF $(DEPDIR)/NetworkManager-nm-device-bond.Tpo -c -o NetworkManager-nm-device-bond.obj `if test -f 'nm-device-bond.c'; then $(CYGPATH_W) 'nm-device-bond.c'; else $(CYGPATH_W) '$(srcdir)/nm-device-bond.c'; fi`
+@am__fastdepCC_TRUE@	$(AM_V_at)$(am__mv) $(DEPDIR)/NetworkManager-nm-device-bond.Tpo $(DEPDIR)/NetworkManager-nm-device-bond.Po
+@am__fastdepCC_FALSE@	$(AM_V_CC) @AM_BACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@	source='nm-device-bond.c' object='NetworkManager-nm-device-bond.obj' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@	DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@	$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(NetworkManager_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o NetworkManager-nm-device-bond.obj `if test -f 'nm-device-bond.c'; then $(CYGPATH_W) 'nm-device-bond.c'; else $(CYGPATH_W) '$(srcdir)/nm-device-bond.c'; fi`
+
+NetworkManager-nm-device-vlan.o: nm-device-vlan.c
+@am__fastdepCC_TRUE@	$(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(NetworkManager_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT NetworkManager-nm-device-vlan.o -MD -MP -MF $(DEPDIR)/NetworkManager-nm-device-vlan.Tpo -c -o NetworkManager-nm-device-vlan.o `test -f 'nm-device-vlan.c' || echo '$(srcdir)/'`nm-device-vlan.c
+@am__fastdepCC_TRUE@	$(AM_V_at)$(am__mv) $(DEPDIR)/NetworkManager-nm-device-vlan.Tpo $(DEPDIR)/NetworkManager-nm-device-vlan.Po
+@am__fastdepCC_FALSE@	$(AM_V_CC) @AM_BACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@	source='nm-device-vlan.c' object='NetworkManager-nm-device-vlan.o' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@	DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@	$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(NetworkManager_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o NetworkManager-nm-device-vlan.o `test -f 'nm-device-vlan.c' || echo '$(srcdir)/'`nm-device-vlan.c
+
+NetworkManager-nm-device-vlan.obj: nm-device-vlan.c
+@am__fastdepCC_TRUE@	$(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(NetworkManager_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT NetworkManager-nm-device-vlan.obj -MD -MP -MF $(DEPDIR)/NetworkManager-nm-device-vlan.Tpo -c -o NetworkManager-nm-device-vlan.obj `if test -f 'nm-device-vlan.c'; then $(CYGPATH_W) 'nm-device-vlan.c'; else $(CYGPATH_W) '$(srcdir)/nm-device-vlan.c'; fi`
+@am__fastdepCC_TRUE@	$(AM_V_at)$(am__mv) $(DEPDIR)/NetworkManager-nm-device-vlan.Tpo $(DEPDIR)/NetworkManager-nm-device-vlan.Po
+@am__fastdepCC_FALSE@	$(AM_V_CC) @AM_BACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@	source='nm-device-vlan.c' object='NetworkManager-nm-device-vlan.obj' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@	DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@	$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(NetworkManager_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o NetworkManager-nm-device-vlan.obj `if test -f 'nm-device-vlan.c'; then $(CYGPATH_W) 'nm-device-vlan.c'; else $(CYGPATH_W) '$(srcdir)/nm-device-vlan.c'; fi`
+
 NetworkManager-nm-wifi-ap.o: nm-wifi-ap.c
 @am__fastdepCC_TRUE@	$(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(NetworkManager_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT NetworkManager-nm-wifi-ap.o -MD -MP -MF $(DEPDIR)/NetworkManager-nm-wifi-ap.Tpo -c -o NetworkManager-nm-wifi-ap.o `test -f 'nm-wifi-ap.c' || echo '$(srcdir)/'`nm-wifi-ap.c
 @am__fastdepCC_TRUE@	$(AM_V_at)$(am__mv) $(DEPDIR)/NetworkManager-nm-wifi-ap.Tpo $(DEPDIR)/NetworkManager-nm-wifi-ap.Po
@@ -1443,22 +1498,6 @@ NetworkManager-nm-properties-changed-signal.obj: nm-properties-changed-signal.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-properties-changed-signal.obj `if test -f 'nm-properties-changed-signal.c'; then $(CYGPATH_W) 'nm-properties-changed-signal.c'; else $(CYGPATH_W) '$(srcdir)/nm-properties-changed-signal.c'; fi`
 
-NetworkManager-wpa.o: wpa.c
-@am__fastdepCC_TRUE@	$(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(NetworkManager_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT NetworkManager-wpa.o -MD -MP -MF $(DEPDIR)/NetworkManager-wpa.Tpo -c -o NetworkManager-wpa.o `test -f 'wpa.c' || echo '$(srcdir)/'`wpa.c
-@am__fastdepCC_TRUE@	$(AM_V_at)$(am__mv) $(DEPDIR)/NetworkManager-wpa.Tpo $(DEPDIR)/NetworkManager-wpa.Po
-@am__fastdepCC_FALSE@	$(AM_V_CC) @AM_BACKSLASH@
-@AMDEP_TRUE@@am__fastdepCC_FALSE@	source='wpa.c' object='NetworkManager-wpa.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-wpa.o `test -f 'wpa.c' || echo '$(srcdir)/'`wpa.c
-
-NetworkManager-wpa.obj: wpa.c
-@am__fastdepCC_TRUE@	$(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(NetworkManager_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT NetworkManager-wpa.obj -MD -MP -MF $(DEPDIR)/NetworkManager-wpa.Tpo -c -o NetworkManager-wpa.obj `if test -f 'wpa.c'; then $(CYGPATH_W) 'wpa.c'; else $(CYGPATH_W) '$(srcdir)/wpa.c'; fi`
-@am__fastdepCC_TRUE@	$(AM_V_at)$(am__mv) $(DEPDIR)/NetworkManager-wpa.Tpo $(DEPDIR)/NetworkManager-wpa.Po
-@am__fastdepCC_FALSE@	$(AM_V_CC) @AM_BACKSLASH@
-@AMDEP_TRUE@@am__fastdepCC_FALSE@	source='wpa.c' object='NetworkManager-wpa.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-wpa.obj `if test -f 'wpa.c'; then $(CYGPATH_W) 'wpa.c'; else $(CYGPATH_W) '$(srcdir)/wpa.c'; fi`
-
 NetworkManager-nm-dhcp4-config.o: nm-dhcp4-config.c
 @am__fastdepCC_TRUE@	$(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(NetworkManager_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT NetworkManager-nm-dhcp4-config.o -MD -MP -MF $(DEPDIR)/NetworkManager-nm-dhcp4-config.Tpo -c -o NetworkManager-nm-dhcp4-config.o `test -f 'nm-dhcp4-config.c' || echo '$(srcdir)/'`nm-dhcp4-config.c
 @am__fastdepCC_TRUE@	$(AM_V_at)$(am__mv) $(DEPDIR)/NetworkManager-nm-dhcp4-config.Tpo $(DEPDIR)/NetworkManager-nm-dhcp4-config.Po
@@ -1491,21 +1530,85 @@ NetworkManager-nm-dhcp6-config.obj: nm-dhcp6-config.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-dhcp6-config.obj `if test -f 'nm-dhcp6-config.c'; then $(CYGPATH_W) 'nm-dhcp6-config.c'; else $(CYGPATH_W) '$(srcdir)/nm-dhcp6-config.c'; fi`
 
-NetworkManager-nm-session-monitor.o: nm-session-monitor.c
-@am__fastdepCC_TRUE@	$(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(NetworkManager_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT NetworkManager-nm-session-monitor.o -MD -MP -MF $(DEPDIR)/NetworkManager-nm-session-monitor.Tpo -c -o NetworkManager-nm-session-monitor.o `test -f 'nm-session-monitor.c' || echo '$(srcdir)/'`nm-session-monitor.c
-@am__fastdepCC_TRUE@	$(AM_V_at)$(am__mv) $(DEPDIR)/NetworkManager-nm-session-monitor.Tpo $(DEPDIR)/NetworkManager-nm-session-monitor.Po
+NetworkManager-nm-session-utils.o: nm-session-utils.c
+@am__fastdepCC_TRUE@	$(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(NetworkManager_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT NetworkManager-nm-session-utils.o -MD -MP -MF $(DEPDIR)/NetworkManager-nm-session-utils.Tpo -c -o NetworkManager-nm-session-utils.o `test -f 'nm-session-utils.c' || echo '$(srcdir)/'`nm-session-utils.c
+@am__fastdepCC_TRUE@	$(AM_V_at)$(am__mv) $(DEPDIR)/NetworkManager-nm-session-utils.Tpo $(DEPDIR)/NetworkManager-nm-session-utils.Po
+@am__fastdepCC_FALSE@	$(AM_V_CC) @AM_BACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@	source='nm-session-utils.c' object='NetworkManager-nm-session-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-session-utils.o `test -f 'nm-session-utils.c' || echo '$(srcdir)/'`nm-session-utils.c
+
+NetworkManager-nm-session-utils.obj: nm-session-utils.c
+@am__fastdepCC_TRUE@	$(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(NetworkManager_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT NetworkManager-nm-session-utils.obj -MD -MP -MF $(DEPDIR)/NetworkManager-nm-session-utils.Tpo -c -o NetworkManager-nm-session-utils.obj `if test -f 'nm-session-utils.c'; then $(CYGPATH_W) 'nm-session-utils.c'; else $(CYGPATH_W) '$(srcdir)/nm-session-utils.c'; fi`
+@am__fastdepCC_TRUE@	$(AM_V_at)$(am__mv) $(DEPDIR)/NetworkManager-nm-session-utils.Tpo $(DEPDIR)/NetworkManager-nm-session-utils.Po
+@am__fastdepCC_FALSE@	$(AM_V_CC) @AM_BACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@	source='nm-session-utils.c' object='NetworkManager-nm-session-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-session-utils.obj `if test -f 'nm-session-utils.c'; then $(CYGPATH_W) 'nm-session-utils.c'; else $(CYGPATH_W) '$(srcdir)/nm-session-utils.c'; fi`
+
+NetworkManager-nm-connectivity.o: nm-connectivity.c
+@am__fastdepCC_TRUE@	$(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(NetworkManager_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT NetworkManager-nm-connectivity.o -MD -MP -MF $(DEPDIR)/NetworkManager-nm-connectivity.Tpo -c -o NetworkManager-nm-connectivity.o `test -f 'nm-connectivity.c' || echo '$(srcdir)/'`nm-connectivity.c
+@am__fastdepCC_TRUE@	$(AM_V_at)$(am__mv) $(DEPDIR)/NetworkManager-nm-connectivity.Tpo $(DEPDIR)/NetworkManager-nm-connectivity.Po
+@am__fastdepCC_FALSE@	$(AM_V_CC) @AM_BACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@	source='nm-connectivity.c' object='NetworkManager-nm-connectivity.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-connectivity.o `test -f 'nm-connectivity.c' || echo '$(srcdir)/'`nm-connectivity.c
+
+NetworkManager-nm-connectivity.obj: nm-connectivity.c
+@am__fastdepCC_TRUE@	$(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(NetworkManager_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT NetworkManager-nm-connectivity.obj -MD -MP -MF $(DEPDIR)/NetworkManager-nm-connectivity.Tpo -c -o NetworkManager-nm-connectivity.obj `if test -f 'nm-connectivity.c'; then $(CYGPATH_W) 'nm-connectivity.c'; else $(CYGPATH_W) '$(srcdir)/nm-connectivity.c'; fi`
+@am__fastdepCC_TRUE@	$(AM_V_at)$(am__mv) $(DEPDIR)/NetworkManager-nm-connectivity.Tpo $(DEPDIR)/NetworkManager-nm-connectivity.Po
+@am__fastdepCC_FALSE@	$(AM_V_CC) @AM_BACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@	source='nm-connectivity.c' object='NetworkManager-nm-connectivity.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-connectivity.obj `if test -f 'nm-connectivity.c'; then $(CYGPATH_W) 'nm-connectivity.c'; else $(CYGPATH_W) '$(srcdir)/nm-connectivity.c'; fi`
+
+NetworkManager-nm-session-monitor-systemd.o: nm-session-monitor-systemd.c
+@am__fastdepCC_TRUE@	$(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(NetworkManager_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT NetworkManager-nm-session-monitor-systemd.o -MD -MP -MF $(DEPDIR)/NetworkManager-nm-session-monitor-systemd.Tpo -c -o NetworkManager-nm-session-monitor-systemd.o `test -f 'nm-session-monitor-systemd.c' || echo '$(srcdir)/'`nm-session-monitor-systemd.c
+@am__fastdepCC_TRUE@	$(AM_V_at)$(am__mv) $(DEPDIR)/NetworkManager-nm-session-monitor-systemd.Tpo $(DEPDIR)/NetworkManager-nm-session-monitor-systemd.Po
+@am__fastdepCC_FALSE@	$(AM_V_CC) @AM_BACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@	source='nm-session-monitor-systemd.c' object='NetworkManager-nm-session-monitor-systemd.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-session-monitor-systemd.o `test -f 'nm-session-monitor-systemd.c' || echo '$(srcdir)/'`nm-session-monitor-systemd.c
+
+NetworkManager-nm-session-monitor-systemd.obj: nm-session-monitor-systemd.c
+@am__fastdepCC_TRUE@	$(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(NetworkManager_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT NetworkManager-nm-session-monitor-systemd.obj -MD -MP -MF $(DEPDIR)/NetworkManager-nm-session-monitor-systemd.Tpo -c -o NetworkManager-nm-session-monitor-systemd.obj `if test -f 'nm-session-monitor-systemd.c'; then $(CYGPATH_W) 'nm-session-monitor-systemd.c'; else $(CYGPATH_W) '$(srcdir)/nm-session-monitor-systemd.c'; fi`
+@am__fastdepCC_TRUE@	$(AM_V_at)$(am__mv) $(DEPDIR)/NetworkManager-nm-session-monitor-systemd.Tpo $(DEPDIR)/NetworkManager-nm-session-monitor-systemd.Po
+@am__fastdepCC_FALSE@	$(AM_V_CC) @AM_BACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@	source='nm-session-monitor-systemd.c' object='NetworkManager-nm-session-monitor-systemd.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-session-monitor-systemd.obj `if test -f 'nm-session-monitor-systemd.c'; then $(CYGPATH_W) 'nm-session-monitor-systemd.c'; else $(CYGPATH_W) '$(srcdir)/nm-session-monitor-systemd.c'; fi`
+
+NetworkManager-nm-session-monitor-ck.o: nm-session-monitor-ck.c
+@am__fastdepCC_TRUE@	$(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(NetworkManager_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT NetworkManager-nm-session-monitor-ck.o -MD -MP -MF $(DEPDIR)/NetworkManager-nm-session-monitor-ck.Tpo -c -o NetworkManager-nm-session-monitor-ck.o `test -f 'nm-session-monitor-ck.c' || echo '$(srcdir)/'`nm-session-monitor-ck.c
+@am__fastdepCC_TRUE@	$(AM_V_at)$(am__mv) $(DEPDIR)/NetworkManager-nm-session-monitor-ck.Tpo $(DEPDIR)/NetworkManager-nm-session-monitor-ck.Po
 @am__fastdepCC_FALSE@	$(AM_V_CC) @AM_BACKSLASH@
-@AMDEP_TRUE@@am__fastdepCC_FALSE@	source='nm-session-monitor.c' object='NetworkManager-nm-session-monitor.o' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@	source='nm-session-monitor-ck.c' object='NetworkManager-nm-session-monitor-ck.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-session-monitor.o `test -f 'nm-session-monitor.c' || echo '$(srcdir)/'`nm-session-monitor.c
+@am__fastdepCC_FALSE@	$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(NetworkManager_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o NetworkManager-nm-session-monitor-ck.o `test -f 'nm-session-monitor-ck.c' || echo '$(srcdir)/'`nm-session-monitor-ck.c
 
-NetworkManager-nm-session-monitor.obj: nm-session-monitor.c
-@am__fastdepCC_TRUE@	$(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(NetworkManager_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT NetworkManager-nm-session-monitor.obj -MD -MP -MF $(DEPDIR)/NetworkManager-nm-session-monitor.Tpo -c -o NetworkManager-nm-session-monitor.obj `if test -f 'nm-session-monitor.c'; then $(CYGPATH_W) 'nm-session-monitor.c'; else $(CYGPATH_W) '$(srcdir)/nm-session-monitor.c'; fi`
-@am__fastdepCC_TRUE@	$(AM_V_at)$(am__mv) $(DEPDIR)/NetworkManager-nm-session-monitor.Tpo $(DEPDIR)/NetworkManager-nm-session-monitor.Po
+NetworkManager-nm-session-monitor-ck.obj: nm-session-monitor-ck.c
+@am__fastdepCC_TRUE@	$(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(NetworkManager_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT NetworkManager-nm-session-monitor-ck.obj -MD -MP -MF $(DEPDIR)/NetworkManager-nm-session-monitor-ck.Tpo -c -o NetworkManager-nm-session-monitor-ck.obj `if test -f 'nm-session-monitor-ck.c'; then $(CYGPATH_W) 'nm-session-monitor-ck.c'; else $(CYGPATH_W) '$(srcdir)/nm-session-monitor-ck.c'; fi`
+@am__fastdepCC_TRUE@	$(AM_V_at)$(am__mv) $(DEPDIR)/NetworkManager-nm-session-monitor-ck.Tpo $(DEPDIR)/NetworkManager-nm-session-monitor-ck.Po
 @am__fastdepCC_FALSE@	$(AM_V_CC) @AM_BACKSLASH@
-@AMDEP_TRUE@@am__fastdepCC_FALSE@	source='nm-session-monitor.c' object='NetworkManager-nm-session-monitor.obj' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@	source='nm-session-monitor-ck.c' object='NetworkManager-nm-session-monitor-ck.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-session-monitor.obj `if test -f 'nm-session-monitor.c'; then $(CYGPATH_W) 'nm-session-monitor.c'; else $(CYGPATH_W) '$(srcdir)/nm-session-monitor.c'; fi`
+@am__fastdepCC_FALSE@	$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(NetworkManager_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o NetworkManager-nm-session-monitor-ck.obj `if test -f 'nm-session-monitor-ck.c'; then $(CYGPATH_W) 'nm-session-monitor-ck.c'; else $(CYGPATH_W) '$(srcdir)/nm-session-monitor-ck.c'; fi`
+
+NetworkManager-nm-session-monitor-null.o: nm-session-monitor-null.c
+@am__fastdepCC_TRUE@	$(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(NetworkManager_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT NetworkManager-nm-session-monitor-null.o -MD -MP -MF $(DEPDIR)/NetworkManager-nm-session-monitor-null.Tpo -c -o NetworkManager-nm-session-monitor-null.o `test -f 'nm-session-monitor-null.c' || echo '$(srcdir)/'`nm-session-monitor-null.c
+@am__fastdepCC_TRUE@	$(AM_V_at)$(am__mv) $(DEPDIR)/NetworkManager-nm-session-monitor-null.Tpo $(DEPDIR)/NetworkManager-nm-session-monitor-null.Po
+@am__fastdepCC_FALSE@	$(AM_V_CC) @AM_BACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@	source='nm-session-monitor-null.c' object='NetworkManager-nm-session-monitor-null.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-session-monitor-null.o `test -f 'nm-session-monitor-null.c' || echo '$(srcdir)/'`nm-session-monitor-null.c
+
+NetworkManager-nm-session-monitor-null.obj: nm-session-monitor-null.c
+@am__fastdepCC_TRUE@	$(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(NetworkManager_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT NetworkManager-nm-session-monitor-null.obj -MD -MP -MF $(DEPDIR)/NetworkManager-nm-session-monitor-null.Tpo -c -o NetworkManager-nm-session-monitor-null.obj `if test -f 'nm-session-monitor-null.c'; then $(CYGPATH_W) 'nm-session-monitor-null.c'; else $(CYGPATH_W) '$(srcdir)/nm-session-monitor-null.c'; fi`
+@am__fastdepCC_TRUE@	$(AM_V_at)$(am__mv) $(DEPDIR)/NetworkManager-nm-session-monitor-null.Tpo $(DEPDIR)/NetworkManager-nm-session-monitor-null.Po
+@am__fastdepCC_FALSE@	$(AM_V_CC) @AM_BACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@	source='nm-session-monitor-null.c' object='NetworkManager-nm-session-monitor-null.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-session-monitor-null.obj `if test -f 'nm-session-monitor-null.c'; then $(CYGPATH_W) 'nm-session-monitor-null.c'; else $(CYGPATH_W) '$(srcdir)/nm-session-monitor-null.c'; fi`
 
 nm_crash_logger-nm-crash-logger.o: nm-crash-logger.c
 @am__fastdepCC_TRUE@	$(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(nm_crash_logger_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT nm_crash_logger-nm-crash-logger.o -MD -MP -MF $(DEPDIR)/nm_crash_logger-nm-crash-logger.Tpo -c -o nm_crash_logger-nm-crash-logger.o `test -f 'nm-crash-logger.c' || echo '$(srcdir)/'`nm-crash-logger.c
@@ -1909,6 +2012,9 @@ nm-device-interface-glue.h: $(top_srcdir)/introspection/nm-device.xml
 nm-device-ethernet-glue.h: $(top_srcdir)/introspection/nm-device-ethernet.xml
 	$(AM_V_GEN) dbus-binding-tool --prefix=nm_device_ethernet --mode=glib-server --output=$@ $<
 
+nm-device-infiniband-glue.h: $(top_srcdir)/introspection/nm-device-infiniband.xml
+	$(AM_V_GEN) dbus-binding-tool --prefix=nm_device_infiniband --mode=glib-server --output=$@ $<
+
 nm-device-wifi-glue.h: $(top_srcdir)/introspection/nm-device-wifi.xml
 	$(AM_V_GEN) dbus-binding-tool --prefix=nm_device_wifi --mode=glib-server --output=$@ $<
 
@@ -1918,6 +2024,12 @@ nm-device-bt-glue.h: $(top_srcdir)/introspection/nm-device-bt.xml
 nm-device-olpc-mesh-glue.h: $(top_srcdir)/introspection/nm-device-olpc-mesh.xml
 	$(AM_V_GEN) dbus-binding-tool --prefix=nm_device_olpc_mesh --mode=glib-server --output=$@ $<
 
+nm-device-bond-glue.h: $(top_srcdir)/introspection/nm-device-bond.xml
+	$(AM_V_GEN) dbus-binding-tool --prefix=nm_device_bond --mode=glib-server --output=$@ $<
+
+nm-device-vlan-glue.h: $(top_srcdir)/introspection/nm-device-vlan.xml
+	$(AM_V_GEN) dbus-binding-tool --prefix=nm_device_vlan --mode=glib-server --output=$@ $<
+
 nm-ip4-config-glue.h: $(top_srcdir)/introspection/nm-ip4-config.xml
 	$(AM_V_GEN) dbus-binding-tool --prefix=nm_ip4_config --mode=glib-server --output=$@ $<
 
@@ -1935,6 +2047,7 @@ nm-dhcp6-config-glue.h: $(top_srcdir)/introspection/nm-dhcp6-config.xml
 
 nm-device-modem-glue.h: $(top_srcdir)/introspection/nm-device-modem.xml
 	$(AM_V_GEN) dbus-binding-tool --prefix=nm_device_modem --mode=glib-server --output=$@ $<
+	-DARP_DEBUG
 install-data-hook:
 	$(mkinstalldirs) -m 0700 $(DESTDIR)$(rundir)
 	$(mkinstalldirs) -m 0700 $(DESTDIR)$(statedir)
diff --git a/src/NetworkManagerUtils.c b/src/NetworkManagerUtils.c
index 451de6d0..6c2c0446 100644
--- a/src/NetworkManagerUtils.c
+++ b/src/NetworkManagerUtils.c
@@ -32,8 +32,6 @@
 #include "nm-utils.h"
 #include "nm-logging.h"
 #include "nm-device.h"
-#include "nm-device-wifi.h"
-#include "nm-device-ethernet.h"
 #include "nm-dbus-manager.h"
 #include "nm-dispatcher-action.h"
 #include "nm-dbus-glib-types.h"
@@ -159,22 +157,11 @@ nm_utils_ip4_prefix_to_netmask (guint32 prefix)
 	return (guint32) htonl (netmask);
 }
 
-char *
-nm_ether_ntop (const struct ether_addr *mac)
-{
-	/* we like leading zeros and all-caps, instead
-	 * of what glibc's ether_ntop() gives us
-	 */
-	return 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]);
-}
-
 void
 nm_utils_merge_ip4_config (NMIP4Config *ip4_config, NMSettingIP4Config *setting)
 {
 	int i, j;
+	gboolean setting_never_default;
 
 	if (!setting)
 		return; /* Defaults are just fine */
@@ -264,8 +251,14 @@ nm_utils_merge_ip4_config (NMIP4Config *ip4_config, NMSettingIP4Config *setting)
 			nm_ip4_config_add_route (ip4_config, setting_route);
 	}
 
-	if (nm_setting_ip4_config_get_never_default (setting))
-		nm_ip4_config_set_never_default (ip4_config, TRUE);
+	setting_never_default = nm_setting_ip4_config_get_never_default (setting);
+
+	if (nm_setting_ip4_config_get_ignore_auto_routes (setting))
+		nm_ip4_config_set_never_default (ip4_config, setting_never_default);
+	else {
+		if (setting_never_default)
+			nm_ip4_config_set_never_default (ip4_config, TRUE);
+	}
 }
 
 static inline gboolean
@@ -862,7 +855,7 @@ nm_utils_do_sysctl (const char *path, const char *value)
 gboolean
 nm_utils_get_proc_sys_net_value (const char *path,
                                  const char *iface,
-                                 guint32 *out_value)
+                                 gint32 *out_value)
 {
 	GError *error = NULL;
 	char *contents = NULL;
@@ -878,8 +871,8 @@ nm_utils_get_proc_sys_net_value (const char *path,
 	} else {
 		errno = 0;
 		tmp = strtol (contents, NULL, 10);
-		if ((errno == 0) && (tmp == 0 || tmp == 1)) {
-			*out_value = (guint32) tmp;
+		if (errno == 0) {
+			*out_value = (gint32) tmp;
 			success = TRUE;
 		}
 		g_free (contents);
@@ -888,6 +881,28 @@ nm_utils_get_proc_sys_net_value (const char *path,
 	return success;
 }
 
+gboolean
+nm_utils_get_proc_sys_net_value_with_bounds (const char *path,
+                                             const char *iface,
+                                             gint32 *out_value,
+                                             gint32 valid_min,
+                                             gint32 valid_max)
+{
+	gboolean result;
+	gint32 val;
+
+	result = nm_utils_get_proc_sys_net_value (path, iface, &val);
+
+	if (result) {
+		if (val >= valid_min && val <= valid_max)
+			*out_value = val;
+		else
+			result = FALSE;
+	}
+
+	return result;
+}
+
 static char *
 get_new_connection_name (const GSList *existing,
                          const char *format,
@@ -955,7 +970,7 @@ nm_utils_complete_generic (NMConnection *connection,
 	const char *method;
 	char *id, *uuid;
 
-	s_con = (NMSettingConnection *) nm_connection_get_setting (connection, NM_TYPE_SETTING_CONNECTION);
+	s_con = nm_connection_get_setting_connection (connection);
 	if (!s_con) {
 		s_con = (NMSettingConnection *) nm_setting_connection_new ();
 		nm_connection_add_setting (connection, NM_SETTING (s_con));
@@ -976,7 +991,7 @@ nm_utils_complete_generic (NMConnection *connection,
 	}
 
 	/* Add an 'auto' IPv4 connection if present */
-	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) {
 		s_ip4 = (NMSettingIP4Config *) nm_setting_ip4_config_new ();
 		nm_connection_add_setting (connection, NM_SETTING (s_ip4));
@@ -989,7 +1004,7 @@ nm_utils_complete_generic (NMConnection *connection,
 	}
 
 	/* Add an 'auto' IPv6 setting if allowed and not preset */
-	s_ip6 = (NMSettingIP6Config *) nm_connection_get_setting (connection, NM_TYPE_SETTING_IP6_CONFIG);
+	s_ip6 = nm_connection_get_setting_ip6_config (connection);
 	if (!s_ip6 && default_enable_ipv6) {
 		s_ip6 = (NMSettingIP6Config *) nm_setting_ip6_config_new ();
 		nm_connection_add_setting (connection, NM_SETTING (s_ip6));
@@ -1002,3 +1017,26 @@ nm_utils_complete_generic (NMConnection *connection,
 	}
 }
 
+gboolean
+nm_utils_is_uuid (const char *str)
+{
+	const char *p = str;
+	int num_dashes = 0;
+
+	while (*p) {
+		if (*p == '-')
+			num_dashes++;
+		else if (!isxdigit (*p))
+			return FALSE;
+		p++;
+	}
+
+	return (num_dashes == 4) && (p - str == 36);
+}
+
+char *
+nm_utils_new_vlan_name (const char *parent_iface, guint32 vlan_id)
+{
+	return g_strdup_printf ("%s.%d", parent_iface, vlan_id);
+}
+
diff --git a/src/NetworkManagerUtils.h b/src/NetworkManagerUtils.h
index 1bf741ed..2474f654 100644
--- a/src/NetworkManagerUtils.h
+++ b/src/NetworkManagerUtils.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) 2004 - 2010 Red Hat, Inc.
+ * Copyright (C) 2004 - 2011 Red Hat, Inc.
  * Copyright (C) 2005 - 2008 Novell, Inc.
  */
 
@@ -37,8 +37,6 @@ gboolean nm_ethernet_address_is_valid (const struct ether_addr *test_addr);
 
 int nm_spawn_process (const char *args);
 
-char *nm_ether_ntop (const struct ether_addr *mac);
-
 void nm_utils_merge_ip4_config (NMIP4Config *ip4_config, NMSettingIP4Config *setting);
 void nm_utils_merge_ip6_config (NMIP6Config *ip6_config, NMSettingIP6Config *setting);
 
@@ -85,7 +83,13 @@ gboolean nm_utils_do_sysctl (const char *path, const char *value);
 
 gboolean nm_utils_get_proc_sys_net_value (const char *path,
                                           const char *iface,
-                                          guint32 *out_value);
+                                          gint32 *out_value);
+
+gboolean nm_utils_get_proc_sys_net_value_with_bounds (const char *path,
+                                                      const char *iface,
+                                                      gint32 *out_value,
+                                                      gint32 valid_min,
+                                                      gint32 valid_max);
 
 void nm_utils_complete_generic (NMConnection *connection,
                                 const char *ctype,
@@ -94,4 +98,8 @@ void nm_utils_complete_generic (NMConnection *connection,
                                 const char *preferred,
                                 gboolean default_enable_ipv6);
 
+gboolean nm_utils_is_uuid (const char *str);
+
+char *nm_utils_new_vlan_name (const char *parent_iface, guint32 vlan_id);
+
 #endif /* NETWORK_MANAGER_UTILS_H */
diff --git a/src/backends/Makefile.am b/src/backends/Makefile.am
index c0780d0b..11a154a0 100644
--- a/src/backends/Makefile.am
+++ b/src/backends/Makefile.am
@@ -2,13 +2,16 @@ INCLUDES = \
 	-I${top_srcdir} \
 	-I${top_srcdir}/src/logging \
 	-I${top_srcdir}/include \
+	-I${top_builddir}/include \
 	-I${top_srcdir}/src \
 	-I${top_srcdir}/libnm-util
 
 noinst_LTLIBRARIES = libnmbackend.la
 
-libnmbackend_la_SOURCES = NetworkManagerGeneric.c	\
-				NetworkManagerGeneric.h
+libnmbackend_la_SOURCES = \
+	NetworkManagerGeneric.c \
+	NetworkManagerGeneric.h \
+	nm-backend.h
 
 libnmbackend_la_LIBADD =
 
diff --git a/src/backends/Makefile.in b/src/backends/Makefile.in
index 87d3df4e..9c6f7d0c 100644
--- a/src/backends/Makefile.in
+++ b/src/backends/Makefile.in
@@ -74,7 +74,7 @@ libnmbackend_la_DEPENDENCIES = $(am__DEPENDENCIES_1) \
 	$(am__DEPENDENCIES_1) $(am__DEPENDENCIES_1) \
 	$(am__DEPENDENCIES_1)
 am__libnmbackend_la_SOURCES_DIST = NetworkManagerGeneric.c \
-	NetworkManagerGeneric.h NetworkManagerRedHat.c \
+	NetworkManagerGeneric.h nm-backend.h NetworkManagerRedHat.c \
 	NetworkManagerSuSE.c NetworkManagerGentoo.c \
 	NetworkManagerDebian.c NetworkManagerSlackware.c \
 	NetworkManagerArch.c NetworkManagerPaldo.c \
@@ -187,6 +187,8 @@ GIO_LIBS = @GIO_LIBS@
 GLIB_CFLAGS = @GLIB_CFLAGS@
 GLIB_GENMARSHAL = @GLIB_GENMARSHAL@
 GLIB_LIBS = @GLIB_LIBS@
+GLIB_MAKEFILE = @GLIB_MAKEFILE@
+GLIB_MKENUMS = @GLIB_MKENUMS@
 GMODULE_CFLAGS = @GMODULE_CFLAGS@
 GMODULE_LIBS = @GMODULE_LIBS@
 GMSGFMT = @GMSGFMT@
@@ -241,11 +243,15 @@ LIBNL2_LIBS = @LIBNL2_LIBS@
 LIBNL3_CFLAGS = @LIBNL3_CFLAGS@
 LIBNL3_LIBS = @LIBNL3_LIBS@
 LIBNL_CFLAGS = @LIBNL_CFLAGS@
+LIBNL_GENL3_CFLAGS = @LIBNL_GENL3_CFLAGS@
+LIBNL_GENL3_LIBS = @LIBNL_GENL3_LIBS@
 LIBNL_LIBS = @LIBNL_LIBS@
 LIBNL_ROUTE3_CFLAGS = @LIBNL_ROUTE3_CFLAGS@
 LIBNL_ROUTE3_LIBS = @LIBNL_ROUTE3_LIBS@
 LIBOBJS = @LIBOBJS@
 LIBS = @LIBS@
+LIBSOUP_CFLAGS = @LIBSOUP_CFLAGS@
+LIBSOUP_LIBS = @LIBSOUP_LIBS@
 LIBTOOL = @LIBTOOL@
 LIPO = @LIPO@
 LN_S = @LN_S@
@@ -256,6 +262,7 @@ MAINT = @MAINT@
 MAKEINFO = @MAKEINFO@
 MANIFEST_TOOL = @MANIFEST_TOOL@
 MKDIR_P = @MKDIR_P@
+MOC = @MOC@
 MSGFMT = @MSGFMT@
 MSGFMT_015 = @MSGFMT_015@
 MSGMERGE = @MSGMERGE@
@@ -295,6 +302,8 @@ SED = @SED@
 SET_MAKE = @SET_MAKE@
 SHELL = @SHELL@
 STRIP = @STRIP@
+SYSTEMD_CFLAGS = @SYSTEMD_CFLAGS@
+SYSTEMD_LIBS = @SYSTEMD_LIBS@
 SYSTEM_CA_PATH = @SYSTEM_CA_PATH@
 UDEV_BASE_DIR = @UDEV_BASE_DIR@
 USE_NLS = @USE_NLS@
@@ -362,16 +371,17 @@ INCLUDES = \
 	-I${top_srcdir} \
 	-I${top_srcdir}/src/logging \
 	-I${top_srcdir}/include \
+	-I${top_builddir}/include \
 	-I${top_srcdir}/src \
 	-I${top_srcdir}/libnm-util
 
 noinst_LTLIBRARIES = libnmbackend.la
 libnmbackend_la_SOURCES = NetworkManagerGeneric.c \
-	NetworkManagerGeneric.h $(am__append_1) $(am__append_2) \
-	$(am__append_3) $(am__append_4) $(am__append_5) \
-	$(am__append_6) $(am__append_7) $(am__append_8) \
-	$(am__append_10) $(am__append_11) $(am__append_12) \
-	$(am__append_13)
+	NetworkManagerGeneric.h nm-backend.h $(am__append_1) \
+	$(am__append_2) $(am__append_3) $(am__append_4) \
+	$(am__append_5) $(am__append_6) $(am__append_7) \
+	$(am__append_8) $(am__append_10) $(am__append_11) \
+	$(am__append_12) $(am__append_13)
 libnmbackend_la_LIBADD = $(am__append_9) \
 	$(top_builddir)/src/logging/libnm-logging.la $(LIBNL_LIBS) \
 	$(DBUS_LIBS) $(GLIB_LIBS)
diff --git a/src/backends/NetworkManagerArch.c b/src/backends/NetworkManagerArch.c
index c70e2459..7e25ee37 100644
--- a/src/backends/NetworkManagerArch.c
+++ b/src/backends/NetworkManagerArch.c
@@ -28,43 +28,33 @@
  *
  * (C) Copyright 2004 Tom Parker
  * (C) Copyright 2004 Matthew Garrett
- * (C) Copyright 2004 Red Hat, Inc.
+ * (C) Copyright 2004 - 2012 Red Hat, Inc.
  */
 
 #ifdef HAVE_CONFIG_H
 #include <config.h>
 #endif
 
-#include <stdio.h>
-#include <string.h>
-#include <stdlib.h>
-
 #include "NetworkManagerGeneric.h"
-#include "nm-system.h"
 #include "NetworkManagerUtils.h"
 
-/*
- * nm_system_enable_loopback
- *
- * Bring up the loopback interface
- *
- */
-void nm_system_enable_loopback (void)
+void nm_backend_enable_loopback (void)
 {
 	nm_generic_enable_loopback ();
 }
 
-/*
- * nm_system_update_dns
- *
- * Make glibc/nscd aware of any changes to the resolv.conf file by
- * restarting nscd.
- *
- */
-void nm_system_update_dns (void)
+void nm_backend_update_dns (void)
 {
-	/* Check if the daemon was already running - do not start a new instance */
+	/* Make glibc/nscd aware of any changes to the resolv.conf file by
+	 * restarting nscd; check if the daemon was already running - do not
+	 * start a new instance
+	 */
 	if (g_file_test("/var/run/daemons/nscd", G_FILE_TEST_EXISTS))
 		nm_spawn_process ("/etc/rc.d/nscd restart");
 }
 
+int nm_backend_ipv6_use_tempaddr (void)
+{
+	return nm_generic_ipv6_use_tempaddr ();
+}
+
diff --git a/src/backends/NetworkManagerDebian.c b/src/backends/NetworkManagerDebian.c
index 37eb6457..ed29dd3a 100644
--- a/src/backends/NetworkManagerDebian.c
+++ b/src/backends/NetworkManagerDebian.c
@@ -21,29 +21,18 @@
  *
  * (C) Copyright 2004 Tom Parker
  * (C) Copyright 2004 Matthew Garrett
- * (C) Copyright 2004 Red Hat, Inc.
+ * (C) Copyright 2004 - 2012 Red Hat, Inc.
  */
 
 #ifdef HAVE_CONFIG_H
 #include <config.h>
 #endif
 
-#include <stdio.h>
-#include <string.h>
-#include <stdlib.h>
-
 #include "NetworkManagerGeneric.h"
-#include "nm-system.h"
 #include "NetworkManagerUtils.h"
 #include "nm-logging.h"
 
-/*
- * nm_system_enable_loopback
- *
- * Bring up the loopback interface
- *
- */
-void nm_system_enable_loopback (void)
+void nm_backend_enable_loopback (void)
 {
 	/* ifupdown isn't always installed (bgo #625427) */
 	if (g_file_test ("/sbin/ifup", G_FILE_TEST_EXISTS))
@@ -52,18 +41,17 @@ void nm_system_enable_loopback (void)
 		nm_generic_enable_loopback ();
 }
 
-/*
- * nm_system_update_dns
- *
- * Invalidate the nscd host cache, if it exists, since
- * we changed resolv.conf.
- *
- */
-void nm_system_update_dns (void)
+void nm_backend_update_dns (void)
 {
+	/* Invalidate the nscd host cache since we changed resolv.conf */
 	if (g_file_test ("/usr/sbin/nscd", G_FILE_TEST_IS_EXECUTABLE)) {
 		nm_log_info (LOGD_DNS, "Clearing nscd hosts cache.");
 		nm_spawn_process ("/usr/sbin/nscd -i hosts");
 	}
 }
 
+int nm_backend_ipv6_use_tempaddr (void)
+{
+	return nm_generic_ipv6_use_tempaddr ();
+}
+
diff --git a/src/backends/NetworkManagerExherbo.c b/src/backends/NetworkManagerExherbo.c
index d7e24cf6..d0277896 100644
--- a/src/backends/NetworkManagerExherbo.c
+++ b/src/backends/NetworkManagerExherbo.c
@@ -18,7 +18,7 @@
  * with this program; if not, write to the Free Software Foundation, Inc.,
  * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
  *
- * (C) Copyright 2004 Red Hat, Inc.
+ * (C) Copyright 2004 - 2012 Red Hat, Inc.
  * (C) Copyright 2004 Dan Willemsen
  * (C) Copyright 2004 Robert Paskowitz
  */
@@ -27,38 +27,28 @@
 #include <config.h>
 #endif
 
-#include <stdio.h>
-#include <string.h>
-#include <stdlib.h>
-
 #include "NetworkManagerGeneric.h"
-#include "nm-system.h"
 #include "NetworkManagerUtils.h"
 #include "nm-logging.h"
 
-/*
- * nm_system_enable_loopback
- *
- * Bring up the loopback interface
- *
- */
-void nm_system_enable_loopback (void)
+void nm_backend_enable_loopback (void)
 {
 	nm_generic_enable_loopback ();
 }
 
-/*
- * nm_system_update_dns
- *
- * Make glibc/nscd aware of any changes to the resolv.conf file by
- * restarting nscd. Only restart if already running.
- *
- */
-void nm_system_update_dns (void)
+void nm_backend_update_dns (void)
 {
+	/* Make glibc/nscd aware of any changes to the resolv.conf file by
+	 * restarting nscd. Only restart if already running.
+	 */
 	if (g_file_test ("/usr/sbin/nscd", G_FILE_TEST_IS_EXECUTABLE)) {
 		nm_log_info (LOGD_DNS, "Clearing nscd hosts cache.");
 		nm_spawn_process ("/usr/sbin/nscd -i hosts");
 	}
 }
 
+int nm_backend_ipv6_use_tempaddr (void)
+{
+	return nm_generic_ipv6_use_tempaddr ();
+}
+
diff --git a/src/backends/NetworkManagerFrugalware.c b/src/backends/NetworkManagerFrugalware.c
index dfe62921..301751e9 100644
--- a/src/backends/NetworkManagerFrugalware.c
+++ b/src/backends/NetworkManagerFrugalware.c
@@ -23,36 +23,21 @@
  * (C) Copyright 2006 Alex Smith
  */
 
-#include <stdio.h>
-#include <string.h>
-#include <stdlib.h>
-
-#include "nm-system.h"
-
 /* Provided by the frugalwareutils package on Frugalware */
 #include <libfwnetconfig.h> 
 
-/*
- * nm_system_enable_loopback
- *
- * Bring up the loopback interface
- *
- */
-void nm_system_enable_loopback (void)
+void nm_backend_enable_loopback (void)
 {
 	fwnet_loup ();
 }
 
-
-/*
- * nm_system_update_dns
- *
- * Make glibc/nscd aware of any changes to the resolv.conf file by
- * restarting nscd.
- *
- */
-void nm_system_update_dns (void)
+void nm_backend_update_dns (void)
 {
 	/* I'm not running nscd */
 }
 
+int nm_backend_ipv6_use_tempaddr (void)
+{
+	return nm_generic_ipv6_use_tempaddr ();
+}
+
diff --git a/src/backends/NetworkManagerGeneric.c b/src/backends/NetworkManagerGeneric.c
index 89b8a46d..eae6f733 100644
--- a/src/backends/NetworkManagerGeneric.c
+++ b/src/backends/NetworkManagerGeneric.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.
  *
- * (C) Copyright 2004 - 2010 Red Hat, Inc.
+ * (C) Copyright 2004 - 2012 Red Hat, Inc.
  * (C) Copyright 2006 Timothee Lecomte <timothee.lecomte@ens.fr>
  */
 
@@ -113,3 +113,65 @@ void nm_generic_update_dns (void)
 {
 }
 
+/*
+ * nm_generic_ipv6_use_tempaddr
+ *
+ * Get net.ipv6.conf.default.use_tempaddr value from /etc/sysctl.conf or
+ * /lib/sysctl.d/sysctl.conf
+ *
+ */
+int nm_generic_ipv6_use_tempaddr (void)
+{
+	char *contents = NULL;
+	gsize len = 0;
+	const char *group_name = "[forged_group]\n";
+	char *sysctl_data = NULL;
+	GKeyFile *keyfile;
+	GError *error = NULL;
+	int tmp, ret = -1;
+
+	/* Read file contents to a string. */
+	if (!g_file_get_contents ("/etc/sysctl.conf", &contents, &len, NULL))
+		if (!g_file_get_contents ("/lib/sysctl.d/sysctl.conf", &contents, &len, NULL))
+			return -1;
+
+	/* Prepend a group so that we can use GKeyFile parser. */
+	sysctl_data = g_strdup_printf ("%s%s", group_name, contents);
+
+	keyfile = g_key_file_new ();
+	if (keyfile == NULL)
+		goto done;
+
+	if (!g_key_file_load_from_data (keyfile, sysctl_data, len + strlen (group_name), G_KEY_FILE_NONE, NULL))
+		goto done;
+
+	tmp = g_key_file_get_integer (keyfile, "forged_group", "net.ipv6.conf.default.use_tempaddr", &error);
+	if (error == NULL)
+		ret = tmp;
+
+done:
+	g_free (contents);
+	g_free (sysctl_data);
+	g_clear_error (&error);
+	g_key_file_free (keyfile);
+
+	return ret;
+}
+
+#ifdef TARGET_GENERIC
+void nm_backend_enable_loopback (void)
+{
+	nm_generic_enable_loopback ();
+}
+
+void nm_backend_update_dns (void)
+{
+	nm_generic_update_dns ();
+}
+
+int nm_backend_ipv6_use_tempaddr (void)
+{
+	return nm_generic_ipv6_use_tempaddr ();
+}
+#endif
+
diff --git a/src/backends/NetworkManagerGeneric.h b/src/backends/NetworkManagerGeneric.h
index 0a0a88a2..3d4017e4 100644
--- a/src/backends/NetworkManagerGeneric.h
+++ b/src/backends/NetworkManagerGeneric.h
@@ -18,13 +18,16 @@
  * with this program; if not, write to the Free Software Foundation, Inc.,
  * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
  *
- * (C) Copyright 2004 Red Hat, Inc.
+ * (C) Copyright 2004 - 2012 Red Hat, Inc.
  */
 
-#ifndef NETWORK_MANAGER_GENERIC_H
-#define NETWORK_MANAGER_GENERIC_H
+#ifndef NM_GENERIC_H
+#define NM_GENERIC_H
 
-void nm_generic_enable_loopback	(void);
-void nm_generic_update_dns		(void);
+#include "nm-backend.h"
 
-#endif
+void nm_generic_enable_loopback (void);
+void nm_generic_update_dns      (void);
+int nm_generic_ipv6_use_tempaddr (void);
+
+#endif  /* NM_GENERIC_H */
diff --git a/src/backends/NetworkManagerGentoo.c b/src/backends/NetworkManagerGentoo.c
index e5b09384..7370645a 100644
--- a/src/backends/NetworkManagerGentoo.c
+++ b/src/backends/NetworkManagerGentoo.c
@@ -18,7 +18,7 @@
  * with this program; if not, write to the Free Software Foundation, Inc.,
  * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
  *
- * (C) Copyright 2004 Red Hat, Inc.
+ * (C) Copyright 2004 - 2012 Red Hat, Inc.
  * (C) Copyright 2004 Dan Willemsen
  * (C) Copyright 2004 Robert Paskowitz
  */
@@ -27,18 +27,12 @@
 #include <config.h>
 #endif
 
-#include <stdio.h>
-#include <string.h>
-#include <stdlib.h>
-#include <gio/gio.h>
+#include <glib.h>
 
 #include "NetworkManagerGeneric.h"
-#include "nm-system.h"
 #include "NetworkManagerUtils.h"
 #include "nm-logging.h"
 
-#define BUFFER_SIZE 512
-
 static void openrc_start_lo_if_necessary() 
 {
 	/* No need to run net.lo if it is already running */
@@ -46,18 +40,11 @@ static void openrc_start_lo_if_necessary()
                 nm_spawn_process ("/etc/init.d/net.lo start");
 }
 
-/*
- * nm_system_enable_loopback
- *
- * Bring up the loopback interface
- *
- */
-void nm_system_enable_loopback (void)
+void nm_backend_enable_loopback (void)
 {
 	gchar *comm;
 
-	/* If anything goes wrong trying to open /proc/1/comm, we will assume
-	   OpenRC. */
+	/* If anything goes wrong trying to open /proc/1/comm, we will assume OpenRC */
 	if (!g_file_get_contents ("/proc/1/comm", &comm, NULL, NULL)) {
 		nm_log_info (LOGD_CORE, "NetworkManager is running with OpenRC...");
 		openrc_start_lo_if_necessary ();
@@ -77,18 +64,19 @@ void nm_system_enable_loopback (void)
 	g_free (comm);
 }
 
-/*
- * nm_system_update_dns
- *
- * Make glibc/nscd aware of any changes to the resolv.conf file by
- * restarting nscd. Only restart if already running.
- *
- */
-void nm_system_update_dns (void)
+void nm_backend_update_dns (void)
 {
+	/* Make glibc/nscd aware of any changes to the resolv.conf file by
+	 * restarting nscd. Only restart if already running.
+	 */
 	if (g_file_test ("/usr/sbin/nscd", G_FILE_TEST_IS_EXECUTABLE)) {
 		nm_log_info (LOGD_DNS, "Clearing nscd hosts cache.");
 		nm_spawn_process ("/usr/sbin/nscd -i hosts");
 	}
 }
 
+int nm_backend_ipv6_use_tempaddr (void)
+{
+	return nm_generic_ipv6_use_tempaddr ();
+}
+
diff --git a/src/backends/NetworkManagerLinexa.c b/src/backends/NetworkManagerLinexa.c
index 015aa17c..34fed3bb 100644
--- a/src/backends/NetworkManagerLinexa.c
+++ b/src/backends/NetworkManagerLinexa.c
@@ -21,46 +21,33 @@
  *
  * (C) Copyright 2004 Tom Parker
  * (C) Copyright 2004 Matthew Garrett
- * (C) Copyright 2004 Red Hat, Inc.
+ * (C) Copyright 2004 - 2012 Red Hat, Inc.
  */
 
 #ifdef HAVE_CONFIG_H
 #include <config.h>
 #endif
 
-#include <stdio.h>
-#include <string.h>
-#include <stdlib.h>
-
 #include "NetworkManagerGeneric.h"
-#include "nm-system.h"
 #include "NetworkManagerUtils.h"
 #include "nm-logging.h"
 
-/*
- * nm_system_enable_loopback
- *
- * Bring up the loopback interface
- *
- */
-void nm_system_enable_loopback (void)
+void nm_backend_enable_loopback (void)
 {
 	nm_generic_enable_loopback ();
 }
 
-/*
- * nm_system_update_dns
- *
- * Invalidate the nscd host cache, if it exists, since
- * we changed resolv.conf.
- *
- */
-void nm_system_update_dns (void)
+void nm_backend_update_dns (void)
 {
+	/* Invalidate the nscd host cache, if it exists, since we changed resolv.conf */
 	if (g_file_test ("/usr/sbin/nscd", G_FILE_TEST_IS_EXECUTABLE)) {
 		nm_log_info (LOGD_DNS, "Clearing nscd hosts cache.");
 		nm_spawn_process ("/usr/sbin/nscd -i hosts");
 	}
 }
 
+int nm_backend_ipv6_use_tempaddr (void)
+{
+	return nm_generic_ipv6_use_tempaddr ();
+}
 
diff --git a/src/backends/NetworkManagerMandriva.c b/src/backends/NetworkManagerMandriva.c
index 8209ff4f..f059beb6 100644
--- a/src/backends/NetworkManagerMandriva.c
+++ b/src/backends/NetworkManagerMandriva.c
@@ -17,7 +17,7 @@
  * with this program; if not, write to the Free Software Foundation, Inc.,
  * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
  *
- * (C) Copyright 2004 Red Hat, Inc.
+ * (C) Copyright 2004 - 2012 Red Hat, Inc.
  * (C) Copyright 2008 Per Øyvind Karlsen
  */
 
@@ -25,37 +25,25 @@
 #include <config.h>
 #endif
 
-#include <stdio.h>
-#include <string.h>
-#include <stdlib.h>
-
 #include "NetworkManagerGeneric.h"
-#include "nm-system.h"
 #include "NetworkManagerUtils.h"
 
-/*
- * nm_system_enable_loopback
- *
- * Bring up the loopback interface
- *
- */
-void nm_system_enable_loopback (void)
+void nm_backend_enable_loopback (void)
 {
 	nm_generic_enable_loopback ();
 }
 
-/*
- * nm_system_update_dns
- *
- * Invalidate the nscd host cache, if it exists, since
- * we changed resolv.conf.
- *
- */
-void nm_system_update_dns (void)
+void nm_backend_update_dns (void)
 {
+	/* Invalidate the nscd host cache, if it exists, since we changed resolv.conf */
 	if (g_file_test ("/usr/sbin/nscd", G_FILE_TEST_EXISTS | G_FILE_TEST_IS_EXECUTABLE | G_FILE_TEST_IS_REGULAR)) {
 		nm_spawn_process ("/etc/init.d/nscd condrestart");
 		nm_spawn_process ("/usr/sbin/nscd -i hosts");
 	}
 }
 
+int nm_backend_ipv6_use_tempaddr (void)
+{
+	return nm_generic_ipv6_use_tempaddr ();
+}
+
diff --git a/src/backends/NetworkManagerPaldo.c b/src/backends/NetworkManagerPaldo.c
index 0c67e5bd..2d01d857 100644
--- a/src/backends/NetworkManagerPaldo.c
+++ b/src/backends/NetworkManagerPaldo.c
@@ -18,7 +18,7 @@
  * with this program; if not, write to the Free Software Foundation, Inc.,
  * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
  *
- * (C) Copyright 2004 Red Hat, Inc.
+ * (C) Copyright 2004 - 2012 Red Hat, Inc.
  * (C) Copyright 2006 Jürg Billeter
  */
 
@@ -26,36 +26,26 @@
 #include <config.h>
 #endif
 
-#include <stdio.h>
-#include <string.h>
-#include <stdlib.h>
-
 #include "NetworkManagerGeneric.h"
-#include "nm-system.h"
 #include "NetworkManagerUtils.h"
 #include "nm-logging.h"
 
-/*
- * nm_system_enable_loopback
- *
- * Bring up the loopback interface
- *
- */
-void nm_system_enable_loopback (void)
+void nm_backend_enable_loopback (void)
 {
 	nm_generic_enable_loopback ();
 }
 
-/*
- * nm_system_update_dns
- *
- * Invalidate the nscd host cache, if it exists, since
- * we changed resolv.conf.
- *
- */
-void nm_system_update_dns (void)
+void nm_backend_update_dns (void)
+{
+	/* Invalidate the nscd host cache, if it exists, since we changed resolv.conf */
+	if (g_file_test ("/usr/sbin/nscd", G_FILE_TEST_IS_EXECUTABLE)) {
+		nm_log_info (LOGD_DNS, "Clearing nscd hosts cache.");
+		nm_spawn_process ("/usr/sbin/nscd -i hosts");
+	}
+}
+
+int nm_backend_ipv6_use_tempaddr (void)
 {
-	nm_log_info (LOGD_DNS, "Clearing nscd hosts cache.");
-	nm_spawn_process ("/usr/sbin/nscd -i hosts");
+	return nm_generic_ipv6_use_tempaddr ();
 }
 
diff --git a/src/backends/NetworkManagerPardus.c b/src/backends/NetworkManagerPardus.c
index d952cf36..acfeaed3 100644
--- a/src/backends/NetworkManagerPardus.c
+++ b/src/backends/NetworkManagerPardus.c
@@ -16,7 +16,7 @@
  * with this program; if not, write to the Free Software Foundation, Inc.,
  * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
  *
- * (C) Copyright 2004 RedHat, Inc.
+ * (C) Copyright 2004 - 2012 RedHat, Inc.
  * (C) Copyright 2009 TUBITAK/UEKAE
  */
 
@@ -24,34 +24,19 @@
 #include <config.h>
 #endif
 
-#include <stdio.h>
-#include <string.h>
-#include <stdlib.h>
-
 #include "NetworkManagerGeneric.h"
-#include "nm-system.h"
 
-/*
- * nm_system_enable_loopback
- *
- * Bring up the loopback interface
- *
- */
-void nm_system_enable_loopback (void)
+void nm_backend_enable_loopback (void)
 {
 	nm_generic_enable_loopback ();
 }
 
+void nm_backend_update_dns (void)
+{
+}
 
-/*
- * nm_system_update_dns
- *
- * Make glibc/nscd aware of any changes to the resolv.conf file by
- * restarting nscd.
- *
- */
-void nm_system_update_dns (void)
+int nm_backend_ipv6_use_tempaddr (void)
 {
-	/* I'm not running nscd */
+	return nm_generic_ipv6_use_tempaddr ();
 }
 
diff --git a/src/backends/NetworkManagerRedHat.c b/src/backends/NetworkManagerRedHat.c
index 954e58a8..c14eb837 100644
--- a/src/backends/NetworkManagerRedHat.c
+++ b/src/backends/NetworkManagerRedHat.c
@@ -16,44 +16,32 @@
  * with this program; if not, write to the Free Software Foundation, Inc.,
  * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
  *
- * (C) Copyright 2004 Red Hat, Inc.
+ * (C) Copyright 2004 - 2012 Red Hat, Inc.
  */
 
 #ifdef HAVE_CONFIG_H
 #include <config.h>
 #endif
 
-#include <stdio.h>
-#include <string.h>
-#include <stdlib.h>
-
 #include "NetworkManagerGeneric.h"
-#include "nm-system.h"
 #include "NetworkManagerUtils.h"
 
-/*
- * nm_system_enable_loopback
- *
- * Bring up the loopback interface
- *
- */
-void nm_system_enable_loopback (void)
+void nm_backend_enable_loopback (void)
 {
 	nm_generic_enable_loopback ();
 }
 
-/*
- * nm_system_update_dns
- *
- * Invalidate the nscd host cache, if it exists, since
- * we changed resolv.conf.
- *
- */
-void nm_system_update_dns (void)
+void nm_backend_update_dns (void)
 {
+	/* Invalidate the nscd host cache since we changed resolv.conf */
 	if (g_file_test ("/usr/sbin/nscd", G_FILE_TEST_EXISTS | G_FILE_TEST_IS_EXECUTABLE | G_FILE_TEST_IS_REGULAR)) {
 		nm_spawn_process ("/etc/init.d/nscd condrestart");
 		nm_spawn_process ("/usr/sbin/nscd -i hosts");
 	}
 }
 
+int nm_backend_ipv6_use_tempaddr (void)
+{
+	return nm_generic_ipv6_use_tempaddr ();
+}
+
diff --git a/src/backends/NetworkManagerSlackware.c b/src/backends/NetworkManagerSlackware.c
index a35e1bb6..cdd2dfb0 100644
--- a/src/backends/NetworkManagerSlackware.c
+++ b/src/backends/NetworkManagerSlackware.c
@@ -16,7 +16,7 @@
  * with this program; if not, write to the Free Software Foundation, Inc.,
  * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
  *
- * (C) Copyright 2004 RedHat, Inc.
+ * (C) Copyright 2004 - 2012 RedHat, Inc.
  * (C) Copyright 2004 Narayan Newton
  */
 
@@ -24,34 +24,19 @@
 #include <config.h>
 #endif
 
-#include <stdio.h>
-#include <string.h>
-#include <stdlib.h>
-
 #include "NetworkManagerGeneric.h"
-#include "nm-system.h"
 
-/*
- * nm_system_enable_loopback
- *
- * Bring up the loopback interface
- *
- */
-void nm_system_enable_loopback (void)
+void nm_backend_enable_loopback (void)
 {
 	nm_generic_enable_loopback ();
 }
 
+void nm_backend_update_dns (void)
+{
+}
 
-/*
- * nm_system_update_dns
- *
- * Make glibc/nscd aware of any changes to the resolv.conf file by
- * restarting nscd.
- *
- */
-void nm_system_update_dns (void)
+int nm_backend_ipv6_use_tempaddr (void)
 {
-	/* I'm not running nscd */
+	return nm_generic_ipv6_use_tempaddr ();
 }
 
diff --git a/src/backends/NetworkManagerSuSE.c b/src/backends/NetworkManagerSuSE.c
index 6c8ec1a5..12618532 100644
--- a/src/backends/NetworkManagerSuSE.c
+++ b/src/backends/NetworkManagerSuSE.c
@@ -19,7 +19,7 @@
  * with this program; if not, write to the Free Software Foundation, Inc.,
  * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
  *
- * (C) Copyright 2004 Red Hat, Inc.
+ * (C) Copyright 2004 - 2012 Red Hat, Inc.
  * (C) Copyright 2005-2006 SuSE GmbH
  */
 
@@ -27,36 +27,26 @@
 #include <config.h>
 #endif
 
-#include <stdio.h>
-#include <string.h>
-#include <stdlib.h>
-
 #include "NetworkManagerGeneric.h"
-#include "nm-system.h"
 #include "NetworkManagerUtils.h"
 #include "nm-logging.h"
 
-/*
- * nm_system_enable_loopback
- *
- * Bring up the loopback interface
- *
- */
-void nm_system_enable_loopback (void)
+void nm_backend_enable_loopback (void)
 {
 	nm_generic_enable_loopback ();
 }
 
-/*
- * nm_system_update_dns
- *
- * Invalidate the nscd host cache, if it exists, since
- * we changed resolv.conf.
- *
- */
-void nm_system_update_dns (void)
+void nm_backend_update_dns (void)
+{
+	/* Invalidate the nscd host cache, if it exists, since we changed resolv.conf */
+	if (g_file_test ("/usr/sbin/nscd", G_FILE_TEST_IS_EXECUTABLE)) {
+		nm_log_info (LOGD_DNS, "Clearing nscd hosts cache.");
+		nm_spawn_process ("/usr/sbin/nscd -i hosts");
+	}
+}
+
+int nm_backend_ipv6_use_tempaddr (void)
 {
-	nm_log_info (LOGD_DNS, "Clearing nscd hosts cache.");
-	nm_spawn_process ("/usr/sbin/nscd -i hosts");
+	return nm_generic_ipv6_use_tempaddr ();
 }
 
diff --git a/src/backends/nm-backend.h b/src/backends/nm-backend.h
new file mode 100644
index 00000000..17d1ff64
--- /dev/null
+++ b/src/backends/nm-backend.h
@@ -0,0 +1,30 @@
+/* -*- 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 - 2012 Red Hat, Inc.
+ */
+
+#ifndef NM_BACKEND_H
+#define NM_BACKEND_H
+
+/* Random disto-specific stuff */
+
+void nm_backend_enable_loopback (void);
+void nm_backend_update_dns      (void);
+int nm_backend_ipv6_use_tempaddr (void);
+
+#endif  /* NM_BACKEND_H */
diff --git a/src/bluez-manager/Makefile.am b/src/bluez-manager/Makefile.am
index 623c1060..10b32d25 100644
--- a/src/bluez-manager/Makefile.am
+++ b/src/bluez-manager/Makefile.am
@@ -1,10 +1,13 @@
 INCLUDES = \
 	-I${top_srcdir} \
 	-I${top_srcdir}/include \
+	-I${top_builddir}/include \
 	-I${top_srcdir}/libnm-util \
+	-I${top_builddir}/libnm-util \
 	-I${top_srcdir}/src \
-	-I${top_srcdir}/src/logging \
-	-I${top_builddir}/marshallers
+	-I${top_srcdir}/src/generated \
+	-I${top_builddir}/src/generated \
+	-I${top_srcdir}/src/logging
 
 noinst_LTLIBRARIES = libbluez-manager.la
 
@@ -29,7 +32,7 @@ libbluez_manager_la_CPPFLAGS = \
 	-DLOCALSTATEDIR=\"$(localstatedir)\"
 
 libbluez_manager_la_LIBADD = \
-	$(top_builddir)/marshallers/libmarshallers.la \
+	$(top_builddir)/src/generated/libnm-generated.la \
 	$(top_builddir)/src/logging/libnm-logging.la \
 	$(DBUS_LIBS) \
 	$(GLIB_LIBS) \
diff --git a/src/bluez-manager/Makefile.in b/src/bluez-manager/Makefile.in
index 9eb31c80..efb5ab4e 100644
--- a/src/bluez-manager/Makefile.in
+++ b/src/bluez-manager/Makefile.in
@@ -57,7 +57,7 @@ CONFIG_CLEAN_VPATH_FILES =
 LTLIBRARIES = $(noinst_LTLIBRARIES)
 am__DEPENDENCIES_1 =
 libbluez_manager_la_DEPENDENCIES =  \
-	$(top_builddir)/marshallers/libmarshallers.la \
+	$(top_builddir)/src/generated/libnm-generated.la \
 	$(top_builddir)/src/logging/libnm-logging.la \
 	$(am__DEPENDENCIES_1) $(am__DEPENDENCIES_1)
 am_libbluez_manager_la_OBJECTS =  \
@@ -144,6 +144,8 @@ GIO_LIBS = @GIO_LIBS@
 GLIB_CFLAGS = @GLIB_CFLAGS@
 GLIB_GENMARSHAL = @GLIB_GENMARSHAL@
 GLIB_LIBS = @GLIB_LIBS@
+GLIB_MAKEFILE = @GLIB_MAKEFILE@
+GLIB_MKENUMS = @GLIB_MKENUMS@
 GMODULE_CFLAGS = @GMODULE_CFLAGS@
 GMODULE_LIBS = @GMODULE_LIBS@
 GMSGFMT = @GMSGFMT@
@@ -198,11 +200,15 @@ LIBNL2_LIBS = @LIBNL2_LIBS@
 LIBNL3_CFLAGS = @LIBNL3_CFLAGS@
 LIBNL3_LIBS = @LIBNL3_LIBS@
 LIBNL_CFLAGS = @LIBNL_CFLAGS@
+LIBNL_GENL3_CFLAGS = @LIBNL_GENL3_CFLAGS@
+LIBNL_GENL3_LIBS = @LIBNL_GENL3_LIBS@
 LIBNL_LIBS = @LIBNL_LIBS@
 LIBNL_ROUTE3_CFLAGS = @LIBNL_ROUTE3_CFLAGS@
 LIBNL_ROUTE3_LIBS = @LIBNL_ROUTE3_LIBS@
 LIBOBJS = @LIBOBJS@
 LIBS = @LIBS@
+LIBSOUP_CFLAGS = @LIBSOUP_CFLAGS@
+LIBSOUP_LIBS = @LIBSOUP_LIBS@
 LIBTOOL = @LIBTOOL@
 LIPO = @LIPO@
 LN_S = @LN_S@
@@ -213,6 +219,7 @@ MAINT = @MAINT@
 MAKEINFO = @MAKEINFO@
 MANIFEST_TOOL = @MANIFEST_TOOL@
 MKDIR_P = @MKDIR_P@
+MOC = @MOC@
 MSGFMT = @MSGFMT@
 MSGFMT_015 = @MSGFMT_015@
 MSGMERGE = @MSGMERGE@
@@ -252,6 +259,8 @@ SED = @SED@
 SET_MAKE = @SET_MAKE@
 SHELL = @SHELL@
 STRIP = @STRIP@
+SYSTEMD_CFLAGS = @SYSTEMD_CFLAGS@
+SYSTEMD_LIBS = @SYSTEMD_LIBS@
 SYSTEM_CA_PATH = @SYSTEM_CA_PATH@
 UDEV_BASE_DIR = @UDEV_BASE_DIR@
 USE_NLS = @USE_NLS@
@@ -318,10 +327,13 @@ top_srcdir = @top_srcdir@
 INCLUDES = \
 	-I${top_srcdir} \
 	-I${top_srcdir}/include \
+	-I${top_builddir}/include \
 	-I${top_srcdir}/libnm-util \
+	-I${top_builddir}/libnm-util \
 	-I${top_srcdir}/src \
-	-I${top_srcdir}/src/logging \
-	-I${top_builddir}/marshallers
+	-I${top_srcdir}/src/generated \
+	-I${top_builddir}/src/generated \
+	-I${top_srcdir}/src/logging
 
 noinst_LTLIBRARIES = libbluez-manager.la
 libbluez_manager_la_SOURCES = \
@@ -345,7 +357,7 @@ libbluez_manager_la_CPPFLAGS = \
 	-DLOCALSTATEDIR=\"$(localstatedir)\"
 
 libbluez_manager_la_LIBADD = \
-	$(top_builddir)/marshallers/libmarshallers.la \
+	$(top_builddir)/src/generated/libnm-generated.la \
 	$(top_builddir)/src/logging/libnm-logging.la \
 	$(DBUS_LIBS) \
 	$(GLIB_LIBS) \
diff --git a/src/bluez-manager/nm-bluez-manager.c b/src/bluez-manager/nm-bluez-manager.c
index 5381151e..942d0f34 100644
--- a/src/bluez-manager/nm-bluez-manager.c
+++ b/src/bluez-manager/nm-bluez-manager.c
@@ -181,8 +181,11 @@ default_adapter_cb (DBusGProxy *proxy, DBusGProxyCall *call, gpointer user_data)
 	if (!dbus_g_proxy_end_call (proxy, call, &err,
 	                            DBUS_TYPE_G_OBJECT_PATH, &default_adapter,
 	                            G_TYPE_INVALID)) {
-		nm_log_warn (LOGD_BT, "bluez error getting default adapter: %s",
-		             err && err->message ? err->message : "(unknown)");
+		/* Ignore "No such adapter" errors; just means bluetooth isn't active */
+		if (!dbus_g_error_has_name (err, "org.bluez.Error.NoSuchAdapter")) {
+			nm_log_warn (LOGD_BT, "bluez error getting default adapter: %s",
+			             err && err->message ? err->message : "(unknown)");
+		}
 		g_error_free (err);
 		return;
 	}
diff --git a/src/dhcp-manager/Makefile.am b/src/dhcp-manager/Makefile.am
index 14ddde0b..ce34c416 100644
--- a/src/dhcp-manager/Makefile.am
+++ b/src/dhcp-manager/Makefile.am
@@ -3,9 +3,12 @@ SUBDIRS=. tests
 INCLUDES = \
 	-I${top_srcdir} \
 	-I${top_srcdir}/include \
-	-I${top_builddir}/marshallers \
+	-I${top_builddir}/include \
+	-I${top_srcdir}/src/generated \
+	-I${top_builddir}/src/generated \
 	-I${top_srcdir}/src/logging \
 	-I${top_srcdir}/libnm-util \
+	-I${top_builddir}/libnm-util \
 	-I${top_srcdir}/src
 
 noinst_LTLIBRARIES = libdhcp-manager.la libdhcp-dhclient.la
@@ -29,7 +32,6 @@ libdhcp_dhclient_la_CPPFLAGS = \
 	-DDHCLIENT_V$(DHCLIENT_VERSION)
 
 libdhcp_dhclient_la_LIBADD = \
-	$(top_builddir)/marshallers/libmarshallers.la \
 	$(top_builddir)/src/logging/libnm-logging.la \
 	$(top_builddir)/libnm-util/libnm-util.la \
 	$(DBUS_LIBS) \
@@ -55,7 +57,6 @@ libdhcp_manager_la_CPPFLAGS = \
 	-DDHCPCD_PATH=\"$(DHCPCD_PATH)\"
 
 libdhcp_manager_la_LIBADD = \
-	$(top_builddir)/marshallers/libmarshallers.la \
 	$(top_builddir)/src/logging/libnm-logging.la \
 	$(builddir)/libdhcp-dhclient.la \
 	$(DBUS_LIBS) \
diff --git a/src/dhcp-manager/Makefile.in b/src/dhcp-manager/Makefile.in
index 2d90f043..4c389562 100644
--- a/src/dhcp-manager/Makefile.in
+++ b/src/dhcp-manager/Makefile.in
@@ -57,7 +57,6 @@ CONFIG_CLEAN_VPATH_FILES =
 LTLIBRARIES = $(noinst_LTLIBRARIES)
 am__DEPENDENCIES_1 =
 libdhcp_dhclient_la_DEPENDENCIES =  \
-	$(top_builddir)/marshallers/libmarshallers.la \
 	$(top_builddir)/src/logging/libnm-logging.la \
 	$(top_builddir)/libnm-util/libnm-util.la $(am__DEPENDENCIES_1) \
 	$(am__DEPENDENCIES_1)
@@ -69,7 +68,6 @@ AM_V_lt = $(am__v_lt_$(V))
 am__v_lt_ = $(am__v_lt_$(AM_DEFAULT_VERBOSITY))
 am__v_lt_0 = --silent
 libdhcp_manager_la_DEPENDENCIES =  \
-	$(top_builddir)/marshallers/libmarshallers.la \
 	$(top_builddir)/src/logging/libnm-logging.la \
 	$(builddir)/libdhcp-dhclient.la $(am__DEPENDENCIES_1) \
 	$(am__DEPENDENCIES_1)
@@ -192,6 +190,8 @@ GIO_LIBS = @GIO_LIBS@
 GLIB_CFLAGS = @GLIB_CFLAGS@
 GLIB_GENMARSHAL = @GLIB_GENMARSHAL@
 GLIB_LIBS = @GLIB_LIBS@
+GLIB_MAKEFILE = @GLIB_MAKEFILE@
+GLIB_MKENUMS = @GLIB_MKENUMS@
 GMODULE_CFLAGS = @GMODULE_CFLAGS@
 GMODULE_LIBS = @GMODULE_LIBS@
 GMSGFMT = @GMSGFMT@
@@ -246,11 +246,15 @@ LIBNL2_LIBS = @LIBNL2_LIBS@
 LIBNL3_CFLAGS = @LIBNL3_CFLAGS@
 LIBNL3_LIBS = @LIBNL3_LIBS@
 LIBNL_CFLAGS = @LIBNL_CFLAGS@
+LIBNL_GENL3_CFLAGS = @LIBNL_GENL3_CFLAGS@
+LIBNL_GENL3_LIBS = @LIBNL_GENL3_LIBS@
 LIBNL_LIBS = @LIBNL_LIBS@
 LIBNL_ROUTE3_CFLAGS = @LIBNL_ROUTE3_CFLAGS@
 LIBNL_ROUTE3_LIBS = @LIBNL_ROUTE3_LIBS@
 LIBOBJS = @LIBOBJS@
 LIBS = @LIBS@
+LIBSOUP_CFLAGS = @LIBSOUP_CFLAGS@
+LIBSOUP_LIBS = @LIBSOUP_LIBS@
 LIBTOOL = @LIBTOOL@
 LIPO = @LIPO@
 LN_S = @LN_S@
@@ -261,6 +265,7 @@ MAINT = @MAINT@
 MAKEINFO = @MAKEINFO@
 MANIFEST_TOOL = @MANIFEST_TOOL@
 MKDIR_P = @MKDIR_P@
+MOC = @MOC@
 MSGFMT = @MSGFMT@
 MSGFMT_015 = @MSGFMT_015@
 MSGMERGE = @MSGMERGE@
@@ -300,6 +305,8 @@ SED = @SED@
 SET_MAKE = @SET_MAKE@
 SHELL = @SHELL@
 STRIP = @STRIP@
+SYSTEMD_CFLAGS = @SYSTEMD_CFLAGS@
+SYSTEMD_LIBS = @SYSTEMD_LIBS@
 SYSTEM_CA_PATH = @SYSTEM_CA_PATH@
 UDEV_BASE_DIR = @UDEV_BASE_DIR@
 USE_NLS = @USE_NLS@
@@ -367,9 +374,12 @@ SUBDIRS = . tests
 INCLUDES = \
 	-I${top_srcdir} \
 	-I${top_srcdir}/include \
-	-I${top_builddir}/marshallers \
+	-I${top_builddir}/include \
+	-I${top_srcdir}/src/generated \
+	-I${top_builddir}/src/generated \
 	-I${top_srcdir}/src/logging \
 	-I${top_srcdir}/libnm-util \
+	-I${top_builddir}/libnm-util \
 	-I${top_srcdir}/src
 
 noinst_LTLIBRARIES = libdhcp-manager.la libdhcp-dhclient.la
@@ -392,7 +402,6 @@ libdhcp_dhclient_la_CPPFLAGS = \
 	-DDHCLIENT_V$(DHCLIENT_VERSION)
 
 libdhcp_dhclient_la_LIBADD = \
-	$(top_builddir)/marshallers/libmarshallers.la \
 	$(top_builddir)/src/logging/libnm-logging.la \
 	$(top_builddir)/libnm-util/libnm-util.la \
 	$(DBUS_LIBS) \
@@ -418,7 +427,6 @@ libdhcp_manager_la_CPPFLAGS = \
 	-DDHCPCD_PATH=\"$(DHCPCD_PATH)\"
 
 libdhcp_manager_la_LIBADD = \
-	$(top_builddir)/marshallers/libmarshallers.la \
 	$(top_builddir)/src/logging/libnm-logging.la \
 	$(builddir)/libdhcp-dhclient.la \
 	$(DBUS_LIBS) \
diff --git a/src/dhcp-manager/nm-dhcp-dhclient-utils.c b/src/dhcp-manager/nm-dhcp-dhclient-utils.c
index caf90f11..ab49a765 100644
--- a/src/dhcp-manager/nm-dhcp-dhclient-utils.c
+++ b/src/dhcp-manager/nm-dhcp-dhclient-utils.c
@@ -78,8 +78,8 @@ nm_dhcp_dhclient_create_config (const char *interface,
 			/* Override config file "dhcp-client-id" and use one from the
 			 * connection.
 			 */
-		    if (   s_ip4
-		        && nm_setting_ip4_config_get_dhcp_client_id (s_ip4)
+			if (   s_ip4
+			    && nm_setting_ip4_config_get_dhcp_client_id (s_ip4)
 			    && !strncmp (p, CLIENTID_TAG, strlen (CLIENTID_TAG)))
 				continue;
 
diff --git a/src/dhcp-manager/nm-dhcp-manager.c b/src/dhcp-manager/nm-dhcp-manager.c
index e65f6935..1af1b163 100644
--- a/src/dhcp-manager/nm-dhcp-manager.c
+++ b/src/dhcp-manager/nm-dhcp-manager.c
@@ -44,8 +44,6 @@
 #include "nm-dbus-glib-types.h"
 #include "nm-glib-compat.h"
 
-#define ENUM_ENTRY(NAME, DESC) { NAME, "" #NAME "", DESC }
-
 GQuark
 nm_dhcp_manager_error_quark (void)
 {
@@ -57,22 +55,6 @@ nm_dhcp_manager_error_quark (void)
     return ret;
 }
 
-GType
-nm_dhcp_manager_error_get_type (void)
-{
-    static GType etype = 0;
-
-    if (etype == 0) {
-        static const GEnumValue values[] = {
-            ENUM_ENTRY (NM_DHCP_MANAGER_ERROR_BAD_CLIENT, "BadClient"),
-            ENUM_ENTRY (NM_DHCP_MANAGER_ERROR_INTERNAL,   "InternalError"),
-            { 0, 0, 0 }
-        };
-        etype = g_enum_register_static ("NMDhcpManagerError", values);
-    }
-    return etype;
-}
-
 #define NM_DHCP_CLIENT_DBUS_SERVICE "org.freedesktop.nm_dhcp_client"
 #define NM_DHCP_CLIENT_DBUS_IFACE   "org.freedesktop.nm_dhcp_client"
 
diff --git a/src/dhcp-manager/nm-dhcp-manager.h b/src/dhcp-manager/nm-dhcp-manager.h
index 9d83d096..d585c142 100644
--- a/src/dhcp-manager/nm-dhcp-manager.h
+++ b/src/dhcp-manager/nm-dhcp-manager.h
@@ -33,16 +33,14 @@
 #include "nm-dhcp4-config.h"
 #include "nm-hostname-provider.h"
 
-enum {
-    NM_DHCP_MANAGER_ERROR_BAD_CLIENT = 0,
-    NM_DHCP_MANAGER_ERROR_INTERNAL = 1,
-};
+typedef enum {
+	NM_DHCP_MANAGER_ERROR_BAD_CLIENT = 0, /*< nick=BadClient >*/
+	NM_DHCP_MANAGER_ERROR_INTERNAL = 1,   /*< nick=InternalError >*/
+} NMDHCPManagerError;
 
 #define NM_DHCP_MANAGER_ERROR (nm_dhcp_manager_error_quark ())
-#define NN_TYPE_DHCP_MANAGER_ERROR (nm_dhcp_manager_error_get_type ())
 
 GQuark nm_dhcp_manager_error_quark    (void);
-GType  nm_dhcp_manager_error_get_type (void);
 
 
 #define NM_TYPE_DHCP_MANAGER            (nm_dhcp_manager_get_type ())
diff --git a/src/dhcp-manager/tests/Makefile.am b/src/dhcp-manager/tests/Makefile.am
index b075fd68..1feade86 100644
--- a/src/dhcp-manager/tests/Makefile.am
+++ b/src/dhcp-manager/tests/Makefile.am
@@ -1,6 +1,8 @@
 INCLUDES = \
 	-I$(top_srcdir)/include \
+	-I$(top_builddir)/include \
 	-I${top_srcdir}/libnm-util \
+	-I${top_builddir}/libnm-util \
 	-I$(top_srcdir)/src/dhcp-manager
 
 noinst_PROGRAMS = test-dhcp-dhclient
diff --git a/src/dhcp-manager/tests/Makefile.in b/src/dhcp-manager/tests/Makefile.in
index 5c4c23a5..20422cdb 100644
--- a/src/dhcp-manager/tests/Makefile.in
+++ b/src/dhcp-manager/tests/Makefile.in
@@ -142,6 +142,8 @@ GIO_LIBS = @GIO_LIBS@
 GLIB_CFLAGS = @GLIB_CFLAGS@
 GLIB_GENMARSHAL = @GLIB_GENMARSHAL@
 GLIB_LIBS = @GLIB_LIBS@
+GLIB_MAKEFILE = @GLIB_MAKEFILE@
+GLIB_MKENUMS = @GLIB_MKENUMS@
 GMODULE_CFLAGS = @GMODULE_CFLAGS@
 GMODULE_LIBS = @GMODULE_LIBS@
 GMSGFMT = @GMSGFMT@
@@ -196,11 +198,15 @@ LIBNL2_LIBS = @LIBNL2_LIBS@
 LIBNL3_CFLAGS = @LIBNL3_CFLAGS@
 LIBNL3_LIBS = @LIBNL3_LIBS@
 LIBNL_CFLAGS = @LIBNL_CFLAGS@
+LIBNL_GENL3_CFLAGS = @LIBNL_GENL3_CFLAGS@
+LIBNL_GENL3_LIBS = @LIBNL_GENL3_LIBS@
 LIBNL_LIBS = @LIBNL_LIBS@
 LIBNL_ROUTE3_CFLAGS = @LIBNL_ROUTE3_CFLAGS@
 LIBNL_ROUTE3_LIBS = @LIBNL_ROUTE3_LIBS@
 LIBOBJS = @LIBOBJS@
 LIBS = @LIBS@
+LIBSOUP_CFLAGS = @LIBSOUP_CFLAGS@
+LIBSOUP_LIBS = @LIBSOUP_LIBS@
 LIBTOOL = @LIBTOOL@
 LIPO = @LIPO@
 LN_S = @LN_S@
@@ -211,6 +217,7 @@ MAINT = @MAINT@
 MAKEINFO = @MAKEINFO@
 MANIFEST_TOOL = @MANIFEST_TOOL@
 MKDIR_P = @MKDIR_P@
+MOC = @MOC@
 MSGFMT = @MSGFMT@
 MSGFMT_015 = @MSGFMT_015@
 MSGMERGE = @MSGMERGE@
@@ -250,6 +257,8 @@ SED = @SED@
 SET_MAKE = @SET_MAKE@
 SHELL = @SHELL@
 STRIP = @STRIP@
+SYSTEMD_CFLAGS = @SYSTEMD_CFLAGS@
+SYSTEMD_LIBS = @SYSTEMD_LIBS@
 SYSTEM_CA_PATH = @SYSTEM_CA_PATH@
 UDEV_BASE_DIR = @UDEV_BASE_DIR@
 USE_NLS = @USE_NLS@
@@ -315,7 +324,9 @@ top_builddir = @top_builddir@
 top_srcdir = @top_srcdir@
 INCLUDES = \
 	-I$(top_srcdir)/include \
+	-I$(top_builddir)/include \
 	-I${top_srcdir}/libnm-util \
+	-I${top_builddir}/libnm-util \
 	-I$(top_srcdir)/src/dhcp-manager
 
 
diff --git a/src/dns-manager/Makefile.am b/src/dns-manager/Makefile.am
index b51f667b..331f85c4 100644
--- a/src/dns-manager/Makefile.am
+++ b/src/dns-manager/Makefile.am
@@ -1,8 +1,10 @@
 INCLUDES = \
 	-I${top_srcdir}/src/logging \
 	-I${top_srcdir}/libnm-util \
+	-I${top_builddir}/libnm-util \
 	-I${top_srcdir}/src \
-	-I${top_srcdir}/include
+	-I${top_srcdir}/include \
+	-I${top_builddir}/include
 
 noinst_LTLIBRARIES = libdns-manager.la
 
diff --git a/src/dns-manager/Makefile.in b/src/dns-manager/Makefile.in
index 571f585b..c9b8b0b3 100644
--- a/src/dns-manager/Makefile.in
+++ b/src/dns-manager/Makefile.in
@@ -145,6 +145,8 @@ GIO_LIBS = @GIO_LIBS@
 GLIB_CFLAGS = @GLIB_CFLAGS@
 GLIB_GENMARSHAL = @GLIB_GENMARSHAL@
 GLIB_LIBS = @GLIB_LIBS@
+GLIB_MAKEFILE = @GLIB_MAKEFILE@
+GLIB_MKENUMS = @GLIB_MKENUMS@
 GMODULE_CFLAGS = @GMODULE_CFLAGS@
 GMODULE_LIBS = @GMODULE_LIBS@
 GMSGFMT = @GMSGFMT@
@@ -199,11 +201,15 @@ LIBNL2_LIBS = @LIBNL2_LIBS@
 LIBNL3_CFLAGS = @LIBNL3_CFLAGS@
 LIBNL3_LIBS = @LIBNL3_LIBS@
 LIBNL_CFLAGS = @LIBNL_CFLAGS@
+LIBNL_GENL3_CFLAGS = @LIBNL_GENL3_CFLAGS@
+LIBNL_GENL3_LIBS = @LIBNL_GENL3_LIBS@
 LIBNL_LIBS = @LIBNL_LIBS@
 LIBNL_ROUTE3_CFLAGS = @LIBNL_ROUTE3_CFLAGS@
 LIBNL_ROUTE3_LIBS = @LIBNL_ROUTE3_LIBS@
 LIBOBJS = @LIBOBJS@
 LIBS = @LIBS@
+LIBSOUP_CFLAGS = @LIBSOUP_CFLAGS@
+LIBSOUP_LIBS = @LIBSOUP_LIBS@
 LIBTOOL = @LIBTOOL@
 LIPO = @LIPO@
 LN_S = @LN_S@
@@ -214,6 +220,7 @@ MAINT = @MAINT@
 MAKEINFO = @MAKEINFO@
 MANIFEST_TOOL = @MANIFEST_TOOL@
 MKDIR_P = @MKDIR_P@
+MOC = @MOC@
 MSGFMT = @MSGFMT@
 MSGFMT_015 = @MSGFMT_015@
 MSGMERGE = @MSGMERGE@
@@ -253,6 +260,8 @@ SED = @SED@
 SET_MAKE = @SET_MAKE@
 SHELL = @SHELL@
 STRIP = @STRIP@
+SYSTEMD_CFLAGS = @SYSTEMD_CFLAGS@
+SYSTEMD_LIBS = @SYSTEMD_LIBS@
 SYSTEM_CA_PATH = @SYSTEM_CA_PATH@
 UDEV_BASE_DIR = @UDEV_BASE_DIR@
 USE_NLS = @USE_NLS@
@@ -319,8 +328,10 @@ top_srcdir = @top_srcdir@
 INCLUDES = \
 	-I${top_srcdir}/src/logging \
 	-I${top_srcdir}/libnm-util \
+	-I${top_builddir}/libnm-util \
 	-I${top_srcdir}/src \
-	-I${top_srcdir}/include
+	-I${top_srcdir}/include \
+	-I${top_builddir}/include
 
 noinst_LTLIBRARIES = libdns-manager.la
 libdns_manager_la_SOURCES = \
diff --git a/src/dns-manager/nm-dns-bind.c b/src/dns-manager/nm-dns-bind.c
index 55fce030..1a3243be 100644
--- a/src/dns-manager/nm-dns-bind.c
+++ b/src/dns-manager/nm-dns-bind.c
@@ -413,7 +413,7 @@ update (NMDnsPlugin *plugin,
 		g_clear_error (&error);
 		goto out;
 	}
-	ignored = chmod (CONFFILE, 0600);
+	ignored = chmod (CONFFILE, 0644);
 
 	nm_log_dbg (LOGD_DNS, "BIND local caching DNS configuration:");
 	nm_log_dbg (LOGD_DNS, "%s", conf->str);
diff --git a/src/dns-manager/nm-dns-dnsmasq.c b/src/dns-manager/nm-dns-dnsmasq.c
index a602c54f..8e216f4d 100644
--- a/src/dns-manager/nm-dns-dnsmasq.c
+++ b/src/dns-manager/nm-dns-dnsmasq.c
@@ -294,7 +294,7 @@ update (NMDnsPlugin *plugin,
 		g_clear_error (&error);
 		goto out;
 	}
-	ignored = chmod (CONFFILE, 0600);
+	ignored = chmod (CONFFILE, 0644);
 
 	nm_log_dbg (LOGD_DNS, "dnsmasq local caching DNS configuration:");
 	nm_log_dbg (LOGD_DNS, "%s", conf->str);
@@ -302,13 +302,14 @@ update (NMDnsPlugin *plugin,
 	argv[0] = find_dnsmasq ();
 	argv[1] = "--no-resolv";  /* Use only commandline */
 	argv[2] = "--keep-in-foreground";
-	argv[3] = "--strict-order";
+	argv[3] = "--no-hosts"; /* don't use /etc/hosts to resolve */
 	argv[4] = "--bind-interfaces";
 	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] = "--cache-size=400";
-	argv[9] = NULL;
+	argv[9] = "--proxy-dnssec"; /* Allow DNSSEC to pass through */
+	argv[10] = 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 ddfd47c8..6272e374 100644
--- a/src/dns-manager/nm-dns-manager.c
+++ b/src/dns-manager/nm-dns-manager.c
@@ -40,7 +40,7 @@
 #include "nm-ip4-config.h"
 #include "nm-ip6-config.h"
 #include "nm-logging.h"
-#include "nm-system.h"
+#include "backends/nm-backend.h"
 #include "NetworkManagerUtils.h"
 
 #include "nm-dns-plugin.h"
@@ -752,7 +752,7 @@ update_dns (NMDnsManager *self,
 		success = update_resolv_conf (domain, searches, nameservers, iface, error);
 
 	if (success)
-		nm_system_update_dns ();
+		nm_backend_update_dns ();
 
 	if (searches)
 		g_strfreev (searches);
diff --git a/src/dnsmasq-manager/Makefile.in b/src/dnsmasq-manager/Makefile.in
index 5b1328bf..bb1e56c0 100644
--- a/src/dnsmasq-manager/Makefile.in
+++ b/src/dnsmasq-manager/Makefile.in
@@ -141,6 +141,8 @@ GIO_LIBS = @GIO_LIBS@
 GLIB_CFLAGS = @GLIB_CFLAGS@
 GLIB_GENMARSHAL = @GLIB_GENMARSHAL@
 GLIB_LIBS = @GLIB_LIBS@
+GLIB_MAKEFILE = @GLIB_MAKEFILE@
+GLIB_MKENUMS = @GLIB_MKENUMS@
 GMODULE_CFLAGS = @GMODULE_CFLAGS@
 GMODULE_LIBS = @GMODULE_LIBS@
 GMSGFMT = @GMSGFMT@
@@ -195,11 +197,15 @@ LIBNL2_LIBS = @LIBNL2_LIBS@
 LIBNL3_CFLAGS = @LIBNL3_CFLAGS@
 LIBNL3_LIBS = @LIBNL3_LIBS@
 LIBNL_CFLAGS = @LIBNL_CFLAGS@
+LIBNL_GENL3_CFLAGS = @LIBNL_GENL3_CFLAGS@
+LIBNL_GENL3_LIBS = @LIBNL_GENL3_LIBS@
 LIBNL_LIBS = @LIBNL_LIBS@
 LIBNL_ROUTE3_CFLAGS = @LIBNL_ROUTE3_CFLAGS@
 LIBNL_ROUTE3_LIBS = @LIBNL_ROUTE3_LIBS@
 LIBOBJS = @LIBOBJS@
 LIBS = @LIBS@
+LIBSOUP_CFLAGS = @LIBSOUP_CFLAGS@
+LIBSOUP_LIBS = @LIBSOUP_LIBS@
 LIBTOOL = @LIBTOOL@
 LIPO = @LIPO@
 LN_S = @LN_S@
@@ -210,6 +216,7 @@ MAINT = @MAINT@
 MAKEINFO = @MAKEINFO@
 MANIFEST_TOOL = @MANIFEST_TOOL@
 MKDIR_P = @MKDIR_P@
+MOC = @MOC@
 MSGFMT = @MSGFMT@
 MSGFMT_015 = @MSGFMT_015@
 MSGMERGE = @MSGMERGE@
@@ -249,6 +256,8 @@ SED = @SED@
 SET_MAKE = @SET_MAKE@
 SHELL = @SHELL@
 STRIP = @STRIP@
+SYSTEMD_CFLAGS = @SYSTEMD_CFLAGS@
+SYSTEMD_LIBS = @SYSTEMD_LIBS@
 SYSTEM_CA_PATH = @SYSTEM_CA_PATH@
 UDEV_BASE_DIR = @UDEV_BASE_DIR@
 USE_NLS = @USE_NLS@
diff --git a/src/firewall-manager/Makefile.am b/src/firewall-manager/Makefile.am
new file mode 100644
index 00000000..2cfe32d0
--- /dev/null
+++ b/src/firewall-manager/Makefile.am
@@ -0,0 +1,23 @@
+INCLUDES = \
+	-I${top_srcdir}/src \
+	-I${top_srcdir}/src/logging \
+	-I${top_srcdir}/include \
+	-I${top_srcdir}/libnm-util
+
+noinst_LTLIBRARIES = libfirewall-manager.la
+
+libfirewall_manager_la_SOURCES = \
+	nm-firewall-manager.h \
+	nm-firewall-manager.c
+
+libfirewall_manager_la_CPPFLAGS = \
+	$(DBUS_CFLAGS) \
+	$(GLIB_CFLAGS) \
+	-DNM_PKGDATADIR=\"$(pkgdatadir)\" \
+	-DNM_LOCALSTATEDIR=\"$(localstatedir)\"
+
+libfirewall_manager_la_LIBADD = \
+	$(top_builddir)/src/logging/libnm-logging.la \
+	$(DBUS_LIBS) \
+	$(GLIB_LIBS)
+
diff --git a/src/firewall-manager/Makefile.in b/src/firewall-manager/Makefile.in
new file mode 100644
index 00000000..821fa838
--- /dev/null
+++ b/src/firewall-manager/Makefile.in
@@ -0,0 +1,641 @@
+# Makefile.in generated by automake 1.11.1 from Makefile.am.
+# @configure_input@
+
+# Copyright (C) 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002,
+# 2003, 2004, 2005, 2006, 2007, 2008, 2009  Free Software Foundation,
+# Inc.
+# This Makefile.in is free software; the Free Software Foundation
+# gives unlimited permission to copy and/or distribute it,
+# with or without modifications, as long as this notice is preserved.
+
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY, to the extent permitted by law; without
+# even the implied warranty of MERCHANTABILITY or FITNESS FOR A
+# PARTICULAR PURPOSE.
+
+@SET_MAKE@
+
+VPATH = @srcdir@
+pkgdatadir = $(datadir)/@PACKAGE@
+pkgincludedir = $(includedir)/@PACKAGE@
+pkglibdir = $(libdir)/@PACKAGE@
+pkglibexecdir = $(libexecdir)/@PACKAGE@
+am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd
+install_sh_DATA = $(install_sh) -c -m 644
+install_sh_PROGRAM = $(install_sh) -c
+install_sh_SCRIPT = $(install_sh) -c
+INSTALL_HEADER = $(INSTALL_DATA)
+transform = $(program_transform_name)
+NORMAL_INSTALL = :
+PRE_INSTALL = :
+POST_INSTALL = :
+NORMAL_UNINSTALL = :
+PRE_UNINSTALL = :
+POST_UNINSTALL = :
+build_triplet = @build@
+host_triplet = @host@
+subdir = src/firewall-manager
+DIST_COMMON = $(srcdir)/Makefile.am $(srcdir)/Makefile.in
+ACLOCAL_M4 = $(top_srcdir)/aclocal.m4
+am__aclocal_m4_deps = $(top_srcdir)/m4/compiler_warnings.m4 \
+	$(top_srcdir)/m4/gettext.m4 $(top_srcdir)/m4/gtk-doc.m4 \
+	$(top_srcdir)/m4/iconv.m4 $(top_srcdir)/m4/intlmacosx.m4 \
+	$(top_srcdir)/m4/intltool.m4 $(top_srcdir)/m4/introspection.m4 \
+	$(top_srcdir)/m4/lib-ld.m4 $(top_srcdir)/m4/lib-link.m4 \
+	$(top_srcdir)/m4/lib-prefix.m4 $(top_srcdir)/m4/libnl-check.m4 \
+	$(top_srcdir)/m4/libtool.m4 $(top_srcdir)/m4/ltoptions.m4 \
+	$(top_srcdir)/m4/ltsugar.m4 $(top_srcdir)/m4/ltversion.m4 \
+	$(top_srcdir)/m4/lt~obsolete.m4 $(top_srcdir)/m4/nls.m4 \
+	$(top_srcdir)/m4/po.m4 $(top_srcdir)/m4/progtest.m4 \
+	$(top_srcdir)/configure.ac
+am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \
+	$(ACLOCAL_M4)
+mkinstalldirs = $(install_sh) -d
+CONFIG_HEADER = $(top_builddir)/config.h
+CONFIG_CLEAN_FILES =
+CONFIG_CLEAN_VPATH_FILES =
+LTLIBRARIES = $(noinst_LTLIBRARIES)
+am__DEPENDENCIES_1 =
+libfirewall_manager_la_DEPENDENCIES =  \
+	$(top_builddir)/src/logging/libnm-logging.la \
+	$(am__DEPENDENCIES_1) $(am__DEPENDENCIES_1)
+am_libfirewall_manager_la_OBJECTS =  \
+	libfirewall_manager_la-nm-firewall-manager.lo
+libfirewall_manager_la_OBJECTS = $(am_libfirewall_manager_la_OBJECTS)
+AM_V_lt = $(am__v_lt_$(V))
+am__v_lt_ = $(am__v_lt_$(AM_DEFAULT_VERBOSITY))
+am__v_lt_0 = --silent
+DEFAULT_INCLUDES = -I.@am__isrc@ -I$(top_builddir)
+depcomp = $(SHELL) $(top_srcdir)/build-aux/depcomp
+am__depfiles_maybe = depfiles
+am__mv = mv -f
+COMPILE = $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) \
+	$(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS)
+LTCOMPILE = $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) \
+	$(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) \
+	$(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) \
+	$(AM_CFLAGS) $(CFLAGS)
+AM_V_CC = $(am__v_CC_$(V))
+am__v_CC_ = $(am__v_CC_$(AM_DEFAULT_VERBOSITY))
+am__v_CC_0 = @echo "  CC    " $@;
+AM_V_at = $(am__v_at_$(V))
+am__v_at_ = $(am__v_at_$(AM_DEFAULT_VERBOSITY))
+am__v_at_0 = @
+CCLD = $(CC)
+LINK = $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) \
+	$(LIBTOOLFLAGS) --mode=link $(CCLD) $(AM_CFLAGS) $(CFLAGS) \
+	$(AM_LDFLAGS) $(LDFLAGS) -o $@
+AM_V_CCLD = $(am__v_CCLD_$(V))
+am__v_CCLD_ = $(am__v_CCLD_$(AM_DEFAULT_VERBOSITY))
+am__v_CCLD_0 = @echo "  CCLD  " $@;
+AM_V_GEN = $(am__v_GEN_$(V))
+am__v_GEN_ = $(am__v_GEN_$(AM_DEFAULT_VERBOSITY))
+am__v_GEN_0 = @echo "  GEN   " $@;
+SOURCES = $(libfirewall_manager_la_SOURCES)
+DIST_SOURCES = $(libfirewall_manager_la_SOURCES)
+ETAGS = etags
+CTAGS = ctags
+DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST)
+ACLOCAL = @ACLOCAL@
+ALL_LINGUAS = @ALL_LINGUAS@
+AMTAR = @AMTAR@
+AM_DEFAULT_VERBOSITY = @AM_DEFAULT_VERBOSITY@
+AR = @AR@
+AUTOCONF = @AUTOCONF@
+AUTOHEADER = @AUTOHEADER@
+AUTOMAKE = @AUTOMAKE@
+AWK = @AWK@
+CC = @CC@
+CCDEPMODE = @CCDEPMODE@
+CFLAGS = @CFLAGS@
+CPP = @CPP@
+CPPFLAGS = @CPPFLAGS@
+CXX = @CXX@
+CXXCPP = @CXXCPP@
+CXXDEPMODE = @CXXDEPMODE@
+CXXFLAGS = @CXXFLAGS@
+CYGPATH_W = @CYGPATH_W@
+DATADIRNAME = @DATADIRNAME@
+DBUS_CFLAGS = @DBUS_CFLAGS@
+DBUS_LIBS = @DBUS_LIBS@
+DBUS_SYS_DIR = @DBUS_SYS_DIR@
+DEFS = @DEFS@
+DEPDIR = @DEPDIR@
+DHCLIENT_PATH = @DHCLIENT_PATH@
+DHCLIENT_VERSION = @DHCLIENT_VERSION@
+DHCPCD_PATH = @DHCPCD_PATH@
+DISABLE_DEPRECATED = @DISABLE_DEPRECATED@
+DLLTOOL = @DLLTOOL@
+DSYMUTIL = @DSYMUTIL@
+DUMPBIN = @DUMPBIN@
+ECHO_C = @ECHO_C@
+ECHO_N = @ECHO_N@
+ECHO_T = @ECHO_T@
+EGREP = @EGREP@
+EXEEXT = @EXEEXT@
+FGREP = @FGREP@
+GETTEXT_MACRO_VERSION = @GETTEXT_MACRO_VERSION@
+GETTEXT_PACKAGE = @GETTEXT_PACKAGE@
+GIO_CFLAGS = @GIO_CFLAGS@
+GIO_LIBS = @GIO_LIBS@
+GLIB_CFLAGS = @GLIB_CFLAGS@
+GLIB_GENMARSHAL = @GLIB_GENMARSHAL@
+GLIB_LIBS = @GLIB_LIBS@
+GLIB_MAKEFILE = @GLIB_MAKEFILE@
+GLIB_MKENUMS = @GLIB_MKENUMS@
+GMODULE_CFLAGS = @GMODULE_CFLAGS@
+GMODULE_LIBS = @GMODULE_LIBS@
+GMSGFMT = @GMSGFMT@
+GMSGFMT_015 = @GMSGFMT_015@
+GNUTLS_CFLAGS = @GNUTLS_CFLAGS@
+GNUTLS_LIBS = @GNUTLS_LIBS@
+GREP = @GREP@
+GTKDOC_CHECK = @GTKDOC_CHECK@
+GTKDOC_DEPS_CFLAGS = @GTKDOC_DEPS_CFLAGS@
+GTKDOC_DEPS_LIBS = @GTKDOC_DEPS_LIBS@
+GTKDOC_MKPDF = @GTKDOC_MKPDF@
+GTKDOC_REBASE = @GTKDOC_REBASE@
+GUDEV_CFLAGS = @GUDEV_CFLAGS@
+GUDEV_LIBS = @GUDEV_LIBS@
+HTML_DIR = @HTML_DIR@
+INSTALL = @INSTALL@
+INSTALL_DATA = @INSTALL_DATA@
+INSTALL_PROGRAM = @INSTALL_PROGRAM@
+INSTALL_SCRIPT = @INSTALL_SCRIPT@
+INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@
+INTLLIBS = @INTLLIBS@
+INTLTOOL_EXTRACT = @INTLTOOL_EXTRACT@
+INTLTOOL_MERGE = @INTLTOOL_MERGE@
+INTLTOOL_PERL = @INTLTOOL_PERL@
+INTLTOOL_UPDATE = @INTLTOOL_UPDATE@
+INTL_MACOSX_LIBS = @INTL_MACOSX_LIBS@
+INTROSPECTION_CFLAGS = @INTROSPECTION_CFLAGS@
+INTROSPECTION_COMPILER = @INTROSPECTION_COMPILER@
+INTROSPECTION_GENERATE = @INTROSPECTION_GENERATE@
+INTROSPECTION_GIRDIR = @INTROSPECTION_GIRDIR@
+INTROSPECTION_LIBS = @INTROSPECTION_LIBS@
+INTROSPECTION_MAKEFILE = @INTROSPECTION_MAKEFILE@
+INTROSPECTION_SCANNER = @INTROSPECTION_SCANNER@
+INTROSPECTION_TYPELIBDIR = @INTROSPECTION_TYPELIBDIR@
+IPTABLES_PATH = @IPTABLES_PATH@
+IWMX_SDK_CFLAGS = @IWMX_SDK_CFLAGS@
+IWMX_SDK_LIBS = @IWMX_SDK_LIBS@
+KERNEL_FIRMWARE_DIR = @KERNEL_FIRMWARE_DIR@
+LD = @LD@
+LDFLAGS = @LDFLAGS@
+LIBDL = @LIBDL@
+LIBGCRYPT_CFLAGS = @LIBGCRYPT_CFLAGS@
+LIBGCRYPT_CONFIG = @LIBGCRYPT_CONFIG@
+LIBGCRYPT_LIBS = @LIBGCRYPT_LIBS@
+LIBICONV = @LIBICONV@
+LIBINTL = @LIBINTL@
+LIBM = @LIBM@
+LIBNL1_CFLAGS = @LIBNL1_CFLAGS@
+LIBNL1_LIBS = @LIBNL1_LIBS@
+LIBNL2_CFLAGS = @LIBNL2_CFLAGS@
+LIBNL2_LIBS = @LIBNL2_LIBS@
+LIBNL3_CFLAGS = @LIBNL3_CFLAGS@
+LIBNL3_LIBS = @LIBNL3_LIBS@
+LIBNL_CFLAGS = @LIBNL_CFLAGS@
+LIBNL_GENL3_CFLAGS = @LIBNL_GENL3_CFLAGS@
+LIBNL_GENL3_LIBS = @LIBNL_GENL3_LIBS@
+LIBNL_LIBS = @LIBNL_LIBS@
+LIBNL_ROUTE3_CFLAGS = @LIBNL_ROUTE3_CFLAGS@
+LIBNL_ROUTE3_LIBS = @LIBNL_ROUTE3_LIBS@
+LIBOBJS = @LIBOBJS@
+LIBS = @LIBS@
+LIBSOUP_CFLAGS = @LIBSOUP_CFLAGS@
+LIBSOUP_LIBS = @LIBSOUP_LIBS@
+LIBTOOL = @LIBTOOL@
+LIPO = @LIPO@
+LN_S = @LN_S@
+LTLIBICONV = @LTLIBICONV@
+LTLIBINTL = @LTLIBINTL@
+LTLIBOBJS = @LTLIBOBJS@
+MAINT = @MAINT@
+MAKEINFO = @MAKEINFO@
+MANIFEST_TOOL = @MANIFEST_TOOL@
+MKDIR_P = @MKDIR_P@
+MOC = @MOC@
+MSGFMT = @MSGFMT@
+MSGFMT_015 = @MSGFMT_015@
+MSGMERGE = @MSGMERGE@
+NM = @NM@
+NMEDIT = @NMEDIT@
+NM_MAJOR_VERSION = @NM_MAJOR_VERSION@
+NM_MICRO_VERSION = @NM_MICRO_VERSION@
+NM_MINOR_VERSION = @NM_MINOR_VERSION@
+NM_VERSION = @NM_VERSION@
+NSS_CFLAGS = @NSS_CFLAGS@
+NSS_LIBS = @NSS_LIBS@
+OBJDUMP = @OBJDUMP@
+OBJEXT = @OBJEXT@
+OTOOL = @OTOOL@
+OTOOL64 = @OTOOL64@
+PACKAGE = @PACKAGE@
+PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@
+PACKAGE_NAME = @PACKAGE_NAME@
+PACKAGE_STRING = @PACKAGE_STRING@
+PACKAGE_TARNAME = @PACKAGE_TARNAME@
+PACKAGE_URL = @PACKAGE_URL@
+PACKAGE_VERSION = @PACKAGE_VERSION@
+PATH_SEPARATOR = @PATH_SEPARATOR@
+PKGCONFIG_PATH = @PKGCONFIG_PATH@
+PKG_CONFIG = @PKG_CONFIG@
+PKG_CONFIG_LIBDIR = @PKG_CONFIG_LIBDIR@
+PKG_CONFIG_PATH = @PKG_CONFIG_PATH@
+POLKIT_CFLAGS = @POLKIT_CFLAGS@
+POLKIT_LIBS = @POLKIT_LIBS@
+POSUB = @POSUB@
+PPPD_PLUGIN_DIR = @PPPD_PLUGIN_DIR@
+QT_CFLAGS = @QT_CFLAGS@
+QT_LIBS = @QT_LIBS@
+RANLIB = @RANLIB@
+RESOLVCONF_PATH = @RESOLVCONF_PATH@
+SED = @SED@
+SET_MAKE = @SET_MAKE@
+SHELL = @SHELL@
+STRIP = @STRIP@
+SYSTEMD_CFLAGS = @SYSTEMD_CFLAGS@
+SYSTEMD_LIBS = @SYSTEMD_LIBS@
+SYSTEM_CA_PATH = @SYSTEM_CA_PATH@
+UDEV_BASE_DIR = @UDEV_BASE_DIR@
+USE_NLS = @USE_NLS@
+UUID_CFLAGS = @UUID_CFLAGS@
+UUID_LIBS = @UUID_LIBS@
+VERSION = @VERSION@
+XGETTEXT = @XGETTEXT@
+XGETTEXT_015 = @XGETTEXT_015@
+XGETTEXT_EXTRA_OPTIONS = @XGETTEXT_EXTRA_OPTIONS@
+abs_builddir = @abs_builddir@
+abs_srcdir = @abs_srcdir@
+abs_top_builddir = @abs_top_builddir@
+abs_top_srcdir = @abs_top_srcdir@
+ac_ct_AR = @ac_ct_AR@
+ac_ct_CC = @ac_ct_CC@
+ac_ct_CXX = @ac_ct_CXX@
+ac_ct_DUMPBIN = @ac_ct_DUMPBIN@
+am__include = @am__include@
+am__leading_dot = @am__leading_dot@
+am__quote = @am__quote@
+am__tar = @am__tar@
+am__untar = @am__untar@
+bindir = @bindir@
+build = @build@
+build_alias = @build_alias@
+build_cpu = @build_cpu@
+build_os = @build_os@
+build_vendor = @build_vendor@
+builddir = @builddir@
+datadir = @datadir@
+datarootdir = @datarootdir@
+docdir = @docdir@
+dvidir = @dvidir@
+exec_prefix = @exec_prefix@
+host = @host@
+host_alias = @host_alias@
+host_cpu = @host_cpu@
+host_os = @host_os@
+host_vendor = @host_vendor@
+htmldir = @htmldir@
+includedir = @includedir@
+infodir = @infodir@
+install_sh = @install_sh@
+libdir = @libdir@
+libexecdir = @libexecdir@
+localedir = @localedir@
+localstatedir = @localstatedir@
+mandir = @mandir@
+mkdir_p = @mkdir_p@
+oldincludedir = @oldincludedir@
+pdfdir = @pdfdir@
+prefix = @prefix@
+program_transform_name = @program_transform_name@
+psdir = @psdir@
+sbindir = @sbindir@
+sharedstatedir = @sharedstatedir@
+srcdir = @srcdir@
+sysconfdir = @sysconfdir@
+systemdsystemunitdir = @systemdsystemunitdir@
+target_alias = @target_alias@
+top_build_prefix = @top_build_prefix@
+top_builddir = @top_builddir@
+top_srcdir = @top_srcdir@
+INCLUDES = \
+	-I${top_srcdir}/src \
+	-I${top_srcdir}/src/logging \
+	-I${top_srcdir}/include \
+	-I${top_srcdir}/libnm-util
+
+noinst_LTLIBRARIES = libfirewall-manager.la
+libfirewall_manager_la_SOURCES = \
+	nm-firewall-manager.h \
+	nm-firewall-manager.c
+
+libfirewall_manager_la_CPPFLAGS = \
+	$(DBUS_CFLAGS) \
+	$(GLIB_CFLAGS) \
+	-DNM_PKGDATADIR=\"$(pkgdatadir)\" \
+	-DNM_LOCALSTATEDIR=\"$(localstatedir)\"
+
+libfirewall_manager_la_LIBADD = \
+	$(top_builddir)/src/logging/libnm-logging.la \
+	$(DBUS_LIBS) \
+	$(GLIB_LIBS)
+
+all: all-am
+
+.SUFFIXES:
+.SUFFIXES: .c .lo .o .obj
+$(srcdir)/Makefile.in: @MAINTAINER_MODE_TRUE@ $(srcdir)/Makefile.am  $(am__configure_deps)
+	@for dep in $?; do \
+	  case '$(am__configure_deps)' in \
+	    *$$dep*) \
+	      ( cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh ) \
+	        && { if test -f $@; then exit 0; else break; fi; }; \
+	      exit 1;; \
+	  esac; \
+	done; \
+	echo ' cd $(top_srcdir) && $(AUTOMAKE) --gnu src/firewall-manager/Makefile'; \
+	$(am__cd) $(top_srcdir) && \
+	  $(AUTOMAKE) --gnu src/firewall-manager/Makefile
+.PRECIOUS: Makefile
+Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status
+	@case '$?' in \
+	  *config.status*) \
+	    cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh;; \
+	  *) \
+	    echo ' cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe)'; \
+	    cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe);; \
+	esac;
+
+$(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES)
+	cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+
+$(top_srcdir)/configure: @MAINTAINER_MODE_TRUE@ $(am__configure_deps)
+	cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+$(ACLOCAL_M4): @MAINTAINER_MODE_TRUE@ $(am__aclocal_m4_deps)
+	cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+$(am__aclocal_m4_deps):
+
+clean-noinstLTLIBRARIES:
+	-test -z "$(noinst_LTLIBRARIES)" || rm -f $(noinst_LTLIBRARIES)
+	@list='$(noinst_LTLIBRARIES)'; for p in $$list; do \
+	  dir="`echo $$p | sed -e 's|/[^/]*$$||'`"; \
+	  test "$$dir" != "$$p" || dir=.; \
+	  echo "rm -f \"$${dir}/so_locations\""; \
+	  rm -f "$${dir}/so_locations"; \
+	done
+libfirewall-manager.la: $(libfirewall_manager_la_OBJECTS) $(libfirewall_manager_la_DEPENDENCIES) 
+	$(AM_V_CCLD)$(LINK)  $(libfirewall_manager_la_OBJECTS) $(libfirewall_manager_la_LIBADD) $(LIBS)
+
+mostlyclean-compile:
+	-rm -f *.$(OBJEXT)
+
+distclean-compile:
+	-rm -f *.tab.c
+
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libfirewall_manager_la-nm-firewall-manager.Plo@am__quote@
+
+.c.o:
+@am__fastdepCC_TRUE@	$(AM_V_CC)depbase=`echo $@ | sed 's|[^/]*$$|$(DEPDIR)/&|;s|\.o$$||'`;\
+@am__fastdepCC_TRUE@	$(COMPILE) -MT $@ -MD -MP -MF $$depbase.Tpo -c -o $@ $< &&\
+@am__fastdepCC_TRUE@	$(am__mv) $$depbase.Tpo $$depbase.Po
+@am__fastdepCC_FALSE@	$(AM_V_CC) @AM_BACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@	source='$<' object='$@' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@	DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@	$(COMPILE) -c -o $@ $<
+
+.c.obj:
+@am__fastdepCC_TRUE@	$(AM_V_CC)depbase=`echo $@ | sed 's|[^/]*$$|$(DEPDIR)/&|;s|\.obj$$||'`;\
+@am__fastdepCC_TRUE@	$(COMPILE) -MT $@ -MD -MP -MF $$depbase.Tpo -c -o $@ `$(CYGPATH_W) '$<'` &&\
+@am__fastdepCC_TRUE@	$(am__mv) $$depbase.Tpo $$depbase.Po
+@am__fastdepCC_FALSE@	$(AM_V_CC) @AM_BACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@	source='$<' object='$@' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@	DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@	$(COMPILE) -c -o $@ `$(CYGPATH_W) '$<'`
+
+.c.lo:
+@am__fastdepCC_TRUE@	$(AM_V_CC)depbase=`echo $@ | sed 's|[^/]*$$|$(DEPDIR)/&|;s|\.lo$$||'`;\
+@am__fastdepCC_TRUE@	$(LTCOMPILE) -MT $@ -MD -MP -MF $$depbase.Tpo -c -o $@ $< &&\
+@am__fastdepCC_TRUE@	$(am__mv) $$depbase.Tpo $$depbase.Plo
+@am__fastdepCC_FALSE@	$(AM_V_CC) @AM_BACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@	source='$<' object='$@' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@	DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@	$(LTCOMPILE) -c -o $@ $<
+
+libfirewall_manager_la-nm-firewall-manager.lo: nm-firewall-manager.c
+@am__fastdepCC_TRUE@	$(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libfirewall_manager_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT libfirewall_manager_la-nm-firewall-manager.lo -MD -MP -MF $(DEPDIR)/libfirewall_manager_la-nm-firewall-manager.Tpo -c -o libfirewall_manager_la-nm-firewall-manager.lo `test -f 'nm-firewall-manager.c' || echo '$(srcdir)/'`nm-firewall-manager.c
+@am__fastdepCC_TRUE@	$(AM_V_at)$(am__mv) $(DEPDIR)/libfirewall_manager_la-nm-firewall-manager.Tpo $(DEPDIR)/libfirewall_manager_la-nm-firewall-manager.Plo
+@am__fastdepCC_FALSE@	$(AM_V_CC) @AM_BACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@	source='nm-firewall-manager.c' object='libfirewall_manager_la-nm-firewall-manager.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@	DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@	$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libfirewall_manager_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o libfirewall_manager_la-nm-firewall-manager.lo `test -f 'nm-firewall-manager.c' || echo '$(srcdir)/'`nm-firewall-manager.c
+
+mostlyclean-libtool:
+	-rm -f *.lo
+
+clean-libtool:
+	-rm -rf .libs _libs
+
+ID: $(HEADERS) $(SOURCES) $(LISP) $(TAGS_FILES)
+	list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \
+	unique=`for i in $$list; do \
+	    if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \
+	  done | \
+	  $(AWK) '{ files[$$0] = 1; nonempty = 1; } \
+	      END { if (nonempty) { for (i in files) print i; }; }'`; \
+	mkid -fID $$unique
+tags: TAGS
+
+TAGS:  $(HEADERS) $(SOURCES)  $(TAGS_DEPENDENCIES) \
+		$(TAGS_FILES) $(LISP)
+	set x; \
+	here=`pwd`; \
+	list='$(SOURCES) $(HEADERS)  $(LISP) $(TAGS_FILES)'; \
+	unique=`for i in $$list; do \
+	    if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \
+	  done | \
+	  $(AWK) '{ files[$$0] = 1; nonempty = 1; } \
+	      END { if (nonempty) { for (i in files) print i; }; }'`; \
+	shift; \
+	if test -z "$(ETAGS_ARGS)$$*$$unique"; then :; else \
+	  test -n "$$unique" || unique=$$empty_fix; \
+	  if test $$# -gt 0; then \
+	    $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \
+	      "$$@" $$unique; \
+	  else \
+	    $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \
+	      $$unique; \
+	  fi; \
+	fi
+ctags: CTAGS
+CTAGS:  $(HEADERS) $(SOURCES)  $(TAGS_DEPENDENCIES) \
+		$(TAGS_FILES) $(LISP)
+	list='$(SOURCES) $(HEADERS)  $(LISP) $(TAGS_FILES)'; \
+	unique=`for i in $$list; do \
+	    if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \
+	  done | \
+	  $(AWK) '{ files[$$0] = 1; nonempty = 1; } \
+	      END { if (nonempty) { for (i in files) print i; }; }'`; \
+	test -z "$(CTAGS_ARGS)$$unique" \
+	  || $(CTAGS) $(CTAGSFLAGS) $(AM_CTAGSFLAGS) $(CTAGS_ARGS) \
+	     $$unique
+
+GTAGS:
+	here=`$(am__cd) $(top_builddir) && pwd` \
+	  && $(am__cd) $(top_srcdir) \
+	  && gtags -i $(GTAGS_ARGS) "$$here"
+
+distclean-tags:
+	-rm -f TAGS ID GTAGS GRTAGS GSYMS GPATH tags
+
+distdir: $(DISTFILES)
+	@srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \
+	topsrcdirstrip=`echo "$(top_srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \
+	list='$(DISTFILES)'; \
+	  dist_files=`for file in $$list; do echo $$file; done | \
+	  sed -e "s|^$$srcdirstrip/||;t" \
+	      -e "s|^$$topsrcdirstrip/|$(top_builddir)/|;t"`; \
+	case $$dist_files in \
+	  */*) $(MKDIR_P) `echo "$$dist_files" | \
+			   sed '/\//!d;s|^|$(distdir)/|;s,/[^/]*$$,,' | \
+			   sort -u` ;; \
+	esac; \
+	for file in $$dist_files; do \
+	  if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \
+	  if test -d $$d/$$file; then \
+	    dir=`echo "/$$file" | sed -e 's,/[^/]*$$,,'`; \
+	    if test -d "$(distdir)/$$file"; then \
+	      find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \
+	    fi; \
+	    if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \
+	      cp -fpR $(srcdir)/$$file "$(distdir)$$dir" || exit 1; \
+	      find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \
+	    fi; \
+	    cp -fpR $$d/$$file "$(distdir)$$dir" || exit 1; \
+	  else \
+	    test -f "$(distdir)/$$file" \
+	    || cp -p $$d/$$file "$(distdir)/$$file" \
+	    || exit 1; \
+	  fi; \
+	done
+check-am: all-am
+check: check-am
+all-am: Makefile $(LTLIBRARIES)
+installdirs:
+install: install-am
+install-exec: install-exec-am
+install-data: install-data-am
+uninstall: uninstall-am
+
+install-am: all-am
+	@$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am
+
+installcheck: installcheck-am
+install-strip:
+	$(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \
+	  install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \
+	  `test -z '$(STRIP)' || \
+	    echo "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'"` install
+mostlyclean-generic:
+
+clean-generic:
+
+distclean-generic:
+	-test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES)
+	-test . = "$(srcdir)" || test -z "$(CONFIG_CLEAN_VPATH_FILES)" || rm -f $(CONFIG_CLEAN_VPATH_FILES)
+
+maintainer-clean-generic:
+	@echo "This command is intended for maintainers to use"
+	@echo "it deletes files that may require special tools to rebuild."
+clean: clean-am
+
+clean-am: clean-generic clean-libtool clean-noinstLTLIBRARIES \
+	mostlyclean-am
+
+distclean: distclean-am
+	-rm -rf ./$(DEPDIR)
+	-rm -f Makefile
+distclean-am: clean-am distclean-compile distclean-generic \
+	distclean-tags
+
+dvi: dvi-am
+
+dvi-am:
+
+html: html-am
+
+html-am:
+
+info: info-am
+
+info-am:
+
+install-data-am:
+
+install-dvi: install-dvi-am
+
+install-dvi-am:
+
+install-exec-am:
+
+install-html: install-html-am
+
+install-html-am:
+
+install-info: install-info-am
+
+install-info-am:
+
+install-man:
+
+install-pdf: install-pdf-am
+
+install-pdf-am:
+
+install-ps: install-ps-am
+
+install-ps-am:
+
+installcheck-am:
+
+maintainer-clean: maintainer-clean-am
+	-rm -rf ./$(DEPDIR)
+	-rm -f Makefile
+maintainer-clean-am: distclean-am maintainer-clean-generic
+
+mostlyclean: mostlyclean-am
+
+mostlyclean-am: mostlyclean-compile mostlyclean-generic \
+	mostlyclean-libtool
+
+pdf: pdf-am
+
+pdf-am:
+
+ps: ps-am
+
+ps-am:
+
+uninstall-am:
+
+.MAKE: install-am install-strip
+
+.PHONY: CTAGS GTAGS all all-am check check-am clean clean-generic \
+	clean-libtool clean-noinstLTLIBRARIES ctags distclean \
+	distclean-compile distclean-generic distclean-libtool \
+	distclean-tags distdir dvi dvi-am html html-am info info-am \
+	install install-am install-data install-data-am install-dvi \
+	install-dvi-am install-exec install-exec-am install-html \
+	install-html-am install-info install-info-am install-man \
+	install-pdf install-pdf-am install-ps install-ps-am \
+	install-strip installcheck installcheck-am installdirs \
+	maintainer-clean maintainer-clean-generic mostlyclean \
+	mostlyclean-compile mostlyclean-generic mostlyclean-libtool \
+	pdf pdf-am ps ps-am tags uninstall uninstall-am
+
+
+# Tell versions [3.59,3.63) of GNU make to not export all variables.
+# Otherwise a system limit (for SysV at least) may be exceeded.
+.NOEXPORT:
diff --git a/src/firewall-manager/nm-firewall-manager.c b/src/firewall-manager/nm-firewall-manager.c
new file mode 100644
index 00000000..c19be5e8
--- /dev/null
+++ b/src/firewall-manager/nm-firewall-manager.c
@@ -0,0 +1,327 @@
+/* -*- 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 <string.h>
+#include <glib.h>
+#include <dbus/dbus.h>
+
+#include "nm-firewall-manager.h"
+#include "nm-dbus-manager.h"
+#include "nm-logging.h"
+
+#define NM_FIREWALL_MANAGER_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), \
+                                              NM_TYPE_FIREWALL_MANAGER, \
+                                              NMFirewallManagerPrivate))
+
+G_DEFINE_TYPE (NMFirewallManager, nm_firewall_manager, G_TYPE_OBJECT)
+
+/* Properties */
+enum {
+	PROP_0 = 0,
+	PROP_AVAILABLE,
+	LAST_PROP
+};
+
+typedef struct {
+	NMDBusManager * dbus_mgr;
+	guint           name_owner_id;
+	DBusGProxy *    proxy;
+	gboolean        running;
+	gboolean        disposed;
+} NMFirewallManagerPrivate;
+
+enum {
+	STARTED,
+
+	LAST_SIGNAL
+};
+
+static guint signals[LAST_SIGNAL] = { 0 };
+
+/********************************************************************/
+
+typedef struct {
+	char *iface;
+	FwAddToZoneFunc callback;
+	gpointer user_data;
+} CBInfo;
+
+static void
+cb_info_free (CBInfo *info)
+{
+	g_return_if_fail (info != NULL);
+	g_free (info->iface);
+	g_free (info);
+}
+
+static void
+add_or_change_cb (DBusGProxy *proxy, DBusGProxyCall *call_id, gpointer user_data)
+{
+	CBInfo *info = user_data;
+	GError *error = NULL;
+	char *zone = NULL;
+
+	if (!dbus_g_proxy_end_call (proxy, call_id, &error,
+	                            G_TYPE_STRING, &zone,
+	                            G_TYPE_INVALID)) {
+		g_assert (error);
+		nm_log_warn (LOGD_FIREWALL, "(%s) firewall zone add/change failed: (%d) %s",
+		             info->iface, error->code, error->message);
+	}
+
+	info->callback (error, info->user_data);
+
+	g_free (zone);
+	g_clear_error (&error);
+}
+
+gpointer
+nm_firewall_manager_add_or_change_zone (NMFirewallManager *self,
+                                        const char *iface,
+                                        const char *zone,
+                                        gboolean add, /* TRUE == add, FALSE == change */
+                                        FwAddToZoneFunc callback,
+                                        gpointer user_data)
+{
+	NMFirewallManagerPrivate *priv = NM_FIREWALL_MANAGER_GET_PRIVATE (self);
+	CBInfo *info;
+
+	if (priv->running == FALSE) {
+		nm_log_dbg (LOGD_FIREWALL, "(%s) firewall zone add/change skipped (not running)", iface);
+		callback (NULL, user_data);
+		return NULL;
+	}
+
+	info = g_malloc0 (sizeof (*info));
+	info->iface = g_strdup (iface);
+	info->callback = callback;
+	info->user_data = user_data;
+
+	nm_log_dbg (LOGD_FIREWALL, "(%s) firewall zone %s -> %s", iface, add ? "add" : "change", zone);
+	return dbus_g_proxy_begin_call_with_timeout (priv->proxy,
+	                                             add ? "addInterface" : "changeZone",
+	                                             add_or_change_cb,
+	                                             info,
+	                                             (GDestroyNotify) cb_info_free,
+	                                             10000,      /* timeout */
+	                                             G_TYPE_STRING, zone ? zone : "",
+	                                             G_TYPE_STRING, iface,
+	                                             G_TYPE_INVALID);
+}
+
+static void
+remove_cb (DBusGProxy *proxy, DBusGProxyCall *call_id, gpointer user_data)
+{
+	CBInfo *info = user_data;
+	GError *error = NULL;
+	char * zone = NULL;
+
+	if (!dbus_g_proxy_end_call (proxy, call_id, &error,
+	                            G_TYPE_STRING, &zone,
+	                            G_TYPE_INVALID)) {
+		g_assert (error);
+		nm_log_warn (LOGD_FIREWALL, "(%s) firewall zone remove failed: (%d) %s",
+		             info->iface, error->code, error->message);
+	}
+
+	g_free (zone);
+	g_clear_error (&error);
+}
+
+gpointer
+nm_firewall_manager_remove_from_zone (NMFirewallManager *self,
+                                      const char *iface,
+                                      const char *zone)
+{
+	NMFirewallManagerPrivate *priv = NM_FIREWALL_MANAGER_GET_PRIVATE (self);
+	CBInfo *info;
+
+	if (priv->running == FALSE) {
+		nm_log_dbg (LOGD_FIREWALL, "(%s) firewall zone remove skipped (not running)", iface);
+		return NULL;
+	}
+
+	info = g_malloc0 (sizeof (*info));
+	info->iface = g_strdup (iface);
+
+	nm_log_dbg (LOGD_FIREWALL, "(%s) firewall zone remove -> %s", iface, zone );
+	return dbus_g_proxy_begin_call_with_timeout (priv->proxy,
+	                                             "removeInterface",
+	                                             remove_cb,
+	                                             info,
+	                                             (GDestroyNotify) cb_info_free,
+	                                             10000,      /* timeout */
+	                                             G_TYPE_STRING, zone ? zone : "",
+	                                             G_TYPE_STRING, iface,
+	                                             G_TYPE_INVALID);
+}
+
+void nm_firewall_manager_cancel_call (NMFirewallManager *self, gpointer call)
+{
+	g_return_if_fail (self != NULL);
+	g_return_if_fail (NM_IS_FIREWALL_MANAGER (self));
+	dbus_g_proxy_cancel_call (NM_FIREWALL_MANAGER_GET_PRIVATE (self)->proxy,
+	                          (DBusGProxyCall *) call);
+}
+
+static void
+set_running (NMFirewallManager *self, gboolean now_running)
+{
+	NMFirewallManagerPrivate *priv = NM_FIREWALL_MANAGER_GET_PRIVATE (self);
+	gboolean old_running = priv->running;
+
+	priv->running = now_running;
+	if (old_running != priv->running)
+		g_object_notify (G_OBJECT (self), NM_FIREWALL_MANAGER_AVAILABLE);
+}
+
+static void
+name_owner_changed (NMDBusManager *dbus_mgr,
+                    const char *name,
+                    const char *old_owner,
+                    const char *new_owner,
+                    gpointer user_data)
+{
+	NMFirewallManager *self = NM_FIREWALL_MANAGER (user_data);
+	gboolean old_owner_good = (old_owner && strlen (old_owner));
+	gboolean new_owner_good = (new_owner && strlen (new_owner));
+
+	/* We only care about the firewall here */
+	if (strcmp (FIREWALL_DBUS_SERVICE, name) != 0)
+		return;
+
+	if (!old_owner_good && new_owner_good) {
+		nm_log_dbg (LOGD_FIREWALL, "firewall started");
+		set_running (self, TRUE);
+		g_signal_emit (self, signals[STARTED], 0);
+	} else if (old_owner_good && !new_owner_good) {
+		nm_log_dbg (LOGD_FIREWALL, "firewall stopped");
+		set_running (self, FALSE);
+	}
+}
+
+/*******************************************************************/
+
+NMFirewallManager *
+nm_firewall_manager_get (void)
+{
+	static NMFirewallManager *singleton = NULL;
+
+	if (!singleton)
+		singleton = NM_FIREWALL_MANAGER (g_object_new (NM_TYPE_FIREWALL_MANAGER, NULL));
+	else
+		g_object_ref (singleton);
+
+	g_assert (singleton);
+	return singleton;
+}
+
+static void
+nm_firewall_manager_init (NMFirewallManager * self)
+{
+	NMFirewallManagerPrivate *priv = NM_FIREWALL_MANAGER_GET_PRIVATE (self);
+	DBusGConnection *bus;
+
+	priv->dbus_mgr = nm_dbus_manager_get ();
+	priv->name_owner_id = g_signal_connect (priv->dbus_mgr,
+	                                        NM_DBUS_MANAGER_NAME_OWNER_CHANGED,
+	                                        G_CALLBACK (name_owner_changed),
+	                                        self);
+	priv->running = nm_dbus_manager_name_has_owner (priv->dbus_mgr, FIREWALL_DBUS_SERVICE);
+	nm_log_dbg (LOGD_FIREWALL, "firewall %s running", priv->running ? "is" : "is not" );
+
+	bus = nm_dbus_manager_get_connection (priv->dbus_mgr);
+	priv->proxy = dbus_g_proxy_new_for_name (bus,
+	                                         FIREWALL_DBUS_SERVICE,
+	                                         FIREWALL_DBUS_PATH,
+	                                         FIREWALL_DBUS_INTERFACE_ZONE);
+}
+
+static void
+set_property (GObject *object, guint prop_id, const GValue *value, GParamSpec *pspec)
+{
+	G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+}
+
+static void
+get_property (GObject *object, guint prop_id, GValue *value, GParamSpec *pspec)
+{
+	switch (prop_id) {
+	case PROP_AVAILABLE:
+		g_value_set_boolean (value, NM_FIREWALL_MANAGER_GET_PRIVATE (object)->running);
+		break;
+	default:
+		G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+		break;
+	}
+}
+
+static void
+dispose (GObject *object)
+{
+	NMFirewallManagerPrivate *priv = NM_FIREWALL_MANAGER_GET_PRIVATE (object);
+
+	if (priv->disposed)
+		goto out;
+	priv->disposed = TRUE;
+
+	if (priv->dbus_mgr) {
+		if (priv->name_owner_id)
+			g_signal_handler_disconnect (priv->dbus_mgr, priv->name_owner_id);
+		g_object_unref (G_OBJECT (priv->dbus_mgr));
+	}
+
+	if (priv->proxy)
+		g_object_unref (priv->proxy);
+
+out:
+	/* Chain up to the parent class */
+	G_OBJECT_CLASS (nm_firewall_manager_parent_class)->dispose (object);
+}
+
+static void
+nm_firewall_manager_class_init (NMFirewallManagerClass *klass)
+{
+	GObjectClass *object_class = G_OBJECT_CLASS (klass);
+
+	g_type_class_add_private (object_class, sizeof (NMFirewallManagerPrivate));
+
+	object_class->get_property = get_property;
+	object_class->set_property = set_property;
+	object_class->dispose = dispose;
+
+	g_object_class_install_property (object_class, PROP_AVAILABLE,
+		g_param_spec_boolean (NM_FIREWALL_MANAGER_AVAILABLE,
+		                      "Available",
+		                      "Available",
+		                      FALSE,
+		                      G_PARAM_READABLE));
+
+	signals[STARTED] =
+		g_signal_new ("started",
+					  G_OBJECT_CLASS_TYPE (object_class),
+					  G_SIGNAL_RUN_FIRST,
+					  G_STRUCT_OFFSET (NMFirewallManagerClass, started),
+					  NULL, NULL,
+					  g_cclosure_marshal_VOID__VOID,
+					  G_TYPE_NONE, 0);
+
+}
+
diff --git a/src/firewall-manager/nm-firewall-manager.h b/src/firewall-manager/nm-firewall-manager.h
new file mode 100644
index 00000000..a77984e3
--- /dev/null
+++ b/src/firewall-manager/nm-firewall-manager.h
@@ -0,0 +1,73 @@
+/* -*- 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_FIREWALL_MANAGER_H
+#define NM_FIREWALL_MANAGER_H
+
+#include <glib-object.h>
+#include <dbus/dbus-glib.h>
+
+#define FIREWALL_DBUS_SERVICE         "org.fedoraproject.FirewallD1"
+#define FIREWALL_DBUS_PATH            "/org/fedoraproject/FirewallD1"
+#define FIREWALL_DBUS_INTERFACE       "org.fedoraproject.FirewallD1"
+#define FIREWALL_DBUS_INTERFACE_ZONE  "org.fedoraproject.FirewallD1.zone"
+
+
+G_BEGIN_DECLS
+
+#define NM_TYPE_FIREWALL_MANAGER				(nm_firewall_manager_get_type ())
+#define NM_FIREWALL_MANAGER(obj)				(G_TYPE_CHECK_INSTANCE_CAST ((obj), NM_TYPE_FIREWALL_MANAGER, NMFirewallManager))
+#define NM_FIREWALL_MANAGER_CLASS(klass)		(G_TYPE_CHECK_CLASS_CAST ((klass),  NM_TYPE_FIREWALL_MANAGER, NMFirewallManagerClass))
+#define NM_IS_FIREWALL_MANAGER(obj)				(G_TYPE_CHECK_INSTANCE_TYPE ((obj), NM_TYPE_FIREWALL_MANAGER))
+#define NM_IS_FIREWALL_MANAGER_CLASS(klass)		(G_TYPE_CHECK_CLASS_TYPE ((klass),  NM_TYPE_FIREWALL_MANAGER))
+#define NM_FIREWALL_MANAGER_GET_CLASS(obj)		(G_TYPE_INSTANCE_GET_CLASS ((obj),  NM_TYPE_FIREWALL_MANAGER, NMFirewallManagerClass))
+
+#define NM_FIREWALL_MANAGER_AVAILABLE "available"
+
+typedef struct {
+	GObject parent;
+} NMFirewallManager;
+
+typedef struct {
+	GObjectClass parent;
+
+	/* Signals */
+	void (*started) (NMFirewallManager *manager);
+} NMFirewallManagerClass;
+
+GType nm_firewall_manager_get_type (void);
+
+NMFirewallManager *nm_firewall_manager_get (void);
+
+typedef void (*FwAddToZoneFunc) (GError *error, gpointer user_data);
+
+gpointer nm_firewall_manager_add_or_change_zone (NMFirewallManager *mgr,
+                                                 const char *iface,
+                                                 const char *zone,
+                                                 gboolean add,
+                                                 FwAddToZoneFunc callback,
+                                                 gpointer user_data);
+gpointer nm_firewall_manager_remove_from_zone (NMFirewallManager *mgr,
+                                               const char *iface,
+                                               const char *zone);
+
+void nm_firewall_manager_cancel_call (NMFirewallManager *mgr, gpointer fw_call);
+
+#endif /* NM_FIREWALL_MANAGER_H */
diff --git a/src/generated/Makefile.am b/src/generated/Makefile.am
new file mode 100644
index 00000000..b7f13b88
--- /dev/null
+++ b/src/generated/Makefile.am
@@ -0,0 +1,77 @@
+include $(GLIB_MAKEFILE)
+
+noinst_LTLIBRARIES = libnm-generated.la
+
+libnm_generated_la_SOURCES = \
+	nm-enum-types.c \
+	nm-enum-types.h \
+	nm-marshal.c \
+	nm-marshal.h
+
+nm_daemon_all_sources = \
+	$(top_srcdir)/src/*.[ch] \
+	$(top_srcdir)/src/logging/*.[ch] \
+	$(top_srcdir)/src/dns-manager/*.[ch] \
+	$(top_srcdir)/src/vpn-manager/*.[ch] \
+	$(top_srcdir)/src/dhcp-manager/*.[ch] \
+	$(top_srcdir)/src/ip6-manager/*.[ch] \
+	$(top_srcdir)/src/supplicant-manager/*.[ch] \
+	$(top_srcdir)/src/backends/*.[ch] \
+	$(top_srcdir)/src/ppp-manager/*.[ch] \
+	$(top_srcdir)/src/dnsmasq-manager/*.[ch] \
+	$(top_srcdir)/src/modem-manager/*.[ch] \
+	$(top_srcdir)/src/bluez-manager/*.[ch] \
+	$(top_srcdir)/src/firewall-manager/*.[ch] \
+	$(top_srcdir)/src/settings/*.[ch]
+
+if WITH_WIMAX
+nm_daemon_all_sources += $(top_srcdir)/src/wimax/*.[ch]
+endif
+
+nm_daemon_sources = \
+	$(filter-out %-glue.h %-bindings.h, $(wildcard $(nm_daemon_all_sources)))
+
+GLIB_GENERATED = nm-enum-types.h nm-enum-types.c
+nm_enum_types_sources = $(nm_daemon_sources)
+GLIB_MKENUMS_H_FLAGS = --identifier-prefix NM
+GLIB_MKENUMS_C_FLAGS = --identifier-prefix NM
+
+GLIB_GENERATED += nm-marshal.h nm-marshal.c
+nm_marshal_sources = $(nm_daemon_sources)
+
+INCLUDES = \
+	-I${top_srcdir}/include \
+	-I${top_builddir}/include \
+	-I${top_srcdir}/src \
+	-I${top_srcdir}/src/logging \
+	-I${top_srcdir}/src/dns-manager \
+	-I${top_srcdir}/src/vpn-manager \
+	-I${top_srcdir}/src/dhcp-manager \
+	-I${top_srcdir}/src/ip6-manager \
+	-I${top_srcdir}/src/supplicant-manager \
+	-I${top_srcdir}/src/backends \
+	-I${top_srcdir}/src/ppp-manager \
+	-I${top_srcdir}/src/dnsmasq-manager \
+	-I${top_srcdir}/src/modem-manager \
+	-I$(top_srcdir)/src/bluez-manager \
+	-I$(top_srcdir)/src/firewall-manager \
+	-I$(top_srcdir)/src/settings \
+	-I$(top_srcdir)/src/wifi \
+	-I$(top_srcdir)/src/wimax \
+	-I$(top_srcdir)/libnm-util
+
+libnm_generated_la_CPPFLAGS = \
+	$(DBUS_CFLAGS) \
+	$(GLIB_CFLAGS) \
+	$(GUDEV_CFLAGS) \
+	$(LIBNL_CFLAGS) \
+	$(GMODULE_CFLAGS) \
+	$(POLKIT_CFLAGS) \
+	$(SYSTEMD_CFLAGS) \
+	$(IWMX_SDK_CFLAGS)
+
+libnm_generated_la_LIBADD = \
+	$(GLIB_LIBS)
+
+BUILT_SOURCES = $(GLIB_GENERATED)
+
diff --git a/src/generated/Makefile.in b/src/generated/Makefile.in
new file mode 100644
index 00000000..85a346be
--- /dev/null
+++ b/src/generated/Makefile.in
@@ -0,0 +1,697 @@
+# Makefile.in generated by automake 1.11.1 from Makefile.am.
+# @configure_input@
+
+# Copyright (C) 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002,
+# 2003, 2004, 2005, 2006, 2007, 2008, 2009  Free Software Foundation,
+# Inc.
+# This Makefile.in is free software; the Free Software Foundation
+# gives unlimited permission to copy and/or distribute it,
+# with or without modifications, as long as this notice is preserved.
+
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY, to the extent permitted by law; without
+# even the implied warranty of MERCHANTABILITY or FITNESS FOR A
+# PARTICULAR PURPOSE.
+
+@SET_MAKE@
+
+VPATH = @srcdir@
+pkgdatadir = $(datadir)/@PACKAGE@
+pkgincludedir = $(includedir)/@PACKAGE@
+pkglibdir = $(libdir)/@PACKAGE@
+pkglibexecdir = $(libexecdir)/@PACKAGE@
+am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd
+install_sh_DATA = $(install_sh) -c -m 644
+install_sh_PROGRAM = $(install_sh) -c
+install_sh_SCRIPT = $(install_sh) -c
+INSTALL_HEADER = $(INSTALL_DATA)
+transform = $(program_transform_name)
+NORMAL_INSTALL = :
+PRE_INSTALL = :
+POST_INSTALL = :
+NORMAL_UNINSTALL = :
+PRE_UNINSTALL = :
+POST_UNINSTALL = :
+build_triplet = @build@
+host_triplet = @host@
+@WITH_WIMAX_TRUE@am__append_1 = $(top_srcdir)/src/wimax/*.[ch]
+subdir = src/generated
+DIST_COMMON = $(srcdir)/Makefile.am $(srcdir)/Makefile.in
+ACLOCAL_M4 = $(top_srcdir)/aclocal.m4
+am__aclocal_m4_deps = $(top_srcdir)/m4/compiler_warnings.m4 \
+	$(top_srcdir)/m4/gettext.m4 $(top_srcdir)/m4/gtk-doc.m4 \
+	$(top_srcdir)/m4/iconv.m4 $(top_srcdir)/m4/intlmacosx.m4 \
+	$(top_srcdir)/m4/intltool.m4 $(top_srcdir)/m4/introspection.m4 \
+	$(top_srcdir)/m4/lib-ld.m4 $(top_srcdir)/m4/lib-link.m4 \
+	$(top_srcdir)/m4/lib-prefix.m4 $(top_srcdir)/m4/libnl-check.m4 \
+	$(top_srcdir)/m4/libtool.m4 $(top_srcdir)/m4/ltoptions.m4 \
+	$(top_srcdir)/m4/ltsugar.m4 $(top_srcdir)/m4/ltversion.m4 \
+	$(top_srcdir)/m4/lt~obsolete.m4 $(top_srcdir)/m4/nls.m4 \
+	$(top_srcdir)/m4/po.m4 $(top_srcdir)/m4/progtest.m4 \
+	$(top_srcdir)/configure.ac
+am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \
+	$(ACLOCAL_M4)
+mkinstalldirs = $(install_sh) -d
+CONFIG_HEADER = $(top_builddir)/config.h
+CONFIG_CLEAN_FILES =
+CONFIG_CLEAN_VPATH_FILES =
+LTLIBRARIES = $(noinst_LTLIBRARIES)
+am__DEPENDENCIES_1 =
+libnm_generated_la_DEPENDENCIES = $(am__DEPENDENCIES_1)
+am_libnm_generated_la_OBJECTS = libnm_generated_la-nm-enum-types.lo \
+	libnm_generated_la-nm-marshal.lo
+libnm_generated_la_OBJECTS = $(am_libnm_generated_la_OBJECTS)
+AM_V_lt = $(am__v_lt_$(V))
+am__v_lt_ = $(am__v_lt_$(AM_DEFAULT_VERBOSITY))
+am__v_lt_0 = --silent
+DEFAULT_INCLUDES = -I.@am__isrc@ -I$(top_builddir)
+depcomp = $(SHELL) $(top_srcdir)/build-aux/depcomp
+am__depfiles_maybe = depfiles
+am__mv = mv -f
+COMPILE = $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) \
+	$(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS)
+LTCOMPILE = $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) \
+	$(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) \
+	$(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) \
+	$(AM_CFLAGS) $(CFLAGS)
+AM_V_CC = $(am__v_CC_$(V))
+am__v_CC_ = $(am__v_CC_$(AM_DEFAULT_VERBOSITY))
+am__v_CC_0 = @echo "  CC    " $@;
+AM_V_at = $(am__v_at_$(V))
+am__v_at_ = $(am__v_at_$(AM_DEFAULT_VERBOSITY))
+am__v_at_0 = @
+CCLD = $(CC)
+LINK = $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) \
+	$(LIBTOOLFLAGS) --mode=link $(CCLD) $(AM_CFLAGS) $(CFLAGS) \
+	$(AM_LDFLAGS) $(LDFLAGS) -o $@
+AM_V_CCLD = $(am__v_CCLD_$(V))
+am__v_CCLD_ = $(am__v_CCLD_$(AM_DEFAULT_VERBOSITY))
+am__v_CCLD_0 = @echo "  CCLD  " $@;
+AM_V_GEN = $(am__v_GEN_$(V))
+am__v_GEN_ = $(am__v_GEN_$(AM_DEFAULT_VERBOSITY))
+am__v_GEN_0 = @echo "  GEN   " $@;
+SOURCES = $(libnm_generated_la_SOURCES)
+DIST_SOURCES = $(libnm_generated_la_SOURCES)
+ETAGS = etags
+CTAGS = ctags
+DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST)
+ACLOCAL = @ACLOCAL@
+ALL_LINGUAS = @ALL_LINGUAS@
+AMTAR = @AMTAR@
+AM_DEFAULT_VERBOSITY = @AM_DEFAULT_VERBOSITY@
+AR = @AR@
+AUTOCONF = @AUTOCONF@
+AUTOHEADER = @AUTOHEADER@
+AUTOMAKE = @AUTOMAKE@
+AWK = @AWK@
+CC = @CC@
+CCDEPMODE = @CCDEPMODE@
+CFLAGS = @CFLAGS@
+CPP = @CPP@
+CPPFLAGS = @CPPFLAGS@
+CXX = @CXX@
+CXXCPP = @CXXCPP@
+CXXDEPMODE = @CXXDEPMODE@
+CXXFLAGS = @CXXFLAGS@
+CYGPATH_W = @CYGPATH_W@
+DATADIRNAME = @DATADIRNAME@
+DBUS_CFLAGS = @DBUS_CFLAGS@
+DBUS_LIBS = @DBUS_LIBS@
+DBUS_SYS_DIR = @DBUS_SYS_DIR@
+DEFS = @DEFS@
+DEPDIR = @DEPDIR@
+DHCLIENT_PATH = @DHCLIENT_PATH@
+DHCLIENT_VERSION = @DHCLIENT_VERSION@
+DHCPCD_PATH = @DHCPCD_PATH@
+DISABLE_DEPRECATED = @DISABLE_DEPRECATED@
+DLLTOOL = @DLLTOOL@
+DSYMUTIL = @DSYMUTIL@
+DUMPBIN = @DUMPBIN@
+ECHO_C = @ECHO_C@
+ECHO_N = @ECHO_N@
+ECHO_T = @ECHO_T@
+EGREP = @EGREP@
+EXEEXT = @EXEEXT@
+FGREP = @FGREP@
+GETTEXT_MACRO_VERSION = @GETTEXT_MACRO_VERSION@
+GETTEXT_PACKAGE = @GETTEXT_PACKAGE@
+GIO_CFLAGS = @GIO_CFLAGS@
+GIO_LIBS = @GIO_LIBS@
+GLIB_CFLAGS = @GLIB_CFLAGS@
+GLIB_GENMARSHAL = @GLIB_GENMARSHAL@
+GLIB_LIBS = @GLIB_LIBS@
+GLIB_MAKEFILE = @GLIB_MAKEFILE@
+GLIB_MKENUMS = @GLIB_MKENUMS@
+GMODULE_CFLAGS = @GMODULE_CFLAGS@
+GMODULE_LIBS = @GMODULE_LIBS@
+GMSGFMT = @GMSGFMT@
+GMSGFMT_015 = @GMSGFMT_015@
+GNUTLS_CFLAGS = @GNUTLS_CFLAGS@
+GNUTLS_LIBS = @GNUTLS_LIBS@
+GREP = @GREP@
+GTKDOC_CHECK = @GTKDOC_CHECK@
+GTKDOC_DEPS_CFLAGS = @GTKDOC_DEPS_CFLAGS@
+GTKDOC_DEPS_LIBS = @GTKDOC_DEPS_LIBS@
+GTKDOC_MKPDF = @GTKDOC_MKPDF@
+GTKDOC_REBASE = @GTKDOC_REBASE@
+GUDEV_CFLAGS = @GUDEV_CFLAGS@
+GUDEV_LIBS = @GUDEV_LIBS@
+HTML_DIR = @HTML_DIR@
+INSTALL = @INSTALL@
+INSTALL_DATA = @INSTALL_DATA@
+INSTALL_PROGRAM = @INSTALL_PROGRAM@
+INSTALL_SCRIPT = @INSTALL_SCRIPT@
+INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@
+INTLLIBS = @INTLLIBS@
+INTLTOOL_EXTRACT = @INTLTOOL_EXTRACT@
+INTLTOOL_MERGE = @INTLTOOL_MERGE@
+INTLTOOL_PERL = @INTLTOOL_PERL@
+INTLTOOL_UPDATE = @INTLTOOL_UPDATE@
+INTL_MACOSX_LIBS = @INTL_MACOSX_LIBS@
+INTROSPECTION_CFLAGS = @INTROSPECTION_CFLAGS@
+INTROSPECTION_COMPILER = @INTROSPECTION_COMPILER@
+INTROSPECTION_GENERATE = @INTROSPECTION_GENERATE@
+INTROSPECTION_GIRDIR = @INTROSPECTION_GIRDIR@
+INTROSPECTION_LIBS = @INTROSPECTION_LIBS@
+INTROSPECTION_MAKEFILE = @INTROSPECTION_MAKEFILE@
+INTROSPECTION_SCANNER = @INTROSPECTION_SCANNER@
+INTROSPECTION_TYPELIBDIR = @INTROSPECTION_TYPELIBDIR@
+IPTABLES_PATH = @IPTABLES_PATH@
+IWMX_SDK_CFLAGS = @IWMX_SDK_CFLAGS@
+IWMX_SDK_LIBS = @IWMX_SDK_LIBS@
+KERNEL_FIRMWARE_DIR = @KERNEL_FIRMWARE_DIR@
+LD = @LD@
+LDFLAGS = @LDFLAGS@
+LIBDL = @LIBDL@
+LIBGCRYPT_CFLAGS = @LIBGCRYPT_CFLAGS@
+LIBGCRYPT_CONFIG = @LIBGCRYPT_CONFIG@
+LIBGCRYPT_LIBS = @LIBGCRYPT_LIBS@
+LIBICONV = @LIBICONV@
+LIBINTL = @LIBINTL@
+LIBM = @LIBM@
+LIBNL1_CFLAGS = @LIBNL1_CFLAGS@
+LIBNL1_LIBS = @LIBNL1_LIBS@
+LIBNL2_CFLAGS = @LIBNL2_CFLAGS@
+LIBNL2_LIBS = @LIBNL2_LIBS@
+LIBNL3_CFLAGS = @LIBNL3_CFLAGS@
+LIBNL3_LIBS = @LIBNL3_LIBS@
+LIBNL_CFLAGS = @LIBNL_CFLAGS@
+LIBNL_GENL3_CFLAGS = @LIBNL_GENL3_CFLAGS@
+LIBNL_GENL3_LIBS = @LIBNL_GENL3_LIBS@
+LIBNL_LIBS = @LIBNL_LIBS@
+LIBNL_ROUTE3_CFLAGS = @LIBNL_ROUTE3_CFLAGS@
+LIBNL_ROUTE3_LIBS = @LIBNL_ROUTE3_LIBS@
+LIBOBJS = @LIBOBJS@
+LIBS = @LIBS@
+LIBSOUP_CFLAGS = @LIBSOUP_CFLAGS@
+LIBSOUP_LIBS = @LIBSOUP_LIBS@
+LIBTOOL = @LIBTOOL@
+LIPO = @LIPO@
+LN_S = @LN_S@
+LTLIBICONV = @LTLIBICONV@
+LTLIBINTL = @LTLIBINTL@
+LTLIBOBJS = @LTLIBOBJS@
+MAINT = @MAINT@
+MAKEINFO = @MAKEINFO@
+MANIFEST_TOOL = @MANIFEST_TOOL@
+MKDIR_P = @MKDIR_P@
+MOC = @MOC@
+MSGFMT = @MSGFMT@
+MSGFMT_015 = @MSGFMT_015@
+MSGMERGE = @MSGMERGE@
+NM = @NM@
+NMEDIT = @NMEDIT@
+NM_MAJOR_VERSION = @NM_MAJOR_VERSION@
+NM_MICRO_VERSION = @NM_MICRO_VERSION@
+NM_MINOR_VERSION = @NM_MINOR_VERSION@
+NM_VERSION = @NM_VERSION@
+NSS_CFLAGS = @NSS_CFLAGS@
+NSS_LIBS = @NSS_LIBS@
+OBJDUMP = @OBJDUMP@
+OBJEXT = @OBJEXT@
+OTOOL = @OTOOL@
+OTOOL64 = @OTOOL64@
+PACKAGE = @PACKAGE@
+PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@
+PACKAGE_NAME = @PACKAGE_NAME@
+PACKAGE_STRING = @PACKAGE_STRING@
+PACKAGE_TARNAME = @PACKAGE_TARNAME@
+PACKAGE_URL = @PACKAGE_URL@
+PACKAGE_VERSION = @PACKAGE_VERSION@
+PATH_SEPARATOR = @PATH_SEPARATOR@
+PKGCONFIG_PATH = @PKGCONFIG_PATH@
+PKG_CONFIG = @PKG_CONFIG@
+PKG_CONFIG_LIBDIR = @PKG_CONFIG_LIBDIR@
+PKG_CONFIG_PATH = @PKG_CONFIG_PATH@
+POLKIT_CFLAGS = @POLKIT_CFLAGS@
+POLKIT_LIBS = @POLKIT_LIBS@
+POSUB = @POSUB@
+PPPD_PLUGIN_DIR = @PPPD_PLUGIN_DIR@
+QT_CFLAGS = @QT_CFLAGS@
+QT_LIBS = @QT_LIBS@
+RANLIB = @RANLIB@
+RESOLVCONF_PATH = @RESOLVCONF_PATH@
+SED = @SED@
+SET_MAKE = @SET_MAKE@
+SHELL = @SHELL@
+STRIP = @STRIP@
+SYSTEMD_CFLAGS = @SYSTEMD_CFLAGS@
+SYSTEMD_LIBS = @SYSTEMD_LIBS@
+SYSTEM_CA_PATH = @SYSTEM_CA_PATH@
+UDEV_BASE_DIR = @UDEV_BASE_DIR@
+USE_NLS = @USE_NLS@
+UUID_CFLAGS = @UUID_CFLAGS@
+UUID_LIBS = @UUID_LIBS@
+VERSION = @VERSION@
+XGETTEXT = @XGETTEXT@
+XGETTEXT_015 = @XGETTEXT_015@
+XGETTEXT_EXTRA_OPTIONS = @XGETTEXT_EXTRA_OPTIONS@
+abs_builddir = @abs_builddir@
+abs_srcdir = @abs_srcdir@
+abs_top_builddir = @abs_top_builddir@
+abs_top_srcdir = @abs_top_srcdir@
+ac_ct_AR = @ac_ct_AR@
+ac_ct_CC = @ac_ct_CC@
+ac_ct_CXX = @ac_ct_CXX@
+ac_ct_DUMPBIN = @ac_ct_DUMPBIN@
+am__include = @am__include@
+am__leading_dot = @am__leading_dot@
+am__quote = @am__quote@
+am__tar = @am__tar@
+am__untar = @am__untar@
+bindir = @bindir@
+build = @build@
+build_alias = @build_alias@
+build_cpu = @build_cpu@
+build_os = @build_os@
+build_vendor = @build_vendor@
+builddir = @builddir@
+datadir = @datadir@
+datarootdir = @datarootdir@
+docdir = @docdir@
+dvidir = @dvidir@
+exec_prefix = @exec_prefix@
+host = @host@
+host_alias = @host_alias@
+host_cpu = @host_cpu@
+host_os = @host_os@
+host_vendor = @host_vendor@
+htmldir = @htmldir@
+includedir = @includedir@
+infodir = @infodir@
+install_sh = @install_sh@
+libdir = @libdir@
+libexecdir = @libexecdir@
+localedir = @localedir@
+localstatedir = @localstatedir@
+mandir = @mandir@
+mkdir_p = @mkdir_p@
+oldincludedir = @oldincludedir@
+pdfdir = @pdfdir@
+prefix = @prefix@
+program_transform_name = @program_transform_name@
+psdir = @psdir@
+sbindir = @sbindir@
+sharedstatedir = @sharedstatedir@
+srcdir = @srcdir@
+sysconfdir = @sysconfdir@
+systemdsystemunitdir = @systemdsystemunitdir@
+target_alias = @target_alias@
+top_build_prefix = @top_build_prefix@
+top_builddir = @top_builddir@
+top_srcdir = @top_srcdir@
+noinst_LTLIBRARIES = libnm-generated.la
+libnm_generated_la_SOURCES = \
+	nm-enum-types.c \
+	nm-enum-types.h \
+	nm-marshal.c \
+	nm-marshal.h
+
+nm_daemon_all_sources = $(top_srcdir)/src/*.[ch] \
+	$(top_srcdir)/src/logging/*.[ch] \
+	$(top_srcdir)/src/dns-manager/*.[ch] \
+	$(top_srcdir)/src/vpn-manager/*.[ch] \
+	$(top_srcdir)/src/dhcp-manager/*.[ch] \
+	$(top_srcdir)/src/ip6-manager/*.[ch] \
+	$(top_srcdir)/src/supplicant-manager/*.[ch] \
+	$(top_srcdir)/src/backends/*.[ch] \
+	$(top_srcdir)/src/ppp-manager/*.[ch] \
+	$(top_srcdir)/src/dnsmasq-manager/*.[ch] \
+	$(top_srcdir)/src/modem-manager/*.[ch] \
+	$(top_srcdir)/src/bluez-manager/*.[ch] \
+	$(top_srcdir)/src/firewall-manager/*.[ch] \
+	$(top_srcdir)/src/settings/*.[ch] $(am__append_1)
+nm_daemon_sources = \
+	$(filter-out %-glue.h %-bindings.h, $(wildcard $(nm_daemon_all_sources)))
+
+GLIB_GENERATED = nm-enum-types.h nm-enum-types.c nm-marshal.h \
+	nm-marshal.c
+nm_enum_types_sources = $(nm_daemon_sources)
+GLIB_MKENUMS_H_FLAGS = --identifier-prefix NM
+GLIB_MKENUMS_C_FLAGS = --identifier-prefix NM
+nm_marshal_sources = $(nm_daemon_sources)
+INCLUDES = \
+	-I${top_srcdir}/include \
+	-I${top_builddir}/include \
+	-I${top_srcdir}/src \
+	-I${top_srcdir}/src/logging \
+	-I${top_srcdir}/src/dns-manager \
+	-I${top_srcdir}/src/vpn-manager \
+	-I${top_srcdir}/src/dhcp-manager \
+	-I${top_srcdir}/src/ip6-manager \
+	-I${top_srcdir}/src/supplicant-manager \
+	-I${top_srcdir}/src/backends \
+	-I${top_srcdir}/src/ppp-manager \
+	-I${top_srcdir}/src/dnsmasq-manager \
+	-I${top_srcdir}/src/modem-manager \
+	-I$(top_srcdir)/src/bluez-manager \
+	-I$(top_srcdir)/src/firewall-manager \
+	-I$(top_srcdir)/src/settings \
+	-I$(top_srcdir)/src/wifi \
+	-I$(top_srcdir)/src/wimax \
+	-I$(top_srcdir)/libnm-util
+
+libnm_generated_la_CPPFLAGS = \
+	$(DBUS_CFLAGS) \
+	$(GLIB_CFLAGS) \
+	$(GUDEV_CFLAGS) \
+	$(LIBNL_CFLAGS) \
+	$(GMODULE_CFLAGS) \
+	$(POLKIT_CFLAGS) \
+	$(SYSTEMD_CFLAGS) \
+	$(IWMX_SDK_CFLAGS)
+
+libnm_generated_la_LIBADD = \
+	$(GLIB_LIBS)
+
+BUILT_SOURCES = $(GLIB_GENERATED)
+all: $(BUILT_SOURCES)
+	$(MAKE) $(AM_MAKEFLAGS) all-am
+
+.SUFFIXES:
+.SUFFIXES: .c .lo .o .obj
+$(srcdir)/Makefile.in: @MAINTAINER_MODE_TRUE@ $(srcdir)/Makefile.am  $(am__configure_deps)
+	@for dep in $?; do \
+	  case '$(am__configure_deps)' in \
+	    *$$dep*) \
+	      ( cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh ) \
+	        && { if test -f $@; then exit 0; else break; fi; }; \
+	      exit 1;; \
+	  esac; \
+	done; \
+	echo ' cd $(top_srcdir) && $(AUTOMAKE) --gnu src/generated/Makefile'; \
+	$(am__cd) $(top_srcdir) && \
+	  $(AUTOMAKE) --gnu src/generated/Makefile
+.PRECIOUS: Makefile
+Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status
+	@case '$?' in \
+	  *config.status*) \
+	    cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh;; \
+	  *) \
+	    echo ' cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe)'; \
+	    cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe);; \
+	esac;
+
+$(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES)
+	cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+
+$(top_srcdir)/configure: @MAINTAINER_MODE_TRUE@ $(am__configure_deps)
+	cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+$(ACLOCAL_M4): @MAINTAINER_MODE_TRUE@ $(am__aclocal_m4_deps)
+	cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+$(am__aclocal_m4_deps):
+
+clean-noinstLTLIBRARIES:
+	-test -z "$(noinst_LTLIBRARIES)" || rm -f $(noinst_LTLIBRARIES)
+	@list='$(noinst_LTLIBRARIES)'; for p in $$list; do \
+	  dir="`echo $$p | sed -e 's|/[^/]*$$||'`"; \
+	  test "$$dir" != "$$p" || dir=.; \
+	  echo "rm -f \"$${dir}/so_locations\""; \
+	  rm -f "$${dir}/so_locations"; \
+	done
+libnm-generated.la: $(libnm_generated_la_OBJECTS) $(libnm_generated_la_DEPENDENCIES) 
+	$(AM_V_CCLD)$(LINK)  $(libnm_generated_la_OBJECTS) $(libnm_generated_la_LIBADD) $(LIBS)
+
+mostlyclean-compile:
+	-rm -f *.$(OBJEXT)
+
+distclean-compile:
+	-rm -f *.tab.c
+
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libnm_generated_la-nm-enum-types.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libnm_generated_la-nm-marshal.Plo@am__quote@
+
+.c.o:
+@am__fastdepCC_TRUE@	$(AM_V_CC)depbase=`echo $@ | sed 's|[^/]*$$|$(DEPDIR)/&|;s|\.o$$||'`;\
+@am__fastdepCC_TRUE@	$(COMPILE) -MT $@ -MD -MP -MF $$depbase.Tpo -c -o $@ $< &&\
+@am__fastdepCC_TRUE@	$(am__mv) $$depbase.Tpo $$depbase.Po
+@am__fastdepCC_FALSE@	$(AM_V_CC) @AM_BACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@	source='$<' object='$@' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@	DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@	$(COMPILE) -c -o $@ $<
+
+.c.obj:
+@am__fastdepCC_TRUE@	$(AM_V_CC)depbase=`echo $@ | sed 's|[^/]*$$|$(DEPDIR)/&|;s|\.obj$$||'`;\
+@am__fastdepCC_TRUE@	$(COMPILE) -MT $@ -MD -MP -MF $$depbase.Tpo -c -o $@ `$(CYGPATH_W) '$<'` &&\
+@am__fastdepCC_TRUE@	$(am__mv) $$depbase.Tpo $$depbase.Po
+@am__fastdepCC_FALSE@	$(AM_V_CC) @AM_BACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@	source='$<' object='$@' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@	DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@	$(COMPILE) -c -o $@ `$(CYGPATH_W) '$<'`
+
+.c.lo:
+@am__fastdepCC_TRUE@	$(AM_V_CC)depbase=`echo $@ | sed 's|[^/]*$$|$(DEPDIR)/&|;s|\.lo$$||'`;\
+@am__fastdepCC_TRUE@	$(LTCOMPILE) -MT $@ -MD -MP -MF $$depbase.Tpo -c -o $@ $< &&\
+@am__fastdepCC_TRUE@	$(am__mv) $$depbase.Tpo $$depbase.Plo
+@am__fastdepCC_FALSE@	$(AM_V_CC) @AM_BACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@	source='$<' object='$@' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@	DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@	$(LTCOMPILE) -c -o $@ $<
+
+libnm_generated_la-nm-enum-types.lo: nm-enum-types.c
+@am__fastdepCC_TRUE@	$(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libnm_generated_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT libnm_generated_la-nm-enum-types.lo -MD -MP -MF $(DEPDIR)/libnm_generated_la-nm-enum-types.Tpo -c -o libnm_generated_la-nm-enum-types.lo `test -f 'nm-enum-types.c' || echo '$(srcdir)/'`nm-enum-types.c
+@am__fastdepCC_TRUE@	$(AM_V_at)$(am__mv) $(DEPDIR)/libnm_generated_la-nm-enum-types.Tpo $(DEPDIR)/libnm_generated_la-nm-enum-types.Plo
+@am__fastdepCC_FALSE@	$(AM_V_CC) @AM_BACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@	source='nm-enum-types.c' object='libnm_generated_la-nm-enum-types.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@	DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@	$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libnm_generated_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o libnm_generated_la-nm-enum-types.lo `test -f 'nm-enum-types.c' || echo '$(srcdir)/'`nm-enum-types.c
+
+libnm_generated_la-nm-marshal.lo: nm-marshal.c
+@am__fastdepCC_TRUE@	$(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libnm_generated_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT libnm_generated_la-nm-marshal.lo -MD -MP -MF $(DEPDIR)/libnm_generated_la-nm-marshal.Tpo -c -o libnm_generated_la-nm-marshal.lo `test -f 'nm-marshal.c' || echo '$(srcdir)/'`nm-marshal.c
+@am__fastdepCC_TRUE@	$(AM_V_at)$(am__mv) $(DEPDIR)/libnm_generated_la-nm-marshal.Tpo $(DEPDIR)/libnm_generated_la-nm-marshal.Plo
+@am__fastdepCC_FALSE@	$(AM_V_CC) @AM_BACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@	source='nm-marshal.c' object='libnm_generated_la-nm-marshal.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@	DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@	$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libnm_generated_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o libnm_generated_la-nm-marshal.lo `test -f 'nm-marshal.c' || echo '$(srcdir)/'`nm-marshal.c
+
+mostlyclean-libtool:
+	-rm -f *.lo
+
+clean-libtool:
+	-rm -rf .libs _libs
+
+ID: $(HEADERS) $(SOURCES) $(LISP) $(TAGS_FILES)
+	list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \
+	unique=`for i in $$list; do \
+	    if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \
+	  done | \
+	  $(AWK) '{ files[$$0] = 1; nonempty = 1; } \
+	      END { if (nonempty) { for (i in files) print i; }; }'`; \
+	mkid -fID $$unique
+tags: TAGS
+
+TAGS:  $(HEADERS) $(SOURCES)  $(TAGS_DEPENDENCIES) \
+		$(TAGS_FILES) $(LISP)
+	set x; \
+	here=`pwd`; \
+	list='$(SOURCES) $(HEADERS)  $(LISP) $(TAGS_FILES)'; \
+	unique=`for i in $$list; do \
+	    if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \
+	  done | \
+	  $(AWK) '{ files[$$0] = 1; nonempty = 1; } \
+	      END { if (nonempty) { for (i in files) print i; }; }'`; \
+	shift; \
+	if test -z "$(ETAGS_ARGS)$$*$$unique"; then :; else \
+	  test -n "$$unique" || unique=$$empty_fix; \
+	  if test $$# -gt 0; then \
+	    $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \
+	      "$$@" $$unique; \
+	  else \
+	    $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \
+	      $$unique; \
+	  fi; \
+	fi
+ctags: CTAGS
+CTAGS:  $(HEADERS) $(SOURCES)  $(TAGS_DEPENDENCIES) \
+		$(TAGS_FILES) $(LISP)
+	list='$(SOURCES) $(HEADERS)  $(LISP) $(TAGS_FILES)'; \
+	unique=`for i in $$list; do \
+	    if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \
+	  done | \
+	  $(AWK) '{ files[$$0] = 1; nonempty = 1; } \
+	      END { if (nonempty) { for (i in files) print i; }; }'`; \
+	test -z "$(CTAGS_ARGS)$$unique" \
+	  || $(CTAGS) $(CTAGSFLAGS) $(AM_CTAGSFLAGS) $(CTAGS_ARGS) \
+	     $$unique
+
+GTAGS:
+	here=`$(am__cd) $(top_builddir) && pwd` \
+	  && $(am__cd) $(top_srcdir) \
+	  && gtags -i $(GTAGS_ARGS) "$$here"
+
+distclean-tags:
+	-rm -f TAGS ID GTAGS GRTAGS GSYMS GPATH tags
+
+distdir: $(DISTFILES)
+	@srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \
+	topsrcdirstrip=`echo "$(top_srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \
+	list='$(DISTFILES)'; \
+	  dist_files=`for file in $$list; do echo $$file; done | \
+	  sed -e "s|^$$srcdirstrip/||;t" \
+	      -e "s|^$$topsrcdirstrip/|$(top_builddir)/|;t"`; \
+	case $$dist_files in \
+	  */*) $(MKDIR_P) `echo "$$dist_files" | \
+			   sed '/\//!d;s|^|$(distdir)/|;s,/[^/]*$$,,' | \
+			   sort -u` ;; \
+	esac; \
+	for file in $$dist_files; do \
+	  if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \
+	  if test -d $$d/$$file; then \
+	    dir=`echo "/$$file" | sed -e 's,/[^/]*$$,,'`; \
+	    if test -d "$(distdir)/$$file"; then \
+	      find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \
+	    fi; \
+	    if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \
+	      cp -fpR $(srcdir)/$$file "$(distdir)$$dir" || exit 1; \
+	      find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \
+	    fi; \
+	    cp -fpR $$d/$$file "$(distdir)$$dir" || exit 1; \
+	  else \
+	    test -f "$(distdir)/$$file" \
+	    || cp -p $$d/$$file "$(distdir)/$$file" \
+	    || exit 1; \
+	  fi; \
+	done
+check-am: all-am
+check: $(BUILT_SOURCES)
+	$(MAKE) $(AM_MAKEFLAGS) check-am
+all-am: Makefile $(LTLIBRARIES)
+installdirs:
+install: $(BUILT_SOURCES)
+	$(MAKE) $(AM_MAKEFLAGS) install-am
+install-exec: install-exec-am
+install-data: install-data-am
+uninstall: uninstall-am
+
+install-am: all-am
+	@$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am
+
+installcheck: installcheck-am
+install-strip:
+	$(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \
+	  install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \
+	  `test -z '$(STRIP)' || \
+	    echo "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'"` install
+mostlyclean-generic:
+
+clean-generic:
+
+distclean-generic:
+	-test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES)
+	-test . = "$(srcdir)" || test -z "$(CONFIG_CLEAN_VPATH_FILES)" || rm -f $(CONFIG_CLEAN_VPATH_FILES)
+
+maintainer-clean-generic:
+	@echo "This command is intended for maintainers to use"
+	@echo "it deletes files that may require special tools to rebuild."
+	-test -z "$(BUILT_SOURCES)" || rm -f $(BUILT_SOURCES)
+clean: clean-am
+
+clean-am: clean-generic clean-libtool clean-noinstLTLIBRARIES \
+	mostlyclean-am
+
+distclean: distclean-am
+	-rm -rf ./$(DEPDIR)
+	-rm -f Makefile
+distclean-am: clean-am distclean-compile distclean-generic \
+	distclean-tags
+
+dvi: dvi-am
+
+dvi-am:
+
+html: html-am
+
+html-am:
+
+info: info-am
+
+info-am:
+
+install-data-am:
+
+install-dvi: install-dvi-am
+
+install-dvi-am:
+
+install-exec-am:
+
+install-html: install-html-am
+
+install-html-am:
+
+install-info: install-info-am
+
+install-info-am:
+
+install-man:
+
+install-pdf: install-pdf-am
+
+install-pdf-am:
+
+install-ps: install-ps-am
+
+install-ps-am:
+
+installcheck-am:
+
+maintainer-clean: maintainer-clean-am
+	-rm -rf ./$(DEPDIR)
+	-rm -f Makefile
+maintainer-clean-am: distclean-am maintainer-clean-generic
+
+mostlyclean: mostlyclean-am
+
+mostlyclean-am: mostlyclean-compile mostlyclean-generic \
+	mostlyclean-libtool
+
+pdf: pdf-am
+
+pdf-am:
+
+ps: ps-am
+
+ps-am:
+
+uninstall-am:
+
+.MAKE: all check install install-am install-strip
+
+.PHONY: CTAGS GTAGS all all-am check check-am clean clean-generic \
+	clean-libtool clean-noinstLTLIBRARIES ctags distclean \
+	distclean-compile distclean-generic distclean-libtool \
+	distclean-tags distdir dvi dvi-am html html-am info info-am \
+	install install-am install-data install-data-am install-dvi \
+	install-dvi-am install-exec install-exec-am install-html \
+	install-html-am install-info install-info-am install-man \
+	install-pdf install-pdf-am install-ps install-ps-am \
+	install-strip installcheck installcheck-am installdirs \
+	maintainer-clean maintainer-clean-generic mostlyclean \
+	mostlyclean-compile mostlyclean-generic mostlyclean-libtool \
+	pdf pdf-am ps ps-am tags uninstall uninstall-am
+
+include $(GLIB_MAKEFILE)
+
+# Tell versions [3.59,3.63) of GNU make to not export all variables.
+# Otherwise a system limit (for SysV at least) may be exceeded.
+.NOEXPORT:
diff --git a/src/generated/nm-enum-types.c b/src/generated/nm-enum-types.c
new file mode 100644
index 00000000..a9973b4d
--- /dev/null
+++ b/src/generated/nm-enum-types.c
@@ -0,0 +1,913 @@
+
+
+
+/* Generated by glib-mkenums. Do not edit */
+
+#include "nm-enum-types.h"
+
+#include "nm-device-vlan.h" 
+#include "nm-device-olpc-mesh.h" 
+#include "nm-hostname-provider.h" 
+#include "nm-device.h" 
+#include "nm-rfkill.h" 
+#include "NetworkManagerUtils.h" 
+#include "nm-device-factory.h" 
+#include "nm-active-connection.h" 
+#include "nm-wifi-ap.h" 
+#include "nm-device-ethernet.h" 
+#include "nm-device-bt.h" 
+#include "nm-device-wifi.h" 
+#include "nm-dbus-manager.h" 
+#include "nm-dhcp4-config.h" 
+#include "nm-dhcp6-config.h" 
+#include "nm-netlink-compat.h" 
+#include "nm-session-monitor.h" 
+#include "nm-ip4-config.h" 
+#include "nm-device-bond.h" 
+#include "nm-wifi-ap-utils.h" 
+#include "nm-call-store.h" 
+#include "nm-policy-hosts.h" 
+#include "nm-udev-manager.h" 
+#include "nm-manager.h" 
+#include "nm-device-modem.h" 
+#include "nm-device-wired.h" 
+#include "nm-activation-request.h" 
+#include "nm-session-utils.h" 
+#include "nm-policy-hostname.h" 
+#include "nm-device-infiniband.h" 
+#include "nm-properties-changed-signal.h" 
+#include "nm-ip6-config.h" 
+#include "nm-device-private.h" 
+#include "nm-policy.h" 
+#include "nm-manager-auth.h" 
+#include "nm-config.h" 
+#include "nm-netlink-utils.h" 
+#include "nm-netlink-monitor.h" 
+#include "nm-system.h" 
+#include "nm-connectivity.h" 
+#include "nm-logging.h" 
+#include "nm-dns-utils.h" 
+#include "nm-dns-plugin.h" 
+#include "nm-dns-manager.h" 
+#include "nm-dns-bind.h" 
+#include "nm-dns-dnsmasq.h" 
+#include "nm-vpn-manager.h" 
+#include "nm-vpn-service.h" 
+#include "nm-vpn-connection.h" 
+#include "nm-dhcp-dhcpcd.h" 
+#include "nm-dhcp-dhclient.h" 
+#include "nm-dhcp-client.h" 
+#include "nm-dhcp-dhclient-utils.h" 
+#include "nm-dhcp-manager.h" 
+#include "nm-ip6-manager.h" 
+#include "nm-supplicant-types.h" 
+#include "nm-supplicant-config.h" 
+#include "nm-supplicant-settings-verify.h" 
+#include "nm-supplicant-manager.h" 
+#include "nm-supplicant-interface.h" 
+#include "nm-backend.h" 
+#include "NetworkManagerGeneric.h" 
+#include "nm-ppp-status.h" 
+#include "nm-pppd-plugin.h" 
+#include "nm-ppp-manager.h" 
+#include "nm-dnsmasq-manager.h" 
+#include "nm-modem.h" 
+#include "nm-modem-cdma.h" 
+#include "nm-modem-types.h" 
+#include "nm-modem-gsm.h" 
+#include "nm-modem-manager.h" 
+#include "nm-bluez-device.h" 
+#include "nm-bluez-manager.h" 
+#include "nm-bluez-adapter.h" 
+#include "nm-bluez-common.h" 
+#include "nm-firewall-manager.h" 
+#include "nm-settings.h" 
+#include "nm-settings-connection.h" 
+#include "nm-default-wired-connection.h" 
+#include "nm-system-config-interface.h" 
+#include "nm-settings-utils.h" 
+#include "nm-settings-error.h" 
+#include "nm-agent-manager.h" 
+#include "nm-inotify-helper.h" 
+#include "nm-secret-agent.h" 
+#include "nm-device-wimax.h" 
+#include "iwmxsdk.h" 
+#include "nm-wimax-types.h" 
+#include "nm-wimax-util.h" 
+#include "nm-wimax-nsp.h"
+
+GType
+nm_vlan_error_get_type (void)
+{
+  static volatile gsize g_define_type_id__volatile = 0;
+
+  if (g_once_init_enter (&g_define_type_id__volatile))
+    {
+      static const GEnumValue values[] = {
+        { NM_VLAN_ERROR_CONNECTION_NOT_VLAN, "NM_VLAN_ERROR_CONNECTION_NOT_VLAN", "ConnectionNotVlan" },
+        { NM_VLAN_ERROR_CONNECTION_INVALID, "NM_VLAN_ERROR_CONNECTION_INVALID", "ConnectionInvalid" },
+        { NM_VLAN_ERROR_CONNECTION_INCOMPATIBLE, "NM_VLAN_ERROR_CONNECTION_INCOMPATIBLE", "ConnectionIncompatible" },
+        { 0, NULL, NULL }
+      };
+      GType g_define_type_id =
+        g_enum_register_static (g_intern_static_string ("NMVlanError"), values);
+      g_once_init_leave (&g_define_type_id__volatile, g_define_type_id);
+    }
+
+  return g_define_type_id__volatile;
+}
+GType
+nm_olpc_mesh_error_get_type (void)
+{
+  static volatile gsize g_define_type_id__volatile = 0;
+
+  if (g_once_init_enter (&g_define_type_id__volatile))
+    {
+      static const GEnumValue values[] = {
+        { NM_OLPC_MESH_ERROR_CONNECTION_NOT_MESH, "NM_OLPC_MESH_ERROR_CONNECTION_NOT_MESH", "ConnectionNotMesh" },
+        { NM_OLPC_MESH_ERROR_CONNECTION_INVALID, "NM_OLPC_MESH_ERROR_CONNECTION_INVALID", "ConnectionInvalid" },
+        { NM_OLPC_MESH_ERROR_CONNECTION_INCOMPATIBLE, "NM_OLPC_MESH_ERROR_CONNECTION_INCOMPATIBLE", "ConnectionIncompatible" },
+        { 0, NULL, NULL }
+      };
+      GType g_define_type_id =
+        g_enum_register_static (g_intern_static_string ("NMOlpcMeshError"), values);
+      g_once_init_leave (&g_define_type_id__volatile, g_define_type_id);
+    }
+
+  return g_define_type_id__volatile;
+}
+GType
+nm_device_error_get_type (void)
+{
+  static volatile gsize g_define_type_id__volatile = 0;
+
+  if (g_once_init_enter (&g_define_type_id__volatile))
+    {
+      static const GEnumValue values[] = {
+        { NM_DEVICE_ERROR_CONNECTION_ACTIVATING, "NM_DEVICE_ERROR_CONNECTION_ACTIVATING", "ConnectionActivating" },
+        { NM_DEVICE_ERROR_CONNECTION_INVALID, "NM_DEVICE_ERROR_CONNECTION_INVALID", "ConnectionInvalid" },
+        { NM_DEVICE_ERROR_NOT_ACTIVE, "NM_DEVICE_ERROR_NOT_ACTIVE", "NotActive" },
+        { 0, NULL, NULL }
+      };
+      GType g_define_type_id =
+        g_enum_register_static (g_intern_static_string ("NMDeviceError"), values);
+      g_once_init_leave (&g_define_type_id__volatile, g_define_type_id);
+    }
+
+  return g_define_type_id__volatile;
+}
+GType
+nm_rf_kill_state_get_type (void)
+{
+  static volatile gsize g_define_type_id__volatile = 0;
+
+  if (g_once_init_enter (&g_define_type_id__volatile))
+    {
+      static const GEnumValue values[] = {
+        { RFKILL_UNBLOCKED, "RFKILL_UNBLOCKED", "unblocked" },
+        { RFKILL_SOFT_BLOCKED, "RFKILL_SOFT_BLOCKED", "soft-blocked" },
+        { RFKILL_HARD_BLOCKED, "RFKILL_HARD_BLOCKED", "hard-blocked" },
+        { 0, NULL, NULL }
+      };
+      GType g_define_type_id =
+        g_enum_register_static (g_intern_static_string ("RfKillState"), values);
+      g_once_init_leave (&g_define_type_id__volatile, g_define_type_id);
+    }
+
+  return g_define_type_id__volatile;
+}
+GType
+nm_rf_kill_type_get_type (void)
+{
+  static volatile gsize g_define_type_id__volatile = 0;
+
+  if (g_once_init_enter (&g_define_type_id__volatile))
+    {
+      static const GEnumValue values[] = {
+        { RFKILL_TYPE_WLAN, "RFKILL_TYPE_WLAN", "wlan" },
+        { RFKILL_TYPE_WWAN, "RFKILL_TYPE_WWAN", "wwan" },
+        { RFKILL_TYPE_WIMAX, "RFKILL_TYPE_WIMAX", "wimax" },
+        { RFKILL_TYPE_UNKNOWN, "RFKILL_TYPE_UNKNOWN", "unknown" },
+        { RFKILL_TYPE_MAX, "RFKILL_TYPE_MAX", "max" },
+        { 0, NULL, NULL }
+      };
+      GType g_define_type_id =
+        g_enum_register_static (g_intern_static_string ("RfKillType"), values);
+      g_once_init_leave (&g_define_type_id__volatile, g_define_type_id);
+    }
+
+  return g_define_type_id__volatile;
+}
+GType
+nm_ethernet_error_get_type (void)
+{
+  static volatile gsize g_define_type_id__volatile = 0;
+
+  if (g_once_init_enter (&g_define_type_id__volatile))
+    {
+      static const GEnumValue values[] = {
+        { NM_ETHERNET_ERROR_CONNECTION_NOT_WIRED, "NM_ETHERNET_ERROR_CONNECTION_NOT_WIRED", "ConnectionNotWired" },
+        { NM_ETHERNET_ERROR_CONNECTION_INVALID, "NM_ETHERNET_ERROR_CONNECTION_INVALID", "ConnectionInvalid" },
+        { NM_ETHERNET_ERROR_CONNECTION_INCOMPATIBLE, "NM_ETHERNET_ERROR_CONNECTION_INCOMPATIBLE", "ConnectionIncompatible" },
+        { 0, NULL, NULL }
+      };
+      GType g_define_type_id =
+        g_enum_register_static (g_intern_static_string ("NMEthernetError"), values);
+      g_once_init_leave (&g_define_type_id__volatile, g_define_type_id);
+    }
+
+  return g_define_type_id__volatile;
+}
+GType
+nm_bt_error_get_type (void)
+{
+  static volatile gsize g_define_type_id__volatile = 0;
+
+  if (g_once_init_enter (&g_define_type_id__volatile))
+    {
+      static const GEnumValue values[] = {
+        { NM_BT_ERROR_CONNECTION_NOT_BT, "NM_BT_ERROR_CONNECTION_NOT_BT", "ConnectionNotBt" },
+        { NM_BT_ERROR_CONNECTION_INVALID, "NM_BT_ERROR_CONNECTION_INVALID", "ConnectionInvalid" },
+        { NM_BT_ERROR_CONNECTION_INCOMPATIBLE, "NM_BT_ERROR_CONNECTION_INCOMPATIBLE", "ConnectionIncompatible" },
+        { 0, NULL, NULL }
+      };
+      GType g_define_type_id =
+        g_enum_register_static (g_intern_static_string ("NMBtError"), values);
+      g_once_init_leave (&g_define_type_id__volatile, g_define_type_id);
+    }
+
+  return g_define_type_id__volatile;
+}
+GType
+nm_wifi_error_get_type (void)
+{
+  static volatile gsize g_define_type_id__volatile = 0;
+
+  if (g_once_init_enter (&g_define_type_id__volatile))
+    {
+      static const GEnumValue values[] = {
+        { NM_WIFI_ERROR_CONNECTION_NOT_WIRELESS, "NM_WIFI_ERROR_CONNECTION_NOT_WIRELESS", "ConnectionNotWireless" },
+        { NM_WIFI_ERROR_CONNECTION_INVALID, "NM_WIFI_ERROR_CONNECTION_INVALID", "ConnectionInvalid" },
+        { NM_WIFI_ERROR_CONNECTION_INCOMPATIBLE, "NM_WIFI_ERROR_CONNECTION_INCOMPATIBLE", "ConnectionIncompatible" },
+        { NM_WIFI_ERROR_ACCESS_POINT_NOT_FOUND, "NM_WIFI_ERROR_ACCESS_POINT_NOT_FOUND", "AccessPointNotFound" },
+        { 0, NULL, NULL }
+      };
+      GType g_define_type_id =
+        g_enum_register_static (g_intern_static_string ("NMWifiError"), values);
+      g_once_init_leave (&g_define_type_id__volatile, g_define_type_id);
+    }
+
+  return g_define_type_id__volatile;
+}
+GType
+nm_ip4_config_compare_flags_get_type (void)
+{
+  static volatile gsize g_define_type_id__volatile = 0;
+
+  if (g_once_init_enter (&g_define_type_id__volatile))
+    {
+      static const GEnumValue values[] = {
+        { NM_IP4_COMPARE_FLAG_NONE, "NM_IP4_COMPARE_FLAG_NONE", "none" },
+        { NM_IP4_COMPARE_FLAG_ADDRESSES, "NM_IP4_COMPARE_FLAG_ADDRESSES", "addresses" },
+        { NM_IP4_COMPARE_FLAG_PTP_ADDRESS, "NM_IP4_COMPARE_FLAG_PTP_ADDRESS", "ptp-address" },
+        { NM_IP4_COMPARE_FLAG_NAMESERVERS, "NM_IP4_COMPARE_FLAG_NAMESERVERS", "nameservers" },
+        { NM_IP4_COMPARE_FLAG_ROUTES, "NM_IP4_COMPARE_FLAG_ROUTES", "routes" },
+        { NM_IP4_COMPARE_FLAG_DOMAINS, "NM_IP4_COMPARE_FLAG_DOMAINS", "domains" },
+        { NM_IP4_COMPARE_FLAG_SEARCHES, "NM_IP4_COMPARE_FLAG_SEARCHES", "searches" },
+        { NM_IP4_COMPARE_FLAG_MTU, "NM_IP4_COMPARE_FLAG_MTU", "mtu" },
+        { NM_IP4_COMPARE_FLAG_MSS, "NM_IP4_COMPARE_FLAG_MSS", "mss" },
+        { NM_IP4_COMPARE_FLAG_WINS_SERVERS, "NM_IP4_COMPARE_FLAG_WINS_SERVERS", "wins-servers" },
+        { NM_IP4_COMPARE_FLAG_NIS_SERVERS, "NM_IP4_COMPARE_FLAG_NIS_SERVERS", "nis-servers" },
+        { NM_IP4_COMPARE_FLAG_NIS_DOMAIN, "NM_IP4_COMPARE_FLAG_NIS_DOMAIN", "nis-domain" },
+        { NM_IP4_COMPARE_FLAG_ALL, "NM_IP4_COMPARE_FLAG_ALL", "all" },
+        { 0, NULL, NULL }
+      };
+      GType g_define_type_id =
+        g_enum_register_static (g_intern_static_string ("NMIP4ConfigCompareFlags"), values);
+      g_once_init_leave (&g_define_type_id__volatile, g_define_type_id);
+    }
+
+  return g_define_type_id__volatile;
+}
+GType
+nm_bond_error_get_type (void)
+{
+  static volatile gsize g_define_type_id__volatile = 0;
+
+  if (g_once_init_enter (&g_define_type_id__volatile))
+    {
+      static const GEnumValue values[] = {
+        { NM_BOND_ERROR_CONNECTION_NOT_BOND, "NM_BOND_ERROR_CONNECTION_NOT_BOND", "ConnectionNotBond" },
+        { NM_BOND_ERROR_CONNECTION_INVALID, "NM_BOND_ERROR_CONNECTION_INVALID", "ConnectionInvalid" },
+        { NM_BOND_ERROR_CONNECTION_INCOMPATIBLE, "NM_BOND_ERROR_CONNECTION_INCOMPATIBLE", "ConnectionIncompatible" },
+        { 0, NULL, NULL }
+      };
+      GType g_define_type_id =
+        g_enum_register_static (g_intern_static_string ("NMBondError"), values);
+      g_once_init_leave (&g_define_type_id__volatile, g_define_type_id);
+    }
+
+  return g_define_type_id__volatile;
+}
+GType
+nm_manager_error_get_type (void)
+{
+  static volatile gsize g_define_type_id__volatile = 0;
+
+  if (g_once_init_enter (&g_define_type_id__volatile))
+    {
+      static const GEnumValue values[] = {
+        { NM_MANAGER_ERROR_UNKNOWN_CONNECTION, "NM_MANAGER_ERROR_UNKNOWN_CONNECTION", "UnknownConnection" },
+        { NM_MANAGER_ERROR_UNKNOWN_DEVICE, "NM_MANAGER_ERROR_UNKNOWN_DEVICE", "UnknownDevice" },
+        { NM_MANAGER_ERROR_UNMANAGED_DEVICE, "NM_MANAGER_ERROR_UNMANAGED_DEVICE", "UnmanagedDevice" },
+        { NM_MANAGER_ERROR_SYSTEM_CONNECTION, "NM_MANAGER_ERROR_SYSTEM_CONNECTION", "SystemConnection" },
+        { NM_MANAGER_ERROR_PERMISSION_DENIED, "NM_MANAGER_ERROR_PERMISSION_DENIED", "PermissionDenied" },
+        { NM_MANAGER_ERROR_CONNECTION_NOT_ACTIVE, "NM_MANAGER_ERROR_CONNECTION_NOT_ACTIVE", "ConnectionNotActive" },
+        { NM_MANAGER_ERROR_ALREADY_ASLEEP_OR_AWAKE, "NM_MANAGER_ERROR_ALREADY_ASLEEP_OR_AWAKE", "AlreadyAsleepOrAwake" },
+        { NM_MANAGER_ERROR_ALREADY_ENABLED_OR_DISABLED, "NM_MANAGER_ERROR_ALREADY_ENABLED_OR_DISABLED", "AlreadyEnabledOrDisabled" },
+        { NM_MANAGER_ERROR_UNSUPPORTED_CONNECTION_TYPE, "NM_MANAGER_ERROR_UNSUPPORTED_CONNECTION_TYPE", "UnsupportedConnectionType" },
+        { NM_MANAGER_ERROR_DEPENDENCY_FAILED, "NM_MANAGER_ERROR_DEPENDENCY_FAILED", "DependencyFailed" },
+        { 0, NULL, NULL }
+      };
+      GType g_define_type_id =
+        g_enum_register_static (g_intern_static_string ("NMManagerError"), values);
+      g_once_init_leave (&g_define_type_id__volatile, g_define_type_id);
+    }
+
+  return g_define_type_id__volatile;
+}
+GType
+nm_act_request_dependency_result_get_type (void)
+{
+  static volatile gsize g_define_type_id__volatile = 0;
+
+  if (g_once_init_enter (&g_define_type_id__volatile))
+    {
+      static const GEnumValue values[] = {
+        { NM_ACT_REQUEST_DEP_RESULT_UNKNOWN, "NM_ACT_REQUEST_DEP_RESULT_UNKNOWN", "unknown" },
+        { NM_ACT_REQUEST_DEP_RESULT_WAIT, "NM_ACT_REQUEST_DEP_RESULT_WAIT", "wait" },
+        { NM_ACT_REQUEST_DEP_RESULT_READY, "NM_ACT_REQUEST_DEP_RESULT_READY", "ready" },
+        { NM_ACT_REQUEST_DEP_RESULT_FAILED, "NM_ACT_REQUEST_DEP_RESULT_FAILED", "failed" },
+        { 0, NULL, NULL }
+      };
+      GType g_define_type_id =
+        g_enum_register_static (g_intern_static_string ("NMActRequestDependencyResult"), values);
+      g_once_init_leave (&g_define_type_id__volatile, g_define_type_id);
+    }
+
+  return g_define_type_id__volatile;
+}
+GType
+nm_session_monitor_error_get_type (void)
+{
+  static volatile gsize g_define_type_id__volatile = 0;
+
+  if (g_once_init_enter (&g_define_type_id__volatile))
+    {
+      static const GEnumValue values[] = {
+        { NM_SESSION_MONITOR_ERROR_IO_ERROR, "NM_SESSION_MONITOR_ERROR_IO_ERROR", "IOError" },
+        { NM_SESSION_MONITOR_ERROR_MALFORMED_DATABASE, "NM_SESSION_MONITOR_ERROR_MALFORMED_DATABASE", "MalformedDatabase" },
+        { NM_SESSION_MONITOR_ERROR_UNKNOWN_USER, "NM_SESSION_MONITOR_ERROR_UNKNOWN_USER", "UnknownUser" },
+        { NM_SESSION_MONITOR_ERROR_NO_DATABASE, "NM_SESSION_MONITOR_ERROR_NO_DATABASE", "NoDatabase" },
+        { 0, NULL, NULL }
+      };
+      GType g_define_type_id =
+        g_enum_register_static (g_intern_static_string ("NMSessionMonitorError"), values);
+      g_once_init_leave (&g_define_type_id__volatile, g_define_type_id);
+    }
+
+  return g_define_type_id__volatile;
+}
+GType
+nm_infiniband_error_get_type (void)
+{
+  static volatile gsize g_define_type_id__volatile = 0;
+
+  if (g_once_init_enter (&g_define_type_id__volatile))
+    {
+      static const GEnumValue values[] = {
+        { NM_INFINIBAND_ERROR_CONNECTION_NOT_INFINIBAND, "NM_INFINIBAND_ERROR_CONNECTION_NOT_INFINIBAND", "ConnectionNotInfiniband" },
+        { NM_INFINIBAND_ERROR_CONNECTION_INVALID, "NM_INFINIBAND_ERROR_CONNECTION_INVALID", "ConnectionInvalid" },
+        { NM_INFINIBAND_ERROR_CONNECTION_INCOMPATIBLE, "NM_INFINIBAND_ERROR_CONNECTION_INCOMPATIBLE", "ConnectionIncompatible" },
+        { 0, NULL, NULL }
+      };
+      GType g_define_type_id =
+        g_enum_register_static (g_intern_static_string ("NMInfinibandError"), values);
+      g_once_init_leave (&g_define_type_id__volatile, g_define_type_id);
+    }
+
+  return g_define_type_id__volatile;
+}
+GType
+nm_ip6_config_compare_flags_get_type (void)
+{
+  static volatile gsize g_define_type_id__volatile = 0;
+
+  if (g_once_init_enter (&g_define_type_id__volatile))
+    {
+      static const GEnumValue values[] = {
+        { NM_IP6_COMPARE_FLAG_NONE, "NM_IP6_COMPARE_FLAG_NONE", "none" },
+        { NM_IP6_COMPARE_FLAG_ADDRESSES, "NM_IP6_COMPARE_FLAG_ADDRESSES", "addresses" },
+        { NM_IP6_COMPARE_FLAG_PTP_ADDRESS, "NM_IP6_COMPARE_FLAG_PTP_ADDRESS", "ptp-address" },
+        { NM_IP6_COMPARE_FLAG_NAMESERVERS, "NM_IP6_COMPARE_FLAG_NAMESERVERS", "nameservers" },
+        { NM_IP6_COMPARE_FLAG_ROUTES, "NM_IP6_COMPARE_FLAG_ROUTES", "routes" },
+        { NM_IP6_COMPARE_FLAG_DOMAINS, "NM_IP6_COMPARE_FLAG_DOMAINS", "domains" },
+        { NM_IP6_COMPARE_FLAG_SEARCHES, "NM_IP6_COMPARE_FLAG_SEARCHES", "searches" },
+        { NM_IP6_COMPARE_FLAG_MSS, "NM_IP6_COMPARE_FLAG_MSS", "mss" },
+        { NM_IP6_COMPARE_FLAG_ALL, "NM_IP6_COMPARE_FLAG_ALL", "all" },
+        { 0, NULL, NULL }
+      };
+      GType g_define_type_id =
+        g_enum_register_static (g_intern_static_string ("NMIP6ConfigCompareFlags"), values);
+      g_once_init_leave (&g_define_type_id__volatile, g_define_type_id);
+    }
+
+  return g_define_type_id__volatile;
+}
+GType
+nm_auth_call_result_get_type (void)
+{
+  static volatile gsize g_define_type_id__volatile = 0;
+
+  if (g_once_init_enter (&g_define_type_id__volatile))
+    {
+      static const GEnumValue values[] = {
+        { NM_AUTH_CALL_RESULT_UNKNOWN, "NM_AUTH_CALL_RESULT_UNKNOWN", "unknown" },
+        { NM_AUTH_CALL_RESULT_YES, "NM_AUTH_CALL_RESULT_YES", "yes" },
+        { NM_AUTH_CALL_RESULT_AUTH, "NM_AUTH_CALL_RESULT_AUTH", "auth" },
+        { NM_AUTH_CALL_RESULT_NO, "NM_AUTH_CALL_RESULT_NO", "no" },
+        { 0, NULL, NULL }
+      };
+      GType g_define_type_id =
+        g_enum_register_static (g_intern_static_string ("NMAuthCallResult"), values);
+      g_once_init_leave (&g_define_type_id__volatile, g_define_type_id);
+    }
+
+  return g_define_type_id__volatile;
+}
+GType
+nm_config_error_get_type (void)
+{
+  static volatile gsize g_define_type_id__volatile = 0;
+
+  if (g_once_init_enter (&g_define_type_id__volatile))
+    {
+      static const GEnumValue values[] = {
+        { NM_CONFIG_ERROR_NO_MEMORY, "NM_CONFIG_ERROR_NO_MEMORY", "NoMemory" },
+        { 0, NULL, NULL }
+      };
+      GType g_define_type_id =
+        g_enum_register_static (g_intern_static_string ("NMConfigError"), values);
+      g_once_init_leave (&g_define_type_id__volatile, g_define_type_id);
+    }
+
+  return g_define_type_id__volatile;
+}
+GType
+nm_nm_nl_prop_get_type (void)
+{
+  static volatile gsize g_define_type_id__volatile = 0;
+
+  if (g_once_init_enter (&g_define_type_id__volatile))
+    {
+      static const GEnumValue values[] = {
+        { NMNL_PROP_INVALID, "NMNL_PROP_INVALID", "invalid" },
+        { NMNL_PROP_PROT, "NMNL_PROP_PROT", "prot" },
+        { NMNL_PROP_SCOPE, "NMNL_PROP_SCOPE", "scope" },
+        { NMNL_PROP_TABLE, "NMNL_PROP_TABLE", "table" },
+        { NMNL_PROP_PRIO, "NMNL_PROP_PRIO", "prio" },
+        { 0, NULL, NULL }
+      };
+      GType g_define_type_id =
+        g_enum_register_static (g_intern_static_string ("NmNlProp"), values);
+      g_once_init_leave (&g_define_type_id__volatile, g_define_type_id);
+    }
+
+  return g_define_type_id__volatile;
+}
+GType
+nm_netlink_monitor_error_get_type (void)
+{
+  static volatile gsize g_define_type_id__volatile = 0;
+
+  if (g_once_init_enter (&g_define_type_id__volatile))
+    {
+      static const GEnumValue values[] = {
+        { NM_NETLINK_MONITOR_ERROR_GENERIC, "NM_NETLINK_MONITOR_ERROR_GENERIC", "generic" },
+        { NM_NETLINK_MONITOR_ERROR_NETLINK_ALLOC_HANDLE, "NM_NETLINK_MONITOR_ERROR_NETLINK_ALLOC_HANDLE", "netlink-alloc-handle" },
+        { NM_NETLINK_MONITOR_ERROR_NETLINK_CONNECT, "NM_NETLINK_MONITOR_ERROR_NETLINK_CONNECT", "netlink-connect" },
+        { NM_NETLINK_MONITOR_ERROR_NETLINK_JOIN_GROUP, "NM_NETLINK_MONITOR_ERROR_NETLINK_JOIN_GROUP", "netlink-join-group" },
+        { NM_NETLINK_MONITOR_ERROR_NETLINK_ALLOC_LINK_CACHE, "NM_NETLINK_MONITOR_ERROR_NETLINK_ALLOC_LINK_CACHE", "netlink-alloc-link-cache" },
+        { NM_NETLINK_MONITOR_ERROR_PROCESSING_MESSAGE, "NM_NETLINK_MONITOR_ERROR_PROCESSING_MESSAGE", "processing-message" },
+        { NM_NETLINK_MONITOR_ERROR_BAD_ALLOC, "NM_NETLINK_MONITOR_ERROR_BAD_ALLOC", "bad-alloc" },
+        { NM_NETLINK_MONITOR_ERROR_WAITING_FOR_SOCKET_DATA, "NM_NETLINK_MONITOR_ERROR_WAITING_FOR_SOCKET_DATA", "waiting-for-socket-data" },
+        { NM_NETLINK_MONITOR_ERROR_LINK_CACHE_UPDATE, "NM_NETLINK_MONITOR_ERROR_LINK_CACHE_UPDATE", "link-cache-update" },
+        { 0, NULL, NULL }
+      };
+      GType g_define_type_id =
+        g_enum_register_static (g_intern_static_string ("NMNetlinkMonitorError"), values);
+      g_once_init_leave (&g_define_type_id__volatile, g_define_type_id);
+    }
+
+  return g_define_type_id__volatile;
+}
+GType
+nm_logging_error_get_type (void)
+{
+  static volatile gsize g_define_type_id__volatile = 0;
+
+  if (g_once_init_enter (&g_define_type_id__volatile))
+    {
+      static const GEnumValue values[] = {
+        { NM_LOGGING_ERROR_UNKNOWN_LEVEL, "NM_LOGGING_ERROR_UNKNOWN_LEVEL", "UnknownLevel" },
+        { NM_LOGGING_ERROR_UNKNOWN_DOMAIN, "NM_LOGGING_ERROR_UNKNOWN_DOMAIN", "UnknownDomain" },
+        { 0, NULL, NULL }
+      };
+      GType g_define_type_id =
+        g_enum_register_static (g_intern_static_string ("NMLoggingError"), values);
+      g_once_init_leave (&g_define_type_id__volatile, g_define_type_id);
+    }
+
+  return g_define_type_id__volatile;
+}
+GType
+nm_dns_manager_error_get_type (void)
+{
+  static volatile gsize g_define_type_id__volatile = 0;
+
+  if (g_once_init_enter (&g_define_type_id__volatile))
+    {
+      static const GEnumValue values[] = {
+        { NM_DNS_MANAGER_ERROR_SYSTEM, "NM_DNS_MANAGER_ERROR_SYSTEM", "system" },
+        { NM_DNS_MANAGER_ERROR_INVALID_NAMESERVER, "NM_DNS_MANAGER_ERROR_INVALID_NAMESERVER", "invalid-nameserver" },
+        { NM_DNS_MANAGER_ERROR_INVALID_HOST, "NM_DNS_MANAGER_ERROR_INVALID_HOST", "invalid-host" },
+        { NM_DNS_MANAGER_ERROR_INVALID_ID, "NM_DNS_MANAGER_ERROR_INVALID_ID", "invalid-id" },
+        { 0, NULL, NULL }
+      };
+      GType g_define_type_id =
+        g_enum_register_static (g_intern_static_string ("NMDnsManagerError"), values);
+      g_once_init_leave (&g_define_type_id__volatile, g_define_type_id);
+    }
+
+  return g_define_type_id__volatile;
+}
+GType
+nm_dns_ip_config_type_get_type (void)
+{
+  static volatile gsize g_define_type_id__volatile = 0;
+
+  if (g_once_init_enter (&g_define_type_id__volatile))
+    {
+      static const GEnumValue values[] = {
+        { NM_DNS_IP_CONFIG_TYPE_DEFAULT, "NM_DNS_IP_CONFIG_TYPE_DEFAULT", "default" },
+        { NM_DNS_IP_CONFIG_TYPE_BEST_DEVICE, "NM_DNS_IP_CONFIG_TYPE_BEST_DEVICE", "best-device" },
+        { NM_DNS_IP_CONFIG_TYPE_VPN, "NM_DNS_IP_CONFIG_TYPE_VPN", "vpn" },
+        { 0, NULL, NULL }
+      };
+      GType g_define_type_id =
+        g_enum_register_static (g_intern_static_string ("NMDnsIPConfigType"), values);
+      g_once_init_leave (&g_define_type_id__volatile, g_define_type_id);
+    }
+
+  return g_define_type_id__volatile;
+}
+GType
+nm_vpn_manager_error_get_type (void)
+{
+  static volatile gsize g_define_type_id__volatile = 0;
+
+  if (g_once_init_enter (&g_define_type_id__volatile))
+    {
+      static const GEnumValue values[] = {
+        { NM_VPN_MANAGER_ERROR_DEVICE_NOT_ACTIVE, "NM_VPN_MANAGER_ERROR_DEVICE_NOT_ACTIVE", "BaseDeviceNotActive" },
+        { NM_VPN_MANAGER_ERROR_CONNECTION_INVALID, "NM_VPN_MANAGER_ERROR_CONNECTION_INVALID", "ConnectionInvalid" },
+        { NM_VPN_MANAGER_ERROR_SERVICE_INVALID, "NM_VPN_MANAGER_ERROR_SERVICE_INVALID", "ServiceInvalid" },
+        { NM_VPN_MANAGER_ERROR_SERVICE_START_FAILED, "NM_VPN_MANAGER_ERROR_SERVICE_START_FAILED", "ServiceStartFailed" },
+        { 0, NULL, NULL }
+      };
+      GType g_define_type_id =
+        g_enum_register_static (g_intern_static_string ("NMVPNManagerError"), values);
+      g_once_init_leave (&g_define_type_id__volatile, g_define_type_id);
+    }
+
+  return g_define_type_id__volatile;
+}
+GType
+nm_dhcp_state_get_type (void)
+{
+  static volatile gsize g_define_type_id__volatile = 0;
+
+  if (g_once_init_enter (&g_define_type_id__volatile))
+    {
+      static const GEnumValue values[] = {
+        { DHC_NBI, "DHC_NBI", "nbi" },
+        { DHC_PREINIT, "DHC_PREINIT", "preinit" },
+        { DHC_PREINIT6, "DHC_PREINIT6", "preinit6" },
+        { DHC_BOUND4, "DHC_BOUND4", "bound4" },
+        { DHC_BOUND6, "DHC_BOUND6", "bound6" },
+        { DHC_IPV4LL, "DHC_IPV4LL", "ipv4ll" },
+        { DHC_RENEW4, "DHC_RENEW4", "renew4" },
+        { DHC_RENEW6, "DHC_RENEW6", "renew6" },
+        { DHC_REBOOT, "DHC_REBOOT", "reboot" },
+        { DHC_REBIND4, "DHC_REBIND4", "rebind4" },
+        { DHC_REBIND6, "DHC_REBIND6", "rebind6" },
+        { DHC_DEPREF6, "DHC_DEPREF6", "depref6" },
+        { DHC_STOP, "DHC_STOP", "stop" },
+        { DHC_STOP6, "DHC_STOP6", "stop6" },
+        { DHC_MEDIUM, "DHC_MEDIUM", "medium" },
+        { DHC_TIMEOUT, "DHC_TIMEOUT", "timeout" },
+        { DHC_FAIL, "DHC_FAIL", "fail" },
+        { DHC_EXPIRE, "DHC_EXPIRE", "expire" },
+        { DHC_EXPIRE6, "DHC_EXPIRE6", "expire6" },
+        { DHC_RELEASE, "DHC_RELEASE", "release" },
+        { DHC_RELEASE6, "DHC_RELEASE6", "release6" },
+        { DHC_START, "DHC_START", "start" },
+        { DHC_ABEND, "DHC_ABEND", "abend" },
+        { DHC_END, "DHC_END", "end" },
+        { DHC_END_OPTIONS, "DHC_END_OPTIONS", "end-options" },
+        { 0, NULL, NULL }
+      };
+      GType g_define_type_id =
+        g_enum_register_static (g_intern_static_string ("NMDHCPState"), values);
+      g_once_init_leave (&g_define_type_id__volatile, g_define_type_id);
+    }
+
+  return g_define_type_id__volatile;
+}
+GType
+nm_dhcp_manager_error_get_type (void)
+{
+  static volatile gsize g_define_type_id__volatile = 0;
+
+  if (g_once_init_enter (&g_define_type_id__volatile))
+    {
+      static const GEnumValue values[] = {
+        { NM_DHCP_MANAGER_ERROR_BAD_CLIENT, "NM_DHCP_MANAGER_ERROR_BAD_CLIENT", "BadClient" },
+        { NM_DHCP_MANAGER_ERROR_INTERNAL, "NM_DHCP_MANAGER_ERROR_INTERNAL", "InternalError" },
+        { 0, NULL, NULL }
+      };
+      GType g_define_type_id =
+        g_enum_register_static (g_intern_static_string ("NMDHCPManagerError"), values);
+      g_once_init_leave (&g_define_type_id__volatile, g_define_type_id);
+    }
+
+  return g_define_type_id__volatile;
+}
+GType
+nm_opt_type_get_type (void)
+{
+  static volatile gsize g_define_type_id__volatile = 0;
+
+  if (g_once_init_enter (&g_define_type_id__volatile))
+    {
+      static const GEnumValue values[] = {
+        { TYPE_INVALID, "TYPE_INVALID", "invalid" },
+        { TYPE_INT, "TYPE_INT", "int" },
+        { TYPE_BYTES, "TYPE_BYTES", "bytes" },
+        { TYPE_UTF8, "TYPE_UTF8", "utf8" },
+        { TYPE_KEYWORD, "TYPE_KEYWORD", "keyword" },
+        { TYPE_STRING, "TYPE_STRING", "string" },
+        { 0, NULL, NULL }
+      };
+      GType g_define_type_id =
+        g_enum_register_static (g_intern_static_string ("OptType"), values);
+      g_once_init_leave (&g_define_type_id__volatile, g_define_type_id);
+    }
+
+  return g_define_type_id__volatile;
+}
+GType
+nm_ppp_status_get_type (void)
+{
+  static volatile gsize g_define_type_id__volatile = 0;
+
+  if (g_once_init_enter (&g_define_type_id__volatile))
+    {
+      static const GEnumValue values[] = {
+        { NM_PPP_STATUS_UNKNOWN, "NM_PPP_STATUS_UNKNOWN", "unknown" },
+        { NM_PPP_STATUS_DEAD, "NM_PPP_STATUS_DEAD", "dead" },
+        { NM_PPP_STATUS_INITIALIZE, "NM_PPP_STATUS_INITIALIZE", "initialize" },
+        { NM_PPP_STATUS_SERIALCONN, "NM_PPP_STATUS_SERIALCONN", "serialconn" },
+        { NM_PPP_STATUS_DORMANT, "NM_PPP_STATUS_DORMANT", "dormant" },
+        { NM_PPP_STATUS_ESTABLISH, "NM_PPP_STATUS_ESTABLISH", "establish" },
+        { NM_PPP_STATUS_AUTHENTICATE, "NM_PPP_STATUS_AUTHENTICATE", "authenticate" },
+        { NM_PPP_STATUS_CALLBACK, "NM_PPP_STATUS_CALLBACK", "callback" },
+        { NM_PPP_STATUS_NETWORK, "NM_PPP_STATUS_NETWORK", "network" },
+        { NM_PPP_STATUS_RUNNING, "NM_PPP_STATUS_RUNNING", "running" },
+        { NM_PPP_STATUS_TERMINATE, "NM_PPP_STATUS_TERMINATE", "terminate" },
+        { NM_PPP_STATUS_DISCONNECT, "NM_PPP_STATUS_DISCONNECT", "disconnect" },
+        { NM_PPP_STATUS_HOLDOFF, "NM_PPP_STATUS_HOLDOFF", "holdoff" },
+        { NM_PPP_STATUS_MASTER, "NM_PPP_STATUS_MASTER", "master" },
+        { 0, NULL, NULL }
+      };
+      GType g_define_type_id =
+        g_enum_register_static (g_intern_static_string ("NMPPPStatus"), values);
+      g_once_init_leave (&g_define_type_id__volatile, g_define_type_id);
+    }
+
+  return g_define_type_id__volatile;
+}
+GType
+nm_dns_masq_status_get_type (void)
+{
+  static volatile gsize g_define_type_id__volatile = 0;
+
+  if (g_once_init_enter (&g_define_type_id__volatile))
+    {
+      static const GEnumValue values[] = {
+        { NM_DNSMASQ_STATUS_UNKNOWN, "NM_DNSMASQ_STATUS_UNKNOWN", "unknown" },
+        { NM_DNSMASQ_STATUS_DEAD, "NM_DNSMASQ_STATUS_DEAD", "dead" },
+        { NM_DNSMASQ_STATUS_RUNNING, "NM_DNSMASQ_STATUS_RUNNING", "running" },
+        { 0, NULL, NULL }
+      };
+      GType g_define_type_id =
+        g_enum_register_static (g_intern_static_string ("NMDnsMasqStatus"), values);
+      g_once_init_leave (&g_define_type_id__volatile, g_define_type_id);
+    }
+
+  return g_define_type_id__volatile;
+}
+GType
+nm_cdma_error_get_type (void)
+{
+  static volatile gsize g_define_type_id__volatile = 0;
+
+  if (g_once_init_enter (&g_define_type_id__volatile))
+    {
+      static const GEnumValue values[] = {
+        { NM_CDMA_ERROR_CONNECTION_NOT_CDMA, "NM_CDMA_ERROR_CONNECTION_NOT_CDMA", "ConnectionNotCdma" },
+        { NM_CDMA_ERROR_CONNECTION_INVALID, "NM_CDMA_ERROR_CONNECTION_INVALID", "ConnectionInvalid" },
+        { NM_CDMA_ERROR_CONNECTION_INCOMPATIBLE, "NM_CDMA_ERROR_CONNECTION_INCOMPATIBLE", "ConnectionIncompatible" },
+        { 0, NULL, NULL }
+      };
+      GType g_define_type_id =
+        g_enum_register_static (g_intern_static_string ("NMCdmaError"), values);
+      g_once_init_leave (&g_define_type_id__volatile, g_define_type_id);
+    }
+
+  return g_define_type_id__volatile;
+}
+GType
+nm_gsm_error_get_type (void)
+{
+  static volatile gsize g_define_type_id__volatile = 0;
+
+  if (g_once_init_enter (&g_define_type_id__volatile))
+    {
+      static const GEnumValue values[] = {
+        { NM_GSM_ERROR_CONNECTION_NOT_GSM, "NM_GSM_ERROR_CONNECTION_NOT_GSM", "ConnectionNotGsm" },
+        { NM_GSM_ERROR_CONNECTION_INVALID, "NM_GSM_ERROR_CONNECTION_INVALID", "ConnectionInvalid" },
+        { NM_GSM_ERROR_CONNECTION_INCOMPATIBLE, "NM_GSM_ERROR_CONNECTION_INCOMPATIBLE", "ConnectionIncompatible" },
+        { 0, NULL, NULL }
+      };
+      GType g_define_type_id =
+        g_enum_register_static (g_intern_static_string ("NMGsmError"), values);
+      g_once_init_leave (&g_define_type_id__volatile, g_define_type_id);
+    }
+
+  return g_define_type_id__volatile;
+}
+GType
+nm_system_config_interface_capabilities_get_type (void)
+{
+  static volatile gsize g_define_type_id__volatile = 0;
+
+  if (g_once_init_enter (&g_define_type_id__volatile))
+    {
+      static const GEnumValue values[] = {
+        { NM_SYSTEM_CONFIG_INTERFACE_CAP_NONE, "NM_SYSTEM_CONFIG_INTERFACE_CAP_NONE", "none" },
+        { NM_SYSTEM_CONFIG_INTERFACE_CAP_MODIFY_CONNECTIONS, "NM_SYSTEM_CONFIG_INTERFACE_CAP_MODIFY_CONNECTIONS", "modify-connections" },
+        { NM_SYSTEM_CONFIG_INTERFACE_CAP_MODIFY_HOSTNAME, "NM_SYSTEM_CONFIG_INTERFACE_CAP_MODIFY_HOSTNAME", "modify-hostname" },
+        { 0, NULL, NULL }
+      };
+      GType g_define_type_id =
+        g_enum_register_static (g_intern_static_string ("NMSystemConfigInterfaceCapabilities"), values);
+      g_once_init_leave (&g_define_type_id__volatile, g_define_type_id);
+    }
+
+  return g_define_type_id__volatile;
+}
+GType
+nm_system_config_interface_prop_get_type (void)
+{
+  static volatile gsize g_define_type_id__volatile = 0;
+
+  if (g_once_init_enter (&g_define_type_id__volatile))
+    {
+      static const GEnumValue values[] = {
+        { NM_SYSTEM_CONFIG_INTERFACE_PROP_FIRST, "NM_SYSTEM_CONFIG_INTERFACE_PROP_FIRST", "first" },
+        { NM_SYSTEM_CONFIG_INTERFACE_PROP_NAME, "NM_SYSTEM_CONFIG_INTERFACE_PROP_NAME", "name" },
+        { NM_SYSTEM_CONFIG_INTERFACE_PROP_INFO, "NM_SYSTEM_CONFIG_INTERFACE_PROP_INFO", "info" },
+        { NM_SYSTEM_CONFIG_INTERFACE_PROP_CAPABILITIES, "NM_SYSTEM_CONFIG_INTERFACE_PROP_CAPABILITIES", "capabilities" },
+        { NM_SYSTEM_CONFIG_INTERFACE_PROP_HOSTNAME, "NM_SYSTEM_CONFIG_INTERFACE_PROP_HOSTNAME", "hostname" },
+        { 0, NULL, NULL }
+      };
+      GType g_define_type_id =
+        g_enum_register_static (g_intern_static_string ("NMSystemConfigInterfaceProp"), values);
+      g_once_init_leave (&g_define_type_id__volatile, g_define_type_id);
+    }
+
+  return g_define_type_id__volatile;
+}
+GType
+nm_settings_error_get_type (void)
+{
+  static volatile gsize g_define_type_id__volatile = 0;
+
+  if (g_once_init_enter (&g_define_type_id__volatile))
+    {
+      static const GEnumValue values[] = {
+        { NM_SETTINGS_ERROR_GENERAL, "NM_SETTINGS_ERROR_GENERAL", "GeneralError" },
+        { NM_SETTINGS_ERROR_INVALID_CONNECTION, "NM_SETTINGS_ERROR_INVALID_CONNECTION", "InvalidConnection" },
+        { NM_SETTINGS_ERROR_READ_ONLY_CONNECTION, "NM_SETTINGS_ERROR_READ_ONLY_CONNECTION", "ReadOnlyConnection" },
+        { NM_SETTINGS_ERROR_INTERNAL_ERROR, "NM_SETTINGS_ERROR_INTERNAL_ERROR", "InternalError" },
+        { NM_SETTINGS_ERROR_SECRETS_UNAVAILABLE, "NM_SETTINGS_ERROR_SECRETS_UNAVAILABLE", "SecretsUnavailable" },
+        { NM_SETTINGS_ERROR_SECRETS_REQUEST_CANCELED, "NM_SETTINGS_ERROR_SECRETS_REQUEST_CANCELED", "SecretsRequestCanceled" },
+        { NM_SETTINGS_ERROR_PERMISSION_DENIED, "NM_SETTINGS_ERROR_PERMISSION_DENIED", "PermissionDenied" },
+        { NM_SETTINGS_ERROR_INVALID_SETTING, "NM_SETTINGS_ERROR_INVALID_SETTING", "InvalidSetting" },
+        { NM_SETTINGS_ERROR_NOT_PRIVILEGED, "NM_SETTINGS_ERROR_NOT_PRIVILEGED", "NotPrivileged" },
+        { NM_SETTINGS_ERROR_ADD_NOT_SUPPORTED, "NM_SETTINGS_ERROR_ADD_NOT_SUPPORTED", "AddNotSupported" },
+        { NM_SETTINGS_ERROR_UPDATE_NOT_SUPPORTED, "NM_SETTINGS_ERROR_UPDATE_NOT_SUPPORTED", "UpdateNotSupported" },
+        { NM_SETTINGS_ERROR_DELETE_NOT_SUPPORTED, "NM_SETTINGS_ERROR_DELETE_NOT_SUPPORTED", "DeleteNotSupported" },
+        { NM_SETTINGS_ERROR_ADD_FAILED, "NM_SETTINGS_ERROR_ADD_FAILED", "AddFailed" },
+        { NM_SETTINGS_ERROR_SAVE_HOSTNAME_NOT_SUPPORTED, "NM_SETTINGS_ERROR_SAVE_HOSTNAME_NOT_SUPPORTED", "SaveHostnameNotSupported" },
+        { NM_SETTINGS_ERROR_SAVE_HOSTNAME_FAILED, "NM_SETTINGS_ERROR_SAVE_HOSTNAME_FAILED", "SaveHostnameFailed" },
+        { NM_SETTINGS_ERROR_UUID_EXISTS, "NM_SETTINGS_ERROR_UUID_EXISTS", "UuidExists" },
+        { 0, NULL, NULL }
+      };
+      GType g_define_type_id =
+        g_enum_register_static (g_intern_static_string ("NMSettingsError"), values);
+      g_once_init_leave (&g_define_type_id__volatile, g_define_type_id);
+    }
+
+  return g_define_type_id__volatile;
+}
+GType
+nm_agent_manager_error_get_type (void)
+{
+  static volatile gsize g_define_type_id__volatile = 0;
+
+  if (g_once_init_enter (&g_define_type_id__volatile))
+    {
+      static const GEnumValue values[] = {
+        { NM_AGENT_MANAGER_ERROR_SENDER_UNKNOWN, "NM_AGENT_MANAGER_ERROR_SENDER_UNKNOWN", "SenderUnknown" },
+        { NM_AGENT_MANAGER_ERROR_PERMISSION_DENIED, "NM_AGENT_MANAGER_ERROR_PERMISSION_DENIED", "PermissionDenied" },
+        { NM_AGENT_MANAGER_ERROR_SESSION_NOT_FOUND, "NM_AGENT_MANAGER_ERROR_SESSION_NOT_FOUND", "SessionNotFound" },
+        { NM_AGENT_MANAGER_ERROR_INVALID_IDENTIFIER, "NM_AGENT_MANAGER_ERROR_INVALID_IDENTIFIER", "InvalidIdentifier" },
+        { NM_AGENT_MANAGER_ERROR_NOT_REGISTERED, "NM_AGENT_MANAGER_ERROR_NOT_REGISTERED", "NotRegistered" },
+        { NM_AGENT_MANAGER_ERROR_INTERNAL_ERROR, "NM_AGENT_MANAGER_ERROR_INTERNAL_ERROR", "InternalError" },
+        { NM_AGENT_MANAGER_ERROR_NO_SECRETS, "NM_AGENT_MANAGER_ERROR_NO_SECRETS", "NoSecrets" },
+        { 0, NULL, NULL }
+      };
+      GType g_define_type_id =
+        g_enum_register_static (g_intern_static_string ("NMAgentManagerError"), values);
+      g_once_init_leave (&g_define_type_id__volatile, g_define_type_id);
+    }
+
+  return g_define_type_id__volatile;
+}
+GType
+nm_wimax_error_get_type (void)
+{
+  static volatile gsize g_define_type_id__volatile = 0;
+
+  if (g_once_init_enter (&g_define_type_id__volatile))
+    {
+      static const GEnumValue values[] = {
+        { NM_WIMAX_ERROR_CONNECTION_NOT_WIMAX, "NM_WIMAX_ERROR_CONNECTION_NOT_WIMAX", "ConnectionNotWimax" },
+        { NM_WIMAX_ERROR_CONNECTION_INVALID, "NM_WIMAX_ERROR_CONNECTION_INVALID", "ConnectionInvalid" },
+        { NM_WIMAX_ERROR_CONNECTION_INCOMPATIBLE, "NM_WIMAX_ERROR_CONNECTION_INCOMPATIBLE", "ConnectionIncompatible" },
+        { NM_WIMAX_ERROR_NSP_NOT_FOUND, "NM_WIMAX_ERROR_NSP_NOT_FOUND", "NspNotFound" },
+        { 0, NULL, NULL }
+      };
+      GType g_define_type_id =
+        g_enum_register_static (g_intern_static_string ("NMWimaxError"), values);
+      g_once_init_leave (&g_define_type_id__volatile, g_define_type_id);
+    }
+
+  return g_define_type_id__volatile;
+}
+GType
+nm_wimax_nsp_network_type_get_type (void)
+{
+  static volatile gsize g_define_type_id__volatile = 0;
+
+  if (g_once_init_enter (&g_define_type_id__volatile))
+    {
+      static const GEnumValue values[] = {
+        { NM_WIMAX_NSP_NETWORK_TYPE_UNKNOWN, "NM_WIMAX_NSP_NETWORK_TYPE_UNKNOWN", "unknown" },
+        { NM_WIMAX_NSP_NETWORK_TYPE_HOME, "NM_WIMAX_NSP_NETWORK_TYPE_HOME", "home" },
+        { NM_WIMAX_NSP_NETWORK_TYPE_PARTNER, "NM_WIMAX_NSP_NETWORK_TYPE_PARTNER", "partner" },
+        { NM_WIMAX_NSP_NETWORK_TYPE_ROAMING_PARTNER, "NM_WIMAX_NSP_NETWORK_TYPE_ROAMING_PARTNER", "roaming-partner" },
+        { 0, NULL, NULL }
+      };
+      GType g_define_type_id =
+        g_enum_register_static (g_intern_static_string ("NMWimaxNspNetworkType"), values);
+      g_once_init_leave (&g_define_type_id__volatile, g_define_type_id);
+    }
+
+  return g_define_type_id__volatile;
+}
+
+
+
diff --git a/src/generated/nm-enum-types.h b/src/generated/nm-enum-types.h
new file mode 100644
index 00000000..324dbf6a
--- /dev/null
+++ b/src/generated/nm-enum-types.h
@@ -0,0 +1,89 @@
+
+
+
+/* Generated by glib-mkenums. Do not edit */
+
+#ifndef __NM_ENUM_TYPES_H__
+#define __NM_ENUM_TYPES_H__
+
+#include <glib-object.h>
+
+G_BEGIN_DECLS
+GType nm_vlan_error_get_type (void) G_GNUC_CONST;
+#define NM_TYPE_VLAN_ERROR (nm_vlan_error_get_type ())
+GType nm_olpc_mesh_error_get_type (void) G_GNUC_CONST;
+#define NM_TYPE_OLPC_MESH_ERROR (nm_olpc_mesh_error_get_type ())
+GType nm_device_error_get_type (void) G_GNUC_CONST;
+#define NM_TYPE_DEVICE_ERROR (nm_device_error_get_type ())
+GType nm_rf_kill_state_get_type (void) G_GNUC_CONST;
+#define NM_TYPE_RF_KILL_STATE (nm_rf_kill_state_get_type ())
+GType nm_rf_kill_type_get_type (void) G_GNUC_CONST;
+#define NM_TYPE_RF_KILL_TYPE (nm_rf_kill_type_get_type ())
+GType nm_ethernet_error_get_type (void) G_GNUC_CONST;
+#define NM_TYPE_ETHERNET_ERROR (nm_ethernet_error_get_type ())
+GType nm_bt_error_get_type (void) G_GNUC_CONST;
+#define NM_TYPE_BT_ERROR (nm_bt_error_get_type ())
+GType nm_wifi_error_get_type (void) G_GNUC_CONST;
+#define NM_TYPE_WIFI_ERROR (nm_wifi_error_get_type ())
+GType nm_ip4_config_compare_flags_get_type (void) G_GNUC_CONST;
+#define NM_TYPE_IP4_CONFIG_COMPARE_FLAGS (nm_ip4_config_compare_flags_get_type ())
+GType nm_bond_error_get_type (void) G_GNUC_CONST;
+#define NM_TYPE_BOND_ERROR (nm_bond_error_get_type ())
+GType nm_manager_error_get_type (void) G_GNUC_CONST;
+#define NM_TYPE_MANAGER_ERROR (nm_manager_error_get_type ())
+GType nm_act_request_dependency_result_get_type (void) G_GNUC_CONST;
+#define NM_TYPE_ACT_REQUEST_DEPENDENCY_RESULT (nm_act_request_dependency_result_get_type ())
+GType nm_session_monitor_error_get_type (void) G_GNUC_CONST;
+#define NM_TYPE_SESSION_MONITOR_ERROR (nm_session_monitor_error_get_type ())
+GType nm_infiniband_error_get_type (void) G_GNUC_CONST;
+#define NM_TYPE_INFINIBAND_ERROR (nm_infiniband_error_get_type ())
+GType nm_ip6_config_compare_flags_get_type (void) G_GNUC_CONST;
+#define NM_TYPE_IP6_CONFIG_COMPARE_FLAGS (nm_ip6_config_compare_flags_get_type ())
+GType nm_auth_call_result_get_type (void) G_GNUC_CONST;
+#define NM_TYPE_AUTH_CALL_RESULT (nm_auth_call_result_get_type ())
+GType nm_config_error_get_type (void) G_GNUC_CONST;
+#define NM_TYPE_CONFIG_ERROR (nm_config_error_get_type ())
+GType nm_nm_nl_prop_get_type (void) G_GNUC_CONST;
+#define NM_TYPE_NM_NL_PROP (nm_nm_nl_prop_get_type ())
+GType nm_netlink_monitor_error_get_type (void) G_GNUC_CONST;
+#define NM_TYPE_NETLINK_MONITOR_ERROR (nm_netlink_monitor_error_get_type ())
+GType nm_logging_error_get_type (void) G_GNUC_CONST;
+#define NM_TYPE_LOGGING_ERROR (nm_logging_error_get_type ())
+GType nm_dns_manager_error_get_type (void) G_GNUC_CONST;
+#define NM_TYPE_DNS_MANAGER_ERROR (nm_dns_manager_error_get_type ())
+GType nm_dns_ip_config_type_get_type (void) G_GNUC_CONST;
+#define NM_TYPE_DNS_IP_CONFIG_TYPE (nm_dns_ip_config_type_get_type ())
+GType nm_vpn_manager_error_get_type (void) G_GNUC_CONST;
+#define NM_TYPE_VPN_MANAGER_ERROR (nm_vpn_manager_error_get_type ())
+GType nm_dhcp_state_get_type (void) G_GNUC_CONST;
+#define NM_TYPE_DHCP_STATE (nm_dhcp_state_get_type ())
+GType nm_dhcp_manager_error_get_type (void) G_GNUC_CONST;
+#define NM_TYPE_DHCP_MANAGER_ERROR (nm_dhcp_manager_error_get_type ())
+GType nm_opt_type_get_type (void) G_GNUC_CONST;
+#define NM_TYPE_OPT_TYPE (nm_opt_type_get_type ())
+GType nm_ppp_status_get_type (void) G_GNUC_CONST;
+#define NM_TYPE_PPP_STATUS (nm_ppp_status_get_type ())
+GType nm_dns_masq_status_get_type (void) G_GNUC_CONST;
+#define NM_TYPE_DNS_MASQ_STATUS (nm_dns_masq_status_get_type ())
+GType nm_cdma_error_get_type (void) G_GNUC_CONST;
+#define NM_TYPE_CDMA_ERROR (nm_cdma_error_get_type ())
+GType nm_gsm_error_get_type (void) G_GNUC_CONST;
+#define NM_TYPE_GSM_ERROR (nm_gsm_error_get_type ())
+GType nm_system_config_interface_capabilities_get_type (void) G_GNUC_CONST;
+#define NM_TYPE_SYSTEM_CONFIG_INTERFACE_CAPABILITIES (nm_system_config_interface_capabilities_get_type ())
+GType nm_system_config_interface_prop_get_type (void) G_GNUC_CONST;
+#define NM_TYPE_SYSTEM_CONFIG_INTERFACE_PROP (nm_system_config_interface_prop_get_type ())
+GType nm_settings_error_get_type (void) G_GNUC_CONST;
+#define NM_TYPE_SETTINGS_ERROR (nm_settings_error_get_type ())
+GType nm_agent_manager_error_get_type (void) G_GNUC_CONST;
+#define NM_TYPE_AGENT_MANAGER_ERROR (nm_agent_manager_error_get_type ())
+GType nm_wimax_error_get_type (void) G_GNUC_CONST;
+#define NM_TYPE_WIMAX_ERROR (nm_wimax_error_get_type ())
+GType nm_wimax_nsp_network_type_get_type (void) G_GNUC_CONST;
+#define NM_TYPE_WIMAX_NSP_NETWORK_TYPE (nm_wimax_nsp_network_type_get_type ())
+G_END_DECLS
+
+#endif /* __NM_ENUM_TYPES_H__ */
+
+
+
diff --git a/src/generated/nm-marshal.c b/src/generated/nm-marshal.c
new file mode 100644
index 00000000..4ba973af
--- /dev/null
+++ b/src/generated/nm-marshal.c
@@ -0,0 +1,705 @@
+#include "nm-marshal.h"
+
+#include	<glib-object.h>
+
+
+#ifdef G_ENABLE_DEBUG
+#define g_marshal_value_peek_boolean(v)  g_value_get_boolean (v)
+#define g_marshal_value_peek_char(v)     g_value_get_char (v)
+#define g_marshal_value_peek_uchar(v)    g_value_get_uchar (v)
+#define g_marshal_value_peek_int(v)      g_value_get_int (v)
+#define g_marshal_value_peek_uint(v)     g_value_get_uint (v)
+#define g_marshal_value_peek_long(v)     g_value_get_long (v)
+#define g_marshal_value_peek_ulong(v)    g_value_get_ulong (v)
+#define g_marshal_value_peek_int64(v)    g_value_get_int64 (v)
+#define g_marshal_value_peek_uint64(v)   g_value_get_uint64 (v)
+#define g_marshal_value_peek_enum(v)     g_value_get_enum (v)
+#define g_marshal_value_peek_flags(v)    g_value_get_flags (v)
+#define g_marshal_value_peek_float(v)    g_value_get_float (v)
+#define g_marshal_value_peek_double(v)   g_value_get_double (v)
+#define g_marshal_value_peek_string(v)   (char*) g_value_get_string (v)
+#define g_marshal_value_peek_param(v)    g_value_get_param (v)
+#define g_marshal_value_peek_boxed(v)    g_value_get_boxed (v)
+#define g_marshal_value_peek_pointer(v)  g_value_get_pointer (v)
+#define g_marshal_value_peek_object(v)   g_value_get_object (v)
+#define g_marshal_value_peek_variant(v)  g_value_get_variant (v)
+#else /* !G_ENABLE_DEBUG */
+/* WARNING: This code accesses GValues directly, which is UNSUPPORTED API.
+ *          Do not access GValues directly in your code. Instead, use the
+ *          g_value_get_*() functions
+ */
+#define g_marshal_value_peek_boolean(v)  (v)->data[0].v_int
+#define g_marshal_value_peek_char(v)     (v)->data[0].v_int
+#define g_marshal_value_peek_uchar(v)    (v)->data[0].v_uint
+#define g_marshal_value_peek_int(v)      (v)->data[0].v_int
+#define g_marshal_value_peek_uint(v)     (v)->data[0].v_uint
+#define g_marshal_value_peek_long(v)     (v)->data[0].v_long
+#define g_marshal_value_peek_ulong(v)    (v)->data[0].v_ulong
+#define g_marshal_value_peek_int64(v)    (v)->data[0].v_int64
+#define g_marshal_value_peek_uint64(v)   (v)->data[0].v_uint64
+#define g_marshal_value_peek_enum(v)     (v)->data[0].v_long
+#define g_marshal_value_peek_flags(v)    (v)->data[0].v_ulong
+#define g_marshal_value_peek_float(v)    (v)->data[0].v_float
+#define g_marshal_value_peek_double(v)   (v)->data[0].v_double
+#define g_marshal_value_peek_string(v)   (v)->data[0].v_pointer
+#define g_marshal_value_peek_param(v)    (v)->data[0].v_pointer
+#define g_marshal_value_peek_boxed(v)    (v)->data[0].v_pointer
+#define g_marshal_value_peek_pointer(v)  (v)->data[0].v_pointer
+#define g_marshal_value_peek_object(v)   (v)->data[0].v_pointer
+#define g_marshal_value_peek_variant(v)  (v)->data[0].v_pointer
+#endif /* !G_ENABLE_DEBUG */
+
+
+/* BOOLEAN:VOID (nm-marshal.list:1) */
+void
+_nm_marshal_BOOLEAN__VOID (GClosure     *closure,
+                           GValue       *return_value G_GNUC_UNUSED,
+                           guint         n_param_values,
+                           const GValue *param_values,
+                           gpointer      invocation_hint G_GNUC_UNUSED,
+                           gpointer      marshal_data)
+{
+  typedef gboolean (*GMarshalFunc_BOOLEAN__VOID) (gpointer     data1,
+                                                  gpointer     data2);
+  register GMarshalFunc_BOOLEAN__VOID callback;
+  register GCClosure *cc = (GCClosure*) closure;
+  register gpointer data1, data2;
+  gboolean v_return;
+
+  g_return_if_fail (return_value != NULL);
+  g_return_if_fail (n_param_values == 1);
+
+  if (G_CCLOSURE_SWAP_DATA (closure))
+    {
+      data1 = closure->data;
+      data2 = g_value_peek_pointer (param_values + 0);
+    }
+  else
+    {
+      data1 = g_value_peek_pointer (param_values + 0);
+      data2 = closure->data;
+    }
+  callback = (GMarshalFunc_BOOLEAN__VOID) (marshal_data ? marshal_data : cc->callback);
+
+  v_return = callback (data1,
+                       data2);
+
+  g_value_set_boolean (return_value, v_return);
+}
+
+/* VOID:BOOLEAN,UINT (nm-marshal.list:2) */
+void
+_nm_marshal_VOID__BOOLEAN_UINT (GClosure     *closure,
+                                GValue       *return_value G_GNUC_UNUSED,
+                                guint         n_param_values,
+                                const GValue *param_values,
+                                gpointer      invocation_hint G_GNUC_UNUSED,
+                                gpointer      marshal_data)
+{
+  typedef void (*GMarshalFunc_VOID__BOOLEAN_UINT) (gpointer     data1,
+                                                   gboolean     arg_1,
+                                                   guint        arg_2,
+                                                   gpointer     data2);
+  register GMarshalFunc_VOID__BOOLEAN_UINT callback;
+  register GCClosure *cc = (GCClosure*) closure;
+  register gpointer data1, data2;
+
+  g_return_if_fail (n_param_values == 3);
+
+  if (G_CCLOSURE_SWAP_DATA (closure))
+    {
+      data1 = closure->data;
+      data2 = g_value_peek_pointer (param_values + 0);
+    }
+  else
+    {
+      data1 = g_value_peek_pointer (param_values + 0);
+      data2 = closure->data;
+    }
+  callback = (GMarshalFunc_VOID__BOOLEAN_UINT) (marshal_data ? marshal_data : cc->callback);
+
+  callback (data1,
+            g_marshal_value_peek_boolean (param_values + 1),
+            g_marshal_value_peek_uint (param_values + 2),
+            data2);
+}
+
+/* VOID:INT,UINT,BOOLEAN (nm-marshal.list:3) */
+void
+_nm_marshal_VOID__INT_UINT_BOOLEAN (GClosure     *closure,
+                                    GValue       *return_value G_GNUC_UNUSED,
+                                    guint         n_param_values,
+                                    const GValue *param_values,
+                                    gpointer      invocation_hint G_GNUC_UNUSED,
+                                    gpointer      marshal_data)
+{
+  typedef void (*GMarshalFunc_VOID__INT_UINT_BOOLEAN) (gpointer     data1,
+                                                       gint         arg_1,
+                                                       guint        arg_2,
+                                                       gboolean     arg_3,
+                                                       gpointer     data2);
+  register GMarshalFunc_VOID__INT_UINT_BOOLEAN callback;
+  register GCClosure *cc = (GCClosure*) closure;
+  register gpointer data1, data2;
+
+  g_return_if_fail (n_param_values == 4);
+
+  if (G_CCLOSURE_SWAP_DATA (closure))
+    {
+      data1 = closure->data;
+      data2 = g_value_peek_pointer (param_values + 0);
+    }
+  else
+    {
+      data1 = g_value_peek_pointer (param_values + 0);
+      data2 = closure->data;
+    }
+  callback = (GMarshalFunc_VOID__INT_UINT_BOOLEAN) (marshal_data ? marshal_data : cc->callback);
+
+  callback (data1,
+            g_marshal_value_peek_int (param_values + 1),
+            g_marshal_value_peek_uint (param_values + 2),
+            g_marshal_value_peek_boolean (param_values + 3),
+            data2);
+}
+
+/* VOID:OBJECT,STRING (nm-marshal.list:4) */
+void
+_nm_marshal_VOID__OBJECT_STRING (GClosure     *closure,
+                                 GValue       *return_value G_GNUC_UNUSED,
+                                 guint         n_param_values,
+                                 const GValue *param_values,
+                                 gpointer      invocation_hint G_GNUC_UNUSED,
+                                 gpointer      marshal_data)
+{
+  typedef void (*GMarshalFunc_VOID__OBJECT_STRING) (gpointer     data1,
+                                                    gpointer     arg_1,
+                                                    gpointer     arg_2,
+                                                    gpointer     data2);
+  register GMarshalFunc_VOID__OBJECT_STRING callback;
+  register GCClosure *cc = (GCClosure*) closure;
+  register gpointer data1, data2;
+
+  g_return_if_fail (n_param_values == 3);
+
+  if (G_CCLOSURE_SWAP_DATA (closure))
+    {
+      data1 = closure->data;
+      data2 = g_value_peek_pointer (param_values + 0);
+    }
+  else
+    {
+      data1 = g_value_peek_pointer (param_values + 0);
+      data2 = closure->data;
+    }
+  callback = (GMarshalFunc_VOID__OBJECT_STRING) (marshal_data ? marshal_data : cc->callback);
+
+  callback (data1,
+            g_marshal_value_peek_object (param_values + 1),
+            g_marshal_value_peek_string (param_values + 2),
+            data2);
+}
+
+/* VOID:OBJECT,UINT,UINT (nm-marshal.list:5) */
+void
+_nm_marshal_VOID__OBJECT_UINT_UINT (GClosure     *closure,
+                                    GValue       *return_value G_GNUC_UNUSED,
+                                    guint         n_param_values,
+                                    const GValue *param_values,
+                                    gpointer      invocation_hint G_GNUC_UNUSED,
+                                    gpointer      marshal_data)
+{
+  typedef void (*GMarshalFunc_VOID__OBJECT_UINT_UINT) (gpointer     data1,
+                                                       gpointer     arg_1,
+                                                       guint        arg_2,
+                                                       guint        arg_3,
+                                                       gpointer     data2);
+  register GMarshalFunc_VOID__OBJECT_UINT_UINT callback;
+  register GCClosure *cc = (GCClosure*) closure;
+  register gpointer data1, data2;
+
+  g_return_if_fail (n_param_values == 4);
+
+  if (G_CCLOSURE_SWAP_DATA (closure))
+    {
+      data1 = closure->data;
+      data2 = g_value_peek_pointer (param_values + 0);
+    }
+  else
+    {
+      data1 = g_value_peek_pointer (param_values + 0);
+      data2 = closure->data;
+    }
+  callback = (GMarshalFunc_VOID__OBJECT_UINT_UINT) (marshal_data ? marshal_data : cc->callback);
+
+  callback (data1,
+            g_marshal_value_peek_object (param_values + 1),
+            g_marshal_value_peek_uint (param_values + 2),
+            g_marshal_value_peek_uint (param_values + 3),
+            data2);
+}
+
+/* VOID:POINTER (nm-marshal.list:6) */
+
+/* VOID:POINTER,POINTER,POINTER,POINTER,INT (nm-marshal.list:7) */
+void
+_nm_marshal_VOID__POINTER_POINTER_POINTER_POINTER_INT (GClosure     *closure,
+                                                       GValue       *return_value G_GNUC_UNUSED,
+                                                       guint         n_param_values,
+                                                       const GValue *param_values,
+                                                       gpointer      invocation_hint G_GNUC_UNUSED,
+                                                       gpointer      marshal_data)
+{
+  typedef void (*GMarshalFunc_VOID__POINTER_POINTER_POINTER_POINTER_INT) (gpointer     data1,
+                                                                          gpointer     arg_1,
+                                                                          gpointer     arg_2,
+                                                                          gpointer     arg_3,
+                                                                          gpointer     arg_4,
+                                                                          gint         arg_5,
+                                                                          gpointer     data2);
+  register GMarshalFunc_VOID__POINTER_POINTER_POINTER_POINTER_INT callback;
+  register GCClosure *cc = (GCClosure*) closure;
+  register gpointer data1, data2;
+
+  g_return_if_fail (n_param_values == 6);
+
+  if (G_CCLOSURE_SWAP_DATA (closure))
+    {
+      data1 = closure->data;
+      data2 = g_value_peek_pointer (param_values + 0);
+    }
+  else
+    {
+      data1 = g_value_peek_pointer (param_values + 0);
+      data2 = closure->data;
+    }
+  callback = (GMarshalFunc_VOID__POINTER_POINTER_POINTER_POINTER_INT) (marshal_data ? marshal_data : cc->callback);
+
+  callback (data1,
+            g_marshal_value_peek_pointer (param_values + 1),
+            g_marshal_value_peek_pointer (param_values + 2),
+            g_marshal_value_peek_pointer (param_values + 3),
+            g_marshal_value_peek_pointer (param_values + 4),
+            g_marshal_value_peek_int (param_values + 5),
+            data2);
+}
+
+/* VOID:POINTER,STRING (nm-marshal.list:8) */
+void
+_nm_marshal_VOID__POINTER_STRING (GClosure     *closure,
+                                  GValue       *return_value G_GNUC_UNUSED,
+                                  guint         n_param_values,
+                                  const GValue *param_values,
+                                  gpointer      invocation_hint G_GNUC_UNUSED,
+                                  gpointer      marshal_data)
+{
+  typedef void (*GMarshalFunc_VOID__POINTER_STRING) (gpointer     data1,
+                                                     gpointer     arg_1,
+                                                     gpointer     arg_2,
+                                                     gpointer     data2);
+  register GMarshalFunc_VOID__POINTER_STRING callback;
+  register GCClosure *cc = (GCClosure*) closure;
+  register gpointer data1, data2;
+
+  g_return_if_fail (n_param_values == 3);
+
+  if (G_CCLOSURE_SWAP_DATA (closure))
+    {
+      data1 = closure->data;
+      data2 = g_value_peek_pointer (param_values + 0);
+    }
+  else
+    {
+      data1 = g_value_peek_pointer (param_values + 0);
+      data2 = closure->data;
+    }
+  callback = (GMarshalFunc_VOID__POINTER_STRING) (marshal_data ? marshal_data : cc->callback);
+
+  callback (data1,
+            g_marshal_value_peek_pointer (param_values + 1),
+            g_marshal_value_peek_string (param_values + 2),
+            data2);
+}
+
+/* VOID:STRING,BOXED (nm-marshal.list:9) */
+void
+_nm_marshal_VOID__STRING_BOXED (GClosure     *closure,
+                                GValue       *return_value G_GNUC_UNUSED,
+                                guint         n_param_values,
+                                const GValue *param_values,
+                                gpointer      invocation_hint G_GNUC_UNUSED,
+                                gpointer      marshal_data)
+{
+  typedef void (*GMarshalFunc_VOID__STRING_BOXED) (gpointer     data1,
+                                                   gpointer     arg_1,
+                                                   gpointer     arg_2,
+                                                   gpointer     data2);
+  register GMarshalFunc_VOID__STRING_BOXED callback;
+  register GCClosure *cc = (GCClosure*) closure;
+  register gpointer data1, data2;
+
+  g_return_if_fail (n_param_values == 3);
+
+  if (G_CCLOSURE_SWAP_DATA (closure))
+    {
+      data1 = closure->data;
+      data2 = g_value_peek_pointer (param_values + 0);
+    }
+  else
+    {
+      data1 = g_value_peek_pointer (param_values + 0);
+      data2 = closure->data;
+    }
+  callback = (GMarshalFunc_VOID__STRING_BOXED) (marshal_data ? marshal_data : cc->callback);
+
+  callback (data1,
+            g_marshal_value_peek_string (param_values + 1),
+            g_marshal_value_peek_boxed (param_values + 2),
+            data2);
+}
+
+/* VOID:STRING,BOXED,BOXED (nm-marshal.list:10) */
+void
+_nm_marshal_VOID__STRING_BOXED_BOXED (GClosure     *closure,
+                                      GValue       *return_value G_GNUC_UNUSED,
+                                      guint         n_param_values,
+                                      const GValue *param_values,
+                                      gpointer      invocation_hint G_GNUC_UNUSED,
+                                      gpointer      marshal_data)
+{
+  typedef void (*GMarshalFunc_VOID__STRING_BOXED_BOXED) (gpointer     data1,
+                                                         gpointer     arg_1,
+                                                         gpointer     arg_2,
+                                                         gpointer     arg_3,
+                                                         gpointer     data2);
+  register GMarshalFunc_VOID__STRING_BOXED_BOXED callback;
+  register GCClosure *cc = (GCClosure*) closure;
+  register gpointer data1, data2;
+
+  g_return_if_fail (n_param_values == 4);
+
+  if (G_CCLOSURE_SWAP_DATA (closure))
+    {
+      data1 = closure->data;
+      data2 = g_value_peek_pointer (param_values + 0);
+    }
+  else
+    {
+      data1 = g_value_peek_pointer (param_values + 0);
+      data2 = closure->data;
+    }
+  callback = (GMarshalFunc_VOID__STRING_BOXED_BOXED) (marshal_data ? marshal_data : cc->callback);
+
+  callback (data1,
+            g_marshal_value_peek_string (param_values + 1),
+            g_marshal_value_peek_boxed (param_values + 2),
+            g_marshal_value_peek_boxed (param_values + 3),
+            data2);
+}
+
+/* VOID:STRING,OBJECT (nm-marshal.list:11) */
+void
+_nm_marshal_VOID__STRING_OBJECT (GClosure     *closure,
+                                 GValue       *return_value G_GNUC_UNUSED,
+                                 guint         n_param_values,
+                                 const GValue *param_values,
+                                 gpointer      invocation_hint G_GNUC_UNUSED,
+                                 gpointer      marshal_data)
+{
+  typedef void (*GMarshalFunc_VOID__STRING_OBJECT) (gpointer     data1,
+                                                    gpointer     arg_1,
+                                                    gpointer     arg_2,
+                                                    gpointer     data2);
+  register GMarshalFunc_VOID__STRING_OBJECT callback;
+  register GCClosure *cc = (GCClosure*) closure;
+  register gpointer data1, data2;
+
+  g_return_if_fail (n_param_values == 3);
+
+  if (G_CCLOSURE_SWAP_DATA (closure))
+    {
+      data1 = closure->data;
+      data2 = g_value_peek_pointer (param_values + 0);
+    }
+  else
+    {
+      data1 = g_value_peek_pointer (param_values + 0);
+      data2 = closure->data;
+    }
+  callback = (GMarshalFunc_VOID__STRING_OBJECT) (marshal_data ? marshal_data : cc->callback);
+
+  callback (data1,
+            g_marshal_value_peek_string (param_values + 1),
+            g_marshal_value_peek_object (param_values + 2),
+            data2);
+}
+
+/* VOID:STRING,OBJECT,POINTER (nm-marshal.list:12) */
+void
+_nm_marshal_VOID__STRING_OBJECT_POINTER (GClosure     *closure,
+                                         GValue       *return_value G_GNUC_UNUSED,
+                                         guint         n_param_values,
+                                         const GValue *param_values,
+                                         gpointer      invocation_hint G_GNUC_UNUSED,
+                                         gpointer      marshal_data)
+{
+  typedef void (*GMarshalFunc_VOID__STRING_OBJECT_POINTER) (gpointer     data1,
+                                                            gpointer     arg_1,
+                                                            gpointer     arg_2,
+                                                            gpointer     arg_3,
+                                                            gpointer     data2);
+  register GMarshalFunc_VOID__STRING_OBJECT_POINTER callback;
+  register GCClosure *cc = (GCClosure*) closure;
+  register gpointer data1, data2;
+
+  g_return_if_fail (n_param_values == 4);
+
+  if (G_CCLOSURE_SWAP_DATA (closure))
+    {
+      data1 = closure->data;
+      data2 = g_value_peek_pointer (param_values + 0);
+    }
+  else
+    {
+      data1 = g_value_peek_pointer (param_values + 0);
+      data2 = closure->data;
+    }
+  callback = (GMarshalFunc_VOID__STRING_OBJECT_POINTER) (marshal_data ? marshal_data : cc->callback);
+
+  callback (data1,
+            g_marshal_value_peek_string (param_values + 1),
+            g_marshal_value_peek_object (param_values + 2),
+            g_marshal_value_peek_pointer (param_values + 3),
+            data2);
+}
+
+/* VOID:STRING,POINTER (nm-marshal.list:13) */
+void
+_nm_marshal_VOID__STRING_POINTER (GClosure     *closure,
+                                  GValue       *return_value G_GNUC_UNUSED,
+                                  guint         n_param_values,
+                                  const GValue *param_values,
+                                  gpointer      invocation_hint G_GNUC_UNUSED,
+                                  gpointer      marshal_data)
+{
+  typedef void (*GMarshalFunc_VOID__STRING_POINTER) (gpointer     data1,
+                                                     gpointer     arg_1,
+                                                     gpointer     arg_2,
+                                                     gpointer     data2);
+  register GMarshalFunc_VOID__STRING_POINTER callback;
+  register GCClosure *cc = (GCClosure*) closure;
+  register gpointer data1, data2;
+
+  g_return_if_fail (n_param_values == 3);
+
+  if (G_CCLOSURE_SWAP_DATA (closure))
+    {
+      data1 = closure->data;
+      data2 = g_value_peek_pointer (param_values + 0);
+    }
+  else
+    {
+      data1 = g_value_peek_pointer (param_values + 0);
+      data2 = closure->data;
+    }
+  callback = (GMarshalFunc_VOID__STRING_POINTER) (marshal_data ? marshal_data : cc->callback);
+
+  callback (data1,
+            g_marshal_value_peek_string (param_values + 1),
+            g_marshal_value_peek_pointer (param_values + 2),
+            data2);
+}
+
+/* VOID:STRING,STRING (nm-marshal.list:14) */
+void
+_nm_marshal_VOID__STRING_STRING (GClosure     *closure,
+                                 GValue       *return_value G_GNUC_UNUSED,
+                                 guint         n_param_values,
+                                 const GValue *param_values,
+                                 gpointer      invocation_hint G_GNUC_UNUSED,
+                                 gpointer      marshal_data)
+{
+  typedef void (*GMarshalFunc_VOID__STRING_STRING) (gpointer     data1,
+                                                    gpointer     arg_1,
+                                                    gpointer     arg_2,
+                                                    gpointer     data2);
+  register GMarshalFunc_VOID__STRING_STRING callback;
+  register GCClosure *cc = (GCClosure*) closure;
+  register gpointer data1, data2;
+
+  g_return_if_fail (n_param_values == 3);
+
+  if (G_CCLOSURE_SWAP_DATA (closure))
+    {
+      data1 = closure->data;
+      data2 = g_value_peek_pointer (param_values + 0);
+    }
+  else
+    {
+      data1 = g_value_peek_pointer (param_values + 0);
+      data2 = closure->data;
+    }
+  callback = (GMarshalFunc_VOID__STRING_STRING) (marshal_data ? marshal_data : cc->callback);
+
+  callback (data1,
+            g_marshal_value_peek_string (param_values + 1),
+            g_marshal_value_peek_string (param_values + 2),
+            data2);
+}
+
+/* VOID:STRING,STRING,STRING (nm-marshal.list:15) */
+void
+_nm_marshal_VOID__STRING_STRING_STRING (GClosure     *closure,
+                                        GValue       *return_value G_GNUC_UNUSED,
+                                        guint         n_param_values,
+                                        const GValue *param_values,
+                                        gpointer      invocation_hint G_GNUC_UNUSED,
+                                        gpointer      marshal_data)
+{
+  typedef void (*GMarshalFunc_VOID__STRING_STRING_STRING) (gpointer     data1,
+                                                           gpointer     arg_1,
+                                                           gpointer     arg_2,
+                                                           gpointer     arg_3,
+                                                           gpointer     data2);
+  register GMarshalFunc_VOID__STRING_STRING_STRING callback;
+  register GCClosure *cc = (GCClosure*) closure;
+  register gpointer data1, data2;
+
+  g_return_if_fail (n_param_values == 4);
+
+  if (G_CCLOSURE_SWAP_DATA (closure))
+    {
+      data1 = closure->data;
+      data2 = g_value_peek_pointer (param_values + 0);
+    }
+  else
+    {
+      data1 = g_value_peek_pointer (param_values + 0);
+      data2 = closure->data;
+    }
+  callback = (GMarshalFunc_VOID__STRING_STRING_STRING) (marshal_data ? marshal_data : cc->callback);
+
+  callback (data1,
+            g_marshal_value_peek_string (param_values + 1),
+            g_marshal_value_peek_string (param_values + 2),
+            g_marshal_value_peek_string (param_values + 3),
+            data2);
+}
+
+/* VOID:STRING,STRING,STRING,UINT (nm-marshal.list:16) */
+void
+_nm_marshal_VOID__STRING_STRING_STRING_UINT (GClosure     *closure,
+                                             GValue       *return_value G_GNUC_UNUSED,
+                                             guint         n_param_values,
+                                             const GValue *param_values,
+                                             gpointer      invocation_hint G_GNUC_UNUSED,
+                                             gpointer      marshal_data)
+{
+  typedef void (*GMarshalFunc_VOID__STRING_STRING_STRING_UINT) (gpointer     data1,
+                                                                gpointer     arg_1,
+                                                                gpointer     arg_2,
+                                                                gpointer     arg_3,
+                                                                guint        arg_4,
+                                                                gpointer     data2);
+  register GMarshalFunc_VOID__STRING_STRING_STRING_UINT callback;
+  register GCClosure *cc = (GCClosure*) closure;
+  register gpointer data1, data2;
+
+  g_return_if_fail (n_param_values == 5);
+
+  if (G_CCLOSURE_SWAP_DATA (closure))
+    {
+      data1 = closure->data;
+      data2 = g_value_peek_pointer (param_values + 0);
+    }
+  else
+    {
+      data1 = g_value_peek_pointer (param_values + 0);
+      data2 = closure->data;
+    }
+  callback = (GMarshalFunc_VOID__STRING_STRING_STRING_UINT) (marshal_data ? marshal_data : cc->callback);
+
+  callback (data1,
+            g_marshal_value_peek_string (param_values + 1),
+            g_marshal_value_peek_string (param_values + 2),
+            g_marshal_value_peek_string (param_values + 3),
+            g_marshal_value_peek_uint (param_values + 4),
+            data2);
+}
+
+/* VOID:UINT,UINT (nm-marshal.list:17) */
+void
+_nm_marshal_VOID__UINT_UINT (GClosure     *closure,
+                             GValue       *return_value G_GNUC_UNUSED,
+                             guint         n_param_values,
+                             const GValue *param_values,
+                             gpointer      invocation_hint G_GNUC_UNUSED,
+                             gpointer      marshal_data)
+{
+  typedef void (*GMarshalFunc_VOID__UINT_UINT) (gpointer     data1,
+                                                guint        arg_1,
+                                                guint        arg_2,
+                                                gpointer     data2);
+  register GMarshalFunc_VOID__UINT_UINT callback;
+  register GCClosure *cc = (GCClosure*) closure;
+  register gpointer data1, data2;
+
+  g_return_if_fail (n_param_values == 3);
+
+  if (G_CCLOSURE_SWAP_DATA (closure))
+    {
+      data1 = closure->data;
+      data2 = g_value_peek_pointer (param_values + 0);
+    }
+  else
+    {
+      data1 = g_value_peek_pointer (param_values + 0);
+      data2 = closure->data;
+    }
+  callback = (GMarshalFunc_VOID__UINT_UINT) (marshal_data ? marshal_data : cc->callback);
+
+  callback (data1,
+            g_marshal_value_peek_uint (param_values + 1),
+            g_marshal_value_peek_uint (param_values + 2),
+            data2);
+}
+
+/* VOID:UINT,UINT,UINT (nm-marshal.list:18) */
+void
+_nm_marshal_VOID__UINT_UINT_UINT (GClosure     *closure,
+                                  GValue       *return_value G_GNUC_UNUSED,
+                                  guint         n_param_values,
+                                  const GValue *param_values,
+                                  gpointer      invocation_hint G_GNUC_UNUSED,
+                                  gpointer      marshal_data)
+{
+  typedef void (*GMarshalFunc_VOID__UINT_UINT_UINT) (gpointer     data1,
+                                                     guint        arg_1,
+                                                     guint        arg_2,
+                                                     guint        arg_3,
+                                                     gpointer     data2);
+  register GMarshalFunc_VOID__UINT_UINT_UINT callback;
+  register GCClosure *cc = (GCClosure*) closure;
+  register gpointer data1, data2;
+
+  g_return_if_fail (n_param_values == 4);
+
+  if (G_CCLOSURE_SWAP_DATA (closure))
+    {
+      data1 = closure->data;
+      data2 = g_value_peek_pointer (param_values + 0);
+    }
+  else
+    {
+      data1 = g_value_peek_pointer (param_values + 0);
+      data2 = closure->data;
+    }
+  callback = (GMarshalFunc_VOID__UINT_UINT_UINT) (marshal_data ? marshal_data : cc->callback);
+
+  callback (data1,
+            g_marshal_value_peek_uint (param_values + 1),
+            g_marshal_value_peek_uint (param_values + 2),
+            g_marshal_value_peek_uint (param_values + 3),
+            data2);
+}
+
diff --git a/src/generated/nm-marshal.h b/src/generated/nm-marshal.h
new file mode 100644
index 00000000..9f9ea6ad
--- /dev/null
+++ b/src/generated/nm-marshal.h
@@ -0,0 +1,151 @@
+
+#ifndef ___nm_marshal_MARSHAL_H__
+#define ___nm_marshal_MARSHAL_H__
+
+#include	<glib-object.h>
+
+G_BEGIN_DECLS
+
+/* BOOLEAN:VOID (nm-marshal.list:1) */
+extern void _nm_marshal_BOOLEAN__VOID (GClosure     *closure,
+                                       GValue       *return_value,
+                                       guint         n_param_values,
+                                       const GValue *param_values,
+                                       gpointer      invocation_hint,
+                                       gpointer      marshal_data);
+
+/* VOID:BOOLEAN,UINT (nm-marshal.list:2) */
+extern void _nm_marshal_VOID__BOOLEAN_UINT (GClosure     *closure,
+                                            GValue       *return_value,
+                                            guint         n_param_values,
+                                            const GValue *param_values,
+                                            gpointer      invocation_hint,
+                                            gpointer      marshal_data);
+
+/* VOID:INT,UINT,BOOLEAN (nm-marshal.list:3) */
+extern void _nm_marshal_VOID__INT_UINT_BOOLEAN (GClosure     *closure,
+                                                GValue       *return_value,
+                                                guint         n_param_values,
+                                                const GValue *param_values,
+                                                gpointer      invocation_hint,
+                                                gpointer      marshal_data);
+
+/* VOID:OBJECT,STRING (nm-marshal.list:4) */
+extern void _nm_marshal_VOID__OBJECT_STRING (GClosure     *closure,
+                                             GValue       *return_value,
+                                             guint         n_param_values,
+                                             const GValue *param_values,
+                                             gpointer      invocation_hint,
+                                             gpointer      marshal_data);
+
+/* VOID:OBJECT,UINT,UINT (nm-marshal.list:5) */
+extern void _nm_marshal_VOID__OBJECT_UINT_UINT (GClosure     *closure,
+                                                GValue       *return_value,
+                                                guint         n_param_values,
+                                                const GValue *param_values,
+                                                gpointer      invocation_hint,
+                                                gpointer      marshal_data);
+
+/* VOID:POINTER (nm-marshal.list:6) */
+#define _nm_marshal_VOID__POINTER	g_cclosure_marshal_VOID__POINTER
+
+/* VOID:POINTER,POINTER,POINTER,POINTER,INT (nm-marshal.list:7) */
+extern void _nm_marshal_VOID__POINTER_POINTER_POINTER_POINTER_INT (GClosure     *closure,
+                                                                   GValue       *return_value,
+                                                                   guint         n_param_values,
+                                                                   const GValue *param_values,
+                                                                   gpointer      invocation_hint,
+                                                                   gpointer      marshal_data);
+
+/* VOID:POINTER,STRING (nm-marshal.list:8) */
+extern void _nm_marshal_VOID__POINTER_STRING (GClosure     *closure,
+                                              GValue       *return_value,
+                                              guint         n_param_values,
+                                              const GValue *param_values,
+                                              gpointer      invocation_hint,
+                                              gpointer      marshal_data);
+
+/* VOID:STRING,BOXED (nm-marshal.list:9) */
+extern void _nm_marshal_VOID__STRING_BOXED (GClosure     *closure,
+                                            GValue       *return_value,
+                                            guint         n_param_values,
+                                            const GValue *param_values,
+                                            gpointer      invocation_hint,
+                                            gpointer      marshal_data);
+
+/* VOID:STRING,BOXED,BOXED (nm-marshal.list:10) */
+extern void _nm_marshal_VOID__STRING_BOXED_BOXED (GClosure     *closure,
+                                                  GValue       *return_value,
+                                                  guint         n_param_values,
+                                                  const GValue *param_values,
+                                                  gpointer      invocation_hint,
+                                                  gpointer      marshal_data);
+
+/* VOID:STRING,OBJECT (nm-marshal.list:11) */
+extern void _nm_marshal_VOID__STRING_OBJECT (GClosure     *closure,
+                                             GValue       *return_value,
+                                             guint         n_param_values,
+                                             const GValue *param_values,
+                                             gpointer      invocation_hint,
+                                             gpointer      marshal_data);
+
+/* VOID:STRING,OBJECT,POINTER (nm-marshal.list:12) */
+extern void _nm_marshal_VOID__STRING_OBJECT_POINTER (GClosure     *closure,
+                                                     GValue       *return_value,
+                                                     guint         n_param_values,
+                                                     const GValue *param_values,
+                                                     gpointer      invocation_hint,
+                                                     gpointer      marshal_data);
+
+/* VOID:STRING,POINTER (nm-marshal.list:13) */
+extern void _nm_marshal_VOID__STRING_POINTER (GClosure     *closure,
+                                              GValue       *return_value,
+                                              guint         n_param_values,
+                                              const GValue *param_values,
+                                              gpointer      invocation_hint,
+                                              gpointer      marshal_data);
+
+/* VOID:STRING,STRING (nm-marshal.list:14) */
+extern void _nm_marshal_VOID__STRING_STRING (GClosure     *closure,
+                                             GValue       *return_value,
+                                             guint         n_param_values,
+                                             const GValue *param_values,
+                                             gpointer      invocation_hint,
+                                             gpointer      marshal_data);
+
+/* VOID:STRING,STRING,STRING (nm-marshal.list:15) */
+extern void _nm_marshal_VOID__STRING_STRING_STRING (GClosure     *closure,
+                                                    GValue       *return_value,
+                                                    guint         n_param_values,
+                                                    const GValue *param_values,
+                                                    gpointer      invocation_hint,
+                                                    gpointer      marshal_data);
+
+/* VOID:STRING,STRING,STRING,UINT (nm-marshal.list:16) */
+extern void _nm_marshal_VOID__STRING_STRING_STRING_UINT (GClosure     *closure,
+                                                         GValue       *return_value,
+                                                         guint         n_param_values,
+                                                         const GValue *param_values,
+                                                         gpointer      invocation_hint,
+                                                         gpointer      marshal_data);
+
+/* VOID:UINT,UINT (nm-marshal.list:17) */
+extern void _nm_marshal_VOID__UINT_UINT (GClosure     *closure,
+                                         GValue       *return_value,
+                                         guint         n_param_values,
+                                         const GValue *param_values,
+                                         gpointer      invocation_hint,
+                                         gpointer      marshal_data);
+
+/* VOID:UINT,UINT,UINT (nm-marshal.list:18) */
+extern void _nm_marshal_VOID__UINT_UINT_UINT (GClosure     *closure,
+                                              GValue       *return_value,
+                                              guint         n_param_values,
+                                              const GValue *param_values,
+                                              gpointer      invocation_hint,
+                                              gpointer      marshal_data);
+
+G_END_DECLS
+
+#endif /* ___nm_marshal_MARSHAL_H__ */
+
diff --git a/src/ip6-manager/Makefile.am b/src/ip6-manager/Makefile.am
index b98d6def..016fc25d 100644
--- a/src/ip6-manager/Makefile.am
+++ b/src/ip6-manager/Makefile.am
@@ -1,8 +1,11 @@
 INCLUDES = \
 	-I${top_srcdir} \
 	-I${top_srcdir}/include \
-	-I${top_builddir}/marshallers \
+	-I${top_builddir}/include \
 	-I${top_srcdir}/libnm-util \
+	-I${top_builddir}/libnm-util \
+	-I${top_srcdir}/src/generated \
+	-I${top_builddir}/src/generated \
 	-I${top_srcdir}/src/logging \
 	-I${top_srcdir}/src
 
@@ -19,7 +22,7 @@ libip6_manager_la_CPPFLAGS = \
 	-DG_DISABLE_DEPRECATED
 
 libip6_manager_la_LIBADD = \
-	$(top_builddir)/marshallers/libmarshallers.la \
+	$(top_builddir)/src/generated/libnm-generated.la \
 	$(top_builddir)/src/logging/libnm-logging.la \
 	$(LIBNL_LIBS) \
 	$(DBUS_LIBS) \
diff --git a/src/ip6-manager/Makefile.in b/src/ip6-manager/Makefile.in
index 6eb818c0..59c2e7b4 100644
--- a/src/ip6-manager/Makefile.in
+++ b/src/ip6-manager/Makefile.in
@@ -57,7 +57,7 @@ CONFIG_CLEAN_VPATH_FILES =
 LTLIBRARIES = $(noinst_LTLIBRARIES)
 am__DEPENDENCIES_1 =
 libip6_manager_la_DEPENDENCIES =  \
-	$(top_builddir)/marshallers/libmarshallers.la \
+	$(top_builddir)/src/generated/libnm-generated.la \
 	$(top_builddir)/src/logging/libnm-logging.la \
 	$(am__DEPENDENCIES_1) $(am__DEPENDENCIES_1) \
 	$(am__DEPENDENCIES_1)
@@ -142,6 +142,8 @@ GIO_LIBS = @GIO_LIBS@
 GLIB_CFLAGS = @GLIB_CFLAGS@
 GLIB_GENMARSHAL = @GLIB_GENMARSHAL@
 GLIB_LIBS = @GLIB_LIBS@
+GLIB_MAKEFILE = @GLIB_MAKEFILE@
+GLIB_MKENUMS = @GLIB_MKENUMS@
 GMODULE_CFLAGS = @GMODULE_CFLAGS@
 GMODULE_LIBS = @GMODULE_LIBS@
 GMSGFMT = @GMSGFMT@
@@ -196,11 +198,15 @@ LIBNL2_LIBS = @LIBNL2_LIBS@
 LIBNL3_CFLAGS = @LIBNL3_CFLAGS@
 LIBNL3_LIBS = @LIBNL3_LIBS@
 LIBNL_CFLAGS = @LIBNL_CFLAGS@
+LIBNL_GENL3_CFLAGS = @LIBNL_GENL3_CFLAGS@
+LIBNL_GENL3_LIBS = @LIBNL_GENL3_LIBS@
 LIBNL_LIBS = @LIBNL_LIBS@
 LIBNL_ROUTE3_CFLAGS = @LIBNL_ROUTE3_CFLAGS@
 LIBNL_ROUTE3_LIBS = @LIBNL_ROUTE3_LIBS@
 LIBOBJS = @LIBOBJS@
 LIBS = @LIBS@
+LIBSOUP_CFLAGS = @LIBSOUP_CFLAGS@
+LIBSOUP_LIBS = @LIBSOUP_LIBS@
 LIBTOOL = @LIBTOOL@
 LIPO = @LIPO@
 LN_S = @LN_S@
@@ -211,6 +217,7 @@ MAINT = @MAINT@
 MAKEINFO = @MAKEINFO@
 MANIFEST_TOOL = @MANIFEST_TOOL@
 MKDIR_P = @MKDIR_P@
+MOC = @MOC@
 MSGFMT = @MSGFMT@
 MSGFMT_015 = @MSGFMT_015@
 MSGMERGE = @MSGMERGE@
@@ -250,6 +257,8 @@ SED = @SED@
 SET_MAKE = @SET_MAKE@
 SHELL = @SHELL@
 STRIP = @STRIP@
+SYSTEMD_CFLAGS = @SYSTEMD_CFLAGS@
+SYSTEMD_LIBS = @SYSTEMD_LIBS@
 SYSTEM_CA_PATH = @SYSTEM_CA_PATH@
 UDEV_BASE_DIR = @UDEV_BASE_DIR@
 USE_NLS = @USE_NLS@
@@ -316,8 +325,11 @@ top_srcdir = @top_srcdir@
 INCLUDES = \
 	-I${top_srcdir} \
 	-I${top_srcdir}/include \
-	-I${top_builddir}/marshallers \
+	-I${top_builddir}/include \
 	-I${top_srcdir}/libnm-util \
+	-I${top_builddir}/libnm-util \
+	-I${top_srcdir}/src/generated \
+	-I${top_builddir}/src/generated \
 	-I${top_srcdir}/src/logging \
 	-I${top_srcdir}/src
 
@@ -333,7 +345,7 @@ libip6_manager_la_CPPFLAGS = \
 	-DG_DISABLE_DEPRECATED
 
 libip6_manager_la_LIBADD = \
-	$(top_builddir)/marshallers/libmarshallers.la \
+	$(top_builddir)/src/generated/libnm-generated.la \
 	$(top_builddir)/src/logging/libnm-logging.la \
 	$(LIBNL_LIBS) \
 	$(DBUS_LIBS) \
diff --git a/src/ip6-manager/nm-ip6-manager.c b/src/ip6-manager/nm-ip6-manager.c
index 503dab51..99f85ede 100644
--- a/src/ip6-manager/nm-ip6-manager.c
+++ b/src/ip6-manager/nm-ip6-manager.c
@@ -91,7 +91,7 @@ typedef struct {
 
 	char *disable_ip6_path;
 	gboolean disable_ip6_save_valid;
-	guint32 disable_ip6_save;
+	gint32 disable_ip6_save;
 
 	guint finish_addrconf_id;
 	guint config_changed_id;
@@ -112,6 +112,14 @@ typedef struct {
 } NMIP6Device;
 
 static void
+clear_config_changed (NMIP6Device *device)
+{
+	if (device->config_changed_id)
+		g_source_remove (device->config_changed_id);
+	device->config_changed_id = 0;
+}
+
+static void
 nm_ip6_device_destroy (NMIP6Device *device)
 {
 	g_return_if_fail (device != NULL);
@@ -124,8 +132,9 @@ nm_ip6_device_destroy (NMIP6Device *device)
 
 	if (device->finish_addrconf_id)
 		g_source_remove (device->finish_addrconf_id);
-	if (device->config_changed_id)
-		g_source_remove (device->config_changed_id);
+
+	clear_config_changed (device);
+
 	g_free (device->iface);
 	if (device->rdnss_servers)
 		g_array_free (device->rdnss_servers, TRUE);
@@ -176,9 +185,10 @@ nm_ip6_device_new (NMIP6Manager *manager, int ifindex)
 	device->disable_ip6_path = g_strdup_printf ("/proc/sys/net/ipv6/conf/%s/disable_ipv6",
 	                                            device->iface);
 	g_assert (device->disable_ip6_path);
-	device->disable_ip6_save_valid = nm_utils_get_proc_sys_net_value (device->disable_ip6_path,
-	                                                                  device->iface,
-	                                                                  &device->disable_ip6_save);
+	device->disable_ip6_save_valid = nm_utils_get_proc_sys_net_value_with_bounds (device->disable_ip6_path,
+	                                                                              device->iface,
+	                                                                              &device->disable_ip6_save,
+	                                                                              0, 1);
 
 	return device;
 
@@ -267,6 +277,7 @@ rdnss_expired (gpointer user_data)
 	nm_log_dbg (LOGD_IP6, "(%s): IPv6 RDNSS information expired", device->iface);
 
 	set_rdnss_timeout (device);
+	clear_config_changed (device);
 	emit_config_changed (&info);
 	return FALSE;
 }
@@ -321,11 +332,12 @@ static gboolean
 dnssl_expired (gpointer user_data)
 {
 	NMIP6Device *device = user_data;
-	CallbackInfo info = { device, IP6_DHCP_OPT_NONE };
+	CallbackInfo info = { device, IP6_DHCP_OPT_NONE, FALSE };
 
 	nm_log_dbg (LOGD_IP6, "(%s): IPv6 DNSSL information expired", device->iface);
 
 	set_dnssl_timeout (device);
+	clear_config_changed (device);
 	emit_config_changed (&info);
 	return FALSE;
 }
@@ -434,8 +446,9 @@ nm_ip6_device_sync_from_netlink (NMIP6Device *device, gboolean config_changed)
 		addr = nl_addr_get_binary_addr (nladdr);
 
 		if (inet_ntop (AF_INET6, addr, buf, INET6_ADDRSTRLEN) > 0) {
-			nm_log_dbg (LOGD_IP6, "(%s): netlink address: %s",
-			            device->iface, buf);
+			nm_log_dbg (LOGD_IP6, "(%s): netlink address: %s/%d",
+			            device->iface, buf,
+			            rtnl_addr_get_prefixlen (rtnladdr));
 		}
 
 		if (IN6_IS_ADDR_LINKLOCAL (addr)) {
@@ -972,6 +985,28 @@ static struct nla_policy link_prot_policy[IFLA_INET6_MAX + 1] = {
 	[IFLA_INET6_FLAGS]	= { .type = NLA_U32 },
 };
 
+static char *
+ra_flags_to_string (guint32 ra_flags)
+{
+	GString *s = g_string_sized_new (20);
+
+	g_string_append (s, " (");
+	if (ra_flags & IF_RS_SENT)
+		g_string_append_c (s, 'S');
+
+	if (ra_flags & IF_RA_RCVD)
+		g_string_append_c (s, 'R');
+
+	if (ra_flags & IF_RA_OTHERCONF)
+		g_string_append_c (s, 'O');
+
+	if (ra_flags & IF_RA_MANAGED)
+		g_string_append_c (s, 'M');
+
+	g_string_append_c (s, ')');
+	return g_string_free (s, FALSE);
+}
+
 static NMIP6Device *
 process_newlink (NMIP6Manager *manager, struct nl_msg *msg)
 {
@@ -981,6 +1016,7 @@ process_newlink (NMIP6Manager *manager, struct nl_msg *msg)
 	struct nlattr *tb[IFLA_MAX + 1];
 	struct nlattr *pi[IFLA_INET6_MAX + 1];
 	int err;
+	char *flags_str = NULL;
 
 	/* FIXME: we have to do this manually for now since libnl doesn't yet
 	 * support the IFLA_PROTINFO attribute of NEWLINK messages.  When it does,
@@ -1024,7 +1060,12 @@ process_newlink (NMIP6Manager *manager, struct nl_msg *msg)
 	}
 
 	device->ra_flags = nla_get_u32 (pi[IFLA_INET6_FLAGS]);
-	nm_log_dbg (LOGD_IP6, "(%s): got IPv6 flags 0x%X", device->iface, device->ra_flags);
+
+	if (nm_logging_level_enabled (LOGL_DEBUG))
+		flags_str = ra_flags_to_string (device->ra_flags);
+	nm_log_dbg (LOGD_IP6, "(%s): got IPv6 flags 0x%X%s",
+	            device->iface, device->ra_flags, flags_str ? flags_str : "");
+	g_free (flags_str);
 
 	return device;
 }
@@ -1038,7 +1079,7 @@ netlink_notification (NMNetlinkMonitor *monitor, struct nl_msg *msg, gpointer us
 	gboolean config_changed = FALSE;
 
 	hdr = nlmsg_hdr (msg);
-	nm_log_dbg (LOGD_HW, "netlink notificate type %d", hdr->nlmsg_type);
+	nm_log_dbg (LOGD_HW, "netlink event type %d", hdr->nlmsg_type);
 	switch (hdr->nlmsg_type) {
 	case RTM_NEWADDR:
 	case RTM_DELADDR:
diff --git a/src/logging/Makefile.in b/src/logging/Makefile.in
index 72274507..c73f71b4 100644
--- a/src/logging/Makefile.in
+++ b/src/logging/Makefile.in
@@ -138,6 +138,8 @@ GIO_LIBS = @GIO_LIBS@
 GLIB_CFLAGS = @GLIB_CFLAGS@
 GLIB_GENMARSHAL = @GLIB_GENMARSHAL@
 GLIB_LIBS = @GLIB_LIBS@
+GLIB_MAKEFILE = @GLIB_MAKEFILE@
+GLIB_MKENUMS = @GLIB_MKENUMS@
 GMODULE_CFLAGS = @GMODULE_CFLAGS@
 GMODULE_LIBS = @GMODULE_LIBS@
 GMSGFMT = @GMSGFMT@
@@ -192,11 +194,15 @@ LIBNL2_LIBS = @LIBNL2_LIBS@
 LIBNL3_CFLAGS = @LIBNL3_CFLAGS@
 LIBNL3_LIBS = @LIBNL3_LIBS@
 LIBNL_CFLAGS = @LIBNL_CFLAGS@
+LIBNL_GENL3_CFLAGS = @LIBNL_GENL3_CFLAGS@
+LIBNL_GENL3_LIBS = @LIBNL_GENL3_LIBS@
 LIBNL_LIBS = @LIBNL_LIBS@
 LIBNL_ROUTE3_CFLAGS = @LIBNL_ROUTE3_CFLAGS@
 LIBNL_ROUTE3_LIBS = @LIBNL_ROUTE3_LIBS@
 LIBOBJS = @LIBOBJS@
 LIBS = @LIBS@
+LIBSOUP_CFLAGS = @LIBSOUP_CFLAGS@
+LIBSOUP_LIBS = @LIBSOUP_LIBS@
 LIBTOOL = @LIBTOOL@
 LIPO = @LIPO@
 LN_S = @LN_S@
@@ -207,6 +213,7 @@ MAINT = @MAINT@
 MAKEINFO = @MAKEINFO@
 MANIFEST_TOOL = @MANIFEST_TOOL@
 MKDIR_P = @MKDIR_P@
+MOC = @MOC@
 MSGFMT = @MSGFMT@
 MSGFMT_015 = @MSGFMT_015@
 MSGMERGE = @MSGMERGE@
@@ -246,6 +253,8 @@ SED = @SED@
 SET_MAKE = @SET_MAKE@
 SHELL = @SHELL@
 STRIP = @STRIP@
+SYSTEMD_CFLAGS = @SYSTEMD_CFLAGS@
+SYSTEMD_LIBS = @SYSTEMD_LIBS@
 SYSTEM_CA_PATH = @SYSTEM_CA_PATH@
 UDEV_BASE_DIR = @UDEV_BASE_DIR@
 USE_NLS = @USE_NLS@
diff --git a/src/logging/nm-logging.c b/src/logging/nm-logging.c
index 078f1527..a2b0ebaf 100644
--- a/src/logging/nm-logging.c
+++ b/src/logging/nm-logging.c
@@ -23,7 +23,6 @@
 
 #include <dlfcn.h>
 #include <syslog.h>
-#include <execinfo.h>
 #include <stdio.h>
 #include <stdlib.h>
 #include <unistd.h>
@@ -47,7 +46,7 @@ static guint32 log_domains = \
 	LOGD_DHCP4 | LOGD_DHCP6 | LOGD_PPP | LOGD_IP4 | LOGD_IP6 | LOGD_AUTOIP4 | \
 	LOGD_DNS | LOGD_VPN | LOGD_SHARING | LOGD_SUPPLICANT | LOGD_AGENTS | \
 	LOGD_SETTINGS | LOGD_SUSPEND | LOGD_CORE | LOGD_DEVICE | LOGD_OLPC_MESH | \
-	LOGD_WIMAX;
+	LOGD_WIMAX | LOGD_INFINIBAND | LOGD_FIREWALL;
 
 typedef struct {
 	guint32 num;
@@ -88,18 +87,13 @@ static const LogDesc domain_descs[] = {
 	{ LOGD_DEVICE,    "DEVICE" },
 	{ LOGD_OLPC_MESH, "OLPC" },
 	{ LOGD_WIMAX,     "WIMAX" },
+	{ LOGD_INFINIBAND,"INFINIBAND" },
+	{ LOGD_FIREWALL,  "FIREWALL" },
 	{ 0, NULL }
 };
 
 /************************************************************************/
 
-enum {
-    NM_LOGGING_ERROR_UNKNOWN_LEVEL = 0,
-    NM_LOGGING_ERROR_UNKNOWN_DOMAIN = 1,
-};
-
-#define ENUM_ENTRY(NAME, DESC) { NAME, "" #NAME "", DESC }
-
 GQuark
 nm_logging_error_quark (void)
 {
@@ -110,22 +104,6 @@ nm_logging_error_quark (void)
     return ret;
 }
 
-GType
-nm_logging_error_get_type (void)
-{
-    static GType etype = 0;
-
-    if (etype == 0) {
-        static const GEnumValue values[] = {
-            ENUM_ENTRY (NM_LOGGING_ERROR_UNKNOWN_LEVEL,  "UnknownLevel"),
-            ENUM_ENTRY (NM_LOGGING_ERROR_UNKNOWN_DOMAIN, "UnknownDomain"),
-            { 0, 0, 0 }
-        };
-        etype = g_enum_register_static ("NMLoggingError", values);
-    }
-    return etype;
-}
-
 /************************************************************************/
 
 gboolean
diff --git a/src/logging/nm-logging.h b/src/logging/nm-logging.h
index e3e05f59..7e27f311 100644
--- a/src/logging/nm-logging.h
+++ b/src/logging/nm-logging.h
@@ -52,6 +52,8 @@ enum {
 	LOGD_DEVICE     = 0x00200000, /* Device state and activation */
 	LOGD_OLPC_MESH  = 0x00400000,
 	LOGD_WIMAX      = 0x00800000,
+	LOGD_INFINIBAND = 0x01000000,
+	LOGD_FIREWALL   = 0x02000000,
 };
 
 #define LOGD_DHCP (LOGD_DHCP4 | LOGD_DHCP6)
@@ -64,10 +66,13 @@ enum {
 	LOGL_DEBUG = 0x00000008
 };
 
+typedef enum {
+	NM_LOGGING_ERROR_UNKNOWN_LEVEL = 0,  /*< nick=UnknownLevel >*/
+	NM_LOGGING_ERROR_UNKNOWN_DOMAIN = 1, /*< nick=UnknownDomain >*/
+} NMLoggingError;
+
 #define NM_LOGGING_ERROR (nm_logging_error_quark ())
-#define NM_TYPE_LOGGING_ERROR (nm_logging_error_get_type ())
 GQuark nm_logging_error_quark    (void);
-GType  nm_logging_error_get_type (void);
 
 
 #define nm_log_err(domain, ...) \
diff --git a/src/main.c b/src/main.c
index 12a0b893..4a21959f 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 - 2011 Red Hat, Inc.
+ * Copyright (C) 2004 - 2012 Red Hat, Inc.
  * Copyright (C) 2005 - 2008 Novell, Inc.
  */
 
@@ -25,6 +25,7 @@
 #include <dbus/dbus-glib-lowlevel.h>
 #include <dbus/dbus-glib.h>
 #include <getopt.h>
+#include <locale.h>
 #include <errno.h>
 #include <stdlib.h>
 #include <signal.h>
@@ -40,11 +41,12 @@
 #include "NetworkManagerUtils.h"
 #include "nm-manager.h"
 #include "nm-policy.h"
-#include "nm-system.h"
+#include "backends/nm-backend.h"
 #include "nm-dns-manager.h"
 #include "nm-dbus-manager.h"
 #include "nm-supplicant-manager.h"
 #include "nm-dhcp-manager.h"
+#include "nm-firewall-manager.h"
 #include "nm-hostname-provider.h"
 #include "nm-netlink-monitor.h"
 #include "nm-vpn-manager.h"
@@ -66,80 +68,6 @@ static NMManager *manager = NULL;
 static GMainLoop *main_loop = NULL;
 static int quit_pipe[2] = { -1, -1 };
 
-typedef struct {
-	time_t time;
-	GQuark domain;
-	guint32 code;
-	guint32 count;
-} MonitorInfo;
-
-static gboolean
-detach_monitor (gpointer data)
-{
-	nm_log_warn (LOGD_HW, "detaching netlink event monitor");
-	nm_netlink_monitor_detach (NM_NETLINK_MONITOR (data));
-	return FALSE;
-}
-
-static void
-nm_error_monitoring_device_link_state (NMNetlinkMonitor *monitor,
-									   GError *error,
-									   gpointer user_data)
-{
-	MonitorInfo *info = (MonitorInfo *) user_data;
-	time_t now;
-
-	now = time (NULL);
-
-	if (   (info->domain != error->domain)
-	    || (info->code != error->code)
-	    || (info->time && now > info->time + 10)) {
-		/* FIXME: Try to handle the error instead of just printing it. */
-		nm_log_warn (LOGD_HW, "error monitoring device for netlink events: %s\n", error->message);
-
-		info->time = now;
-		info->domain = error->domain;
-		info->code = error->code;
-		info->count = 0;
-	}
-
-	info->count++;
-	if (info->count > 100) {
-		/* Broken drivers will sometimes cause a flood of netlink errors.
-		 * rh #459205, novell #443429, lp #284507
-		 */
-		nm_log_warn (LOGD_HW, "excessive netlink errors ocurred, disabling netlink monitor.");
-		nm_log_warn (LOGD_HW, "link change events will not be processed.");
-		g_idle_add_full (G_PRIORITY_HIGH, detach_monitor, monitor, NULL);
-	}
-}
-
-static gboolean
-nm_monitor_setup (GError **error)
-{
-	NMNetlinkMonitor *monitor;
-	MonitorInfo *info;
-
-	monitor = nm_netlink_monitor_get ();
-	if (!nm_netlink_monitor_open_connection (monitor, error)) {
-		g_object_unref (monitor);
-		return FALSE;
-	}
-
-	info = g_new0 (MonitorInfo, 1);
-	g_signal_connect_data (G_OBJECT (monitor), "error",
-						   G_CALLBACK (nm_error_monitoring_device_link_state),
-						   info,
-						   (GClosureNotify) g_free,
-						   0);
-	nm_netlink_monitor_attach (monitor);
-
-	/* Request initial status of cards */
-	nm_netlink_monitor_request_status (monitor, NULL);
-
-	return TRUE;
-}
-
 static gboolean quit_early = FALSE;
 
 static void
@@ -212,7 +140,7 @@ setup_signals (void)
 
 	/* Set up our quit pipe */
 	if (pipe (quit_pipe) < 0) {
-		fprintf (stderr, "Failed to initialze SIGTERM pipe: %d", errno);
+		fprintf (stderr, _("Failed to initialize SIGTERM pipe: %d"), errno);
 		exit (1);
 	}
 	fcntl (quit_pipe[1], F_SETFL, O_NONBLOCK | fcntl (quit_pipe[1], F_GETFL));
@@ -243,18 +171,18 @@ write_pidfile (const char *pidfile)
 	gboolean success = FALSE;
  
 	if ((fd = open (pidfile, O_CREAT|O_WRONLY|O_TRUNC, 00644)) < 0) {
-		fprintf (stderr, "Opening %s failed: %s\n", pidfile, strerror (errno));
+		fprintf (stderr, _("Opening %s failed: %s\n"), pidfile, strerror (errno));
 		return FALSE;
 	}
 
  	snprintf (pid, sizeof (pid), "%d", getpid ());
 	if (write (fd, pid, strlen (pid)) < 0)
-		fprintf (stderr, "Writing to %s failed: %s\n", pidfile, strerror (errno));
+		fprintf (stderr, _("Writing to %s failed: %s\n"), pidfile, strerror (errno));
 	else
 		success = TRUE;
 
 	if (close (fd))
-		fprintf (stderr, "Closing %s failed: %s\n", pidfile, strerror (errno));
+		fprintf (stderr, _("Closing %s failed: %s\n"), pidfile, strerror (errno));
 
 	return success;
 }
@@ -297,7 +225,7 @@ check_pidfile (const char *pidfile)
 	if (strcmp (process_name, "NetworkManager") == 0) {
 		/* Check that the process exists */
 		if (kill (pid, 0) == 0) {
-			fprintf (stderr, "NetworkManager is already running (pid %ld)\n", pid);
+			fprintf (stderr, _("NetworkManager is already running (pid %ld)\n"), pid);
 			nm_running = TRUE;
 		}
 	}
@@ -341,8 +269,7 @@ parse_state_file (const char *filename,
 		 * /var/lib/NetworkManager for us since we have to ensure that
 		 * users upgrading NM get this working too.
 		 */
-		if (   tmp_error->domain == G_FILE_ERROR
-		    && tmp_error->code == G_FILE_ERROR_NOENT) {
+		if (g_error_matches (tmp_error, G_FILE_ERROR, G_FILE_ERROR_NOENT)) {
 			char *data, *dirname;
 			gsize len = 0;
 
@@ -419,6 +346,9 @@ main (int argc, char *argv[])
 	char *pidfile = NULL, *state_file = NULL;
 	char *config_path = NULL, *plugins = NULL;
 	char *log_level = NULL, *log_domains = NULL;
+	char *connectivity_uri = NULL;
+	gint connectivity_interval = -1;
+	char *connectivity_response = NULL;
 	gboolean wifi_enabled = TRUE, net_enabled = TRUE, wwan_enabled = TRUE, wimax_enabled = TRUE;
 	gboolean success, show_version = FALSE;
 	NMPolicy *policy = NULL;
@@ -427,47 +357,58 @@ main (int argc, char *argv[])
 	NMDBusManager *dbus_mgr = NULL;
 	NMSupplicantManager *sup_mgr = NULL;
 	NMDHCPManager *dhcp_mgr = NULL;
+	NMFirewallManager *fw_mgr = NULL;
 	NMSettings *settings = NULL;
 	NMConfig *config;
+	NMNetlinkMonitor *monitor = NULL;
 	GError *error = NULL;
 	gboolean wrote_pidfile = FALSE;
 
 	GOptionEntry options[] = {
-		{ "version", 0, 0, G_OPTION_ARG_NONE, &show_version, "Print NetworkManager version and exit", NULL },
-		{ "no-daemon", 0, 0, G_OPTION_ARG_NONE, &become_daemon, "Don't become a daemon", NULL },
-		{ "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_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" },
+		{ "version", 0, 0, G_OPTION_ARG_NONE, &show_version, N_("Print NetworkManager version and exit"), NULL },
+		{ "no-daemon", 0, 0, G_OPTION_ARG_NONE, &become_daemon, N_("Don't become a daemon"), NULL },
+		{ "g-fatal-warnings", 0, 0, G_OPTION_ARG_NONE, &g_fatal_warnings, N_("Make all warnings fatal"), NULL },
+		{ "pid-file", 0, 0, G_OPTION_ARG_FILENAME, &pidfile, N_("Specify the location of a PID file"), N_("filename") },
+		{ "state-file", 0, 0, G_OPTION_ARG_FILENAME, &state_file, N_("State file location"), N_("/path/to/state.file") },
+		{ "config", 0, 0, G_OPTION_ARG_FILENAME, &config_path, N_("Config file location"), N_("/path/to/config.file") },
+		{ "plugins", 0, 0, G_OPTION_ARG_STRING, &plugins, N_("List of plugins separated by ','"), N_("plugin1,plugin2") },
+		/* Translators: Do not translate the values in the square brackets */
+		{ "log-level", 0, 0, G_OPTION_ARG_STRING, &log_level, N_("Log level: one of [ERR, WARN, INFO, DEBUG]"), "INFO" },
 		{ "log-domains", 0, 0, G_OPTION_ARG_STRING, &log_domains,
-		        "Log domains separated by ',': any combination of\n"
+		        /* Translators: Do not translate the values in the square brackets */
+		        N_("Log domains separated by ',': any combination of\n"
 		        "                                          [NONE,HW,RFKILL,ETHER,WIFI,BT,MB,DHCP4,DHCP6,PPP,\n"
 		        "                                           WIFI_SCAN,IP4,IP6,AUTOIP4,DNS,VPN,SHARING,SUPPLICANT,\n"
-		        "                                           AGENTS,SETTINGS,SUSPEND,CORE,DEVICE,OLPC,WIMAX]",
+		        "                                           AGENTS,SETTINGS,SUSPEND,CORE,DEVICE,OLPC,WIMAX,\n"
+		        "                                           INFINIBAND,FIREWALL]"),
 		        "HW,RFKILL,WIFI" },
+		{ "connectivity-uri", 0, 0, G_OPTION_ARG_STRING, &connectivity_uri, "A http(s) address to check internet connectivity" },
+		{ "connectivity-interval", 0, 0, G_OPTION_ARG_INT, &connectivity_interval, "the interval in seconds how often a connectivity check will be done" },
+		{ "connectivity-response", 0, 0, G_OPTION_ARG_STRING, &connectivity_response, "the expected start of the response" },
 		{NULL}
 	};
 
 	if (!g_module_supported ()) {
-		fprintf (stderr, "GModules are not supported on your platform!\n");
+		fprintf (stderr, _("GModules are not supported on your platform!\n"));
 		exit (1);
 	}
 
+	/* Set locale to be able to use environment variables */
+	setlocale (LC_ALL, "");
+
 	bindtextdomain (GETTEXT_PACKAGE, NMLOCALEDIR);
 	bind_textdomain_codeset (GETTEXT_PACKAGE, "UTF-8");
 	textdomain (GETTEXT_PACKAGE);
 
 	/* Parse options */
-	opt_ctx = g_option_context_new ("");
-	g_option_context_set_translation_domain (opt_ctx, "UTF-8");
+	opt_ctx = g_option_context_new (NULL);
+	g_option_context_set_translation_domain (opt_ctx, GETTEXT_PACKAGE);
 	g_option_context_set_ignore_unknown_options (opt_ctx, FALSE);
 	g_option_context_set_help_enabled (opt_ctx, TRUE);
 	g_option_context_add_main_entries (opt_ctx, options, NULL);
 
 	g_option_context_set_summary (opt_ctx,
-		"NetworkManager monitors all network connections and automatically\nchooses the best connection to use.  It also allows the user to\nspecify wireless access points which wireless cards in the computer\nshould associate with.");
+		_("NetworkManager monitors all network connections and automatically\nchooses the best connection to use.  It also allows the user to\nspecify wireless access points which wireless cards in the computer\nshould associate with."));
 
 	success = g_option_context_parse (opt_ctx, &argc, &argv, NULL);
 	g_option_context_free (opt_ctx);
@@ -483,7 +424,7 @@ main (int argc, char *argv[])
 	}
 
 	if (getuid () != 0) {
-		fprintf (stderr, "You must be root to run NetworkManager!\n");
+		fprintf (stderr, _("You must be root to run NetworkManager!\n"));
 		exit (1);
 	}
 
@@ -501,11 +442,12 @@ main (int argc, char *argv[])
 		exit (1);
 
 	/* Read the config file and CLI overrides */
-	config = nm_config_new (config_path, plugins, log_level, log_domains, &error);
+	config = nm_config_new (config_path, plugins, log_level, log_domains,
+	                        connectivity_uri, connectivity_interval, connectivity_response, &error);
 	if (config == NULL) {
-		fprintf (stderr, "Failed to read configuration: (%d) %s\n",
+		fprintf (stderr, _("Failed to read configuration: (%d) %s\n"),
 		         error ? error->code : -1,
-		         (error && error->message) ? error->message : "unknown");
+		         (error && error->message) ? error->message : _("unknown"));
 		exit (1);
 	}
 
@@ -521,10 +463,10 @@ main (int argc, char *argv[])
 
 	/* Parse the state file */
 	if (!parse_state_file (state_file, &net_enabled, &wifi_enabled, &wwan_enabled, &wimax_enabled, &error)) {
-		fprintf (stderr, "State file %s parsing failed: (%d) %s\n",
+		fprintf (stderr, _("State file %s parsing failed: (%d) %s\n"),
 		         state_file,
 		         error ? error->code : -1,
-		         (error && error->message) ? error->message : "unknown");
+		         (error && error->message) ? error->message : _("unknown"));
 		/* Not a hard failure */
 	}
 	g_clear_error (&error);
@@ -538,7 +480,7 @@ main (int argc, char *argv[])
 			int saved_errno;
 
 			saved_errno = errno;
-			fprintf (stderr, "Could not daemonize: %s [error %u]\n",
+			fprintf (stderr, _("Could not daemonize: %s [error %u]\n"),
 			         g_strerror (saved_errno),
 			         saved_errno);
 			exit (1);
@@ -598,12 +540,8 @@ main (int argc, char *argv[])
 
 	main_loop = g_main_loop_new (NULL, FALSE);
 
-	/* Create watch functions that monitor cards for link status. */
-	if (!nm_monitor_setup (&error)) {
-		nm_log_err (LOGD_CORE, "failed to start monitoring devices: %s.",
-		            error && error->message ? error->message : "(unknown)");
-		goto done;
-	}
+	/* Create netlink monitor object */
+	monitor = nm_netlink_monitor_get ();
 
 	/* Initialize our DBus service & connection */
 	dbus_mgr = nm_dbus_manager_get ();
@@ -635,6 +573,9 @@ main (int argc, char *argv[])
 	                          wifi_enabled,
 	                          wwan_enabled,
 	                          wimax_enabled,
+	                          nm_config_get_connectivity_uri (config),
+	                          nm_config_get_connectivity_interval (config),
+	                          nm_config_get_connectivity_response (config),
 	                          &error);
 	if (manager == NULL) {
 		nm_log_err (LOGD_CORE, "failed to initialize the network manager: %s",
@@ -664,6 +605,13 @@ main (int argc, char *argv[])
 
 	nm_dhcp_manager_set_hostname_provider (dhcp_mgr, NM_HOSTNAME_PROVIDER (manager));
 
+	/* Initialize Firewall manager */
+	fw_mgr = nm_firewall_manager_get ();
+	if (!fw_mgr) {
+		nm_log_err (LOGD_CORE, "failed to start the Firewall manager: %s.", error->message);
+		goto done;
+	}
+
 	/* Start our DBus service */
 	if (!nm_dbus_manager_start_service (dbus_mgr)) {
 		nm_log_err (LOGD_CORE, "failed to start the dbus service.");
@@ -676,7 +624,7 @@ main (int argc, char *argv[])
 	nm_manager_start (manager);
 
 	/* Bring up the loopback interface. */
-	nm_system_enable_loopback ();
+	nm_backend_enable_loopback ();
 
 	success = TRUE;
 
@@ -708,6 +656,9 @@ done:
 	if (sup_mgr)
 		g_object_unref (sup_mgr);
 
+	if (fw_mgr)
+		g_object_unref (fw_mgr);
+
 	if (dbus_mgr)
 		g_object_unref (dbus_mgr);
 
@@ -725,6 +676,8 @@ done:
 	g_free (plugins);
 	g_free (log_level);
 	g_free (log_domains);
+	g_free (connectivity_uri);
+	g_free (connectivity_response);
 
 	nm_log_info (LOGD_CORE, "exiting (%s)", success ? "success" : "error");
 	exit (success ? 0 : 1);
diff --git a/src/modem-manager/Makefile.am b/src/modem-manager/Makefile.am
index 3c3af16c..a5c6a668 100644
--- a/src/modem-manager/Makefile.am
+++ b/src/modem-manager/Makefile.am
@@ -1,9 +1,14 @@
+include $(GLIB_MAKEFILE)
+
 INCLUDES = \
 	-I${top_srcdir}/src \
+	-I${top_srcdir}/src/generated \
+	-I${top_builddir}/src/generated \
 	-I${top_srcdir}/src/logging \
 	-I${top_srcdir}/include \
+	-I${top_builddir}/include \
 	-I${top_srcdir}/libnm-util \
-	-I${top_builddir}/marshallers
+	-I${top_builddir}/libnm-util
 
 noinst_LTLIBRARIES = libmodem-manager.la
 
@@ -23,7 +28,7 @@ libmodem_manager_la_CPPFLAGS = \
 	$(DBUS_CFLAGS)
 
 libmodem_manager_la_LIBADD = \
-	$(top_builddir)/marshallers/libmarshallers.la \
+	$(top_builddir)/src/generated/libnm-generated.la \
 	$(top_builddir)/src/logging/libnm-logging.la \
 	$(LIBNL_LIBS) \
 	$(DBUS_LIBS)
diff --git a/src/modem-manager/Makefile.in b/src/modem-manager/Makefile.in
index 494bb1be..87afed0c 100644
--- a/src/modem-manager/Makefile.in
+++ b/src/modem-manager/Makefile.in
@@ -57,7 +57,7 @@ CONFIG_CLEAN_VPATH_FILES =
 LTLIBRARIES = $(noinst_LTLIBRARIES)
 am__DEPENDENCIES_1 =
 libmodem_manager_la_DEPENDENCIES =  \
-	$(top_builddir)/marshallers/libmarshallers.la \
+	$(top_builddir)/src/generated/libnm-generated.la \
 	$(top_builddir)/src/logging/libnm-logging.la \
 	$(am__DEPENDENCIES_1) $(am__DEPENDENCIES_1)
 am_libmodem_manager_la_OBJECTS = libmodem_manager_la-nm-modem.lo \
@@ -144,6 +144,8 @@ GIO_LIBS = @GIO_LIBS@
 GLIB_CFLAGS = @GLIB_CFLAGS@
 GLIB_GENMARSHAL = @GLIB_GENMARSHAL@
 GLIB_LIBS = @GLIB_LIBS@
+GLIB_MAKEFILE = @GLIB_MAKEFILE@
+GLIB_MKENUMS = @GLIB_MKENUMS@
 GMODULE_CFLAGS = @GMODULE_CFLAGS@
 GMODULE_LIBS = @GMODULE_LIBS@
 GMSGFMT = @GMSGFMT@
@@ -198,11 +200,15 @@ LIBNL2_LIBS = @LIBNL2_LIBS@
 LIBNL3_CFLAGS = @LIBNL3_CFLAGS@
 LIBNL3_LIBS = @LIBNL3_LIBS@
 LIBNL_CFLAGS = @LIBNL_CFLAGS@
+LIBNL_GENL3_CFLAGS = @LIBNL_GENL3_CFLAGS@
+LIBNL_GENL3_LIBS = @LIBNL_GENL3_LIBS@
 LIBNL_LIBS = @LIBNL_LIBS@
 LIBNL_ROUTE3_CFLAGS = @LIBNL_ROUTE3_CFLAGS@
 LIBNL_ROUTE3_LIBS = @LIBNL_ROUTE3_LIBS@
 LIBOBJS = @LIBOBJS@
 LIBS = @LIBS@
+LIBSOUP_CFLAGS = @LIBSOUP_CFLAGS@
+LIBSOUP_LIBS = @LIBSOUP_LIBS@
 LIBTOOL = @LIBTOOL@
 LIPO = @LIPO@
 LN_S = @LN_S@
@@ -213,6 +219,7 @@ MAINT = @MAINT@
 MAKEINFO = @MAKEINFO@
 MANIFEST_TOOL = @MANIFEST_TOOL@
 MKDIR_P = @MKDIR_P@
+MOC = @MOC@
 MSGFMT = @MSGFMT@
 MSGFMT_015 = @MSGFMT_015@
 MSGMERGE = @MSGMERGE@
@@ -252,6 +259,8 @@ SED = @SED@
 SET_MAKE = @SET_MAKE@
 SHELL = @SHELL@
 STRIP = @STRIP@
+SYSTEMD_CFLAGS = @SYSTEMD_CFLAGS@
+SYSTEMD_LIBS = @SYSTEMD_LIBS@
 SYSTEM_CA_PATH = @SYSTEM_CA_PATH@
 UDEV_BASE_DIR = @UDEV_BASE_DIR@
 USE_NLS = @USE_NLS@
@@ -317,10 +326,13 @@ top_builddir = @top_builddir@
 top_srcdir = @top_srcdir@
 INCLUDES = \
 	-I${top_srcdir}/src \
+	-I${top_srcdir}/src/generated \
+	-I${top_builddir}/src/generated \
 	-I${top_srcdir}/src/logging \
 	-I${top_srcdir}/include \
+	-I${top_builddir}/include \
 	-I${top_srcdir}/libnm-util \
-	-I${top_builddir}/marshallers
+	-I${top_builddir}/libnm-util
 
 noinst_LTLIBRARIES = libmodem-manager.la
 libmodem_manager_la_SOURCES = \
@@ -339,7 +351,7 @@ libmodem_manager_la_CPPFLAGS = \
 	$(DBUS_CFLAGS)
 
 libmodem_manager_la_LIBADD = \
-	$(top_builddir)/marshallers/libmarshallers.la \
+	$(top_builddir)/src/generated/libnm-generated.la \
 	$(top_builddir)/src/logging/libnm-logging.la \
 	$(LIBNL_LIBS) \
 	$(DBUS_LIBS)
@@ -663,6 +675,7 @@ uninstall-am:
 	mostlyclean-compile mostlyclean-generic mostlyclean-libtool \
 	pdf pdf-am ps ps-am tags uninstall uninstall-am
 
+include $(GLIB_MAKEFILE)
 
 # Tell versions [3.59,3.63) of GNU make to not export all variables.
 # Otherwise a system limit (for SysV at least) may be exceeded.
diff --git a/src/modem-manager/nm-modem-cdma.c b/src/modem-manager/nm-modem-cdma.c
index 5db6a84f..fa19a342 100644
--- a/src/modem-manager/nm-modem-cdma.c
+++ b/src/modem-manager/nm-modem-cdma.c
@@ -27,11 +27,13 @@
 #include "nm-dbus-glib-types.h"
 #include "nm-modem-cdma.h"
 #include "nm-modem-types.h"
+#include "nm-enum-types.h"
 #include "nm-device.h"
 #include "nm-device-private.h"
 #include "nm-dbus-manager.h"
 #include "nm-setting-connection.h"
 #include "nm-setting-cdma.h"
+#include "nm-setting-ppp.h"
 #include "NetworkManagerUtils.h"
 #include "nm-logging.h"
 
@@ -46,14 +48,7 @@ typedef struct {
 } NMModemCdmaPrivate;
 
 
-typedef enum {
-	NM_CDMA_ERROR_CONNECTION_NOT_CDMA = 0,
-	NM_CDMA_ERROR_CONNECTION_INVALID,
-	NM_CDMA_ERROR_CONNECTION_INCOMPATIBLE,
-} NMCdmaError;
-
 #define NM_CDMA_ERROR (nm_cdma_error_quark ())
-#define NM_TYPE_CDMA_ERROR (nm_cdma_error_get_type ())
 
 static GQuark
 nm_cdma_error_quark (void)
@@ -64,29 +59,6 @@ nm_cdma_error_quark (void)
 	return quark;
 }
 
-/* This should really be standard. */
-#define ENUM_ENTRY(NAME, DESC) { NAME, "" #NAME "", DESC }
-
-static GType
-nm_cdma_error_get_type (void)
-{
-	static GType etype = 0;
-
-	if (etype == 0) {
-		static const GEnumValue values[] = {
-			/* Connection was not a CDMA connection. */
-			ENUM_ENTRY (NM_CDMA_ERROR_CONNECTION_NOT_CDMA, "ConnectionNotCdma"),
-			/* Connection was not a valid CDMA connection. */
-			ENUM_ENTRY (NM_CDMA_ERROR_CONNECTION_INVALID, "ConnectionInvalid"),
-			/* Connection does not apply to this device. */
-			ENUM_ENTRY (NM_CDMA_ERROR_CONNECTION_INCOMPATIBLE, "ConnectionIncompatible"),
-			{ 0, 0, 0 }
-		};
-		etype = g_enum_register_static ("NMCdmaError", values);
-	}
-	return etype;
-}
-
 
 NMModem *
 nm_modem_cdma_new (const char *path,
@@ -169,7 +141,7 @@ create_connect_properties (NMConnection *connection)
 	GHashTable *properties;
 	const char *str;
 
-	setting = NM_SETTING_CDMA (nm_connection_get_setting (connection, NM_TYPE_SETTING_CDMA));
+	setting = nm_connection_get_setting_cdma (connection);
 	properties = value_hash_create ();
 
 	str = nm_setting_cdma_get_number (setting);
@@ -230,7 +202,7 @@ real_get_best_auto_connection (NMModem *modem,
 		NMConnection *connection = NM_CONNECTION (iter->data);
 		NMSettingConnection *s_con;
 
-		s_con = (NMSettingConnection *) nm_connection_get_setting (connection, NM_TYPE_SETTING_CONNECTION);
+		s_con = nm_connection_get_setting_connection (connection);
 		g_assert (s_con);
 
 		if (!nm_setting_connection_get_autoconnect (s_con))
@@ -252,7 +224,7 @@ real_check_connection_compatible (NMModem *modem,
 	NMSettingConnection *s_con;
 	NMSettingCdma *s_cdma;
 
-	s_con = NM_SETTING_CONNECTION (nm_connection_get_setting (connection, NM_TYPE_SETTING_CONNECTION));
+	s_con = nm_connection_get_setting_connection (connection);
 	g_assert (s_con);
 
 	if (strcmp (nm_setting_connection_get_connection_type (s_con), NM_SETTING_CDMA_SETTING_NAME)) {
@@ -262,7 +234,7 @@ real_check_connection_compatible (NMModem *modem,
 		return FALSE;
 	}
 
-	s_cdma = NM_SETTING_CDMA (nm_connection_get_setting (connection, NM_TYPE_SETTING_CDMA));
+	s_cdma = nm_connection_get_setting_cdma (connection);
 	if (!s_cdma) {
 		g_set_error (error,
 		             NM_CDMA_ERROR, NM_CDMA_ERROR_CONNECTION_INVALID,
@@ -280,8 +252,9 @@ real_complete_connection (NMModem *modem,
                           GError **error)
 {
 	NMSettingCdma *s_cdma;
+	NMSettingPPP *s_ppp;
 
-	s_cdma = (NMSettingCdma *) nm_connection_get_setting (connection, NM_TYPE_SETTING_CDMA);
+	s_cdma = nm_connection_get_setting_cdma (connection);
 	if (!s_cdma) {
 		s_cdma = (NMSettingCdma *) nm_setting_cdma_new ();
 		nm_connection_add_setting (connection, NM_SETTING (s_cdma));
@@ -290,6 +263,16 @@ real_complete_connection (NMModem *modem,
 	if (!nm_setting_cdma_get_number (s_cdma))
 		g_object_set (G_OBJECT (s_cdma), NM_SETTING_CDMA_NUMBER, "#777", NULL);
 
+	s_ppp = nm_connection_get_setting_ppp (connection);
+	if (!s_ppp) {
+		s_ppp = (NMSettingPPP *) nm_setting_ppp_new ();
+		g_object_set (G_OBJECT (s_ppp),
+		              NM_SETTING_PPP_LCP_ECHO_FAILURE, 5,
+		              NM_SETTING_PPP_LCP_ECHO_INTERVAL, 30,
+		              NULL);
+		nm_connection_add_setting (connection, NM_SETTING (s_ppp));
+	}
+
 	nm_utils_complete_generic (connection,
 	                           NM_SETTING_CDMA_SETTING_NAME,
 	                           existing_connections,
@@ -308,7 +291,7 @@ real_get_user_pass (NMModem *modem,
 {
 	NMSettingCdma *s_cdma;
 
-	s_cdma = (NMSettingCdma *) nm_connection_get_setting (connection, NM_TYPE_SETTING_CDMA);
+	s_cdma = nm_connection_get_setting_cdma (connection);
 	if (!s_cdma)
 		return FALSE;
 
diff --git a/src/modem-manager/nm-modem-cdma.h b/src/modem-manager/nm-modem-cdma.h
index 0abe4e0c..2229c183 100644
--- a/src/modem-manager/nm-modem-cdma.h
+++ b/src/modem-manager/nm-modem-cdma.h
@@ -33,6 +33,12 @@ G_BEGIN_DECLS
 #define NM_IS_MODEM_CDMA_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass),  NM_TYPE_MODEM_CDMA))
 #define NM_MODEM_CDMA_GET_CLASS(obj)  (G_TYPE_INSTANCE_GET_CLASS ((obj),  NM_TYPE_MODEM_CDMA, NMModemCdmaClass))
 
+typedef enum {
+	NM_CDMA_ERROR_CONNECTION_NOT_CDMA = 0, /*< nick=ConnectionNotCdma >*/
+	NM_CDMA_ERROR_CONNECTION_INVALID,      /*< nick=ConnectionInvalid >*/
+	NM_CDMA_ERROR_CONNECTION_INCOMPATIBLE, /*< nick=ConnectionIncompatible >*/
+} NMCdmaError;
+
 typedef struct {
 	NMModem parent;
 } NMModemCdma;
diff --git a/src/modem-manager/nm-modem-gsm.c b/src/modem-manager/nm-modem-gsm.c
index 9a96ae99..183b4780 100644
--- a/src/modem-manager/nm-modem-gsm.c
+++ b/src/modem-manager/nm-modem-gsm.c
@@ -30,7 +30,9 @@
 #include "nm-device-private.h"
 #include "nm-setting-connection.h"
 #include "nm-setting-gsm.h"
+#include "nm-setting-ppp.h"
 #include "nm-modem-types.h"
+#include "nm-enum-types.h"
 #include "nm-logging.h"
 #include "NetworkManagerUtils.h"
 
@@ -60,6 +62,18 @@ typedef enum {
     MM_MODEM_GSM_ALLOWED_MODE_LAST = MM_MODEM_GSM_ALLOWED_MODE_3G_ONLY
 } MMModemGsmAllowedMode;
 
+typedef enum {
+	MM_MODEM_GSM_ALLOWED_AUTH_UNKNOWN  = 0x0000,
+    /* bits 0..4 order match Ericsson device bitmap */
+    MM_MODEM_GSM_ALLOWED_AUTH_NONE     = 0x0001,
+    MM_MODEM_GSM_ALLOWED_AUTH_PAP      = 0x0002,
+    MM_MODEM_GSM_ALLOWED_AUTH_CHAP     = 0x0004,
+    MM_MODEM_GSM_ALLOWED_AUTH_MSCHAP   = 0x0008,
+    MM_MODEM_GSM_ALLOWED_AUTH_MSCHAPV2 = 0x0010,
+    MM_MODEM_GSM_ALLOWED_AUTH_EAP      = 0x0020,
+
+    MM_MODEM_GSM_ALLOWED_AUTH_LAST = MM_MODEM_GSM_ALLOWED_AUTH_EAP
+} MMModemGsmAllowedAuth;
 
 G_DEFINE_TYPE (NMModemGsm, nm_modem_gsm, NM_TYPE_MODEM)
 
@@ -70,17 +84,12 @@ typedef struct {
 
 	GHashTable *connect_properties;
 	guint32 pin_tries;
+
+	guint enable_delay_id;
 } NMModemGsmPrivate;
 
 
-typedef enum {
-	NM_GSM_ERROR_CONNECTION_NOT_GSM = 0,
-	NM_GSM_ERROR_CONNECTION_INVALID,
-	NM_GSM_ERROR_CONNECTION_INCOMPATIBLE,
-} NMGsmError;
-
 #define NM_GSM_ERROR (nm_gsm_error_quark ())
-#define NM_TYPE_GSM_ERROR (nm_gsm_error_get_type ())
 
 static GQuark
 nm_gsm_error_quark (void)
@@ -91,30 +100,6 @@ nm_gsm_error_quark (void)
 	return quark;
 }
 
-/* This should really be standard. */
-#define ENUM_ENTRY(NAME, DESC) { NAME, "" #NAME "", DESC }
-
-static GType
-nm_gsm_error_get_type (void)
-{
-	static GType etype = 0;
-
-	if (etype == 0) {
-		static const GEnumValue values[] = {
-			/* Connection was not a GSM connection. */
-			ENUM_ENTRY (NM_GSM_ERROR_CONNECTION_NOT_GSM, "ConnectionNotGsm"),
-			/* Connection was not a valid GSM connection. */
-			ENUM_ENTRY (NM_GSM_ERROR_CONNECTION_INVALID, "ConnectionInvalid"),
-			/* Connection does not apply to this device. */
-			ENUM_ENTRY (NM_GSM_ERROR_CONNECTION_INCOMPATIBLE, "ConnectionIncompatible"),
-			{ 0, 0, 0 }
-		};
-		etype = g_enum_register_static ("NMGsmError", values);
-	}
-	return etype;
-}
-
-
 NMModem *
 nm_modem_gsm_new (const char *path,
                   const char *device,
@@ -140,20 +125,33 @@ translate_mm_error (GError *error)
 
 	if (dbus_g_error_has_name (error, MM_MODEM_CONNECT_ERROR_NO_CARRIER))
 		reason = NM_DEVICE_STATE_REASON_MODEM_NO_CARRIER;
-	if (dbus_g_error_has_name (error, MM_MODEM_CONNECT_ERROR_NO_DIALTONE))
-		reason = NM_DEVICE_STATE_REASON_MODEM_DIAL_TIMEOUT;
-	if (dbus_g_error_has_name (error, MM_MODEM_CONNECT_ERROR_BUSY))
+	else if (dbus_g_error_has_name (error, MM_MODEM_CONNECT_ERROR_NO_DIALTONE))
+		reason = NM_DEVICE_STATE_REASON_MODEM_NO_DIAL_TONE;
+	else if (dbus_g_error_has_name (error, MM_MODEM_CONNECT_ERROR_BUSY))
 		reason = NM_DEVICE_STATE_REASON_MODEM_BUSY;
-	if (dbus_g_error_has_name (error, MM_MODEM_CONNECT_ERROR_NO_ANSWER))
+	else if (dbus_g_error_has_name (error, MM_MODEM_CONNECT_ERROR_NO_ANSWER))
 		reason = NM_DEVICE_STATE_REASON_MODEM_DIAL_TIMEOUT;
-	if (dbus_g_error_has_name (error, MM_MODEM_ERROR_NETWORK_NOT_ALLOWED))
+	else if (dbus_g_error_has_name (error, MM_MODEM_ERROR_NETWORK_NOT_ALLOWED))
 		reason = NM_DEVICE_STATE_REASON_GSM_REGISTRATION_DENIED;
-	if (dbus_g_error_has_name (error, MM_MODEM_ERROR_NETWORK_TIMEOUT))
+	else if (dbus_g_error_has_name (error, MM_MODEM_ERROR_NETWORK_TIMEOUT))
 		reason = NM_DEVICE_STATE_REASON_GSM_REGISTRATION_TIMEOUT;
-	if (dbus_g_error_has_name (error, MM_MODEM_ERROR_NO_NETWORK))
+	else if (dbus_g_error_has_name (error, MM_MODEM_ERROR_NO_NETWORK))
 		reason = NM_DEVICE_STATE_REASON_GSM_REGISTRATION_NOT_SEARCHING;
+	else if (dbus_g_error_has_name (error, MM_MODEM_ERROR_SIM_NOT_INSERTED))
+		reason = NM_DEVICE_STATE_REASON_GSM_SIM_NOT_INSERTED;
+	else if (dbus_g_error_has_name (error, MM_MODEM_ERROR_SIM_PIN))
+		reason = NM_DEVICE_STATE_REASON_GSM_SIM_PIN_REQUIRED;
+	else if (dbus_g_error_has_name (error, MM_MODEM_ERROR_SIM_PUK))
+		reason = NM_DEVICE_STATE_REASON_GSM_SIM_PUK_REQUIRED;
+	else if (dbus_g_error_has_name (error, MM_MODEM_ERROR_SIM_WRONG))
+		reason = NM_DEVICE_STATE_REASON_GSM_SIM_WRONG;
+	else {
+		/* unable to map the ModemManager error to a NM_DEVICE_STATE_REASON */
+		nm_log_dbg (LOGD_MB, "unmapped dbus error detected: '%s'", dbus_g_error_get_name (error));
+		reason = NM_DEVICE_STATE_REASON_UNKNOWN;
+	}
 
-	/* FIXME: We have only GSM error messages here, and we have no idea which 
+	/* FIXME: We have only GSM error messages here, and we have no idea which
 	   activation state failed. Reasons like:
 	   NM_DEVICE_STATE_REASON_MODEM_DIAL_FAILED,
 	   NM_DEVICE_STATE_REASON_MODEM_INIT_FAILED,
@@ -162,9 +160,6 @@ translate_mm_error (GError *error)
 	   NM_DEVICE_STATE_REASON_GSM_PIN_CHECK_FAILED
 	   are not used.
 	*/
-	else
-		reason = NM_DEVICE_STATE_REASON_UNKNOWN;
-
 	return reason;
 }
 
@@ -237,38 +232,51 @@ do_connect (NMModemGsm *self)
 
 static void stage1_enable_done (DBusGProxy *proxy, DBusGProxyCall *call_id, gpointer user_data);
 
-static void
+/* do_enable() is used as a GSourceFunc, hence the gboolean return */
+static gboolean
 do_enable (NMModemGsm *self)
 {
 	DBusGProxy *proxy;
 
-	g_return_if_fail (self != NULL);
-	g_return_if_fail (NM_IS_MODEM_GSM (self));
+	g_return_val_if_fail (self != NULL, FALSE);
+	g_return_val_if_fail (NM_IS_MODEM_GSM (self), FALSE);
 
+	NM_MODEM_GSM_GET_PRIVATE (self)->enable_delay_id = 0;
 	proxy = nm_modem_get_proxy (NM_MODEM (self), MM_DBUS_INTERFACE_MODEM);
 	dbus_g_proxy_begin_call_with_timeout (proxy,
 	                                      "Enable", stage1_enable_done,
 	                                      self, NULL, 20000,
 	                                      G_TYPE_BOOLEAN, TRUE,
 	                                      G_TYPE_INVALID);
+	return FALSE;
 }
 
 static void
 stage1_pin_done (DBusGProxy *proxy, DBusGProxyCall *call_id, gpointer user_data)
 {
 	NMModemGsm *self = NM_MODEM_GSM (user_data);
+	NMModemGsmPrivate *priv = NM_MODEM_GSM_GET_PRIVATE (self);
+	NMDeviceStateReason reason;
 	GError *error = NULL;
 
 	if (dbus_g_proxy_end_call (proxy, call_id, &error, G_TYPE_INVALID)) {
-		/* Success; go back and try the enable again */
-		do_enable (self);
+		/* Success; try to enable the modem again.  Wait a few seconds to ensure
+		 * that ModemManager is ready for the enable right after the unlock.
+		 */
+		if (priv->enable_delay_id == 0)
+			priv->enable_delay_id = g_timeout_add_seconds (4, (GSourceFunc) do_enable, self);
 	} else {
 		nm_log_warn (LOGD_MB, "GSM PIN unlock failed: (%d) %s",
 		             error ? error->code : -1,
 		             error && error->message ? error->message : "(unknown)");
-		g_error_free (error);
 
-		g_signal_emit_by_name (self, NM_MODEM_PREPARE_RESULT, FALSE, NM_DEVICE_STATE_REASON_MODEM_INIT_FAILED);
+		/* try to translate the error reason */
+		reason = translate_mm_error (error);
+		if (reason == NM_DEVICE_STATE_REASON_UNKNOWN)
+			reason = NM_DEVICE_STATE_REASON_MODEM_INIT_FAILED;
+
+		g_signal_emit_by_name (self, NM_MODEM_PREPARE_RESULT, FALSE, reason);
+		g_error_free (error);
 	}
 }
 
@@ -301,6 +309,7 @@ static void
 stage1_enable_done (DBusGProxy *proxy, DBusGProxyCall *call_id, gpointer user_data)
 {
 	NMModemGsm *self = NM_MODEM_GSM (user_data);
+	NMDeviceStateReason reason;
 	GError *error = NULL;
 
 	if (dbus_g_proxy_end_call (proxy, call_id, &error, G_TYPE_INVALID))
@@ -312,8 +321,13 @@ stage1_enable_done (DBusGProxy *proxy, DBusGProxyCall *call_id, gpointer user_da
 
 		if (dbus_g_error_has_name (error, MM_MODEM_ERROR_SIM_PIN))
 			handle_enable_pin_required (self);
-		else
-			g_signal_emit_by_name (self, NM_MODEM_PREPARE_RESULT, FALSE, NM_DEVICE_STATE_REASON_MODEM_INIT_FAILED);
+		else {
+			/* try to translate the error reason */
+			reason = translate_mm_error (error);
+			if (reason == NM_DEVICE_STATE_REASON_UNKNOWN)
+				reason = NM_DEVICE_STATE_REASON_MODEM_INIT_FAILED;
+			g_signal_emit_by_name (self, NM_MODEM_PREPARE_RESULT, FALSE, reason);
+		}
 
 		g_error_free (error);
 	}
@@ -324,10 +338,11 @@ static GHashTable *
 create_connect_properties (NMConnection *connection)
 {
 	NMSettingGsm *setting;
+	NMSettingPPP *s_ppp;
 	GHashTable *properties;
 	const char *str;
 
-	setting = NM_SETTING_GSM (nm_connection_get_setting (connection, NM_TYPE_SETTING_GSM));
+	setting = nm_connection_get_setting_gsm (connection);
 	properties = value_hash_create ();
 
 	str = nm_setting_gsm_get_number (setting);
@@ -382,6 +397,28 @@ create_connect_properties (NMConnection *connection)
 	if (nm_setting_gsm_get_home_only (setting))
 		value_hash_add_bool (properties, "home_only", TRUE);
 
+	/* For IpMethod == STATIC or DHCP */
+	s_ppp = nm_connection_get_setting_ppp (connection);
+	if (s_ppp) {
+		guint32 auth = MM_MODEM_GSM_ALLOWED_AUTH_UNKNOWN;
+
+		if (nm_setting_ppp_get_noauth (s_ppp))
+			auth |= MM_MODEM_GSM_ALLOWED_AUTH_NONE;
+		if (!nm_setting_ppp_get_refuse_pap (s_ppp))
+			auth |= MM_MODEM_GSM_ALLOWED_AUTH_PAP;
+		if (!nm_setting_ppp_get_refuse_chap (s_ppp))
+			auth |= MM_MODEM_GSM_ALLOWED_AUTH_CHAP;
+		if (!nm_setting_ppp_get_refuse_mschap (s_ppp))
+			auth |= MM_MODEM_GSM_ALLOWED_AUTH_MSCHAP;
+		if (!nm_setting_ppp_get_refuse_mschapv2 (s_ppp))
+			auth |= MM_MODEM_GSM_ALLOWED_AUTH_MSCHAPV2;
+		if (!nm_setting_ppp_get_refuse_eap (s_ppp))
+			auth |= MM_MODEM_GSM_ALLOWED_AUTH_EAP;
+
+		if (auth != MM_MODEM_GSM_ALLOWED_AUTH_UNKNOWN)
+			value_hash_add_uint (properties, "allowed_auth", auth);
+	}
+
 	return properties;
 }
 
@@ -429,7 +466,7 @@ real_get_best_auto_connection (NMModem *modem,
 		NMConnection *connection = NM_CONNECTION (iter->data);
 		NMSettingConnection *s_con;
 
-		s_con = (NMSettingConnection *) nm_connection_get_setting (connection, NM_TYPE_SETTING_CONNECTION);
+		s_con = nm_connection_get_setting_connection (connection);
 		g_assert (s_con);
 
 		if (!nm_setting_connection_get_autoconnect (s_con))
@@ -451,7 +488,7 @@ real_check_connection_compatible (NMModem *modem,
 	NMSettingConnection *s_con;
 	NMSettingGsm *s_gsm;
 
-	s_con = NM_SETTING_CONNECTION (nm_connection_get_setting (connection, NM_TYPE_SETTING_CONNECTION));
+	s_con = nm_connection_get_setting_connection (connection);
 	g_assert (s_con);
 
 	if (strcmp (nm_setting_connection_get_connection_type (s_con), NM_SETTING_GSM_SETTING_NAME)) {
@@ -461,7 +498,7 @@ real_check_connection_compatible (NMModem *modem,
 		return FALSE;
 	}
 
-	s_gsm = NM_SETTING_GSM (nm_connection_get_setting (connection, NM_TYPE_SETTING_GSM));
+	s_gsm = nm_connection_get_setting_gsm (connection);
 	if (!s_gsm) {
 		g_set_error (error,
 		             NM_GSM_ERROR, NM_GSM_ERROR_CONNECTION_INVALID,
@@ -479,8 +516,9 @@ real_complete_connection (NMModem *modem,
                           GError **error)
 {
 	NMSettingGsm *s_gsm;
+	NMSettingPPP *s_ppp;
 
-	s_gsm = (NMSettingGsm *) nm_connection_get_setting (connection, NM_TYPE_SETTING_GSM);
+	s_gsm = nm_connection_get_setting_gsm (connection);
 	if (!s_gsm || !nm_setting_gsm_get_apn (s_gsm)) {
 		/* Need an APN at least */
 		g_set_error_literal (error,
@@ -493,6 +531,16 @@ real_complete_connection (NMModem *modem,
 	if (!nm_setting_gsm_get_number (s_gsm))
 		g_object_set (G_OBJECT (s_gsm), NM_SETTING_GSM_NUMBER, "*99#", NULL);
 
+	s_ppp = nm_connection_get_setting_ppp (connection);
+	if (!s_ppp) {
+		s_ppp = (NMSettingPPP *) nm_setting_ppp_new ();
+		g_object_set (G_OBJECT (s_ppp),
+		              NM_SETTING_PPP_LCP_ECHO_FAILURE, 5,
+		              NM_SETTING_PPP_LCP_ECHO_INTERVAL, 30,
+		              NULL);
+		nm_connection_add_setting (connection, NM_SETTING (s_ppp));
+	}
+
 	nm_utils_complete_generic (connection,
 	                           NM_SETTING_GSM_SETTING_NAME,
 	                           existing_connections,
@@ -511,7 +559,7 @@ real_get_user_pass (NMModem *modem,
 {
 	NMSettingGsm *s_gsm;
 
-	s_gsm = (NMSettingGsm *) nm_connection_get_setting (connection, NM_TYPE_SETTING_GSM);
+	s_gsm = nm_connection_get_setting_gsm (connection);
 	if (!s_gsm)
 		return FALSE;
 
@@ -544,6 +592,9 @@ real_deactivate (NMModem *modem, NMDevice *device)
 
 	priv->pin_tries = 0;
 
+	if (priv->enable_delay_id)
+		g_source_remove (priv->enable_delay_id);
+
 	NM_MODEM_CLASS (nm_modem_gsm_parent_class)->deactivate (modem, device);	
 }
 
@@ -563,6 +614,8 @@ dispose (GObject *object)
 
 	if (priv->connect_properties)
 		g_hash_table_destroy (priv->connect_properties);
+	if (priv->enable_delay_id)
+		g_source_remove (priv->enable_delay_id);
 
 	G_OBJECT_CLASS (nm_modem_gsm_parent_class)->dispose (object);
 }
diff --git a/src/modem-manager/nm-modem-gsm.h b/src/modem-manager/nm-modem-gsm.h
index f481bdb8..e1c94f04 100644
--- a/src/modem-manager/nm-modem-gsm.h
+++ b/src/modem-manager/nm-modem-gsm.h
@@ -33,6 +33,12 @@ G_BEGIN_DECLS
 #define NM_IS_MODEM_GSM_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass),	 NM_TYPE_MODEM_GSM))
 #define NM_MODEM_GSM_GET_CLASS(obj)	 (G_TYPE_INSTANCE_GET_CLASS ((obj),	 NM_TYPE_MODEM_GSM, NMModemGsmClass))
 
+typedef enum {
+	NM_GSM_ERROR_CONNECTION_NOT_GSM = 0,  /*< nick=ConnectionNotGsm >*/
+	NM_GSM_ERROR_CONNECTION_INVALID,      /*< nick=ConnectionInvalid >*/
+	NM_GSM_ERROR_CONNECTION_INCOMPATIBLE, /*< nick=ConnectionIncompatible >*/
+} NMGsmError;
+
 typedef struct {
 	NMModem parent;
 } NMModemGsm;
diff --git a/src/modem-manager/nm-modem-manager.c b/src/modem-manager/nm-modem-manager.c
index 3509d667..051940f5 100644
--- a/src/modem-manager/nm-modem-manager.c
+++ b/src/modem-manager/nm-modem-manager.c
@@ -76,86 +76,56 @@ get_modem_properties (DBusGConnection *connection,
 					  char **data_device,
 					  char **driver,
 					  guint32 *type,
-					  guint32 *ip_method)
+					  guint32 *ip_method,
+					  guint32 *ip_timeout)
 {
 	DBusGProxy *proxy;
-	GValue value = { 0 };
 	GError *err = NULL;
+	GHashTable *props = NULL;
+	GHashTableIter iter;
+	const char *prop;
+	GValue *value;
 
 	proxy = dbus_g_proxy_new_for_name (connection,
-									   MM_DBUS_SERVICE,
-									   path,
-									   "org.freedesktop.DBus.Properties");
-
-	if (dbus_g_proxy_call_with_timeout (proxy, "Get", 15000, &err,
-	                                    G_TYPE_STRING, MM_DBUS_INTERFACE_MODEM,
-	                                    G_TYPE_STRING, "Type",
-	                                    G_TYPE_INVALID,
-	                                    G_TYPE_VALUE, &value,
-	                                    G_TYPE_INVALID)) {
-		*type = g_value_get_uint (&value);
-		g_value_unset (&value);
-	} else {
-		nm_log_warn (LOGD_MB, "could not get device type: %s", err->message);
-		goto out;
-	}
-
-	if (dbus_g_proxy_call_with_timeout (proxy, "Get", 15000, &err,
-	                                    G_TYPE_STRING, MM_DBUS_INTERFACE_MODEM,
-	                                    G_TYPE_STRING, "MasterDevice",
-	                                    G_TYPE_INVALID,
-	                                    G_TYPE_VALUE, &value,
-	                                    G_TYPE_INVALID)) {
-		*device = g_value_dup_string (&value);
-		g_value_unset (&value);
-	} else {
-		nm_log_warn (LOGD_MB, "could not get device: %s", err->message);
-		goto out;
-	}
-
-	if (dbus_g_proxy_call_with_timeout (proxy, "Get", 15000, &err,
-										G_TYPE_STRING, MM_DBUS_INTERFACE_MODEM,
-										G_TYPE_STRING, "IpMethod",
-										G_TYPE_INVALID,
-										G_TYPE_VALUE, &value,
-										G_TYPE_INVALID)) {
-		*ip_method = g_value_get_uint (&value);
-		g_value_unset (&value);
-	} else {
-		nm_log_warn (LOGD_MB, "could not get IP method: %s", err->message);
+	                                   MM_DBUS_SERVICE,
+	                                   path,
+	                                   "org.freedesktop.DBus.Properties");
+
+	if (!dbus_g_proxy_call_with_timeout (proxy, "GetAll", 15000, &err,
+	                                     G_TYPE_STRING, MM_DBUS_INTERFACE_MODEM,
+	                                     G_TYPE_INVALID,
+	                                     DBUS_TYPE_G_MAP_OF_VARIANT, &props,
+	                                     G_TYPE_INVALID)) {
+		nm_log_warn (LOGD_MB, "could not get modem properties: %s %s",
+		             err ? dbus_g_error_get_name (err) : "(none)",
+		             err ? err->message : "(unknown)");
+		g_clear_error (&err);
 		goto out;
 	}
 
-	if (dbus_g_proxy_call_with_timeout (proxy, "Get", 15000, &err,
-										G_TYPE_STRING, MM_DBUS_INTERFACE_MODEM,
-										G_TYPE_STRING, "Device",
-										G_TYPE_INVALID,
-										G_TYPE_VALUE, &value,
-										G_TYPE_INVALID)) {
-		*data_device = g_value_dup_string (&value);
-		g_value_unset (&value);
-	} else {
-		nm_log_warn (LOGD_MB, "could not get modem data device: %s", err->message);
+	if (!props) {
+		nm_log_warn (LOGD_MB, "no modem properties found");
 		goto out;
 	}
 
-	if (dbus_g_proxy_call_with_timeout (proxy, "Get", 15000, &err,
-										G_TYPE_STRING, MM_DBUS_INTERFACE_MODEM,
-										G_TYPE_STRING, "Driver",
-										G_TYPE_INVALID,
-										G_TYPE_VALUE, &value,
-										G_TYPE_INVALID)) {
-		*driver = g_value_dup_string (&value);
-		g_value_unset (&value);
-	} else {
-		nm_log_warn (LOGD_MB, "could not get modem driver: %s", err->message);
-		goto out;
+	g_hash_table_iter_init (&iter, props);
+	while (g_hash_table_iter_next (&iter, (gpointer) &prop, (gpointer) &value)) {
+		if (g_strcmp0 (prop, "Type") == 0)
+			*type = g_value_get_uint (value);
+		else if (g_strcmp0 (prop, "MasterDevice") == 0)
+			*device = g_value_dup_string (value);
+		else if (g_strcmp0 (prop, "IpMethod") == 0)
+			*ip_method = g_value_get_uint (value);
+		else if (g_strcmp0 (prop, "Device") == 0)
+			*data_device = g_value_dup_string (value);
+		else if (g_strcmp0 (prop, "Driver") == 0)
+			*driver = g_value_dup_string (value);
+		else if (g_strcmp0 (prop, "IpTimeout") == 0)
+			*ip_timeout = g_value_get_uint (value);
 	}
+	g_hash_table_unref (props);
 
  out:
-	if (err)
-		g_error_free (err);
-
 	g_object_unref (proxy);
 
 	return *data_device && *driver;
@@ -169,6 +139,7 @@ create_modem (NMModemManager *manager, const char *path)
 	char *data_device = NULL, *driver = NULL, *master_device = NULL;
 	uint modem_type = MM_MODEM_TYPE_UNKNOWN;
 	uint ip_method = MM_MODEM_IP_METHOD_PPP;
+	uint ip_timeout = 0;
 
 	if (g_hash_table_lookup (priv->modems, path)) {
 		nm_log_warn (LOGD_MB, "modem with path %s already exists, ignoring", path);
@@ -177,7 +148,7 @@ create_modem (NMModemManager *manager, const char *path)
 
 	if (!get_modem_properties (nm_dbus_manager_get_connection (priv->dbus_mgr),
 	                           path, &master_device, &data_device, &driver,
-	                           &modem_type, &ip_method))
+	                           &modem_type, &ip_method, &ip_timeout))
 		return;
 
 	if (modem_type == MM_MODEM_TYPE_UNKNOWN) {
@@ -210,6 +181,7 @@ create_modem (NMModemManager *manager, const char *path)
 	g_free (data_device);
 
 	if (modem) {
+		g_object_set (G_OBJECT (modem), NM_MODEM_IP_TIMEOUT, ip_timeout, NULL);
 		g_hash_table_insert (priv->modems, g_strdup (path), modem);
 		g_signal_emit (manager, signals[MODEM_ADDED], 0, modem, driver);
 	}
diff --git a/src/modem-manager/nm-modem.c b/src/modem-manager/nm-modem.c
index debfbdf7..91c0b06d 100644
--- a/src/modem-manager/nm-modem.c
+++ b/src/modem-manager/nm-modem.c
@@ -30,7 +30,6 @@
 #include "nm-logging.h"
 #include "NetworkManagerUtils.h"
 #include "nm-device-private.h"
-#include "nm-device-interface.h"
 #include "nm-dbus-glib-types.h"
 
 G_DEFINE_TYPE (NMModem, nm_modem, G_TYPE_OBJECT)
@@ -43,6 +42,7 @@ enum {
 	PROP_IFACE,
 	PROP_PATH,
 	PROP_IP_METHOD,
+	PROP_IP_TIMEOUT,
 	PROP_ENABLED,
 
 	LAST_PROP
@@ -55,7 +55,6 @@ typedef struct {
 
 	char *path;
 	NMPPPManager *ppp_manager;
-	NMIP4Config	 *pending_ip4_config;
 	guint32 ip_method;
 	char *device;
 	char *iface;
@@ -67,6 +66,7 @@ typedef struct {
 	DBusGProxyCall *call;
 
 	gboolean mm_enabled;
+	guint32 mm_ip_timeout;
 
 	/* PPP stats */
 	guint32 in_bytes;
@@ -129,21 +129,6 @@ nm_modem_get_proxy (NMModem *self,
 	return priv->proxy;
 }
 
-static void
-merge_ip4_config (NMActRequest *req, NMIP4Config *config)
-{
-	NMConnection *connection;
-	NMSettingIP4Config *s_ip4;
-
-	/* Merge user-defined overrides into the IP4Config to be applied */
-	connection = nm_act_request_get_connection (req);
-	g_assert (connection);
-
-	s_ip4 = (NMSettingIP4Config *) nm_connection_get_setting (connection, NM_TYPE_SETTING_IP4_CONFIG);
-	if (s_ip4)
-		nm_utils_merge_ip4_config (config, s_ip4);
-}
-
 /*****************************************************************************/
 /* IP method PPP */
 
@@ -169,7 +154,6 @@ ppp_ip4_config (NMPPPManager *ppp_manager,
 				gpointer user_data)
 {
 	NMModem *self = NM_MODEM (user_data);
-	NMModemPrivate *priv = NM_MODEM_GET_PRIVATE (self);
 	guint32 i, num;
 	guint32 bad_dns1 = htonl (0x0A0B0C0D);
 	guint32 good_dns1 = htonl (0x04020201);  /* GTE nameserver */
@@ -213,7 +197,6 @@ ppp_ip4_config (NMPPPManager *ppp_manager,
 		nm_ip4_config_add_nameserver (config, good_dns2);
 	}
 
-	priv->pending_ip4_config = g_object_ref (config);
 	g_signal_emit (self, signals[IP4_CONFIG_RESULT], 0, iface, config, NULL);
 }
 
@@ -243,6 +226,7 @@ ppp_stage3_ip4_config_start (NMModem *self,
 	const char *ppp_name = NULL;
 	GError *error = NULL;
 	NMActStageReturn ret;
+	guint ip_timeout = 20;
 
 	g_return_val_if_fail (self != NULL, NM_ACT_STAGE_RETURN_FAILURE);
 	g_return_val_if_fail (NM_IS_MODEM (self), NM_ACT_STAGE_RETURN_FAILURE);
@@ -258,8 +242,16 @@ ppp_stage3_ip4_config_start (NMModem *self,
 			return NM_ACT_STAGE_RETURN_FAILURE;
 	}
 
+	/* Check if ModemManager requested a specific IP timeout to be used. If 0 reported,
+	 * use the default one (20s) */
+	if (priv->mm_ip_timeout > 0) {
+		nm_log_info (LOGD_PPP, "using modem-specified IP timeout: %u seconds",
+		             priv->mm_ip_timeout);
+		ip_timeout = priv->mm_ip_timeout;
+	}
+
 	priv->ppp_manager = nm_ppp_manager_new (priv->iface);
-	if (nm_ppp_manager_start (priv->ppp_manager, req, ppp_name, 20, &error)) {
+	if (nm_ppp_manager_start (priv->ppp_manager, req, ppp_name, ip_timeout, &error)) {
 		g_signal_connect (priv->ppp_manager, "state-changed",
 						  G_CALLBACK (ppp_state_changed),
 						  self);
@@ -287,22 +279,6 @@ ppp_stage3_ip4_config_start (NMModem *self,
 	return ret;
 }
 
-static NMActStageReturn
-ppp_stage4 (NMModem *self,
-            NMActRequest *req,
-            NMIP4Config **config,
-            NMDeviceStateReason *reason)
-{
-	NMModemPrivate *priv = NM_MODEM_GET_PRIVATE (self);
-
-	*config = priv->pending_ip4_config;
-	priv->pending_ip4_config = NULL;
-
-	merge_ip4_config (req, *config);
-
-	return NM_ACT_STAGE_RETURN_SUCCESS;
-}
-
 /*****************************************************************************/
 /* IP method static */
 
@@ -336,9 +312,6 @@ static_stage3_done (DBusGProxy *proxy, DBusGProxyCall *call, gpointer user_data)
 			nm_ip4_config_add_nameserver (config, g_value_get_uint (value));
 		}
 		g_value_array_free (ret_array);
-
-		priv->pending_ip4_config = g_object_ref (config);
-		g_signal_emit (self, signals[IP4_CONFIG_RESULT], 0, NULL, config, NULL);
 	}
 
 	g_signal_emit (self, signals[IP4_CONFIG_RESULT], 0, NULL, config, error);
@@ -368,32 +341,6 @@ static_stage3_ip4_config_start (NMModem *self,
 	return NM_ACT_STAGE_RETURN_POSTPONE;
 }
 
-static NMActStageReturn
-static_stage4 (NMModem *self,
-               NMActRequest *req,
-               NMDevice *device,
-               NMIP4Config **config,
-               NMDeviceStateReason *reason)
-{
-	NMModemPrivate *priv = NM_MODEM_GET_PRIVATE (self);
-	gboolean no_firmware = FALSE;
-
-	if (!nm_device_hw_bring_up (device, TRUE, &no_firmware)) {
-		if (no_firmware)
-			*reason = NM_DEVICE_STATE_REASON_FIRMWARE_MISSING;
-		else
-			*reason = NM_DEVICE_STATE_REASON_CONFIG_FAILED;
-		return NM_ACT_STAGE_RETURN_FAILURE;
-	}
-
-	*config = priv->pending_ip4_config;
-	priv->pending_ip4_config = NULL;
-
-	merge_ip4_config (req, *config);
-
-	return NM_ACT_STAGE_RETURN_SUCCESS;
-}
-
 /*****************************************************************************/
 
 NMActStageReturn
@@ -426,7 +373,7 @@ nm_modem_stage3_ip4_config_start (NMModem *self,
 		ret = static_stage3_ip4_config_start (self, req, reason);
 		break;
 	case MM_MODEM_IP_METHOD_DHCP:
-		ret = device_class->act_stage3_ip4_config_start (device, reason);
+		ret = device_class->act_stage3_ip4_config_start (device, NULL, reason);
 		break;
 	default:
 		nm_log_err (LOGD_MB, "unknown IP method %d", priv->ip_method);
@@ -438,45 +385,14 @@ nm_modem_stage3_ip4_config_start (NMModem *self,
 }
 
 NMActStageReturn
-nm_modem_stage4_get_ip4_config (NMModem *self,
-                                NMDevice *device,
-                                NMDeviceClass *device_class,
-								NMIP4Config **config,
-								NMDeviceStateReason *reason)
+nm_modem_stage3_ip6_config_start (NMModem *self,
+                                  NMDevice *device,
+                                  NMDeviceClass *device_class,
+                                  NMDeviceStateReason *reason)
 {
-	NMModemPrivate *priv;
-	NMActRequest *req;
-	NMActStageReturn ret;
-
-	g_return_val_if_fail (self != NULL, NM_ACT_STAGE_RETURN_FAILURE);
-	g_return_val_if_fail (NM_IS_MODEM (self), NM_ACT_STAGE_RETURN_FAILURE);
-	g_return_val_if_fail (device != NULL, NM_ACT_STAGE_RETURN_FAILURE);
-	g_return_val_if_fail (NM_IS_DEVICE (device), NM_ACT_STAGE_RETURN_FAILURE);
-	g_return_val_if_fail (device_class != NULL, NM_ACT_STAGE_RETURN_FAILURE);
-	g_return_val_if_fail (NM_IS_DEVICE_CLASS (device_class), NM_ACT_STAGE_RETURN_FAILURE);
-	g_return_val_if_fail (reason != NULL, NM_ACT_STAGE_RETURN_FAILURE);
-
-	req = nm_device_get_act_request (device);
-	g_assert (req);
-
-	priv = NM_MODEM_GET_PRIVATE (self);
-	switch (priv->ip_method) {
-	case MM_MODEM_IP_METHOD_PPP:
-		ret = ppp_stage4 (self, req, config, reason);
-		break;
-	case MM_MODEM_IP_METHOD_STATIC:
-		ret = static_stage4 (self, req, device, config, reason);
-		break;
-	case MM_MODEM_IP_METHOD_DHCP:
-		ret = device_class->act_stage4_get_ip4_config (device, config, reason);
-		break;
-	default:
-		nm_log_err (LOGD_MB, "unknown IP method %d", priv->ip_method);
-		ret = NM_ACT_STAGE_RETURN_FAILURE;
-		break;
-	}
-
-	return ret;
+	/* FIXME: We don't support IPv6 on modems quite yet... */
+	nm_device_activate_schedule_ip6_config_timeout (device);
+	return NM_ACT_STAGE_RETURN_POSTPONE;
 }
 
 static void
@@ -586,7 +502,7 @@ nm_modem_act_stage1_prepare (NMModem *self,
 		if (hints)
 			g_ptr_array_free (hints, TRUE);
 	}
-	
+
 	return ret;
 }
 
@@ -662,11 +578,6 @@ real_deactivate (NMModem *self, NMDevice *device)
 		priv->call = NULL;
 	}
 
-	if (priv->pending_ip4_config) {
-		g_object_unref (priv->pending_ip4_config);
-		priv->pending_ip4_config = NULL;
-	}
-
 	priv->in_bytes = priv->out_bytes = 0;
 
 	if (priv->ppp_manager) {
@@ -680,10 +591,12 @@ real_deactivate (NMModem *self, NMDevice *device)
 	case MM_MODEM_IP_METHOD_STATIC:
 	case MM_MODEM_IP_METHOD_DHCP:
 		ifindex = nm_device_get_ip_ifindex (device);
-		/* FIXME: use AF_UNSPEC here when we have IPv6 support */
-		nm_system_iface_flush_routes (ifindex, AF_INET);
-		nm_system_iface_flush_addresses (ifindex, AF_UNSPEC);
-		nm_system_iface_set_up (ifindex, FALSE, NULL);
+		if (ifindex >= 0) {
+			/* FIXME: use AF_UNSPEC here when we have IPv6 support */
+			nm_system_iface_flush_routes (ifindex, AF_INET);
+			nm_system_iface_flush_addresses (ifindex, AF_UNSPEC);
+			nm_system_iface_set_up (ifindex, FALSE, NULL);
+		}
 		break;
 	default:
 		nm_log_err (LOGD_MB, "unknown IP method %d", priv->ip_method);
@@ -721,7 +634,7 @@ nm_modem_device_state_changed (NMModem *self,
 	g_return_if_fail (self != NULL);
 	g_return_if_fail (NM_IS_MODEM (self));
 
-	if (IS_ACTIVATING_STATE (old_state) || (old_state == NM_DEVICE_STATE_ACTIVATED))
+	if (old_state >= NM_DEVICE_STATE_PREPARE && old_state <= NM_DEVICE_STATE_ACTIVATED)
 		was_connected = TRUE;
 
 	priv = NM_MODEM_GET_PRIVATE (self);
@@ -758,44 +671,20 @@ nm_modem_device_state_changed (NMModem *self,
 	}
 }
 
-static gboolean
-_state_is_active (NMDeviceState state)
-{
-	return (state >= NM_DEVICE_STATE_IP_CONFIG && state <= NM_DEVICE_STATE_DEACTIVATING);
-}
-
 gboolean
 nm_modem_hw_is_up (NMModem *self, NMDevice *device)
 {
-	guint32 ip_method = NM_MODEM_GET_PRIVATE (self)->ip_method;
+	int ifindex = nm_device_get_ip_ifindex (device);
 
-	if (ip_method == MM_MODEM_IP_METHOD_STATIC || ip_method == MM_MODEM_IP_METHOD_DHCP) {
-		NMModemPrivate *priv = NM_MODEM_GET_PRIVATE (self);
-		NMDeviceState state;
-
-		state = nm_device_interface_get_state (NM_DEVICE_INTERFACE (device));
-		if (priv->pending_ip4_config || _state_is_active (state))
-			return nm_system_iface_is_up (nm_device_get_ip_ifindex (device));
-	}
-
-	return TRUE;
+	return ifindex > 0 ? nm_system_iface_is_up (ifindex) : TRUE;
 }
 
 gboolean
 nm_modem_hw_bring_up (NMModem *self, NMDevice *device, gboolean *no_firmware)
 {
-	guint32 ip_method = NM_MODEM_GET_PRIVATE (self)->ip_method;
-
-	if (ip_method == MM_MODEM_IP_METHOD_STATIC || ip_method == MM_MODEM_IP_METHOD_DHCP) {
-		NMModemPrivate *priv = NM_MODEM_GET_PRIVATE (self);
-		NMDeviceState state;
-
-		state = nm_device_interface_get_state (NM_DEVICE_INTERFACE (device));
-		if (priv->pending_ip4_config || _state_is_active (state))
-			return nm_system_iface_set_up (nm_device_get_ip_ifindex (device), TRUE, no_firmware);
-	}
+	int ifindex = nm_device_get_ip_ifindex (device);
 
-	return TRUE;
+	return ifindex > 0 ? nm_system_iface_set_up (ifindex, TRUE, no_firmware) : TRUE;
 }
 
 const char *
@@ -1013,6 +902,9 @@ get_property (GObject *object, guint prop_id,
 	case PROP_IP_METHOD:
 		g_value_set_uint (value, priv->ip_method);
 		break;
+	case PROP_IP_TIMEOUT:
+		g_value_set_uint (value, priv->mm_ip_timeout);
+		break;
 	case PROP_ENABLED:
 		g_value_set_boolean (value, priv->mm_enabled);
 		break;
@@ -1046,6 +938,9 @@ set_property (GObject *object, guint prop_id,
 		/* Construct only */
 		priv->ip_method = g_value_get_uint (value);
 		break;
+	case PROP_IP_TIMEOUT:
+		priv->mm_ip_timeout = g_value_get_uint (value);
+		break;
 	case PROP_ENABLED:
 		break;
 	default:
@@ -1129,6 +1024,14 @@ nm_modem_class_init (NMModemClass *klass)
 							G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY));
 
 	g_object_class_install_property
+		(object_class, PROP_IP_TIMEOUT,
+		 g_param_spec_uint (NM_MODEM_IP_TIMEOUT,
+		                    "IP timeout",
+		                    "IP timeout",
+		                    0, 360, 20,
+		                    G_PARAM_READWRITE | G_PARAM_CONSTRUCT));
+
+	g_object_class_install_property
 		(object_class, PROP_ENABLED,
 		 g_param_spec_boolean (NM_MODEM_ENABLED,
 		                       "Enabled",
diff --git a/src/modem-manager/nm-modem.h b/src/modem-manager/nm-modem.h
index bad19b04..8fe52bc0 100644
--- a/src/modem-manager/nm-modem.h
+++ b/src/modem-manager/nm-modem.h
@@ -40,6 +40,7 @@ G_BEGIN_DECLS
 #define NM_MODEM_DEVICE    "device"
 #define NM_MODEM_IFACE     "iface"
 #define NM_MODEM_IP_METHOD "ip-method"
+#define NM_MODEM_IP_TIMEOUT "ip-timeout"
 #define NM_MODEM_ENABLED   "enabled"
 
 #define NM_MODEM_PPP_STATS         "ppp-stats"
@@ -129,11 +130,10 @@ NMActStageReturn nm_modem_stage3_ip4_config_start (NMModem *modem,
                                                    NMDeviceClass *device_class,
                                                    NMDeviceStateReason *reason);
 
-NMActStageReturn nm_modem_stage4_get_ip4_config (NMModem *modem,
-                                                 NMDevice *device,
-                                                 NMDeviceClass *device_class,
-                                                 NMIP4Config **config,
-                                                 NMDeviceStateReason *reason);
+NMActStageReturn nm_modem_stage3_ip6_config_start (NMModem *modem,
+                                                   NMDevice *device,
+                                                   NMDeviceClass *device_class,
+                                                   NMDeviceStateReason *reason);
 
 gboolean nm_modem_get_secrets (NMModem *modem,
                                const char *setting_name,
diff --git a/src/nm-activation-request.c b/src/nm-activation-request.c
index d3eb920d..3fc7b538 100644
--- a/src/nm-activation-request.c
+++ b/src/nm-activation-request.c
@@ -15,7 +15,7 @@
  * with this program; if not, write to the Free Software Foundation, Inc.,
  * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
  *
- * Copyright (C) 2005 - 2011 Red Hat, Inc.
+ * Copyright (C) 2005 - 2012 Red Hat, Inc.
  * Copyright (C) 2007 - 2008 Novell, Inc.
  */
 
@@ -34,25 +34,16 @@
 #include "nm-setting-8021x.h"
 #include "nm-dbus-manager.h"
 #include "nm-device.h"
-#include "nm-properties-changed-signal.h"
 #include "nm-active-connection.h"
-#include "nm-dbus-glib-types.h"
-#include "nm-active-connection-glue.h"
 #include "nm-settings-connection.h"
 
 
-G_DEFINE_TYPE (NMActRequest, nm_act_request, G_TYPE_OBJECT)
+G_DEFINE_TYPE (NMActRequest, nm_act_request, NM_TYPE_ACTIVE_CONNECTION)
 
 #define NM_ACT_REQUEST_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), \
                                        NM_TYPE_ACT_REQUEST, \
                                        NMActRequestPrivate))
 
-enum {
-	PROPERTIES_CHANGED,
-	LAST_SIGNAL
-};
-static guint signals[LAST_SIGNAL] = { 0 };
-
 typedef struct {
 	char *table;
 	char *rule;
@@ -65,36 +56,30 @@ typedef struct {
 
 	GSList *secrets_calls;
 
-	char *specific_object;
 	NMDevice *device;
 	gboolean user_requested;
 	gulong user_uid;
 
-	NMActiveConnectionState state;
-	gboolean is_default;
-	gboolean is_default6;
+	NMActiveConnection *dep;
+	guint dep_state_id;
+
 	gboolean shared;
 	GSList *share_rules;
 
-	char *ac_path;
-
 	gboolean assumed;
 } NMActRequestPrivate;
 
 enum {
-	PROP_0,
-	PROP_CONNECTION,
-	PROP_UUID,
-	PROP_SPECIFIC_OBJECT,
-	PROP_DEVICES,
-	PROP_STATE,
-	PROP_DEFAULT,
-	PROP_DEFAULT6,
-	PROP_VPN,
-
-	LAST_PROP
+	PROP_MASTER = 2000,
 };
 
+enum {
+	DEP_RESULT,
+
+	LAST_SIGNAL
+};
+static guint signals[LAST_SIGNAL] = { 0 };
+
 /*******************************************************************/
 
 typedef struct {
@@ -199,29 +184,6 @@ nm_act_request_get_connection (NMActRequest *req)
 	return NM_ACT_REQUEST_GET_PRIVATE (req)->connection;
 }
 
-const char *
-nm_act_request_get_specific_object (NMActRequest *req)
-{
-	g_return_val_if_fail (NM_IS_ACT_REQUEST (req), NULL);
-
-	return NM_ACT_REQUEST_GET_PRIVATE (req)->specific_object;
-}
-
-void
-nm_act_request_set_specific_object (NMActRequest *req,
-                                    const char *specific_object)
-{
-	NMActRequestPrivate *priv;
-
-	g_return_if_fail (NM_IS_ACT_REQUEST (req));
-	g_return_if_fail (specific_object != NULL);
-
-	priv = NM_ACT_REQUEST_GET_PRIVATE (req);
-
-	g_free (priv->specific_object);
-	priv->specific_object = g_strdup (specific_object);
-}
-
 gboolean
 nm_act_request_get_user_requested (NMActRequest *req)
 {
@@ -230,74 +192,47 @@ nm_act_request_get_user_requested (NMActRequest *req)
 	return NM_ACT_REQUEST_GET_PRIVATE (req)->user_requested;
 }
 
-const char *
-nm_act_request_get_active_connection_path (NMActRequest *req)
+GObject *
+nm_act_request_get_device (NMActRequest *req)
 {
 	g_return_val_if_fail (NM_IS_ACT_REQUEST (req), NULL);
 
-	return NM_ACT_REQUEST_GET_PRIVATE (req)->ac_path;
-}
-
-void
-nm_act_request_set_default (NMActRequest *req, gboolean is_default)
-{
-	NMActRequestPrivate *priv;
-
-	g_return_if_fail (NM_IS_ACT_REQUEST (req));
-
-	priv = NM_ACT_REQUEST_GET_PRIVATE (req);
-	if (priv->is_default == is_default)
-		return;
-
-	priv->is_default = is_default;
-	g_object_notify (G_OBJECT (req), NM_ACTIVE_CONNECTION_DEFAULT);
+	return G_OBJECT (NM_ACT_REQUEST_GET_PRIVATE (req)->device);
 }
 
 gboolean
-nm_act_request_get_default (NMActRequest *req)
+nm_act_request_get_assumed (NMActRequest *req)
 {
 	g_return_val_if_fail (NM_IS_ACT_REQUEST (req), FALSE);
 
-	return NM_ACT_REQUEST_GET_PRIVATE (req)->is_default;
+	return NM_ACT_REQUEST_GET_PRIVATE (req)->assumed;
 }
 
-void
-nm_act_request_set_default6 (NMActRequest *req, gboolean is_default6)
+NMActiveConnection *
+nm_act_request_get_dependency (NMActRequest *req)
 {
-	NMActRequestPrivate *priv;
-
-	g_return_if_fail (NM_IS_ACT_REQUEST (req));
-
-	priv = NM_ACT_REQUEST_GET_PRIVATE (req);
-	if (priv->is_default6 == is_default6)
-		return;
-
-	priv->is_default6 = is_default6;
-	g_object_notify (G_OBJECT (req), NM_ACTIVE_CONNECTION_DEFAULT6);
+	return NM_ACT_REQUEST_GET_PRIVATE (req)->dep;
 }
 
-gboolean
-nm_act_request_get_default6 (NMActRequest *req)
+static NMActRequestDependencyResult
+ac_state_to_dep_result (NMActiveConnection *ac)
 {
-	g_return_val_if_fail (NM_IS_ACT_REQUEST (req), FALSE);
+	NMActiveConnectionState state = nm_active_connection_get_state (ac);
 
-	return NM_ACT_REQUEST_GET_PRIVATE (req)->is_default6;
-}
+	if (state == NM_ACTIVE_CONNECTION_STATE_ACTIVATING)
+		return NM_ACT_REQUEST_DEP_RESULT_WAIT;
+	else if (state == NM_ACTIVE_CONNECTION_STATE_ACTIVATED)
+		return NM_ACT_REQUEST_DEP_RESULT_READY;
 
-GObject *
-nm_act_request_get_device (NMActRequest *req)
-{
-	g_return_val_if_fail (NM_IS_ACT_REQUEST (req), NULL);
-
-	return G_OBJECT (NM_ACT_REQUEST_GET_PRIVATE (req)->device);
+	return NM_ACT_REQUEST_DEP_RESULT_FAILED;
 }
 
-gboolean
-nm_act_request_get_assumed (NMActRequest *req)
+NMActRequestDependencyResult
+nm_act_request_get_dependency_result (NMActRequest *req)
 {
-	g_return_val_if_fail (NM_IS_ACT_REQUEST (req), FALSE);
+	NMActRequestPrivate *priv = NM_ACT_REQUEST_GET_PRIVATE (req);
 
-	return NM_ACT_REQUEST_GET_PRIVATE (req)->assumed;
+	return priv->dep ? ac_state_to_dep_result (priv->dep) : NM_ACT_REQUEST_DEP_RESULT_READY;
 }
 
 /********************************************************************/
@@ -423,9 +358,7 @@ device_state_changed (NMDevice *device,
                       gpointer user_data)
 {
 	NMActRequest *self = NM_ACT_REQUEST (user_data);
-	NMActRequestPrivate *priv = NM_ACT_REQUEST_GET_PRIVATE (self);
 	NMActiveConnectionState new_ac_state;
-	gboolean new_default = FALSE, new_default6 = FALSE;
 
 	/* Set NMActiveConnection state based on the device's state */
 	switch (new_state) {
@@ -439,43 +372,84 @@ device_state_changed (NMDevice *device,
 		break;
 	case NM_DEVICE_STATE_ACTIVATED:
 		new_ac_state = NM_ACTIVE_CONNECTION_STATE_ACTIVATED;
-		new_default = priv->is_default;
-		new_default6 = priv->is_default6;
 		break;
 	case NM_DEVICE_STATE_DEACTIVATING:
 		new_ac_state = NM_ACTIVE_CONNECTION_STATE_DEACTIVATING;
 		break;
 	default:
 		new_ac_state = NM_ACTIVE_CONNECTION_STATE_UNKNOWN;
-		new_default = new_default6 = FALSE;
+		nm_active_connection_set_default (NM_ACTIVE_CONNECTION (self), FALSE);
+		nm_active_connection_set_default6 (NM_ACTIVE_CONNECTION (self), FALSE);
 		break;
 	}
 
-	if (new_ac_state != priv->state) {
-		priv->state = new_ac_state;
-		g_object_notify (G_OBJECT (self), NM_ACTIVE_CONNECTION_STATE);
-	}
+	nm_active_connection_set_state (NM_ACTIVE_CONNECTION (self), new_ac_state);
+}
 
-	if (new_default != priv->is_default) {
-		priv->is_default = new_default;
-		g_object_notify (G_OBJECT (self), NM_ACTIVE_CONNECTION_DEFAULT);
-	}
+/********************************************************************/
 
-	if (new_default6 != priv->is_default6) {
-		priv->is_default6 = new_default6;
-		g_object_notify (G_OBJECT (self), NM_ACTIVE_CONNECTION_DEFAULT6);
-	}
+static void
+dep_gone (NMActRequest *self, GObject *ignored)
+{
+	NMActRequestPrivate *priv = NM_ACT_REQUEST_GET_PRIVATE (self);
+
+	g_warn_if_fail (G_OBJECT (priv->dep) == ignored);
+
+	/* Dependent connection is gone; clean up and fail */
+	priv->dep = NULL;
+	priv->dep_state_id = 0;
+	g_signal_emit (self, signals[DEP_RESULT], 0, NM_ACT_REQUEST_DEP_RESULT_FAILED);
 }
 
-/********************************************************************/
+static void
+dep_state_changed (NMActiveConnection *dep,
+                   GParamSpec *pspec,
+                   NMActRequest *self)
+{
+	NMActRequestPrivate *priv = NM_ACT_REQUEST_GET_PRIVATE (self);
+	NMActRequestDependencyResult result;
 
+	g_warn_if_fail (priv->dep == dep);
+
+	result = ac_state_to_dep_result (priv->dep);
+	if (result == NM_ACT_REQUEST_DEP_RESULT_FAILED) {
+		g_object_weak_unref (G_OBJECT (priv->dep), (GWeakNotify) dep_gone, self);
+		g_signal_handler_disconnect (priv->dep, priv->dep_state_id);
+		priv->dep = NULL;
+		priv->dep_state_id = 0;
+	}
+	g_signal_emit (self, signals[DEP_RESULT], 0, result);
+}
+
+/**
+ * nm_act_request_new:
+ *
+ * @connection: the connection to activate @device with
+ * @specific_object: the object path of the specific object (ie, WiFi access point,
+ *    etc) that will be used to activate @connection and @device
+ * @user_requested: pass %TRUE if the activation was requested via D-Bus,
+ *    otherwise %FALSE if requested internally by NM (ie, autoconnect)
+ * @user_uid: if @user_requested is %TRUE, the Unix UID of the user that requested
+ *    the activation
+ * @assumed: pass %TRUE if the activation should "assume" (ie, taking over) an
+ *    existing connection made before this instance of NM started
+ * @device: the device/interface to configure according to @connection
+ * @dependency: if the activation depends on another device (ie, VLAN slave,
+ *    bond slave, etc) pass the #NMActiveConnection that this activation request
+ *    should wait for before proceeding
+ *
+ * Begins activation of @device using the given @connection and other details.
+ *
+ * Returns: the new activation request on success, %NULL on error.
+ */
 NMActRequest *
 nm_act_request_new (NMConnection *connection,
                     const char *specific_object,
                     gboolean user_requested,
                     gulong user_uid,
                     gboolean assumed,
-                    gpointer *device)
+                    gpointer *device,
+                    NMActiveConnection *dependency)
 {
 	GObject *object;
 	NMActRequestPrivate *priv;
@@ -483,16 +457,15 @@ nm_act_request_new (NMConnection *connection,
 	g_return_val_if_fail (NM_IS_CONNECTION (connection), NULL);
 	g_return_val_if_fail (NM_DEVICE (device), NULL);
 
-	object = g_object_new (NM_TYPE_ACT_REQUEST, NULL);
+	object = g_object_new (NM_TYPE_ACT_REQUEST,
+	                       NM_ACTIVE_CONNECTION_SPECIFIC_OBJECT, specific_object,
+	                       NULL);
 	if (!object)
 		return NULL;
 
 	priv = NM_ACT_REQUEST_GET_PRIVATE (object);
 
 	priv->connection = g_object_ref (connection);
-	if (specific_object)
-		priv->specific_object = g_strdup (specific_object);
-
 	priv->device = NM_DEVICE (device);
 	g_signal_connect (device, "state-changed",
 	                  G_CALLBACK (device_state_changed),
@@ -502,23 +475,28 @@ nm_act_request_new (NMConnection *connection,
 	priv->user_requested = user_requested;
 	priv->assumed = assumed;
 
-	return NM_ACT_REQUEST (object);
+	if (dependency) {
+		priv->dep = dependency;
+		g_object_weak_ref (G_OBJECT (dependency), (GWeakNotify) dep_gone, object);
+		priv->dep_state_id = g_signal_connect (dependency,
+		                                       "notify::" NM_ACTIVE_CONNECTION_STATE,
+		                                       G_CALLBACK (dep_state_changed),
+		                                       object);
+	}
+
+	if (!nm_active_connection_export (NM_ACTIVE_CONNECTION (object),
+	                                  connection,
+	                                  nm_device_get_path (NM_DEVICE (device)))) {
+		g_object_unref (object);
+		object = NULL;
+	}
+
+	return (NMActRequest *) object;
 }
 
 static void
 nm_act_request_init (NMActRequest *req)
 {
-	NMActRequestPrivate *priv = NM_ACT_REQUEST_GET_PRIVATE (req);
-	NMDBusManager *dbus_mgr;
-
-	priv->ac_path = nm_active_connection_get_next_object_path ();
-	priv->state = NM_ACTIVE_CONNECTION_STATE_UNKNOWN;
-
-	dbus_mgr = nm_dbus_manager_get ();
-	dbus_g_connection_register_g_object (nm_dbus_manager_get_connection (dbus_mgr),
-	                                     priv->ac_path,
-	                                     G_OBJECT (req));
-	g_object_unref (dbus_mgr);
 }
 
 static void
@@ -526,38 +504,17 @@ get_property (GObject *object, guint prop_id,
 			  GValue *value, GParamSpec *pspec)
 {
 	NMActRequestPrivate *priv = NM_ACT_REQUEST_GET_PRIVATE (object);
-	GPtrArray *devices;
+	NMDevice *master;
 
 	switch (prop_id) {
-	case PROP_CONNECTION:
-		g_value_set_boxed (value, nm_connection_get_path (priv->connection));
-		break;
-	case PROP_UUID:
-		g_value_set_string (value, nm_connection_get_uuid (priv->connection));
-		break;
-	case PROP_SPECIFIC_OBJECT:
-		if (priv->specific_object)
-			g_value_set_boxed (value, priv->specific_object);
-		else
+	case PROP_MASTER:
+		if (priv->dep && NM_IS_ACT_REQUEST (priv->dep)) {
+			master = NM_DEVICE (nm_act_request_get_device (NM_ACT_REQUEST (priv->dep)));
+			g_assert (master);
+			g_value_set_boxed (value, nm_device_get_path (master));
+		} else
 			g_value_set_boxed (value, "/");
 		break;
-	case PROP_DEVICES:
-		devices = g_ptr_array_sized_new (1);
-		g_ptr_array_add (devices, g_strdup (nm_device_get_path (priv->device)));
-		g_value_take_boxed (value, devices);
-		break;
-	case PROP_STATE:
-		g_value_set_uint (value, priv->state);
-		break;
-	case PROP_DEFAULT:
-		g_value_set_boolean (value, priv->is_default);
-		break;
-	case PROP_DEFAULT6:
-		g_value_set_boolean (value, priv->is_default6);
-		break;
-	case PROP_VPN:
-		g_value_set_boolean (value, FALSE);
-		break;
 	default:
 		G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
 		break;
@@ -595,17 +552,19 @@ dispose (GObject *object)
 
 	g_object_unref (priv->connection);
 
+	if (priv->dep) {
+		g_object_weak_unref (G_OBJECT (priv->dep), (GWeakNotify) dep_gone, object);
+		g_signal_handler_disconnect (priv->dep, priv->dep_state_id);
+		priv->dep = NULL;
+		priv->dep_state_id = 0;
+	}
+
 	G_OBJECT_CLASS (nm_act_request_parent_class)->dispose (object);
 }
 
 static void
 finalize (GObject *object)
 {
-	NMActRequestPrivate *priv = NM_ACT_REQUEST_GET_PRIVATE (object);
-
-	g_free (priv->specific_object);
-	g_free (priv->ac_path);
-
 	clear_share_rules (NM_ACT_REQUEST (object));
 
 	G_OBJECT_CLASS (nm_act_request_parent_class)->finalize (object);
@@ -623,23 +582,14 @@ nm_act_request_class_init (NMActRequestClass *req_class)
 	object_class->dispose = dispose;
 	object_class->finalize = finalize;
 
-	/* properties */
-    nm_active_connection_install_properties (object_class,
-                                             PROP_CONNECTION,
-                                             PROP_UUID,
-                                             PROP_SPECIFIC_OBJECT,
-                                             PROP_DEVICES,
-                                             PROP_STATE,
-                                             PROP_DEFAULT,
-                                             PROP_DEFAULT6,
-                                             PROP_VPN);
-
-	/* Signals */
-	signals[PROPERTIES_CHANGED] = 
-		nm_properties_changed_signal_new (object_class,
-		                                  G_STRUCT_OFFSET (NMActRequestClass, properties_changed));
-
-	dbus_g_object_type_install_info (G_TYPE_FROM_CLASS (req_class),
-	                                 &dbus_glib_nm_active_connection_object_info);
+	g_object_class_override_property (object_class, PROP_MASTER, NM_ACTIVE_CONNECTION_MASTER);
+
+	signals[DEP_RESULT] =
+		g_signal_new (NM_ACT_REQUEST_DEPENDENCY_RESULT,
+					  G_OBJECT_CLASS_TYPE (object_class),
+					  G_SIGNAL_RUN_FIRST,
+					  0, NULL, NULL,
+					  g_cclosure_marshal_VOID__UINT,
+					  G_TYPE_NONE, 1, G_TYPE_UINT);
 }
 
diff --git a/src/nm-activation-request.h b/src/nm-activation-request.h
index dac9d89a..d7c094e6 100644
--- a/src/nm-activation-request.h
+++ b/src/nm-activation-request.h
@@ -34,6 +34,15 @@
 #define NM_IS_ACT_REQUEST_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((obj), NM_TYPE_ACT_REQUEST))
 #define NM_ACT_REQUEST_GET_CLASS(obj)  (G_TYPE_INSTANCE_GET_CLASS ((obj), NM_TYPE_ACT_REQUEST, NMActRequestClass))
 
+typedef enum {
+	NM_ACT_REQUEST_DEP_RESULT_UNKNOWN,
+	NM_ACT_REQUEST_DEP_RESULT_WAIT,
+	NM_ACT_REQUEST_DEP_RESULT_READY,
+	NM_ACT_REQUEST_DEP_RESULT_FAILED,
+} NMActRequestDependencyResult;
+
+#define NM_ACT_REQUEST_DEPENDENCY_RESULT "dependency-result"
+
 typedef struct {
 	GObject parent;
 } NMActRequest;
@@ -43,6 +52,8 @@ typedef struct {
 
 	/* Signals */
 	void (*properties_changed) (NMActRequest *req, GHashTable *properties);
+
+	void (*dependency_result) (NMActRequest *req, NMActRequestDependencyResult result);
 } NMActRequestClass;
 
 GType nm_act_request_get_type (void);
@@ -52,26 +63,13 @@ NMActRequest *nm_act_request_new          (NMConnection *connection,
                                            gboolean user_requested,
                                            gulong user_uid,
                                            gboolean assumed,
-                                           gpointer *device);  /* An NMDevice */
+                                           gpointer *device,  /* An NMDevice */
+                                           NMActiveConnection *dependency);
 
 NMConnection *nm_act_request_get_connection     (NMActRequest *req);
-const char *  nm_act_request_get_specific_object (NMActRequest *req);
-
-void          nm_act_request_set_specific_object (NMActRequest *req,
-                                                  const char *specific_object);
 
 gboolean      nm_act_request_get_user_requested (NMActRequest *req);
 
-const char *  nm_act_request_get_active_connection_path (NMActRequest *req);
-
-void          nm_act_request_set_default (NMActRequest *req, gboolean is_default);
-
-gboolean      nm_act_request_get_default (NMActRequest *req);
-
-void          nm_act_request_set_default6 (NMActRequest *req, gboolean is_default6);
-
-gboolean      nm_act_request_get_default6 (NMActRequest *req);
-
 gboolean      nm_act_request_get_shared (NMActRequest *req);
 
 void          nm_act_request_set_shared (NMActRequest *req, gboolean shared);
@@ -84,6 +82,10 @@ GObject *     nm_act_request_get_device (NMActRequest *req);
 
 gboolean      nm_act_request_get_assumed (NMActRequest *req);
 
+NMActiveConnection *         nm_act_request_get_dependency (NMActRequest *req);
+
+NMActRequestDependencyResult nm_act_request_get_dependency_result (NMActRequest *req);
+
 /* Secrets handling */
 
 typedef void (*NMActRequestSecretsFunc) (NMActRequest *req,
diff --git a/src/nm-active-connection.c b/src/nm-active-connection.c
index ae2afb07..2de62197 100644
--- a/src/nm-active-connection.c
+++ b/src/nm-active-connection.c
@@ -15,7 +15,7 @@
  * with this program; if not, write to the Free Software Foundation, Inc.,
  * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
  *
- * Copyright (C) 2008 - 2010 Red Hat, Inc.
+ * Copyright (C) 2008 - 2012 Red Hat, Inc.
  */
 
 #include <glib.h>
@@ -23,55 +23,306 @@
 #include "NetworkManager.h"
 #include "nm-logging.h"
 #include "nm-dbus-glib-types.h"
+#include "nm-dbus-manager.h"
+#include "nm-properties-changed-signal.h"
 
-char *
-nm_active_connection_get_next_object_path (void)
+#include "nm-active-connection-glue.h"
+
+/* Base class for anything implementing the Connection.Active D-Bus interface */
+G_DEFINE_ABSTRACT_TYPE (NMActiveConnection, nm_active_connection, G_TYPE_OBJECT)
+
+#define NM_ACTIVE_CONNECTION_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), \
+                                             NM_TYPE_ACTIVE_CONNECTION, \
+                                             NMActiveConnectionPrivate))
+
+typedef struct {
+	gboolean disposed;
+
+	NMConnection *connection;
+	char *path;
+	char *specific_object;
+	char *device_path;
+	gboolean is_default;
+	gboolean is_default6;
+	NMActiveConnectionState state;
+	gboolean vpn;
+} NMActiveConnectionPrivate;
+
+enum {
+	PROP_0,
+	PROP_CONNECTION,
+	PROP_UUID,
+	PROP_SPECIFIC_OBJECT,
+	PROP_DEVICES,
+	PROP_STATE,
+	PROP_DEFAULT,
+	PROP_DEFAULT6,
+	PROP_VPN,
+	PROP_MASTER,
+
+	LAST_PROP
+};
+
+enum {
+	PROPERTIES_CHANGED,
+	LAST_SIGNAL
+};
+static guint signals[LAST_SIGNAL] = { 0 };
+
+/****************************************************************/
+
+NMActiveConnectionState
+nm_active_connection_get_state (NMActiveConnection *self)
 {
-	static guint32 counter = 0;
+	return NM_ACTIVE_CONNECTION_GET_PRIVATE (self)->state;
+}
 
-	return g_strdup_printf (NM_DBUS_PATH "/ActiveConnection/%d", counter++);
+void
+nm_active_connection_set_state (NMActiveConnection *self,
+                                NMActiveConnectionState new_state)
+{
+	NMActiveConnectionPrivate *priv = NM_ACTIVE_CONNECTION_GET_PRIVATE (self);
+
+	if (priv->state != new_state) {
+		priv->state = new_state;
+		g_object_notify (G_OBJECT (self), NM_ACTIVE_CONNECTION_STATE);
+	}
+}
+
+NMConnection *
+nm_active_connection_get_connection (NMActiveConnection *self)
+{
+	return NM_ACTIVE_CONNECTION_GET_PRIVATE (self)->connection;
+}
+
+const char *
+nm_active_connection_get_path (NMActiveConnection *self)
+{
+	return NM_ACTIVE_CONNECTION_GET_PRIVATE (self)->path;
+}
+
+const char *
+nm_active_connection_get_specific_object (NMActiveConnection *self)
+{
+	return NM_ACTIVE_CONNECTION_GET_PRIVATE (self)->specific_object;
 }
 
 void
-nm_active_connection_install_properties (GObjectClass *object_class,
-                                         guint prop_connection,
-                                         guint prop_uuid,
-                                         guint prop_specific_object,
-                                         guint prop_devices,
-                                         guint prop_state,
-                                         guint prop_default,
-                                         guint prop_default6,
-                                         guint prop_vpn)
-{
-	g_object_class_install_property (object_class, prop_connection,
+nm_active_connection_set_specific_object (NMActiveConnection *self,
+                                          const char *specific_object)
+{
+	NMActiveConnectionPrivate *priv = NM_ACTIVE_CONNECTION_GET_PRIVATE (self);
+
+	if (g_strcmp0 (priv->specific_object, specific_object) == 0)
+		return;
+
+	g_free (priv->specific_object);
+	priv->specific_object = g_strdup (specific_object);
+	g_object_notify (G_OBJECT (self), NM_ACTIVE_CONNECTION_SPECIFIC_OBJECT);
+}
+
+void
+nm_active_connection_set_default (NMActiveConnection *self, gboolean is_default)
+{
+	NMActiveConnectionPrivate *priv;
+
+	g_return_if_fail (NM_IS_ACTIVE_CONNECTION (self));
+
+	priv = NM_ACTIVE_CONNECTION_GET_PRIVATE (self);
+	if (priv->is_default == is_default)
+		return;
+
+	priv->is_default = is_default;
+	g_object_notify (G_OBJECT (self), NM_ACTIVE_CONNECTION_DEFAULT);
+}
+
+gboolean
+nm_active_connection_get_default (NMActiveConnection *self)
+{
+	g_return_val_if_fail (NM_IS_ACTIVE_CONNECTION (self), FALSE);
+
+	return NM_ACTIVE_CONNECTION_GET_PRIVATE (self)->is_default;
+}
+
+void
+nm_active_connection_set_default6 (NMActiveConnection *self, gboolean is_default6)
+{
+	NMActiveConnectionPrivate *priv;
+
+	g_return_if_fail (NM_IS_ACTIVE_CONNECTION (self));
+
+	priv = NM_ACTIVE_CONNECTION_GET_PRIVATE (self);
+	if (priv->is_default6 == is_default6)
+		return;
+
+	priv->is_default6 = is_default6;
+	g_object_notify (G_OBJECT (self), NM_ACTIVE_CONNECTION_DEFAULT6);
+}
+
+gboolean
+nm_active_connection_get_default6 (NMActiveConnection *self)
+{
+	g_return_val_if_fail (NM_IS_ACTIVE_CONNECTION (self), FALSE);
+
+	return NM_ACTIVE_CONNECTION_GET_PRIVATE (self)->is_default6;
+}
+
+gboolean
+nm_active_connection_export (NMActiveConnection *self,
+                             NMConnection *connection,
+                             const char *devpath)
+{
+	NMActiveConnectionPrivate *priv = NM_ACTIVE_CONNECTION_GET_PRIVATE (self);
+	NMDBusManager *dbus_mgr;
+	static guint32 counter = 0;
+
+	g_return_val_if_fail (connection != NULL, FALSE);
+	g_return_val_if_fail (devpath != NULL, FALSE);
+
+	priv->connection = g_object_ref (connection);
+	priv->path = g_strdup_printf (NM_DBUS_PATH "/ActiveConnection/%d", counter++);
+	priv->device_path = g_strdup (devpath);
+
+	dbus_mgr = nm_dbus_manager_get ();
+	dbus_g_connection_register_g_object (nm_dbus_manager_get_connection (dbus_mgr),
+	                                     priv->path, G_OBJECT (self));
+	g_object_unref (dbus_mgr);
+	return TRUE;
+}
+
+/****************************************************************/
+
+static void
+nm_active_connection_init (NMActiveConnection *self)
+{
+}
+
+static void
+dispose (GObject *object)
+{
+	NMActiveConnectionPrivate *priv = NM_ACTIVE_CONNECTION_GET_PRIVATE (object);
+
+	if (!priv->disposed) {
+		priv->disposed = TRUE;
+
+		g_free (priv->path);
+		g_free (priv->specific_object);
+		g_free (priv->device_path);
+		g_object_unref (priv->connection);
+	}
+
+	G_OBJECT_CLASS (nm_active_connection_parent_class)->dispose (object);
+}
+
+static void
+set_property (GObject *object, guint prop_id,
+			  const GValue *value, GParamSpec *pspec)
+{
+	NMActiveConnectionPrivate *priv = NM_ACTIVE_CONNECTION_GET_PRIVATE (object);
+
+	switch (prop_id) {
+	case PROP_SPECIFIC_OBJECT:
+		priv->specific_object = g_value_dup_boxed (value);
+		break;
+	case PROP_DEFAULT:
+		priv->is_default = g_value_get_boolean (value);
+		break;
+	case PROP_DEFAULT6:
+		priv->is_default6 = g_value_get_boolean (value);
+		break;
+	case PROP_VPN:
+		priv->vpn = g_value_get_boolean (value);
+		break;
+	default:
+		G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+		break;
+	}
+}
+
+static void
+get_property (GObject *object, guint prop_id,
+			  GValue *value, GParamSpec *pspec)
+{
+	NMActiveConnectionPrivate *priv = NM_ACTIVE_CONNECTION_GET_PRIVATE (object);
+	GPtrArray *devices;
+
+	switch (prop_id) {
+	case PROP_CONNECTION:
+		g_value_set_boxed (value, nm_connection_get_path (priv->connection));
+		break;
+	case PROP_UUID:
+		g_value_set_string (value, nm_connection_get_uuid (priv->connection));
+		break;
+	case PROP_SPECIFIC_OBJECT:
+		g_value_set_boxed (value, priv->specific_object ? priv->specific_object : "/");
+		break;
+	case PROP_DEVICES:
+		devices = g_ptr_array_sized_new (1);
+		g_ptr_array_add (devices, g_strdup (priv->device_path));
+		g_value_take_boxed (value, devices);
+		break;
+	case PROP_STATE:
+		g_value_set_uint (value, priv->state);
+		break;
+	case PROP_DEFAULT:
+		g_value_set_boolean (value, priv->is_default);
+		break;
+	case PROP_DEFAULT6:
+		g_value_set_boolean (value, priv->is_default6);
+		break;
+	case PROP_VPN:
+		g_value_set_boolean (value, priv->vpn);
+		break;
+	case PROP_MASTER:
+		break;
+	default:
+		G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+		break;
+	}
+}
+
+static void
+nm_active_connection_class_init (NMActiveConnectionClass *vpn_class)
+{
+	GObjectClass *object_class = G_OBJECT_CLASS (vpn_class);
+
+	g_type_class_add_private (vpn_class, sizeof (NMActiveConnectionPrivate));
+
+	/* virtual methods */
+	object_class->get_property = get_property;
+	object_class->set_property = set_property;
+	object_class->dispose = dispose;
+
+	/* properties */
+	g_object_class_install_property (object_class, PROP_CONNECTION,
 		g_param_spec_boxed (NM_ACTIVE_CONNECTION_CONNECTION,
 		                    "Connection",
 		                    "Connection",
 		                    DBUS_TYPE_G_OBJECT_PATH,
 		                    G_PARAM_READABLE));
 
-	g_object_class_install_property (object_class, prop_uuid,
+	g_object_class_install_property (object_class, PROP_UUID,
 		g_param_spec_string (NM_ACTIVE_CONNECTION_UUID,
 		                     "Connection UUID",
 		                     "Connection UUID",
 		                     NULL,
 		                     G_PARAM_READABLE));
 
-	g_object_class_install_property (object_class, prop_specific_object,
+	g_object_class_install_property (object_class, PROP_SPECIFIC_OBJECT,
 		g_param_spec_boxed (NM_ACTIVE_CONNECTION_SPECIFIC_OBJECT,
 		                    "Specific object",
 		                    "Specific object",
 		                    DBUS_TYPE_G_OBJECT_PATH,
-		                    G_PARAM_READABLE));
+		                    G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY));
 
-	g_object_class_install_property (object_class, prop_devices,
+	g_object_class_install_property (object_class, PROP_DEVICES,
 		g_param_spec_boxed (NM_ACTIVE_CONNECTION_DEVICES,
 		                    "Devices",
 		                    "Devices",
 		                    DBUS_TYPE_G_ARRAY_OF_OBJECT_PATH,
 		                    G_PARAM_READABLE));
 
-	g_object_class_install_property (object_class, prop_state,
+	g_object_class_install_property (object_class, PROP_STATE,
 		g_param_spec_uint (NM_ACTIVE_CONNECTION_STATE,
 		                   "State",
 		                   "State",
@@ -80,25 +331,40 @@ nm_active_connection_install_properties (GObjectClass *object_class,
 		                   NM_ACTIVE_CONNECTION_STATE_UNKNOWN,
 		                   G_PARAM_READABLE));
 
-	g_object_class_install_property (object_class, prop_default,
+	g_object_class_install_property (object_class, PROP_DEFAULT,
 		g_param_spec_boolean (NM_ACTIVE_CONNECTION_DEFAULT,
 		                      "Default",
 		                      "Is the default IPv4 active connection",
 		                      FALSE,
-		                      G_PARAM_READABLE));
+		                      G_PARAM_READWRITE));
 
-	g_object_class_install_property (object_class, prop_default6,
+	g_object_class_install_property (object_class, PROP_DEFAULT6,
 		g_param_spec_boolean (NM_ACTIVE_CONNECTION_DEFAULT6,
 		                      "Default6",
 		                      "Is the default IPv6 active connection",
 		                      FALSE,
-		                      G_PARAM_READABLE));
+		                      G_PARAM_READWRITE));
 
-	g_object_class_install_property (object_class, prop_vpn,
+	g_object_class_install_property (object_class, PROP_VPN,
 		g_param_spec_boolean (NM_ACTIVE_CONNECTION_VPN,
 		                      "VPN",
 		                      "Is a VPN connection",
 		                      FALSE,
-		                      G_PARAM_READABLE));
+		                      G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY));
+
+	g_object_class_install_property (object_class, PROP_MASTER,
+		g_param_spec_boxed (NM_ACTIVE_CONNECTION_MASTER,
+		                    "Master",
+		                    "Path of master device",
+		                    DBUS_TYPE_G_OBJECT_PATH,
+		                    G_PARAM_READABLE));
+
+	/* Signals */
+	signals[PROPERTIES_CHANGED] = 
+		nm_properties_changed_signal_new (object_class,
+		                                  G_STRUCT_OFFSET (NMActiveConnectionClass, properties_changed));
+
+	dbus_g_object_type_install_info (G_TYPE_FROM_CLASS (vpn_class),
+									 &dbus_glib_nm_active_connection_object_info);
 }
 
diff --git a/src/nm-active-connection.h b/src/nm-active-connection.h
index 4bd8c78e..419cbcff 100644
--- a/src/nm-active-connection.h
+++ b/src/nm-active-connection.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) 2008 - 2010 Red Hat, Inc.
+ * Copyright (C) 2008 - 2012 Red Hat, Inc.
  */
 
 #ifndef NM_ACTIVE_CONNECTION_H
@@ -24,25 +24,63 @@
 #include <glib-object.h>
 #include "nm-connection.h"
 
-#define NM_ACTIVE_CONNECTION_CONNECTION "connection"
-#define NM_ACTIVE_CONNECTION_UUID "uuid"
+#define NM_TYPE_ACTIVE_CONNECTION            (nm_active_connection_get_type ())
+#define NM_ACTIVE_CONNECTION(obj)            (G_TYPE_CHECK_INSTANCE_CAST ((obj), NM_TYPE_ACTIVE_CONNECTION, NMActiveConnection))
+#define NM_ACTIVE_CONNECTION_CLASS(klass)    (G_TYPE_CHECK_CLASS_CAST ((klass), NM_TYPE_ACTIVE_CONNECTION, NMActiveConnectionClass))
+#define NM_IS_ACTIVE_CONNECTION(obj)         (G_TYPE_CHECK_INSTANCE_TYPE ((obj), NM_TYPE_ACTIVE_CONNECTION))
+#define NM_IS_ACTIVE_CONNECTION_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((obj), NM_TYPE_ACTIVE_CONNECTION))
+#define NM_ACTIVE_CONNECTION_GET_CLASS(obj)  (G_TYPE_INSTANCE_GET_CLASS ((obj), NM_TYPE_ACTIVE_CONNECTION, NMActiveConnectionClass))
+
+/* Properties */
+#define NM_ACTIVE_CONNECTION_CONNECTION      "connection"
+#define NM_ACTIVE_CONNECTION_UUID            "uuid"
 #define NM_ACTIVE_CONNECTION_SPECIFIC_OBJECT "specific-object"
-#define NM_ACTIVE_CONNECTION_DEVICES "devices"
-#define NM_ACTIVE_CONNECTION_STATE "state"
-#define NM_ACTIVE_CONNECTION_DEFAULT "default"
-#define NM_ACTIVE_CONNECTION_DEFAULT6 "default6"
-#define NM_ACTIVE_CONNECTION_VPN "vpn"
-
-char *nm_active_connection_get_next_object_path (void);
-
-void nm_active_connection_install_properties (GObjectClass *object_class,
-                                              guint prop_connection,
-                                              guint prop_uuid,
-                                              guint prop_specific_object,
-                                              guint prop_devices,
-                                              guint prop_state,
-                                              guint prop_default,
-                                              guint prop_default6,
-                                              guint prop_vpn);
+#define NM_ACTIVE_CONNECTION_DEVICES         "devices"
+#define NM_ACTIVE_CONNECTION_STATE           "state"
+#define NM_ACTIVE_CONNECTION_DEFAULT         "default"
+#define NM_ACTIVE_CONNECTION_DEFAULT6        "default6"
+#define NM_ACTIVE_CONNECTION_VPN             "vpn"
+#define NM_ACTIVE_CONNECTION_MASTER          "master"
+
+typedef struct {
+	GObject parent;
+} NMActiveConnection;
+
+typedef struct {
+	GObjectClass parent;
+
+	/* Signals */
+	void (*properties_changed) (NMActiveConnection *req, GHashTable *properties);
+} NMActiveConnectionClass;
+
+GType         nm_active_connection_get_type (void);
+
+gboolean      nm_active_connection_export (NMActiveConnection *self,
+                                           NMConnection *connection,
+                                           const char *devpath);
+
+NMConnection *nm_active_connection_get_connection (NMActiveConnection *self);
+
+const char *  nm_active_connection_get_path (NMActiveConnection *self);
+
+const char *  nm_active_connection_get_specific_object (NMActiveConnection *self);
+
+void          nm_active_connection_set_specific_object (NMActiveConnection *self,
+                                                        const char *specific_object);
+
+void          nm_active_connection_set_default (NMActiveConnection *self,
+                                                gboolean is_default);
+
+gboolean      nm_active_connection_get_default (NMActiveConnection *self);
+
+void          nm_active_connection_set_default6 (NMActiveConnection *self,
+                                                 gboolean is_default6);
+
+gboolean      nm_active_connection_get_default6 (NMActiveConnection *self);
+
+NMActiveConnectionState nm_active_connection_get_state (NMActiveConnection *self);
+
+void          nm_active_connection_set_state (NMActiveConnection *self,
+                                              NMActiveConnectionState state);
 
 #endif /* NM_ACTIVE_CONNECTION_H */
diff --git a/src/nm-config.c b/src/nm-config.c
index 71f67d55..f64b8bdb 100644
--- a/src/nm-config.c
+++ b/src/nm-config.c
@@ -34,6 +34,9 @@ struct NMConfig {
 	char **dns_plugins;
 	char *log_level;
 	char *log_domains;
+	char *connectivity_uri;
+	guint connectivity_interval;
+	char *connectivity_response;
 };
 
 /************************************************************************/
@@ -47,25 +50,6 @@ nm_config_error_quark (void)
 	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 *
@@ -116,6 +100,31 @@ nm_config_get_log_domains (NMConfig *config)
 	return config->log_domains;
 }
 
+const char *
+nm_config_get_connectivity_uri (NMConfig *config)
+{
+	g_return_val_if_fail (config != NULL, NULL);
+
+	return config->connectivity_uri;
+}
+
+const guint
+nm_config_get_connectivity_interval (NMConfig *config)
+{
+	g_return_val_if_fail (config != NULL, -1);
+
+	return config->connectivity_interval;
+}
+
+const char *
+nm_config_get_connectivity_response (NMConfig *config)
+{
+	g_return_val_if_fail (config != NULL, NULL);
+
+	return config->connectivity_response;
+}
+
+
 /************************************************************************/
 
 static gboolean
@@ -124,6 +133,9 @@ fill_from_file (NMConfig *config,
                 const char *cli_plugins,
                 const char *cli_log_level,
                 const char *cli_log_domains,
+                const char *cli_connectivity_uri,
+                const gint cli_connectivity_interval,
+                const char *cli_connectivity_response,
                 GError **error)
 {
 	GKeyFile *kf;
@@ -163,6 +175,22 @@ fill_from_file (NMConfig *config,
 			config->log_domains = g_strdup (cli_log_domains);
 		else
 			config->log_domains = g_key_file_get_value (kf, "logging", "domains", NULL);
+
+		if (cli_connectivity_uri && strlen (cli_connectivity_uri))
+			config->connectivity_uri = g_strdup (cli_connectivity_uri);
+		else
+			config->connectivity_uri = g_key_file_get_value (kf, "connectivity", "uri", NULL);
+
+		if (cli_connectivity_interval >= 0)
+			config->connectivity_interval = cli_connectivity_interval;
+		else
+			config->connectivity_interval = g_key_file_get_integer (kf, "connectivity", "interval", NULL);
+
+		if (cli_connectivity_response && strlen (cli_connectivity_response))
+			config->connectivity_response = g_strdup (cli_connectivity_response);
+		else
+			config->connectivity_response = g_key_file_get_value (kf, "connectivity", "response", NULL);
+
 		success = TRUE;
 	}
 
@@ -175,6 +203,9 @@ nm_config_new (const char *cli_config_path,
                const char *cli_plugins,
                const char *cli_log_level,
                const char *cli_log_domains,
+               const char *cli_connectivity_uri,
+               const gint cli_connectivity_interval,
+               const char *cli_connectivity_response,
                GError **error)
 {
 	NMConfig *config;
@@ -184,7 +215,9 @@ nm_config_new (const char *cli_config_path,
 
 	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)) {
+		if (!fill_from_file (config, cli_config_path, cli_plugins, cli_log_level, cli_log_domains,
+		                     cli_connectivity_uri, cli_connectivity_interval, cli_connectivity_response,
+		                     error)) {
 			nm_config_free (config);
 			return NULL;
 		}
@@ -199,7 +232,9 @@ nm_config_new (const char *cli_config_path,
 	 */
 
 	/* 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))
+	if (fill_from_file (config, NM_OLD_SYSTEM_CONF_FILE, cli_plugins, cli_log_level, cli_log_domains,
+	                    cli_connectivity_uri, cli_connectivity_interval, cli_connectivity_response,
+	                    &local))
 		return config;
 
 	if (g_error_matches (local, G_KEY_FILE_ERROR, G_KEY_FILE_ERROR_NOT_FOUND) == FALSE) {
@@ -211,7 +246,9 @@ nm_config_new (const char *cli_config_path,
 	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))
+	if (fill_from_file (config, NM_DEFAULT_SYSTEM_CONF_FILE, cli_plugins, cli_log_level, cli_log_domains,
+	                    cli_connectivity_uri, cli_connectivity_interval, cli_connectivity_response,
+	                    &local))
 		return config;
 
 	if (g_error_matches (local, G_KEY_FILE_ERROR, G_KEY_FILE_ERROR_NOT_FOUND) == FALSE) {
@@ -224,6 +261,15 @@ nm_config_new (const char *cli_config_path,
 		return NULL;
 	}
 
+	/* If for some reason no config file exists, and NM wasn't given on on
+	 * the command line, just use the default config file path.
+	 */
+	if (config->path == NULL) {
+		config->path = g_strdup (NM_DEFAULT_SYSTEM_CONF_FILE);
+		fprintf (stderr, "No config file found or given; using %s\n",
+		         NM_DEFAULT_SYSTEM_CONF_FILE);
+	}
+
 	/* ignore error if config file not found */
 	g_clear_error (&local);
 	return config;
@@ -240,7 +286,8 @@ nm_config_free (NMConfig *config)
 	g_strfreev (config->dns_plugins);
 	g_free (config->log_level);
 	g_free (config->log_domains);
-
+	g_free (config->connectivity_uri);
+	g_free (config->connectivity_response);
 	memset (config, 0, sizeof (*config));
 	g_free (config);
 }
diff --git a/src/nm-config.h b/src/nm-config.h
index fae344fb..6c4206c1 100644
--- a/src/nm-config.h
+++ b/src/nm-config.h
@@ -27,19 +27,20 @@
 typedef struct NMConfig NMConfig;
 
 typedef enum {
-	NM_CONFIG_ERROR_NO_MEMORY = 0,
+	NM_CONFIG_ERROR_NO_MEMORY = 0, /*< nick=NoMemory >*/
 } 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,
+                         const char *cli_connectivity_check_uri,
+                         const gint connectivity_check_interval,
+                         const char *cli_connectivity_check_response,
                          GError **error);
 
 const char *nm_config_get_path (NMConfig *config);
@@ -48,6 +49,9 @@ 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);
+const char *nm_config_get_connectivity_uri (NMConfig *config);
+const guint nm_config_get_connectivity_interval (NMConfig *config);
+const char *nm_config_get_connectivity_response (NMConfig *config);
 
 void nm_config_free (NMConfig *config);
 
diff --git a/src/nm-connectivity.c b/src/nm-connectivity.c
new file mode 100644
index 00000000..7e0de2c1
--- /dev/null
+++ b/src/nm-connectivity.c
@@ -0,0 +1,368 @@
+/* -*- 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 Thomas Bechtold <thomasbechtold@jpberlin.de>
+ * Copyright (C) 2011 Dan Williams <dcbw@redhat.com>
+ */
+
+#include <config.h>
+
+#include <string.h>
+#include <libsoup/soup.h>
+
+#include "nm-connectivity.h"
+#include "nm-logging.h"
+#include "nm-manager.h"
+
+G_DEFINE_TYPE (NMConnectivity, nm_connectivity, G_TYPE_OBJECT)
+
+#define NM_CONNECTIVITY_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), NM_TYPE_CONNECTIVITY, NMConnectivityPrivate))
+
+
+#define DEFAULT_RESPONSE "NetworkManager is online" /* NOT LOCALIZED */
+
+typedef struct {
+	/* used for http requests */
+	SoupSession *soup_session;
+	/* indicates if a connectivity check is currently running */
+	gboolean running;
+	/* the uri to check */
+	char *uri;
+	/* seconds when a check will be repeated */
+	guint interval;
+	/* the expected response for the connectivity check */
+	char *response;
+	/* indicates if the last connection check was successful */
+	gboolean connected;
+	/* the source id for the periodic check */
+	guint check_id;
+} NMConnectivityPrivate;
+
+enum {
+	PROP_0,
+	PROP_RUNNING,
+	PROP_URI,
+	PROP_INTERVAL,
+	PROP_RESPONSE,
+	PROP_CONNECTED,
+	LAST_PROP
+};
+
+
+gboolean
+nm_connectivity_get_connected (NMConnectivity *connectivity)
+{
+	g_return_val_if_fail (NM_IS_CONNECTIVITY (connectivity), FALSE);
+
+	return NM_CONNECTIVITY_GET_PRIVATE (connectivity)->connected;
+}
+
+static void
+update_connected (NMConnectivity *self, gboolean connected)
+{
+	NMConnectivityPrivate *priv = NM_CONNECTIVITY_GET_PRIVATE (self);
+	gboolean old_connected = priv->connected;
+
+	if (priv->uri == NULL || priv->interval == 0) {
+		/* Default to connected if no checks are to be run */
+		priv->connected = TRUE;
+	} else
+		priv->connected = connected;
+
+	if (priv->connected != old_connected)
+		g_object_notify (G_OBJECT (self), NM_CONNECTIVITY_CONNECTED);
+}
+
+static void
+nm_connectivity_check_cb (SoupSession *session, SoupMessage *msg, gpointer user_data)
+{
+	NMConnectivity *self = NM_CONNECTIVITY (user_data);
+	NMConnectivityPrivate *priv = NM_CONNECTIVITY_GET_PRIVATE (self);
+	SoupURI *soup_uri;
+	gboolean connected_new = FALSE;
+	const char *nm_header;
+	char *uri_string;
+
+	soup_uri = soup_message_get_uri (msg);
+	uri_string = soup_uri_to_string (soup_uri, FALSE);
+
+	/* Check headers; if we find the NM-specific one we're done */
+	nm_header = soup_message_headers_get_one (msg->response_headers, "X-NetworkManager-Status");
+	if (g_strcmp0 (nm_header, "online") == 0) {
+		nm_log_dbg (LOGD_CORE, "Connectivity check for uri '%s' with Status header successful.", uri_string);
+		connected_new = TRUE;
+	} else {
+		/* check response */
+		if (msg->response_body->data &&	(g_str_has_prefix (msg->response_body->data, priv->response))) {
+			nm_log_dbg (LOGD_CORE, "Connectivity check for uri '%s' with expected response '%s' successful.",
+				        uri_string, priv->response);
+			connected_new = TRUE;
+		} else {
+			nm_log_dbg (LOGD_CORE, "Connectivity check for uri '%s' with expected response '%s' failed (status %d).",
+						uri_string, priv->response, msg->status_code);
+		}
+	}
+	g_free (uri_string);
+
+	/* update connectivity and emit signal */
+	update_connected (self, connected_new);
+
+	priv->running = FALSE;
+	g_object_notify (G_OBJECT (self), NM_CONNECTIVITY_RUNNING);
+}
+
+static gboolean
+run_check (gpointer user_data)
+{
+	NMConnectivity *self = NM_CONNECTIVITY (user_data);
+	NMConnectivityPrivate *priv;
+	SoupURI *soup_uri;
+	SoupMessage *msg;
+
+	g_return_val_if_fail (NM_IS_CONNECTIVITY (self), FALSE);
+	priv = NM_CONNECTIVITY_GET_PRIVATE (self);
+
+	/* check given url async */
+	soup_uri = soup_uri_new (priv->uri);
+	if (soup_uri && SOUP_URI_VALID_FOR_HTTP (soup_uri)) {
+		msg = soup_message_new_from_uri ("GET", soup_uri);
+		soup_message_set_flags (msg, SOUP_MESSAGE_NO_REDIRECT);
+		soup_session_queue_message (priv->soup_session,
+		                            msg,
+		                            nm_connectivity_check_cb,
+		                            self);
+
+		priv->running = TRUE;
+		g_object_notify (G_OBJECT (self), NM_CONNECTIVITY_RUNNING);
+		nm_log_dbg (LOGD_CORE, "Connectivity check with uri '%s' started.", priv->uri);
+	} else
+		nm_log_err (LOGD_CORE, "Invalid uri '%s' for connectivity check.", priv->uri);
+
+	if (soup_uri)
+		soup_uri_free (soup_uri);
+
+	return TRUE;  /* keep firing */
+}
+
+void
+nm_connectivity_start_check (NMConnectivity *self)
+{
+	NMConnectivityPrivate *priv = NM_CONNECTIVITY_GET_PRIVATE (self);
+
+	if (!priv->uri || !priv->interval) {
+		nm_connectivity_stop_check (self);
+		return;
+	}
+
+	if (priv->check_id == 0)
+		priv->check_id = g_timeout_add_seconds (priv->interval, run_check, self);
+
+	/* Start an immediate check */
+	if (priv->running == FALSE)
+		run_check (self);
+}
+
+void
+nm_connectivity_stop_check (NMConnectivity *self)
+{
+	NMConnectivityPrivate *priv = NM_CONNECTIVITY_GET_PRIVATE (self);
+
+	if (priv->check_id) {
+		g_source_remove (priv->check_id);
+		priv->check_id = 0;
+	}
+
+	update_connected (self, FALSE);
+}
+
+NMConnectivity *
+nm_connectivity_new (const gchar *check_uri,
+                     guint check_interval,
+                     const gchar *check_response)
+{
+	NMConnectivity *self;
+
+	self = g_object_new (NM_TYPE_CONNECTIVITY,
+	                     NM_CONNECTIVITY_URI, check_uri,
+	                     NM_CONNECTIVITY_INTERVAL, check_interval,
+	                     NM_CONNECTIVITY_RESPONSE, check_response ? check_response : DEFAULT_RESPONSE,
+	                     NULL);
+	g_return_val_if_fail (self != NULL, NULL);
+	update_connected (self, FALSE);
+
+	return self;
+}
+
+static char *
+sanitize_string_val (const GValue *val)
+{
+	char *s;
+
+	/* Return NULL if string is NULL or zero-length */
+	s = g_value_dup_string (val);
+	if (!s || !s[0]) {
+		g_free (s);
+		return NULL;
+	}
+	return s;
+}
+
+static void
+set_property (GObject *object, guint property_id,
+              const GValue *value, GParamSpec *pspec)
+{
+	NMConnectivity *self = NM_CONNECTIVITY (object);
+	NMConnectivityPrivate *priv = NM_CONNECTIVITY_GET_PRIVATE (self);
+
+	switch (property_id) {
+	case PROP_RUNNING:
+		priv->running = g_value_get_boolean (value);
+		break;
+	case PROP_URI:
+		g_free (priv->uri);
+		priv->uri = sanitize_string_val (value);
+		break;
+	case PROP_INTERVAL:
+		priv->interval = g_value_get_uint (value);
+		break;
+	case PROP_RESPONSE:
+		g_free (priv->response);
+		priv->response = sanitize_string_val (value);
+		break;
+	case PROP_CONNECTED:
+		priv->connected = g_value_get_boolean (value);
+		break;
+	default:
+		G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
+		break;
+	}
+}
+
+static void
+get_property (GObject *object, guint property_id,
+              GValue *value, GParamSpec *pspec)
+{
+	NMConnectivity *self = NM_CONNECTIVITY (object);
+	NMConnectivityPrivate *priv = NM_CONNECTIVITY_GET_PRIVATE (self);
+
+	switch (property_id) {
+	case PROP_RUNNING:
+		g_value_set_boolean (value, priv->running);
+		break;
+	case PROP_URI:
+		g_value_set_string (value, priv->uri);
+		break;
+	case PROP_INTERVAL:
+		g_value_set_uint (value, priv->interval);
+		break;
+	case PROP_RESPONSE:
+		g_value_set_string (value, priv->response);
+		break;
+	case PROP_CONNECTED:
+		g_value_set_boolean (value, priv->connected);
+		break;
+	default:
+		G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
+		break;
+	}
+}
+
+
+static void
+nm_connectivity_init (NMConnectivity *self)
+{
+	NMConnectivityPrivate *priv = NM_CONNECTIVITY_GET_PRIVATE (self);
+
+	priv->soup_session = soup_session_async_new_with_options (SOUP_SESSION_TIMEOUT, 15, NULL);
+}
+
+
+static void
+dispose (GObject *object)
+{
+	NMConnectivity *self = NM_CONNECTIVITY (object);
+	NMConnectivityPrivate *priv = NM_CONNECTIVITY_GET_PRIVATE (self);
+
+	if (priv->soup_session) {
+		soup_session_abort (priv->soup_session);
+		g_object_unref (priv->soup_session);
+		priv->soup_session = NULL;
+	}
+
+	g_free (priv->uri);
+	g_free (priv->response);
+
+	if (priv->check_id > 0) {
+		g_source_remove (priv->check_id);
+		priv->check_id = 0;
+	}
+}
+
+
+static void
+nm_connectivity_class_init (NMConnectivityClass *klass)
+{
+	GObjectClass *object_class = G_OBJECT_CLASS (klass);
+	g_type_class_add_private (klass, sizeof (NMConnectivityPrivate));
+
+	/* virtual methods */
+	object_class->set_property = set_property;
+	object_class->get_property = get_property;
+	object_class->dispose = dispose;
+
+	/* properties */
+	g_object_class_install_property
+		(object_class, PROP_RUNNING,
+		 g_param_spec_boolean (NM_CONNECTIVITY_RUNNING,
+		                       "Running",
+		                       "Connectivity check is running",
+		                       FALSE,
+		                       G_PARAM_READABLE));
+
+	g_object_class_install_property
+		(object_class, PROP_URI,
+		 g_param_spec_string (NM_CONNECTIVITY_URI,
+		                      "URI",
+		                      "Connectivity check URI",
+		                      NULL,
+		                      G_PARAM_READWRITE));
+
+	g_object_class_install_property
+		(object_class, PROP_INTERVAL,
+		 g_param_spec_uint (NM_CONNECTIVITY_INTERVAL,
+		                    "Interval",
+		                    "Connectivity check interval in seconds",
+		                    0, G_MAXUINT, 300,
+		                    G_PARAM_READWRITE | G_PARAM_CONSTRUCT));
+
+	g_object_class_install_property
+		(object_class, PROP_RESPONSE,
+		 g_param_spec_string (NM_CONNECTIVITY_RESPONSE,
+		                      "Response",
+		                      "Expected connectivity check reponse",
+		                      DEFAULT_RESPONSE,
+		                      G_PARAM_READWRITE | G_PARAM_CONSTRUCT));
+
+	g_object_class_install_property
+		(object_class, PROP_CONNECTED,
+		 g_param_spec_boolean (NM_CONNECTIVITY_CONNECTED,
+		                       "Connected",
+		                       "Is connected",
+		                       FALSE,
+		                       G_PARAM_READABLE));
+}
+
diff --git a/src/nm-connectivity.h b/src/nm-connectivity.h
new file mode 100644
index 00000000..cecc6676
--- /dev/null
+++ b/src/nm-connectivity.h
@@ -0,0 +1,66 @@
+
+/* -*- Mode: C; tab-width: 4; indent-tabs-mode: t; c-basic-offset: 4 -*- */
+/* NetworkManager -- Network link manager
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Copyright (C) 2011 Thomas Bechtold <thomasbechtold@jpberlin.de>
+ */
+
+#ifndef NM_CONNECTIVITY_H
+#define NM_CONNECTIVITY_H
+
+#include <glib.h>
+#include <glib-object.h>
+
+#include "NetworkManager.h"
+
+#define NM_TYPE_CONNECTIVITY            (nm_connectivity_get_type ())
+#define NM_CONNECTIVITY(obj)            (G_TYPE_CHECK_INSTANCE_CAST ((obj), NM_TYPE_CONNECTIVITY, NMConnectivity))
+#define NM_CONNECTIVITY_CLASS(klass)    (G_TYPE_CHECK_CLASS_CAST ((klass), NM_TYPE_CONNECTIVITY, NMConnectivityClass))
+#define NM_IS_CONNECTIVITY(obj)         (G_TYPE_CHECK_INSTANCE_TYPE ((obj), NM_TYPE_CONNECTIVITY))
+#define NM_IS_CONNECTIVITY_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((obj), NM_TYPE_CONNECTIVITY))
+#define NM_CONNECTIVITY_GET_CLASS(obj)  (G_TYPE_INSTANCE_GET_CLASS ((obj), NM_TYPE_CONNECTIVITY, NMConnectivityClass))
+
+/* Properties */
+#define NM_CONNECTIVITY_RUNNING   "running"
+#define NM_CONNECTIVITY_URI       "uri"
+#define NM_CONNECTIVITY_INTERVAL  "interval"
+#define NM_CONNECTIVITY_RESPONSE  "response"
+#define NM_CONNECTIVITY_CONNECTED "connected"
+
+
+typedef struct {
+	GObject parent;
+} NMConnectivity;
+
+typedef struct {
+	GObjectClass parent;
+} NMConnectivityClass;
+
+GType nm_connectivity_get_type (void);
+
+
+NMConnectivity *nm_connectivity_new           (const gchar *check_uri,
+                                               guint check_interval,
+                                               const gchar *check_response);
+
+void            nm_connectivity_start_check   (NMConnectivity *connectivity);
+
+void            nm_connectivity_stop_check    (NMConnectivity *connectivity);
+
+gboolean        nm_connectivity_get_connected (NMConnectivity *connectivity);
+
+#endif /* NM_CONNECTIVITY_H */
diff --git a/src/nm-device-bond.c b/src/nm-device-bond.c
new file mode 100644
index 00000000..0d99fd71
--- /dev/null
+++ b/src/nm-device-bond.c
@@ -0,0 +1,569 @@
+/* -*- 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 2011 - 2012 Red Hat, Inc.
+ */
+
+#include "config.h"
+
+#include <glib.h>
+#include <glib/gi18n.h>
+
+#include <netinet/ether.h>
+
+#include "nm-device-bond.h"
+#include "nm-logging.h"
+#include "nm-properties-changed-signal.h"
+#include "nm-utils.h"
+#include "NetworkManagerUtils.h"
+#include "nm-device-private.h"
+#include "nm-netlink-monitor.h"
+#include "nm-enum-types.h"
+#include "nm-system.h"
+
+#include "nm-device-bond-glue.h"
+
+
+G_DEFINE_TYPE (NMDeviceBond, nm_device_bond, NM_TYPE_DEVICE_WIRED)
+
+#define NM_DEVICE_BOND_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), NM_TYPE_DEVICE_BOND, NMDeviceBondPrivate))
+
+#define NM_BOND_ERROR (nm_bond_error_quark ())
+
+typedef struct {
+	GSList *slaves;
+} NMDeviceBondPrivate;
+
+enum {
+	PROPERTIES_CHANGED,
+
+	LAST_SIGNAL
+};
+
+static guint signals[LAST_SIGNAL] = { 0 };
+
+enum {
+	PROP_0,
+	PROP_HW_ADDRESS,
+	PROP_CARRIER,
+
+	LAST_PROP
+};
+
+/******************************************************************/
+
+static GQuark
+nm_bond_error_quark (void)
+{
+	static GQuark quark = 0;
+	if (!quark)
+		quark = g_quark_from_static_string ("nm-bond-error");
+	return quark;
+}
+
+/******************************************************************/
+
+static void
+device_state_changed (NMDevice *device,
+                      NMDeviceState new_state,
+                      NMDeviceState old_state,
+                      NMDeviceStateReason reason,
+                      gpointer user_data)
+{
+	if (new_state == NM_DEVICE_STATE_UNAVAILABLE) {
+		/* Use NM_DEVICE_STATE_REASON_CARRIER to make sure num retries is reset */
+		nm_device_queue_state (device, NM_DEVICE_STATE_DISCONNECTED, NM_DEVICE_STATE_REASON_CARRIER);
+	}
+}
+
+static void
+real_update_hw_address (NMDevice *dev)
+{
+	const guint8 *hw_addr;
+	guint8 old_addr[NM_UTILS_HWADDR_LEN_MAX];
+	int addrtype, addrlen;
+
+	addrtype = nm_device_wired_get_hwaddr_type (NM_DEVICE_WIRED (dev));
+	g_assert (addrtype >= 0);
+	addrlen = nm_utils_hwaddr_len (addrtype);
+	g_assert (addrlen > 0);
+
+	hw_addr = nm_device_wired_get_hwaddr (NM_DEVICE_WIRED (dev));
+	memcpy (old_addr, hw_addr, addrlen);
+
+	NM_DEVICE_CLASS (nm_device_bond_parent_class)->update_hw_address (dev);
+
+	hw_addr = nm_device_wired_get_hwaddr (NM_DEVICE_WIRED (dev));
+	if (memcmp (old_addr, hw_addr, addrlen))
+		g_object_notify (G_OBJECT (dev), NM_DEVICE_BOND_HW_ADDRESS);
+}
+
+static guint32
+real_get_generic_capabilities (NMDevice *dev)
+{
+	return NM_DEVICE_CAP_CARRIER_DETECT | NM_DEVICE_CAP_NM_SUPPORTED;
+}
+
+static gboolean
+match_bond_connection (NMDevice *device, NMConnection *connection, GError **error)
+{
+	const char *iface;
+	NMSettingBond *s_bond;
+
+	s_bond = nm_connection_get_setting_bond (connection);
+	if (!s_bond || !nm_connection_is_type (connection, NM_SETTING_BOND_SETTING_NAME)) {
+		g_set_error (error, NM_BOND_ERROR, NM_BOND_ERROR_CONNECTION_NOT_BOND,
+		             "The connection was not a bond connection.");
+		return FALSE;
+	}
+
+	/* Bond connections must specify the virtual interface name */
+	iface = nm_connection_get_virtual_iface_name (connection);
+	if (!iface || strcmp (nm_device_get_iface (device), iface)) {
+		g_set_error (error, NM_BOND_ERROR, NM_BOND_ERROR_CONNECTION_NOT_BOND,
+		             "The bond connection virtual interface name did not match.");
+		return FALSE;
+	}
+
+	/* FIXME: match bond properties like mode, etc? */
+
+	return TRUE;
+}
+
+static NMConnection *
+real_get_best_auto_connection (NMDevice *dev,
+                               GSList *connections,
+                               char **specific_object)
+{
+	GSList *iter;
+
+	for (iter = connections; iter; iter = g_slist_next (iter)) {
+		NMConnection *connection = NM_CONNECTION (iter->data);
+		NMSettingConnection *s_con;
+
+		s_con = nm_connection_get_setting_connection (connection);
+		g_assert (s_con);
+		if (   nm_setting_connection_get_autoconnect (s_con)
+		    && match_bond_connection (dev, connection, NULL))
+			return connection;
+	}
+	return NULL;
+}
+
+static gboolean
+real_check_connection_compatible (NMDevice *device,
+                                  NMConnection *connection,
+                                  GError **error)
+{
+	return match_bond_connection (device, connection, error);
+}
+
+static gboolean
+real_complete_connection (NMDevice *device,
+                          NMConnection *connection,
+                          const char *specific_object,
+                          const GSList *existing_connections,
+                          GError **error)
+{
+	NMSettingBond *s_bond, *tmp;
+	guint32 i = 0;
+	char *name;
+	const GSList *iter;
+	gboolean found;
+
+	nm_utils_complete_generic (connection,
+	                           NM_SETTING_BOND_SETTING_NAME,
+	                           existing_connections,
+	                           _("Bond connection %d"),
+	                           NULL,
+	                           TRUE);
+
+	s_bond = nm_connection_get_setting_bond (connection);
+	if (!s_bond) {
+		s_bond = (NMSettingBond *) nm_setting_bond_new ();
+		nm_connection_add_setting (connection, NM_SETTING (s_bond));
+	}
+
+	/* Grab the first name that doesn't exist in either our connections
+	 * or a device on the system.
+	 */
+	while (i < 500 && !nm_setting_bond_get_interface_name (s_bond)) {
+		name = g_strdup_printf ("bond%u", i);
+		/* check interface names */
+		if (nm_netlink_iface_to_index (name) < 0) {
+			/* check existing bond connections */
+			for (iter = existing_connections, found = FALSE; iter; iter = g_slist_next (iter)) {
+				NMConnection *candidate = iter->data;
+
+				tmp = nm_connection_get_setting_bond (candidate);
+				if (tmp && nm_connection_is_type (candidate, NM_SETTING_BOND_SETTING_NAME)) {
+					if (g_strcmp0 (nm_setting_bond_get_interface_name (tmp), name) == 0) {
+						found = TRUE;
+						break;
+					}
+				}
+			}
+
+			if (!found)
+				g_object_set (G_OBJECT (s_bond), NM_SETTING_BOND_INTERFACE_NAME, name, NULL);
+		}
+
+		g_free (name);
+		i++;
+	}
+
+	return TRUE;
+}
+
+static gboolean
+spec_match_list (NMDevice *device, const GSList *specs)
+{
+	char *hwaddr;
+	gboolean matched;
+
+	hwaddr = nm_utils_hwaddr_ntoa (nm_device_wired_get_hwaddr (NM_DEVICE_WIRED (device)), ARPHRD_ETHER);
+	matched = nm_match_spec_hwaddr (specs, hwaddr);
+	g_free (hwaddr);
+
+	return matched;
+}
+
+static gboolean
+bond_match_config (NMDevice *self, NMConnection *connection)
+{
+	NMSettingBond *s_bond;
+	const char *ifname;
+
+	s_bond = nm_connection_get_setting_bond (connection);
+	if (!s_bond)
+		return FALSE;
+
+	/* Interface name */
+	ifname = nm_setting_bond_get_interface_name (s_bond);
+	if (g_strcmp0 (ifname, nm_device_get_ip_iface (self)) != 0)
+		return FALSE;
+
+	return TRUE;
+}
+
+static NMConnection *
+connection_match_config (NMDevice *self, const GSList *connections)
+{
+	const GSList *iter;
+	GSList *bond_matches;
+	NMConnection *match;
+
+	/* First narrow @connections down to those that match in their
+	 * NMSettingBond configuration.
+	 */
+	bond_matches = NULL;
+	for (iter = connections; iter; iter = iter->next) {
+		NMConnection *candidate = NM_CONNECTION (iter->data);
+
+		if (!nm_connection_is_type (candidate, NM_SETTING_BOND_SETTING_NAME))
+			continue;
+		if (!bond_match_config (self, candidate))
+			continue;
+
+		bond_matches = g_slist_prepend (bond_matches, candidate);
+	}
+
+	/* Now pass those to the super method, which will check IP config */
+	bond_matches = g_slist_reverse (bond_matches);
+	match = NM_DEVICE_CLASS (nm_device_bond_parent_class)->connection_match_config (self, bond_matches);
+	g_slist_free (bond_matches);
+
+	return match;
+}
+
+/******************************************************************/
+
+static NMActStageReturn
+real_act_stage1_prepare (NMDevice *dev, NMDeviceStateReason *reason)
+{
+	NMActStageReturn ret = NM_ACT_STAGE_RETURN_SUCCESS;
+	NMConnection *connection;
+	NMSettingBond *s_bond;
+	gboolean no_firmware = FALSE;
+
+	g_return_val_if_fail (reason != NULL, NM_ACT_STAGE_RETURN_FAILURE);
+
+	ret = NM_DEVICE_CLASS (nm_device_bond_parent_class)->act_stage1_prepare (dev, reason);
+	if (ret == NM_ACT_STAGE_RETURN_SUCCESS) {
+		connection = nm_device_get_connection (dev);
+		g_assert (connection);
+		s_bond = nm_connection_get_setting_bond (connection);
+		g_assert (s_bond);
+
+		/* Interface must be down to set bond options */
+		nm_device_hw_take_down (dev, TRUE);
+
+		if (!nm_system_apply_bonding_config (nm_device_get_ip_iface (dev), s_bond))
+			ret = NM_ACT_STAGE_RETURN_FAILURE;
+
+		nm_device_hw_bring_up (dev, TRUE, &no_firmware);
+	}
+	return ret;
+}
+
+static void
+slave_state_changed (NMDevice *slave,
+                     NMDeviceState new_state,
+                     NMDeviceState old_state,
+                     NMDeviceStateReason reason,
+                     gpointer user_data)
+{
+	NMDeviceBond *self = NM_DEVICE_BOND (user_data);
+
+	nm_log_dbg (LOGD_DEVICE, "(%s): slave %s state change %d -> %d",
+	            nm_device_get_iface (NM_DEVICE (self)),
+	            nm_device_get_iface (slave),
+	            old_state,
+	            new_state);
+
+	if (   old_state > NM_DEVICE_STATE_DISCONNECTED
+	    && new_state <= NM_DEVICE_STATE_DISCONNECTED) {
+		/* Slave is no longer available or managed; can't use it */
+		nm_device_release_slave (NM_DEVICE (self), slave);
+	}
+}
+
+typedef struct {
+	NMDevice *slave;
+	guint state_id;
+} SlaveInfo;
+
+static SlaveInfo *
+find_slave_info_by_device (NMDeviceBond *self, NMDevice *slave)
+{
+	NMDeviceBondPrivate *priv = NM_DEVICE_BOND_GET_PRIVATE (self);
+	GSList *iter;
+
+	for (iter = priv->slaves; iter; iter = g_slist_next (iter)) {
+		if (((SlaveInfo *) iter->data)->slave == slave)
+			return iter->data;
+	}
+	return NULL;
+}
+
+static void
+free_slave_info (SlaveInfo *sinfo)
+{
+	g_return_if_fail (sinfo != NULL);
+	g_return_if_fail (sinfo->slave != NULL);
+
+	g_signal_handler_disconnect (sinfo->slave, sinfo->state_id);
+	g_object_unref (sinfo->slave);
+	memset (sinfo, 0, sizeof (*sinfo));
+	g_free (sinfo);
+}
+
+static gboolean
+enslave_slave (NMDevice *device, NMDevice *slave)
+{
+	NMDeviceBond *self = NM_DEVICE_BOND (device);
+	NMDeviceBondPrivate *priv = NM_DEVICE_BOND_GET_PRIVATE (self);
+	gboolean success, no_firmware = FALSE;
+
+	if (find_slave_info_by_device (self, slave))
+		return TRUE;
+
+	nm_device_hw_take_down (slave, TRUE);
+
+	success = nm_system_iface_enslave (nm_device_get_ip_ifindex (device),
+	                                   nm_device_get_ip_iface (device),
+	                                   nm_device_get_ip_ifindex (slave),
+	                                   nm_device_get_ip_iface (slave));
+	if (success) {
+		SlaveInfo *sinfo;
+
+		sinfo = g_malloc0 (sizeof (*slave));
+		sinfo->slave = g_object_ref (slave);
+		sinfo->state_id = g_signal_connect (slave,
+		                                    "state-changed",
+		                                    (GCallback) slave_state_changed,
+		                                    self);
+		priv->slaves = g_slist_append (priv->slaves, sinfo);
+
+		nm_log_dbg (LOGD_DEVICE, "(%s): enslaved bond slave %s",
+			        nm_device_get_ip_iface (device),
+			        nm_device_get_ip_iface (slave));
+	}
+
+	nm_device_hw_bring_up (slave, TRUE, &no_firmware);
+
+	return success;
+}
+
+static gboolean
+release_slave (NMDevice *device, NMDevice *slave)
+{
+	NMDeviceBond *self = NM_DEVICE_BOND (device);
+	NMDeviceBondPrivate *priv = NM_DEVICE_BOND_GET_PRIVATE (self);
+	gboolean success;
+	SlaveInfo *sinfo;
+
+	sinfo = find_slave_info_by_device (self, slave);
+	if (!sinfo)
+		return FALSE;
+
+	success = nm_system_iface_release (nm_device_get_ip_ifindex (device),
+	                                   nm_device_get_ip_iface (device),
+	                                   nm_device_get_ip_ifindex (slave),
+	                                   nm_device_get_ip_iface (slave));
+	nm_log_dbg (LOGD_DEVICE, "(%s): released bond slave %s (success %d)",
+	            nm_device_get_ip_iface (device),
+	            nm_device_get_ip_iface (slave),
+	            success);
+	priv->slaves = g_slist_remove (priv->slaves, sinfo);
+	free_slave_info (sinfo);
+	return success;
+}
+
+/******************************************************************/
+
+NMDevice *
+nm_device_bond_new (const char *udi, const char *iface)
+{
+	g_return_val_if_fail (udi != NULL, NULL);
+	g_return_val_if_fail (iface != NULL, NULL);
+
+	return (NMDevice *) g_object_new (NM_TYPE_DEVICE_BOND,
+	                                  NM_DEVICE_UDI, udi,
+	                                  NM_DEVICE_IFACE, iface,
+	                                  NM_DEVICE_DRIVER, "bonding",
+	                                  NM_DEVICE_TYPE_DESC, "Bond",
+	                                  NM_DEVICE_DEVICE_TYPE, NM_DEVICE_TYPE_BOND,
+	                                  NULL);
+}
+
+static void
+constructed (GObject *object)
+{
+	G_OBJECT_CLASS (nm_device_bond_parent_class)->constructed (object);
+
+	nm_log_dbg (LOGD_HW | LOGD_DEVICE, "(%s): kernel ifindex %d",
+	            nm_device_get_iface (NM_DEVICE (object)),
+	            nm_device_get_ifindex (NM_DEVICE (object)));
+}
+
+static void
+nm_device_bond_init (NMDeviceBond * self)
+{
+	g_signal_connect (self, "state-changed", G_CALLBACK (device_state_changed), NULL);
+}
+
+static void
+get_property (GObject *object, guint prop_id,
+              GValue *value, GParamSpec *pspec)
+{
+	const guint8 *current_addr;
+
+	switch (prop_id) {
+	case PROP_HW_ADDRESS:
+		current_addr = nm_device_wired_get_hwaddr (NM_DEVICE_WIRED (object));
+		g_value_take_string (value, nm_utils_hwaddr_ntoa (current_addr, ARPHRD_ETHER));
+		break;
+	case PROP_CARRIER:
+		g_value_set_boolean (value, nm_device_wired_get_carrier (NM_DEVICE_WIRED (object)));
+		break;
+	default:
+		G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+		break;
+	}
+}
+
+static void
+set_property (GObject *object, guint prop_id,
+			  const GValue *value, GParamSpec *pspec)
+{
+	switch (prop_id) {
+	default:
+		G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+		break;
+	}
+}
+
+static void
+dispose (GObject *object)
+{
+	NMDeviceBond *self = NM_DEVICE_BOND (object);
+	NMDeviceBondPrivate *priv = NM_DEVICE_BOND_GET_PRIVATE (self);
+	GSList *iter;
+
+	for (iter = priv->slaves; iter; iter = g_slist_next (iter))
+		release_slave (NM_DEVICE (self), ((SlaveInfo *) iter->data)->slave);
+	g_slist_free (priv->slaves);
+	priv->slaves = NULL;
+
+	G_OBJECT_CLASS (nm_device_bond_parent_class)->dispose (object);
+}
+
+static void
+nm_device_bond_class_init (NMDeviceBondClass *klass)
+{
+	GObjectClass *object_class = G_OBJECT_CLASS (klass);
+	NMDeviceClass *parent_class = NM_DEVICE_CLASS (klass);
+
+	g_type_class_add_private (object_class, sizeof (NMDeviceBondPrivate));
+
+	/* virtual methods */
+	object_class->constructed = constructed;
+	object_class->get_property = get_property;
+	object_class->set_property = set_property;
+	object_class->dispose = dispose;
+
+	parent_class->get_generic_capabilities = real_get_generic_capabilities;
+	parent_class->update_hw_address = real_update_hw_address;
+	parent_class->get_best_auto_connection = real_get_best_auto_connection;
+	parent_class->check_connection_compatible = real_check_connection_compatible;
+	parent_class->complete_connection = real_complete_connection;
+
+	parent_class->spec_match_list = spec_match_list;
+	parent_class->connection_match_config = connection_match_config;
+
+	parent_class->act_stage1_prepare = real_act_stage1_prepare;
+	parent_class->enslave_slave = enslave_slave;
+	parent_class->release_slave = release_slave;
+
+	/* properties */
+	g_object_class_install_property
+		(object_class, PROP_HW_ADDRESS,
+		 g_param_spec_string (NM_DEVICE_BOND_HW_ADDRESS,
+							  "Active MAC Address",
+							  "Currently set hardware MAC address",
+							  NULL,
+							  G_PARAM_READABLE));
+
+	g_object_class_install_property
+		(object_class, PROP_CARRIER,
+		 g_param_spec_boolean (NM_DEVICE_BOND_CARRIER,
+							   "Carrier",
+							   "Carrier",
+							   FALSE,
+							   G_PARAM_READABLE));
+
+	/* Signals */
+	signals[PROPERTIES_CHANGED] =
+		nm_properties_changed_signal_new (object_class,
+										  G_STRUCT_OFFSET (NMDeviceBondClass, properties_changed));
+
+	dbus_g_object_type_install_info (G_TYPE_FROM_CLASS (klass),
+									 &dbus_glib_nm_device_bond_object_info);
+
+	dbus_g_error_domain_register (NM_BOND_ERROR, NULL, NM_TYPE_BOND_ERROR);
+}
diff --git a/src/nm-device-bond.h b/src/nm-device-bond.h
new file mode 100644
index 00000000..50ca45ea
--- /dev/null
+++ b/src/nm-device-bond.h
@@ -0,0 +1,65 @@
+/* -*- 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 2012 Red Hat, Inc.
+ */
+
+#ifndef NM_DEVICE_BOND_H
+#define NM_DEVICE_BOND_H
+
+#include <glib-object.h>
+
+#include "nm-device-wired.h"
+
+G_BEGIN_DECLS
+
+#define NM_TYPE_DEVICE_BOND            (nm_device_bond_get_type ())
+#define NM_DEVICE_BOND(obj)            (G_TYPE_CHECK_INSTANCE_CAST ((obj), NM_TYPE_DEVICE_BOND, NMDeviceBond))
+#define NM_DEVICE_BOND_CLASS(klass)    (G_TYPE_CHECK_CLASS_CAST ((klass),  NM_TYPE_DEVICE_BOND, NMDeviceBondClass))
+#define NM_IS_DEVICE_BOND(obj)         (G_TYPE_CHECK_INSTANCE_TYPE ((obj), NM_TYPE_DEVICE_BOND))
+#define NM_IS_DEVICE_BOND_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass),  NM_TYPE_DEVICE_BOND))
+#define NM_DEVICE_BOND_GET_CLASS(obj)  (G_TYPE_INSTANCE_GET_CLASS ((obj),  NM_TYPE_DEVICE_BOND, NMDeviceBondClass))
+
+typedef enum {
+	NM_BOND_ERROR_CONNECTION_NOT_BOND = 0, /*< nick=ConnectionNotBond >*/
+	NM_BOND_ERROR_CONNECTION_INVALID,      /*< nick=ConnectionInvalid >*/
+	NM_BOND_ERROR_CONNECTION_INCOMPATIBLE, /*< nick=ConnectionIncompatible >*/
+} NMBondError;
+
+#define NM_DEVICE_BOND_HW_ADDRESS "hw-address"
+#define NM_DEVICE_BOND_CARRIER "carrier"
+
+typedef struct {
+	NMDeviceWired parent;
+} NMDeviceBond;
+
+typedef struct {
+	NMDeviceWiredClass parent;
+
+	/* Signals */
+	void (*properties_changed) (NMDeviceBond *device, GHashTable *properties);
+} NMDeviceBondClass;
+
+
+GType nm_device_bond_get_type (void);
+
+NMDevice *nm_device_bond_new (const char *udi,
+                              const char *iface);
+
+G_END_DECLS
+
+#endif	/* NM_DEVICE_BOND_H */
diff --git a/src/nm-device-bt.c b/src/nm-device-bt.c
index c36e0c0b..726762b6 100644
--- a/src/nm-device-bt.c
+++ b/src/nm-device-bt.c
@@ -31,7 +31,6 @@
 #include "nm-bluez-common.h"
 #include "nm-dbus-manager.h"
 #include "nm-device-bt.h"
-#include "nm-device-interface.h"
 #include "nm-device-private.h"
 #include "nm-logging.h"
 #include "nm-marshal.h"
@@ -45,6 +44,8 @@
 #include "nm-setting-ppp.h"
 #include "nm-device-bt-glue.h"
 #include "NetworkManagerUtils.h"
+#include "nm-enum-types.h"
+#include "nm-utils.h"
 
 #define BLUETOOTH_DUN_UUID "dun"
 #define BLUETOOTH_NAP_UUID "nap"
@@ -91,14 +92,7 @@ enum {
 static guint signals[LAST_SIGNAL] = { 0 };
 
 
-typedef enum {
-	NM_BT_ERROR_CONNECTION_NOT_BT = 0,
-	NM_BT_ERROR_CONNECTION_INVALID,
-	NM_BT_ERROR_CONNECTION_INCOMPATIBLE,
-} NMBtError;
-
 #define NM_BT_ERROR (nm_bt_error_quark ())
-#define NM_TYPE_BT_ERROR (nm_bt_error_get_type ())
 
 static GQuark
 nm_bt_error_quark (void)
@@ -109,30 +103,6 @@ nm_bt_error_quark (void)
 	return quark;
 }
 
-/* This should really be standard. */
-#define ENUM_ENTRY(NAME, DESC) { NAME, "" #NAME "", DESC }
-
-static GType
-nm_bt_error_get_type (void)
-{
-	static GType etype = 0;
-
-	if (etype == 0) {
-		static const GEnumValue values[] = {
-			/* Connection was not a BT connection. */
-			ENUM_ENTRY (NM_BT_ERROR_CONNECTION_NOT_BT, "ConnectionNotBt"),
-			/* Connection was not a valid BT connection. */
-			ENUM_ENTRY (NM_BT_ERROR_CONNECTION_INVALID, "ConnectionInvalid"),
-			/* Connection does not apply to this device. */
-			ENUM_ENTRY (NM_BT_ERROR_CONNECTION_INCOMPATIBLE, "ConnectionIncompatible"),
-			{ 0, 0, 0 }
-		};
-		etype = g_enum_register_static ("NMBtError", values);
-	}
-	return etype;
-}
-
-
 guint32 nm_device_bt_get_capabilities (NMDeviceBt *self)
 {
 	g_return_val_if_fail (self != NULL, NM_BT_CAPABILITY_NONE);
@@ -155,7 +125,7 @@ get_connection_bt_type (NMConnection *connection)
 	NMSettingBluetooth *s_bt;
 	const char *bt_type;
 
-	s_bt = (NMSettingBluetooth *) nm_connection_get_setting (connection, NM_TYPE_SETTING_BLUETOOTH);
+	s_bt = nm_connection_get_setting_bluetooth (connection);
 	if (!s_bt)
 		return NM_BT_CAPABILITY_NONE;
 
@@ -183,7 +153,7 @@ real_get_best_auto_connection (NMDevice *device,
 		NMSettingConnection *s_con;
 		guint32 bt_type;
 
-		s_con = (NMSettingConnection *) nm_connection_get_setting (connection, NM_TYPE_SETTING_CONNECTION);
+		s_con = nm_connection_get_setting_connection (connection);
 		g_assert (s_con);
 
 		if (!nm_setting_connection_get_autoconnect (s_con))
@@ -214,7 +184,7 @@ real_check_connection_compatible (NMDevice *device,
 	int addr_match = FALSE;
 	guint32 bt_type;
 
-	s_con = NM_SETTING_CONNECTION (nm_connection_get_setting (connection, NM_TYPE_SETTING_CONNECTION));
+	s_con = nm_connection_get_setting_connection (connection);
 	g_assert (s_con);
 
 	if (strcmp (nm_setting_connection_get_connection_type (s_con), NM_SETTING_BLUETOOTH_SETTING_NAME)) {
@@ -224,7 +194,7 @@ real_check_connection_compatible (NMDevice *device,
 		return FALSE;
 	}
 
-	s_bt = NM_SETTING_BLUETOOTH (nm_connection_get_setting (connection, NM_TYPE_SETTING_BLUETOOTH));
+	s_bt = nm_connection_get_setting_bluetooth (connection);
 	if (!s_bt) {
 		g_set_error (error,
 		             NM_BT_ERROR, NM_BT_ERROR_CONNECTION_INVALID,
@@ -276,12 +246,12 @@ real_complete_connection (NMDevice *device,
 	NMSettingPPP *s_ppp;
 	const char *format = NULL, *preferred = NULL;
 
-	s_gsm = (NMSettingGsm *) nm_connection_get_setting (connection, NM_TYPE_SETTING_GSM);
-	s_cdma = (NMSettingCdma *) nm_connection_get_setting (connection, NM_TYPE_SETTING_CDMA);
-	s_serial = (NMSettingSerial *) nm_connection_get_setting (connection, NM_TYPE_SETTING_SERIAL);
-	s_ppp = (NMSettingPPP *) nm_connection_get_setting (connection, NM_TYPE_SETTING_PPP);
+	s_gsm = nm_connection_get_setting_gsm (connection);
+	s_cdma = nm_connection_get_setting_cdma (connection);
+	s_serial = nm_connection_get_setting_serial (connection);
+	s_ppp = nm_connection_get_setting_ppp (connection);
 
-	s_bt = (NMSettingBluetooth *) nm_connection_get_setting (connection, NM_TYPE_SETTING_BLUETOOTH);
+	s_bt = nm_connection_get_setting_bluetooth (connection);
 	if (!s_bt) {
 		s_bt = (NMSettingBluetooth *) nm_setting_bluetooth_new ();
 		nm_connection_add_setting (connection, NM_SETTING (s_bt));
@@ -404,6 +374,42 @@ real_get_generic_capabilities (NMDevice *dev)
 	return NM_DEVICE_CAP_NM_SUPPORTED;
 }
 
+static gboolean
+hwaddr_matches (NMDevice *device,
+                NMConnection *connection,
+                const guint8 *other_hwaddr,
+                guint other_hwaddr_len,
+                gboolean fail_if_no_hwaddr)
+{
+	NMDeviceBtPrivate *priv = NM_DEVICE_BT_GET_PRIVATE (device);
+	NMSettingBluetooth *s_bt;
+	const GByteArray *mac = NULL;
+	gboolean matches = FALSE;
+	GByteArray *devmac;
+
+	s_bt = nm_connection_get_setting_bluetooth (connection);
+	if (s_bt)
+		mac = nm_setting_bluetooth_get_bdaddr (s_bt);
+
+	if (mac) {
+		devmac = nm_utils_hwaddr_atoba (priv->bdaddr, ARPHRD_ETHER);
+		g_return_val_if_fail (devmac != NULL, FALSE);
+		g_return_val_if_fail (devmac->len == mac->len, FALSE);
+
+		if (other_hwaddr) {
+			g_return_val_if_fail (other_hwaddr_len == devmac->len, FALSE);
+			matches = (memcmp (mac->data, other_hwaddr, mac->len) == 0) ? TRUE : FALSE;
+		} else
+			matches = (memcmp (mac->data, devmac->data, mac->len) == 0) ? TRUE : FALSE;
+
+		g_byte_array_free (devmac, TRUE);
+		return matches;
+	} else if (fail_if_no_hwaddr == FALSE)
+		return TRUE;
+
+	return FALSE;
+}
+
 /*****************************************************************************/
 /* IP method PPP */
 
@@ -421,17 +427,19 @@ ppp_failed (NMModem *modem, NMDeviceStateReason reason, gpointer user_data)
 {
 	NMDevice *device = NM_DEVICE (user_data);
 
-	switch (nm_device_interface_get_state (NM_DEVICE_INTERFACE (device))) {
+	switch (nm_device_get_state (device)) {
 	case NM_DEVICE_STATE_PREPARE:
 	case NM_DEVICE_STATE_CONFIG:
 	case NM_DEVICE_STATE_NEED_AUTH:
-	case NM_DEVICE_STATE_IP_CHECK:
-	case NM_DEVICE_STATE_SECONDARIES:
-	case NM_DEVICE_STATE_ACTIVATED:
 		nm_device_state_changed (device, NM_DEVICE_STATE_FAILED, reason);
 		break;
 	case NM_DEVICE_STATE_IP_CONFIG:
-		if (nm_device_ip_config_should_fail (device, FALSE)) {
+	case NM_DEVICE_STATE_IP_CHECK:
+	case NM_DEVICE_STATE_SECONDARIES:
+	case NM_DEVICE_STATE_ACTIVATED:
+		if (nm_device_activate_ip4_state_in_conf (device))
+			nm_device_activate_schedule_ip4_config_timeout (device);
+		else {
 			nm_device_state_changed (device,
 			                         NM_DEVICE_STATE_FAILED,
 			                         NM_DEVICE_STATE_REASON_IP_CONFIG_UNAVAILABLE);
@@ -478,7 +486,7 @@ modem_prepare_result (NMModem *modem,
 	NMDevice *device = NM_DEVICE (user_data);
 	NMDeviceState state;
 
-	state = nm_device_interface_get_state (NM_DEVICE_INTERFACE (device));
+	state = nm_device_get_state (device);
 	g_return_if_fail (state == NM_DEVICE_STATE_CONFIG || state == NM_DEVICE_STATE_NEED_AUTH);
 
 	if (success) {
@@ -526,10 +534,8 @@ modem_ip4_config_result (NMModem *self,
                          gpointer user_data)
 {
 	NMDevice *device = NM_DEVICE (user_data);
-	NMDeviceState state;
 
-	state = nm_device_interface_get_state (NM_DEVICE_INTERFACE (device));
-	g_return_if_fail (state == NM_DEVICE_STATE_IP_CONFIG);
+	g_return_if_fail (nm_device_activate_ip4_state_in_conf (device) == TRUE);
 
 	if (error) {
 		nm_log_warn (LOGD_MB | LOGD_IP4 | LOGD_BT,
@@ -543,7 +549,7 @@ modem_ip4_config_result (NMModem *self,
 		if (iface)
 			nm_device_set_ip_iface (device, iface);
 
-		nm_device_activate_schedule_stage4_ip4_config_get (device);
+		nm_device_activate_schedule_ip4_config_result (device, config);
 	}
 }
 
@@ -613,7 +619,7 @@ nm_device_bt_modem_added (NMDeviceBt *self,
 	/* Can only accept the modem in stage2, but since the interface matched
 	 * what we were expecting, don't let anything else claim the modem either.
 	 */
-	state = nm_device_interface_get_state (NM_DEVICE_INTERFACE (self));
+	state = nm_device_get_state (NM_DEVICE (self));
 	if (state != NM_DEVICE_STATE_CONFIG) {
 		nm_log_warn (LOGD_BT | LOGD_MB,
 		             "(%s): modem found but device not in correct state (%d)",
@@ -847,15 +853,14 @@ static NMActStageReturn
 real_act_stage2_config (NMDevice *device, NMDeviceStateReason *reason)
 {
 	NMDeviceBtPrivate *priv = NM_DEVICE_BT_GET_PRIVATE (device);
-	NMActRequest *req;
 	NMDBusManager *dbus_mgr;
 	DBusGConnection *g_connection;
 	gboolean dun = FALSE;
+	NMConnection *connection;
 
-	req = nm_device_get_act_request (device);
-	g_assert (req);
-
-	priv->bt_type = get_connection_bt_type (nm_act_request_get_connection (req));
+	connection = nm_device_get_connection (device);
+	g_assert (connection);
+	priv->bt_type = get_connection_bt_type (connection);
 	if (priv->bt_type == NM_BT_CAPABILITY_NONE) {
 		// FIXME: set a reason code
 		return NM_ACT_STAGE_RETURN_FAILURE;
@@ -920,7 +925,9 @@ real_act_stage2_config (NMDevice *device, NMDeviceStateReason *reason)
 }
 
 static NMActStageReturn
-real_act_stage3_ip4_config_start (NMDevice *device, NMDeviceStateReason *reason)
+real_act_stage3_ip4_config_start (NMDevice *device,
+                                  NMIP4Config **out_config,
+                                  NMDeviceStateReason *reason)
 {
 	NMDeviceBtPrivate *priv = NM_DEVICE_BT_GET_PRIVATE (device);
 	NMActStageReturn ret;
@@ -931,27 +938,26 @@ real_act_stage3_ip4_config_start (NMDevice *device, NMDeviceStateReason *reason)
 		                                        NM_DEVICE_CLASS (nm_device_bt_parent_class),
 		                                        reason);
 	} else
-		ret = NM_DEVICE_CLASS (nm_device_bt_parent_class)->act_stage3_ip4_config_start (device, reason);
+		ret = NM_DEVICE_CLASS (nm_device_bt_parent_class)->act_stage3_ip4_config_start (device, out_config, reason);
 
 	return ret;
 }
 
 static NMActStageReturn
-real_act_stage4_get_ip4_config (NMDevice *device,
-                                NMIP4Config **config,
-                                NMDeviceStateReason *reason)
+real_act_stage3_ip6_config_start (NMDevice *device,
+                                  NMIP6Config **out_config,
+                                  NMDeviceStateReason *reason)
 {
 	NMDeviceBtPrivate *priv = NM_DEVICE_BT_GET_PRIVATE (device);
 	NMActStageReturn ret;
 
 	if (priv->bt_type == NM_BT_CAPABILITY_DUN) {
-		ret = nm_modem_stage4_get_ip4_config (NM_DEVICE_BT_GET_PRIVATE (device)->modem,
-		                                      device,
-		                                      NM_DEVICE_CLASS (nm_device_bt_parent_class),
-		                                      config,
-		                                      reason);
+		ret = nm_modem_stage3_ip6_config_start (NM_DEVICE_BT_GET_PRIVATE (device)->modem,
+		                                        device,
+		                                        NM_DEVICE_CLASS (nm_device_bt_parent_class),
+		                                        reason);
 	} else
-		ret = NM_DEVICE_CLASS (nm_device_bt_parent_class)->act_stage4_get_ip4_config (device, config, reason);
+		ret = NM_DEVICE_CLASS (nm_device_bt_parent_class)->act_stage3_ip6_config_start (device, out_config, reason);
 
 	return ret;
 }
@@ -1037,15 +1043,15 @@ nm_device_bt_new (const char *udi,
 	g_return_val_if_fail (capabilities != NM_BT_CAPABILITY_NONE, NULL);
 
 	device = (NMDevice *) g_object_new (NM_TYPE_DEVICE_BT,
-	                                    NM_DEVICE_INTERFACE_UDI, udi,
-	                                    NM_DEVICE_INTERFACE_IFACE, bdaddr,
-	                                    NM_DEVICE_INTERFACE_DRIVER, "bluez",
+	                                    NM_DEVICE_UDI, udi,
+	                                    NM_DEVICE_IFACE, bdaddr,
+	                                    NM_DEVICE_DRIVER, "bluez",
 	                                    NM_DEVICE_BT_HW_ADDRESS, bdaddr,
 	                                    NM_DEVICE_BT_NAME, name,
 	                                    NM_DEVICE_BT_CAPABILITIES, capabilities,
-	                                    NM_DEVICE_INTERFACE_MANAGED, managed,
-	                                    NM_DEVICE_INTERFACE_TYPE_DESC, "Bluetooth",
-	                                    NM_DEVICE_INTERFACE_DEVICE_TYPE, NM_DEVICE_TYPE_BT,
+	                                    NM_DEVICE_MANAGED, managed,
+	                                    NM_DEVICE_TYPE_DESC, "Bluetooth",
+	                                    NM_DEVICE_DEVICE_TYPE, NM_DEVICE_TYPE_BT,
 	                                    NULL);
 	if (device)
 		g_signal_connect (device, "state-changed", G_CALLBACK (device_state_changed), device);
@@ -1148,9 +1154,10 @@ nm_device_bt_class_init (NMDeviceBtClass *klass)
 	device_class->deactivate = real_deactivate;
 	device_class->act_stage2_config = real_act_stage2_config;
 	device_class->act_stage3_ip4_config_start = real_act_stage3_ip4_config_start;
-	device_class->act_stage4_get_ip4_config = real_act_stage4_get_ip4_config;
+	device_class->act_stage3_ip6_config_start = real_act_stage3_ip6_config_start;
 	device_class->check_connection_compatible = real_check_connection_compatible;
 	device_class->complete_connection = real_complete_connection;
+	device_class->hwaddr_matches = hwaddr_matches;
 
 	/* Properties */
 	g_object_class_install_property
diff --git a/src/nm-device-bt.h b/src/nm-device-bt.h
index d3187d76..0d54d607 100644
--- a/src/nm-device-bt.h
+++ b/src/nm-device-bt.h
@@ -33,6 +33,12 @@ G_BEGIN_DECLS
 #define NM_IS_DEVICE_BT_CLASS(klass)	(G_TYPE_CHECK_CLASS_TYPE ((klass),  NM_TYPE_DEVICE_BT))
 #define NM_DEVICE_BT_GET_CLASS(obj)	(G_TYPE_INSTANCE_GET_CLASS ((obj),  NM_TYPE_DEVICE_BT, NMDeviceBtClass))
 
+typedef enum {
+	NM_BT_ERROR_CONNECTION_NOT_BT = 0,   /*< nick=ConnectionNotBt >*/
+	NM_BT_ERROR_CONNECTION_INVALID,      /*< nick=ConnectionInvalid >*/
+	NM_BT_ERROR_CONNECTION_INCOMPATIBLE, /*< nick=ConnectionIncompatible >*/
+} NMBtError;
+
 #define NM_DEVICE_BT_HW_ADDRESS   "hw-address"
 #define NM_DEVICE_BT_NAME         "name"
 #define NM_DEVICE_BT_CAPABILITIES "bt-capabilities"
@@ -69,4 +75,4 @@ gboolean nm_device_bt_modem_removed (NMDeviceBt *device, NMModem *modem);
 
 G_END_DECLS
 
-#endif /* NM_GSM_DEVICE_H */
+#endif /* NM_DEVICE_BT_H */
diff --git a/src/nm-device-ethernet.c b/src/nm-device-ethernet.c
index 8556c5bd..df0ae94f 100644
--- a/src/nm-device-ethernet.c
+++ b/src/nm-device-ethernet.c
@@ -15,7 +15,7 @@
  * with this program; if not, write to the Free Software Foundation, Inc.,
  * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
  *
- * Copyright (C) 2005 - 2011 Red Hat, Inc.
+ * Copyright (C) 2005 - 2012 Red Hat, Inc.
  * Copyright (C) 2006 - 2008 Novell, Inc.
  */
 
@@ -24,11 +24,8 @@
 #include <glib/gi18n.h>
 #include <netinet/in.h>
 #include <string.h>
-#include <net/ethernet.h>
 #include <stdlib.h>
-#include <linux/types.h>
 #include <linux/sockios.h>
-#include <linux/version.h>
 #include <linux/ethtool.h>
 #include <sys/ioctl.h>
 #include <unistd.h>
@@ -38,47 +35,37 @@
 
 #include <gudev/gudev.h>
 
-#include <netlink/route/addr.h>
-
 #include "nm-glib-compat.h"
 #include "nm-device-ethernet.h"
-#include "nm-device-interface.h"
 #include "nm-device-private.h"
 #include "nm-activation-request.h"
 #include "NetworkManagerUtils.h"
 #include "nm-supplicant-manager.h"
 #include "nm-supplicant-interface.h"
 #include "nm-supplicant-config.h"
-#include "nm-netlink-monitor.h"
 #include "nm-system.h"
 #include "nm-setting-connection.h"
 #include "nm-setting-wired.h"
 #include "nm-setting-8021x.h"
 #include "nm-setting-pppoe.h"
+#include "nm-setting-bond.h"
 #include "ppp-manager/nm-ppp-manager.h"
 #include "nm-logging.h"
 #include "nm-properties-changed-signal.h"
-#include "nm-dhcp-manager.h"
-#include "nm-netlink-utils.h"
+#include "nm-utils.h"
+#include "nm-enum-types.h"
+#include "nm-netlink-monitor.h"
 
 #include "nm-device-ethernet-glue.h"
 
 
-G_DEFINE_TYPE (NMDeviceEthernet, nm_device_ethernet, NM_TYPE_DEVICE)
+G_DEFINE_TYPE (NMDeviceEthernet, nm_device_ethernet, NM_TYPE_DEVICE_WIRED)
 
 #define NM_DEVICE_ETHERNET_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), NM_TYPE_DEVICE_ETHERNET, NMDeviceEthernetPrivate))
 
 #define WIRED_SECRETS_TRIES "wired-secrets-tries"
 
-typedef enum
-{
-	NM_ETHERNET_ERROR_CONNECTION_NOT_WIRED = 0,
-	NM_ETHERNET_ERROR_CONNECTION_INVALID,
-	NM_ETHERNET_ERROR_CONNECTION_INCOMPATIBLE,
-} NMEthernetError;
-
 #define NM_ETHERNET_ERROR (nm_ethernet_error_quark ())
-#define NM_TYPE_ETHERNET_ERROR (nm_ethernet_error_get_type ()) 
 
 typedef struct Supplicant {
 	NMSupplicantManager *mgr;
@@ -94,17 +81,8 @@ typedef struct Supplicant {
 } Supplicant;
 
 typedef struct {
-	gboolean            disposed;
-
-	guint8              hw_addr[ETH_ALEN];         /* Currently set MAC address */
 	guint8              perm_hw_addr[ETH_ALEN];    /* Permanent MAC address */
 	guint8              initial_hw_addr[ETH_ALEN]; /* Initial MAC address (as seen when NM starts) */
-	gboolean            carrier;
-
-	NMNetlinkMonitor *  monitor;
-	gulong              link_connected_id;
-	gulong              link_disconnected_id;
-	guint               carrier_action_defer_id;
 
 	Supplicant          supplicant;
 	guint               supplicant_timeout_id;
@@ -151,145 +129,6 @@ nm_ethernet_error_quark (void)
 	return quark;
 }
 
-/* This should really be standard. */
-#define ENUM_ENTRY(NAME, DESC) { NAME, "" #NAME "", DESC }
-
-static GType
-nm_ethernet_error_get_type (void)
-{
-	static GType etype = 0;
-
-	if (etype == 0) {
-		static const GEnumValue values[] = {
-			/* Connection was not a wired connection. */
-			ENUM_ENTRY (NM_ETHERNET_ERROR_CONNECTION_NOT_WIRED, "ConnectionNotWired"),
-			/* Connection was not a valid wired connection. */
-			ENUM_ENTRY (NM_ETHERNET_ERROR_CONNECTION_INVALID, "ConnectionInvalid"),
-			/* Connection does not apply to this device. */
-			ENUM_ENTRY (NM_ETHERNET_ERROR_CONNECTION_INCOMPATIBLE, "ConnectionIncompatible"),
-			{ 0, 0, 0 }
-		};
-		etype = g_enum_register_static ("NMEthernetError", values);
-	}
-	return etype;
-}
-
-static void
-carrier_action_defer_clear (NMDeviceEthernet *self)
-{
-	NMDeviceEthernetPrivate *priv = NM_DEVICE_ETHERNET_GET_PRIVATE (self);
-
-	if (priv->carrier_action_defer_id) {
-		g_source_remove (priv->carrier_action_defer_id);
-		priv->carrier_action_defer_id = 0;
-	}
-}
-
-static gboolean
-carrier_action_defer_cb (gpointer user_data)
-{
-	NMDeviceEthernet *self = NM_DEVICE_ETHERNET (user_data);
-	NMDeviceEthernetPrivate *priv = NM_DEVICE_ETHERNET_GET_PRIVATE (self);
-	NMDeviceState state;
-
-	priv->carrier_action_defer_id = 0;
-
-	state = nm_device_interface_get_state (NM_DEVICE_INTERFACE (self));
-	if (state == NM_DEVICE_STATE_UNAVAILABLE) {
-		if (priv->carrier)
-			nm_device_state_changed (NM_DEVICE (self), NM_DEVICE_STATE_DISCONNECTED, NM_DEVICE_STATE_REASON_CARRIER);
-	} else if (state >= NM_DEVICE_STATE_DISCONNECTED) {
-		if (!priv->carrier)
-			nm_device_state_changed (NM_DEVICE (self), NM_DEVICE_STATE_UNAVAILABLE, NM_DEVICE_STATE_REASON_CARRIER);
-	}
-
-	return FALSE;
-}
-
-static void
-set_carrier (NMDeviceEthernet *self,
-             const gboolean carrier,
-             const gboolean defer_action)
-{
-	NMDeviceEthernetPrivate *priv;
-	NMDeviceState state;
-
-	g_return_if_fail (NM_IS_DEVICE (self));
-
-	priv = NM_DEVICE_ETHERNET_GET_PRIVATE (self);
-	if (priv->carrier == carrier)
-		return;
-
-	/* Clear any previous deferred action */
-	carrier_action_defer_clear (self);
-
-	priv->carrier = carrier;
-	g_object_notify (G_OBJECT (self), NM_DEVICE_ETHERNET_CARRIER);
-
-	state = nm_device_interface_get_state (NM_DEVICE_INTERFACE (self));
-	nm_log_info (LOGD_HW | LOGD_ETHER, "(%s): carrier now %s (device state %d%s)",
-	             nm_device_get_iface (NM_DEVICE (self)),
-	             carrier ? "ON" : "OFF",
-	             state,
-	             defer_action ? ", deferring action for 4 seconds" : "");
-
-	if (defer_action)
-		priv->carrier_action_defer_id = g_timeout_add_seconds (4, carrier_action_defer_cb, self);
-	else
-		carrier_action_defer_cb (self);
-}
-
-static void
-carrier_on (NMNetlinkMonitor *monitor,
-            int idx,
-            gpointer user_data)
-{
-	NMDevice *device = NM_DEVICE (user_data);
-	NMDeviceEthernet *self = NM_DEVICE_ETHERNET (device);
-	guint32 caps;
-
-	/* Make sure signal is for us */
-	if (idx == nm_device_get_ifindex (device)) {
-		/* Ignore spurious netlink messages */
-		caps = nm_device_get_capabilities (device);
-		if (!(caps & NM_DEVICE_CAP_CARRIER_DETECT))
-			return;
-
-		set_carrier (self, TRUE, FALSE);
-	}
-}
-
-static void
-carrier_off (NMNetlinkMonitor *monitor,
-             int idx,
-             gpointer user_data)
-{
-	NMDevice *device = NM_DEVICE (user_data);
-	NMDeviceEthernet *self = NM_DEVICE_ETHERNET (device);
-	guint32 caps;
-
-	/* Make sure signal is for us */
-	if (idx == nm_device_get_ifindex (device)) {
-		NMDeviceState state;
-		gboolean defer = FALSE;
-
-		/* Ignore spurious netlink messages */
-		caps = nm_device_get_capabilities (device);
-		if (!(caps & NM_DEVICE_CAP_CARRIER_DETECT))
-			return;
-
-		/* Defer carrier-off event actions while connected by a few seconds
-		 * so that tripping over a cable, power-cycling a switch, or breaking
-		 * off the RJ45 locking tab isn't so catastrophic.
-		 */
-		state = nm_device_interface_get_state (NM_DEVICE_INTERFACE (self));
-		if (state > NM_DEVICE_STATE_DISCONNECTED)
-			defer = TRUE;
-
-		set_carrier (self, FALSE, defer);
-	}
-}
-
 static void
 _update_s390_subchannels (NMDeviceEthernet *self)
 {
@@ -401,75 +240,26 @@ constructor (GType type,
 	GObject *object;
 	NMDeviceEthernetPrivate *priv;
 	NMDevice *self;
-	guint32 caps;
+	int itype;
 
 	object = G_OBJECT_CLASS (nm_device_ethernet_parent_class)->constructor (type,
 	                                                                        n_construct_params,
 	                                                                        construct_params);
-	if (!object)
-		return NULL;
+	if (object) {
+		self = NM_DEVICE (object);
+		priv = NM_DEVICE_ETHERNET_GET_PRIVATE (self);
 
-	self = NM_DEVICE (object);
-	priv = NM_DEVICE_ETHERNET_GET_PRIVATE (self);
-
-	nm_log_dbg (LOGD_HW | LOGD_OLPC_MESH, "(%s): kernel ifindex %d",
-	            nm_device_get_iface (NM_DEVICE (self)),
-	            nm_device_get_ifindex (NM_DEVICE (self)));
-
-	/* s390 stuff */
-	_update_s390_subchannels (NM_DEVICE_ETHERNET (self));
-
-	caps = nm_device_get_capabilities (self);
-	if (caps & NM_DEVICE_CAP_CARRIER_DETECT) {
-		GError *error = NULL;
-		guint32 ifflags = 0;
-
-		/* Only listen to netlink for cards that support carrier detect */
-		priv->monitor = nm_netlink_monitor_get ();
-
-		priv->link_connected_id = g_signal_connect (priv->monitor, "carrier-on",
-		                                            G_CALLBACK (carrier_on),
-		                                            self);
-		priv->link_disconnected_id = g_signal_connect (priv->monitor, "carrier-off",
-		                                               G_CALLBACK (carrier_off),
-		                                               self);
-
-		/* Get initial link state */
-		if (!nm_netlink_monitor_get_flags_sync (priv->monitor,
-		                                        nm_device_get_ifindex (NM_DEVICE (self)),
-		                                        &ifflags,
-		                                        &error)) {
-			nm_log_warn (LOGD_HW | LOGD_ETHER,
-			             "(%s): couldn't get initial carrier state: (%d) %s",
-			             nm_device_get_iface (NM_DEVICE (self)),
-			             error ? error->code : -1,
-			             (error && error->message) ? error->message : "unknown");
-			g_clear_error (&error);
-		} else
-			priv->carrier = !!(ifflags & IFF_LOWER_UP);
-
-		nm_log_info (LOGD_HW | LOGD_ETHER,
-		             "(%s): carrier is %s",
-		             nm_device_get_iface (NM_DEVICE (self)),
-		             priv->carrier ? "ON" : "OFF");
-
-		/* Request link state again just in case an error occurred getting the
-		 * initial link state.
-		 */
-		if (!nm_netlink_monitor_request_status (priv->monitor, &error)) {
-			nm_log_warn (LOGD_HW | LOGD_ETHER,
-			             "(%s): couldn't request carrier state: (%d) %s",
-			             nm_device_get_iface (NM_DEVICE (self)),
-			             error ? error->code : -1,
-			             (error && error->message) ? error->message : "unknown");
-			g_clear_error (&error);
-		}
-	} else {
-		nm_log_info (LOGD_HW | LOGD_ETHER,
-		             "(%s): driver '%s' does not support carrier detection.",
-		             nm_device_get_iface (self),
-		             nm_device_get_driver (self));
-		priv->carrier = TRUE;
+		// FIXME: Convert this into a no-export property so type can be specified
+		//        when the device is created.
+		itype = nm_system_get_iface_type (nm_device_get_ifindex (self), nm_device_get_iface (self));
+		g_assert (itype == NM_IFACE_TYPE_UNSPEC);
+
+		nm_log_dbg (LOGD_HW | LOGD_ETHER, "(%s): kernel ifindex %d",
+			        nm_device_get_iface (NM_DEVICE (self)),
+			        nm_device_get_ifindex (NM_DEVICE (self)));
+
+		/* s390 stuff */
+		_update_s390_subchannels (NM_DEVICE_ETHERNET (self));
 	}
 
 	return object;
@@ -496,7 +286,6 @@ device_state_changed (NMDevice *device,
                       NMDeviceStateReason reason,
                       gpointer user_data)
 {
-
 	switch (new_state) {
 	case NM_DEVICE_STATE_ACTIVATED:
 	case NM_DEVICE_STATE_FAILED:
@@ -544,24 +333,6 @@ real_take_down (NMDevice *dev)
 	}
 }
 
-static gboolean
-real_hw_is_up (NMDevice *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_iface_set_up (nm_device_get_ip_ifindex (dev), TRUE, no_firmware);
-}
-
-static void
-real_hw_take_down (NMDevice *dev)
-{
-	nm_system_iface_set_up (nm_device_get_ip_ifindex (dev), FALSE, NULL);
-}
-
 NMDevice *
 nm_device_ethernet_new (const char *udi,
 						const char *iface,
@@ -572,82 +343,24 @@ nm_device_ethernet_new (const char *udi,
 	g_return_val_if_fail (driver != NULL, NULL);
 
 	return (NMDevice *) g_object_new (NM_TYPE_DEVICE_ETHERNET,
-	                                  NM_DEVICE_INTERFACE_UDI, udi,
-	                                  NM_DEVICE_INTERFACE_IFACE, iface,
-	                                  NM_DEVICE_INTERFACE_DRIVER, driver,
-	                                  NM_DEVICE_INTERFACE_TYPE_DESC, "Ethernet",
-	                                  NM_DEVICE_INTERFACE_DEVICE_TYPE, NM_DEVICE_TYPE_ETHERNET,
+	                                  NM_DEVICE_UDI, udi,
+	                                  NM_DEVICE_IFACE, iface,
+	                                  NM_DEVICE_DRIVER, driver,
+	                                  NM_DEVICE_TYPE_DESC, "Ethernet",
+	                                  NM_DEVICE_DEVICE_TYPE, NM_DEVICE_TYPE_ETHERNET,
 	                                  NULL);
 }
 
-
-/*
- * nm_device_ethernet_get_address
- *
- * Get a device's hardware address
- *
- */
-void
-nm_device_ethernet_get_address (NMDeviceEthernet *self, struct ether_addr *addr)
-{
-	NMDeviceEthernetPrivate *priv;
-
-	g_return_if_fail (self != NULL);
-	g_return_if_fail (addr != NULL);
-
-	priv = NM_DEVICE_ETHERNET_GET_PRIVATE (self);
-	memcpy (addr, &priv->hw_addr, sizeof (priv->hw_addr));
-}
-
-/* Returns speed in Mb/s */
-static guint32
-nm_device_ethernet_get_speed (NMDeviceEthernet *self)
-{
-	int fd;
-	struct ifreq ifr;
-	struct ethtool_cmd edata = {
-		.cmd = ETHTOOL_GSET,
-	};
-	guint32 speed = 0;
-
-	g_return_val_if_fail (self != NULL, 0);
-
-	fd = socket (PF_INET, SOCK_DGRAM, 0);
-	if (fd < 0) {
-		nm_log_warn (LOGD_HW, "couldn't open control socket.");
-		return 0;
-	}
-
-	memset (&ifr, 0, sizeof (struct ifreq));
-	strncpy (ifr.ifr_name, nm_device_get_iface (NM_DEVICE (self)), IFNAMSIZ);
-	ifr.ifr_data = (char *) &edata;
-
-	if (ioctl (fd, SIOCETHTOOL, &ifr) < 0)
-		goto out;
-
-#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,27)
-	speed = edata.speed;
-#else
-	speed = ethtool_cmd_speed (&edata);
-#endif
-
-	if (speed == G_MAXUINT16 || speed == G_MAXUINT32)
-		speed = 0;
-
-out:
-	close (fd);
-	return speed;
-}
-
 static void
 _update_hw_addr (NMDeviceEthernet *self, const guint8 *addr)
 {
-	NMDeviceEthernetPrivate *priv = NM_DEVICE_ETHERNET_GET_PRIVATE (self);
+	const guint8 *current_addr;
 
 	g_return_if_fail (addr != NULL);
 
-	if (memcmp (&priv->hw_addr, addr, ETH_ALEN)) {
-		memcpy (&priv->hw_addr, addr, ETH_ALEN);
+	current_addr = nm_device_wired_get_hwaddr (NM_DEVICE_WIRED (self));
+	if (memcmp (current_addr, addr, ETH_ALEN)) {
+		nm_device_wired_set_hwaddr (NM_DEVICE_WIRED (self), addr, ETH_ALEN);
 		g_object_notify (G_OBJECT (self), NM_DEVICE_ETHERNET_HW_ADDRESS);
 	}
 }
@@ -656,7 +369,7 @@ static gboolean
 _set_hw_addr (NMDeviceEthernet *self, const guint8 *addr, const char *detail)
 {
 	NMDevice *dev = NM_DEVICE (self);
-	NMDeviceEthernetPrivate *priv = NM_DEVICE_ETHERNET_GET_PRIVATE (self);
+	const guint8 *current_addr;
 	const char *iface;
 	char *mac_str = NULL;
 	gboolean success = FALSE;
@@ -665,18 +378,18 @@ _set_hw_addr (NMDeviceEthernet *self, const guint8 *addr, const char *detail)
 
 	iface = nm_device_get_iface (dev);
 
-	mac_str = g_strdup_printf ("%02X:%02X:%02X:%02X:%02X:%02X",
-	                           addr[0], addr[1], addr[2], addr[3], addr[4], addr[5]);
-
 	/* Do nothing if current MAC is same */
-	if (!memcmp (&priv->hw_addr, addr, ETH_ALEN)) {
+	current_addr = nm_device_wired_get_hwaddr (NM_DEVICE_WIRED (self));
+	if (!memcmp (current_addr, addr, ETH_ALEN)) {
 		nm_log_dbg (LOGD_DEVICE | LOGD_ETHER, "(%s): no MAC address change needed", iface);
-		g_free (mac_str);
 		return TRUE;
 	}
 
+	mac_str = g_strdup_printf ("%02X:%02X:%02X:%02X:%02X:%02X",
+	                           addr[0], addr[1], addr[2], addr[3], addr[4], addr[5]);
+
 	/* Can't change MAC address while device is up */
-	real_hw_take_down (dev);
+	nm_device_hw_take_down (dev, FALSE);
 
 	success = nm_system_iface_set_mac (nm_device_get_ip_ifindex (dev), (struct ether_addr *) addr);
 	if (success) {
@@ -688,7 +401,7 @@ _set_hw_addr (NMDeviceEthernet *self, const guint8 *addr, const char *detail)
 		nm_log_warn (LOGD_DEVICE | LOGD_ETHER, "(%s): failed to %s MAC address to %s",
 		             iface, detail, mac_str);
 	}
-	real_hw_bring_up (dev, NULL);
+	nm_device_hw_bring_up (dev, FALSE, NULL);
 	g_free (mac_str);
 
 	return success;
@@ -697,28 +410,17 @@ _set_hw_addr (NMDeviceEthernet *self, const guint8 *addr, const char *detail)
 static void
 real_update_hw_address (NMDevice *dev)
 {
-	NMDeviceEthernet *self = NM_DEVICE_ETHERNET (dev);
-	struct ifreq req;
-	int fd;
-
-	fd = socket (PF_INET, SOCK_DGRAM, 0);
-	if (fd < 0) {
-		nm_log_warn (LOGD_HW, "couldn't open control socket.");
-		return;
-	}
+	const guint8 *hw_addr;
+	guint8 old_addr[ETH_ALEN];
 
-	memset (&req, 0, sizeof (struct ifreq));
-	strncpy (req.ifr_name, nm_device_get_iface (dev), IFNAMSIZ);
+	hw_addr = nm_device_wired_get_hwaddr (NM_DEVICE_WIRED (dev));
+	memcpy (old_addr, hw_addr, ETH_ALEN);
 
-	errno = 0;
-	if (ioctl (fd, SIOCGIFHWADDR, &req) < 0) {
-		nm_log_err (LOGD_HW | LOGD_ETHER,
-		            "(%s) failed to read hardware address (error %d)",
-		            nm_device_get_iface (dev), errno);
-	} else
-		_update_hw_addr (self, (const guint8 *) &req.ifr_hwaddr.sa_data);
+	NM_DEVICE_CLASS (nm_device_ethernet_parent_class)->update_hw_address (dev);
 
-	close (fd);
+	hw_addr = nm_device_wired_get_hwaddr (NM_DEVICE_WIRED (dev));
+	if (memcmp (old_addr, hw_addr, ETH_ALEN))
+		g_object_notify (G_OBJECT (dev), NM_DEVICE_ETHERNET_HW_ADDRESS);
 }
 
 static void
@@ -748,10 +450,13 @@ real_update_permanent_hw_address (NMDevice *dev)
 	errno = 0;
 	ret = ioctl (fd, SIOCETHTOOL, &req);
 	if ((ret < 0) || !nm_ethernet_address_is_valid ((struct ether_addr *) epaddr->data)) {
+		const guint8 *current_addr;
+
 		nm_log_err (LOGD_HW | LOGD_ETHER, "(%s): unable to read permanent MAC address (error %d)",
 		            nm_device_get_iface (dev), errno);
 		/* Fall back to current address */
-		memcpy (epaddr->data, &priv->hw_addr, ETH_ALEN);
+		current_addr = nm_device_wired_get_hwaddr (NM_DEVICE_WIRED (self));
+		memcpy (epaddr->data, current_addr, ETH_ALEN);
 	}
 
 	if (memcmp (&priv->perm_hw_addr, epaddr->data, ETH_ALEN)) {
@@ -767,6 +472,7 @@ real_update_initial_hw_address (NMDevice *dev)
 {
 	NMDeviceEthernet *self = NM_DEVICE_ETHERNET (dev);
 	NMDeviceEthernetPrivate *priv = NM_DEVICE_ETHERNET_GET_PRIVATE (self);
+	const guint8 *current_addr;
 	char *mac_str = NULL;
 	guint8 *addr = priv->initial_hw_addr;
 	guint8 zero[ETH_ALEN] = {0,0,0,0,0,0};
@@ -774,11 +480,12 @@ real_update_initial_hw_address (NMDevice *dev)
 	/* This sets initial MAC address from current MAC address. It should only
 	 * be called from NMDevice constructor() to really get the initial address.
 	 */
-	if (!memcmp (&priv->hw_addr, &zero, ETH_ALEN))
+	current_addr = nm_device_wired_get_hwaddr (NM_DEVICE_WIRED (self));
+	if (!memcmp (current_addr, &zero, ETH_ALEN))
 		real_update_hw_address (dev);
 
-	if (memcmp (&priv->initial_hw_addr, &priv->hw_addr, ETH_ALEN))
-		memcpy (&priv->initial_hw_addr, &priv->hw_addr, ETH_ALEN);
+	if (memcmp (&priv->initial_hw_addr, current_addr, ETH_ALEN))
+		memcpy (&priv->initial_hw_addr, current_addr, ETH_ALEN);
 
 	mac_str = g_strdup_printf ("%02X:%02X:%02X:%02X:%02X:%02X",
 	                           addr[0], addr[1], addr[2], addr[3], addr[4], addr[5]);
@@ -808,34 +515,6 @@ real_get_generic_capabilities (NMDevice *dev)
 }
 
 static gboolean
-real_can_interrupt_activation (NMDevice *dev)
-{
-	NMDeviceEthernet *self = NM_DEVICE_ETHERNET (dev);
-	gboolean interrupt = FALSE;
-
-	/* Devices that support carrier detect can interrupt activation
-	 * if the link becomes inactive.
-	 */
-	if (nm_device_get_capabilities (dev) & NM_DEVICE_CAP_CARRIER_DETECT) {
-		if (NM_DEVICE_ETHERNET_GET_PRIVATE (self)->carrier == FALSE)
-			interrupt = TRUE;
-	}
-	return interrupt;
-}
-
-static gboolean
-real_is_available (NMDevice *dev)
-{
-	NMDeviceEthernet *self = NM_DEVICE_ETHERNET (dev);
-
-	/* Can't do anything if there isn't a carrier */
-	if (!NM_DEVICE_ETHERNET_GET_PRIVATE (self)->carrier)
-		return FALSE;
-
-	return TRUE;
-}
-
-static gboolean
 match_subchans (NMDeviceEthernet *self, NMSettingWired *s_wired, gboolean *try_mac)
 {
 	NMDeviceEthernetPrivate *priv = NM_DEVICE_ETHERNET_GET_PRIVATE (self);
@@ -868,74 +547,97 @@ match_subchans (NMDeviceEthernet *self, NMSettingWired *s_wired, gboolean *try_m
 	return TRUE;
 }
 
+static gboolean
+match_ethernet_connection (NMDevice *device, NMConnection *connection,
+                           gboolean check_blacklist, GError **error)
+{
+	NMDeviceEthernet *self = NM_DEVICE_ETHERNET (device);
+	NMDeviceEthernetPrivate *priv = NM_DEVICE_ETHERNET_GET_PRIVATE (self);
+	NMSettingWired *s_wired;
+
+	s_wired = nm_connection_get_setting_wired (connection);
+
+	if (nm_connection_is_type (connection, NM_SETTING_PPPOE_SETTING_NAME)) {
+		/* NOP */
+	} else if (nm_connection_is_type (connection, NM_SETTING_WIRED_SETTING_NAME)) {
+		if (!s_wired) {
+			g_set_error (error,
+			             NM_ETHERNET_ERROR, NM_ETHERNET_ERROR_CONNECTION_INVALID,
+			             "The connection was not a valid wired connection.");
+			return FALSE;
+		}
+	} else {
+		g_set_error (error,
+		             NM_ETHERNET_ERROR, NM_ETHERNET_ERROR_CONNECTION_NOT_WIRED,
+		             "The connection was not a wired, bond, or PPPoE connection.");
+		return FALSE;
+	}
+
+	if (s_wired) {
+		const GByteArray *mac;
+		gboolean try_mac = TRUE;
+		const GSList *mac_blacklist, *mac_blacklist_iter;
+
+		if (!match_subchans (self, s_wired, &try_mac)) {
+			g_set_error (error,
+			             NM_ETHERNET_ERROR, NM_ETHERNET_ERROR_CONNECTION_INCOMPATIBLE,
+			             "The connection's s390 subchannels did not match this device.");
+			return FALSE;
+		}
+
+		mac = nm_setting_wired_get_mac_address (s_wired);
+		if (try_mac && mac && memcmp (mac->data, &priv->perm_hw_addr, ETH_ALEN)) {
+			g_set_error (error,
+			             NM_ETHERNET_ERROR, NM_ETHERNET_ERROR_CONNECTION_INCOMPATIBLE,
+			             "The connection's MAC address did not match this device.");
+			return FALSE;
+		}
+
+		if (!check_blacklist)
+			return TRUE;
+
+		/* Check for MAC address blacklist */
+		mac_blacklist = nm_setting_wired_get_mac_address_blacklist (s_wired);
+		for (mac_blacklist_iter = mac_blacklist; mac_blacklist_iter;
+			 mac_blacklist_iter = g_slist_next (mac_blacklist_iter)) {
+			struct ether_addr addr;
+
+			if (!ether_aton_r (mac_blacklist_iter->data, &addr)) {
+				g_warn_if_reached ();
+				return FALSE;
+			}
+			if (memcmp (&addr, &priv->perm_hw_addr, ETH_ALEN) == 0) {
+				g_set_error (error,
+				             NM_ETHERNET_ERROR, NM_ETHERNET_ERROR_CONNECTION_INCOMPATIBLE,
+				             "The connection's MAC address (%s) is blacklisted in %s.",
+				             (char *) mac_blacklist_iter->data, NM_SETTING_WIRED_MAC_ADDRESS_BLACKLIST);
+				return FALSE;
+			}
+		}
+	}
+
+	return TRUE;
+}
+
 static NMConnection *
 real_get_best_auto_connection (NMDevice *dev,
                                GSList *connections,
                                char **specific_object)
 {
-	NMDeviceEthernet *self = NM_DEVICE_ETHERNET (dev);
-	NMDeviceEthernetPrivate *priv = NM_DEVICE_ETHERNET_GET_PRIVATE (self);
 	GSList *iter;
 
 	for (iter = connections; iter; iter = g_slist_next (iter)) {
 		NMConnection *connection = NM_CONNECTION (iter->data);
 		NMSettingConnection *s_con;
-		NMSettingWired *s_wired;
-		const char *connection_type;
-		gboolean is_pppoe = FALSE;
-		const GSList *mac_blacklist, *mac_blacklist_iter;
-		gboolean mac_blacklist_found = FALSE;
 
-		s_con = (NMSettingConnection *) nm_connection_get_setting (connection, NM_TYPE_SETTING_CONNECTION);
+		s_con = nm_connection_get_setting_connection (connection);
 		g_assert (s_con);
 
-		connection_type = nm_setting_connection_get_connection_type (s_con);
-		if (!strcmp (connection_type, NM_SETTING_PPPOE_SETTING_NAME))
-			is_pppoe = TRUE;
-
-		if (!is_pppoe && strcmp (connection_type, NM_SETTING_WIRED_SETTING_NAME))
-			continue;
-		if (!nm_setting_connection_get_autoconnect (s_con))
-			continue;
-
-		s_wired = (NMSettingWired *) nm_connection_get_setting (connection, NM_TYPE_SETTING_WIRED);
-		/* Wired setting optional for PPPoE */
-		if (!is_pppoe && !s_wired)
-			continue;
-
-		if (s_wired) {
-			const GByteArray *mac;
-			gboolean try_mac = TRUE;
-
-			if (!match_subchans (self, s_wired, &try_mac))
-				continue;
-
-			mac = nm_setting_wired_get_mac_address (s_wired);
-			if (try_mac && mac && memcmp (mac->data, &priv->perm_hw_addr, ETH_ALEN))
-				continue;
-
-			/* Check for MAC address blacklist */
-			mac_blacklist = nm_setting_wired_get_mac_address_blacklist (s_wired);
-			for (mac_blacklist_iter = mac_blacklist; mac_blacklist_iter;
-			     mac_blacklist_iter = g_slist_next (mac_blacklist_iter)) {
-				struct ether_addr addr;
-
-				if (!ether_aton_r (mac_blacklist_iter->data, &addr)) {
-					g_warn_if_reached ();
-					continue;
-				}
-				if (memcmp (&addr, &priv->perm_hw_addr, ETH_ALEN) == 0) {
-					mac_blacklist_found = TRUE;
-					break;
-				}
-			}
-			/* Found device MAC address in the blacklist - do not use this connection */
-			if (mac_blacklist_found)
-				continue;
-		}
-
-		return connection;
+		if (   nm_setting_connection_get_autoconnect (s_con)
+		    && match_ethernet_connection (dev, connection, TRUE, NULL))
+			return connection;
 	}
+
 	return NULL;
 }
 
@@ -1096,21 +798,21 @@ time_out:
 static NMSupplicantConfig *
 build_supplicant_config (NMDeviceEthernet *self)
 {
-	const char *con_path;
+	const char *con_uuid;
 	NMSupplicantConfig *config = NULL;
 	NMSetting8021x *security;
 	NMConnection *connection;
 
-	connection = nm_act_request_get_connection (nm_device_get_act_request (NM_DEVICE (self)));
-	g_return_val_if_fail (connection, NULL);
-	con_path = nm_connection_get_path (connection);
+	connection = nm_device_get_connection (NM_DEVICE (self));
+	g_assert (connection);
+	con_uuid = nm_connection_get_uuid (connection);
 
 	config = nm_supplicant_config_new ();
 	if (!config)
 		return NULL;
 
-	security = NM_SETTING_802_1X (nm_connection_get_setting (connection, NM_TYPE_SETTING_802_1X));
-	if (!nm_supplicant_config_add_setting_8021x (config, security, con_path, TRUE)) {
+	security = nm_connection_get_setting_802_1x (connection);
+	if (!nm_supplicant_config_add_setting_8021x (config, security, con_uuid, TRUE)) {
 		nm_log_warn (LOGD_DEVICE, "Couldn't add 802.1X security setting to supplicant config.");
 		g_object_unref (config);
 		config = NULL;
@@ -1353,16 +1055,19 @@ real_act_stage1_prepare (NMDevice *dev, NMDeviceStateReason *reason)
 
 	g_return_val_if_fail (reason != NULL, NM_ACT_STAGE_RETURN_FAILURE);
 
-	req = nm_device_get_act_request (NM_DEVICE (self));
-	g_return_val_if_fail (req != NULL, NM_ACT_STAGE_RETURN_FAILURE);
+	ret = NM_DEVICE_CLASS (nm_device_ethernet_parent_class)->act_stage1_prepare (dev, reason);
+	if (ret == NM_ACT_STAGE_RETURN_SUCCESS) {
+		req = nm_device_get_act_request (NM_DEVICE (self));
+		g_return_val_if_fail (req != NULL, NM_ACT_STAGE_RETURN_FAILURE);
 
-	s_wired = NM_SETTING_WIRED (device_get_setting (dev, NM_TYPE_SETTING_WIRED));
-	g_assert (s_wired);
+		s_wired = NM_SETTING_WIRED (device_get_setting (dev, NM_TYPE_SETTING_WIRED));
+		g_assert (s_wired);
 
-	/* Set device MAC address if the connection wants to change it */
-	cloned_mac = nm_setting_wired_get_cloned_mac_address (s_wired);
-	if (cloned_mac && (cloned_mac->len == ETH_ALEN))
-		_set_hw_addr (self, (const guint8 *) cloned_mac->data, "set");
+		/* Set device MAC address if the connection wants to change it */
+		cloned_mac = nm_setting_wired_get_cloned_mac_address (s_wired);
+		if (cloned_mac && (cloned_mac->len == ETH_ALEN))
+			_set_hw_addr (self, (const guint8 *) cloned_mac->data, "set");
+	}
 
 	return ret;
 }
@@ -1376,8 +1081,9 @@ nm_8021x_stage2_config (NMDeviceEthernet *self, NMDeviceStateReason *reason)
 	const char *iface;
 	NMActStageReturn ret = NM_ACT_STAGE_RETURN_FAILURE;
 
-	connection = nm_act_request_get_connection (nm_device_get_act_request (NM_DEVICE (self)));
-	security = NM_SETTING_802_1X (nm_connection_get_setting (connection, NM_TYPE_SETTING_802_1X));
+	connection = nm_device_get_connection (NM_DEVICE (self));
+	g_assert (connection);
+	security = nm_connection_get_setting_802_1x (connection);
 	if (!security) {
 		nm_log_err (LOGD_DEVICE, "Invalid or missing 802.1X security");
 		*reason = NM_DEVICE_STATE_REASON_CONFIG_FAILED;
@@ -1434,19 +1140,17 @@ ppp_state_changed (NMPPPManager *ppp_manager, NMPPPStatus status, gpointer user_
 
 static void
 ppp_ip4_config (NMPPPManager *ppp_manager,
-			 const char *iface,
-			 NMIP4Config *config,
-			 gpointer user_data)
+                const char *iface,
+                NMIP4Config *config,
+                gpointer user_data)
 {
 	NMDevice *device = NM_DEVICE (user_data);
 
 	/* Ignore PPP IP4 events that come in after initial configuration */
-	if (nm_device_get_state (device) != NM_DEVICE_STATE_IP_CONFIG)
-		return;
-
-	nm_device_set_ip_iface (device, iface);
-	NM_DEVICE_ETHERNET_GET_PRIVATE (device)->pending_ip4_config = g_object_ref (config);
-	nm_device_activate_schedule_stage4_ip4_config_get (device);
+	if (nm_device_activate_ip4_state_in_conf (device)) {
+		nm_device_set_ip_iface (device, iface);
+		nm_device_activate_schedule_ip4_config_result (device, config);
+	}
 }
 
 static NMActStageReturn
@@ -1465,7 +1169,7 @@ pppoe_stage3_ip4_config_start (NMDeviceEthernet *self, NMDeviceStateReason *reas
 	connection = nm_act_request_get_connection (req);
 	g_assert (req);
 
-	s_pppoe = (NMSettingPPPOE *) nm_connection_get_setting (connection, NM_TYPE_SETTING_PPPOE);
+	s_pppoe = nm_connection_get_setting_pppoe (connection);
 	g_assert (s_pppoe);
 
 	priv->ppp_manager = nm_ppp_manager_new (nm_device_get_iface (NM_DEVICE (self)));
@@ -1519,7 +1223,9 @@ real_act_stage2_config (NMDevice *device, NMDeviceStateReason *reason)
 }
 
 static NMActStageReturn
-real_act_stage3_ip4_config_start (NMDevice *device, NMDeviceStateReason *reason)
+real_act_stage3_ip4_config_start (NMDevice *device,
+                                  NMIP4Config **out_config,
+                                  NMDeviceStateReason *reason)
 {
 	NMSettingConnection *s_con;
 	const char *connection_type;
@@ -1533,61 +1239,29 @@ real_act_stage3_ip4_config_start (NMDevice *device, NMDeviceStateReason *reason)
 	if (!strcmp (connection_type, NM_SETTING_PPPOE_SETTING_NAME))
 		return pppoe_stage3_ip4_config_start (NM_DEVICE_ETHERNET (device), reason);
 
-	return NM_DEVICE_CLASS (nm_device_ethernet_parent_class)->act_stage3_ip4_config_start (device, reason);
+	return NM_DEVICE_CLASS (nm_device_ethernet_parent_class)->act_stage3_ip4_config_start (device, out_config, reason);
 }
 
-static NMActStageReturn
-real_act_stage4_get_ip4_config (NMDevice *device,
-                                NMIP4Config **config,
-                                NMDeviceStateReason *reason)
+static void
+real_ip4_config_pre_commit (NMDevice *device, NMIP4Config *config)
 {
-	NMDeviceEthernet *self = NM_DEVICE_ETHERNET (device);
-	NMDeviceEthernetPrivate *priv = NM_DEVICE_ETHERNET_GET_PRIVATE (self);
-	NMActStageReturn ret;
-
-	g_return_val_if_fail (config != NULL, NM_ACT_STAGE_RETURN_FAILURE);
-	g_return_val_if_fail (*config == NULL, NM_ACT_STAGE_RETURN_FAILURE);
-	g_return_val_if_fail (reason != NULL, NM_ACT_STAGE_RETURN_FAILURE);
-
-	if (!priv->ppp_manager) {
-		/* Regular ethernet connection. */
-
-		/* Chain up to parent */
-		ret = NM_DEVICE_CLASS (nm_device_ethernet_parent_class)->act_stage4_get_ip4_config (device, config, reason);
-
-		if (ret == NM_ACT_STAGE_RETURN_SUCCESS) {
-			NMConnection *connection;
-			NMSettingWired *s_wired;
-			guint32 mtu;
-
-			connection = nm_act_request_get_connection (nm_device_get_act_request (device));
-			g_assert (connection);
-			s_wired = NM_SETTING_WIRED (nm_connection_get_setting (connection, NM_TYPE_SETTING_WIRED));
-			g_assert (s_wired);
-
-			/* MTU override */
-			mtu = nm_setting_wired_get_mtu (s_wired);
-			if (mtu)
-				nm_ip4_config_set_mtu (*config, mtu);
-		}
-	} else {
-		NMConnection *connection;
-		NMSettingIP4Config *s_ip4;
-
-		/* PPPoE */
-		*config = priv->pending_ip4_config;
-		priv->pending_ip4_config = NULL;
+	NMConnection *connection;
+	NMSettingWired *s_wired;
+	guint32 mtu;
 
-		/* Merge user-defined overrides into the IP4Config to be applied */
-		connection = nm_act_request_get_connection (nm_device_get_act_request (device));
-		g_assert (connection);
-		s_ip4 = (NMSettingIP4Config *) nm_connection_get_setting (connection, NM_TYPE_SETTING_IP4_CONFIG);
-		nm_utils_merge_ip4_config (*config, s_ip4);
+	/* MTU only set for plain ethernet */
+	if (NM_DEVICE_ETHERNET_GET_PRIVATE (device)->ppp_manager)
+		return;
 
-		ret = NM_ACT_STAGE_RETURN_SUCCESS;
-	}
+	connection = nm_device_get_connection (device);
+	g_assert (connection);
+	s_wired = nm_connection_get_setting_wired (connection);
+	g_assert (s_wired);
 
-	return ret;
+	/* MTU override */
+	mtu = nm_setting_wired_get_mtu (s_wired);
+	if (mtu)
+		nm_ip4_config_set_mtu (config, mtu);
 }
 
 static void
@@ -1620,79 +1294,7 @@ real_check_connection_compatible (NMDevice *device,
                                   NMConnection *connection,
                                   GError **error)
 {
-	NMDeviceEthernet *self = NM_DEVICE_ETHERNET (device);
-	NMDeviceEthernetPrivate *priv = NM_DEVICE_ETHERNET_GET_PRIVATE (self);
-	NMSettingConnection *s_con;
-	NMSettingWired *s_wired;
-	const char *connection_type;
-	gboolean is_pppoe = FALSE;
-	const GByteArray *mac;
-	gboolean try_mac = TRUE;
-	const GSList *mac_blacklist, *mac_blacklist_iter;
-
-	s_con = NM_SETTING_CONNECTION (nm_connection_get_setting (connection, NM_TYPE_SETTING_CONNECTION));
-	g_assert (s_con);
-
-	connection_type = nm_setting_connection_get_connection_type (s_con);
-	if (   strcmp (connection_type, NM_SETTING_WIRED_SETTING_NAME)
-	    && strcmp (connection_type, NM_SETTING_PPPOE_SETTING_NAME)) {
-		g_set_error (error,
-		             NM_ETHERNET_ERROR, NM_ETHERNET_ERROR_CONNECTION_NOT_WIRED,
-		             "The connection was not a wired or PPPoE connection.");
-		return FALSE;
-	}
-
-	if (!strcmp (connection_type, NM_SETTING_PPPOE_SETTING_NAME))
-		is_pppoe = TRUE;
-
-	s_wired = (NMSettingWired *) nm_connection_get_setting (connection, NM_TYPE_SETTING_WIRED);
-	/* Wired setting is optional for PPPoE */
-	if (!is_pppoe && !s_wired) {
-		g_set_error (error,
-		             NM_ETHERNET_ERROR, NM_ETHERNET_ERROR_CONNECTION_INVALID,
-		             "The connection was not a valid wired connection.");
-		return FALSE;
-	}
-
-	if (s_wired) {
-		if (!match_subchans (self, s_wired, &try_mac)) {
-			g_set_error (error,
-			             NM_ETHERNET_ERROR, NM_ETHERNET_ERROR_CONNECTION_INCOMPATIBLE,
-			             "The connection's s390 subchannels did not match this device.");
-			return FALSE;
-		}
-
-		mac = nm_setting_wired_get_mac_address (s_wired);
-		if (try_mac && mac && memcmp (mac->data, &priv->perm_hw_addr, ETH_ALEN)) {
-			g_set_error (error,
-			             NM_ETHERNET_ERROR, NM_ETHERNET_ERROR_CONNECTION_INCOMPATIBLE,
-			             "The connection's MAC address did not match this device.");
-			return FALSE;
-		}
-
-		/* Check for MAC address blacklist */
-		mac_blacklist = nm_setting_wired_get_mac_address_blacklist (s_wired);
-		for (mac_blacklist_iter = mac_blacklist; mac_blacklist_iter;
-		     mac_blacklist_iter = g_slist_next (mac_blacklist_iter)) {
-			struct ether_addr addr;
-
-			if (!ether_aton_r (mac_blacklist_iter->data, &addr)) {
-				g_warn_if_reached ();
-				continue;
-			}
-			if (memcmp (&addr, &priv->perm_hw_addr, ETH_ALEN) == 0) {
-				g_set_error (error,
-				             NM_ETHERNET_ERROR, NM_ETHERNET_ERROR_CONNECTION_INCOMPATIBLE,
-				             "The connection's MAC address (%s) is blacklisted in %s.",
-				             (char *) mac_blacklist_iter->data, NM_SETTING_WIRED_MAC_ADDRESS_BLACKLIST);
-				return FALSE;
-			}
-		}
-	}
-
-	// FIXME: check bitrate against device capabilities
-
-	return TRUE;
+	return match_ethernet_connection (device, connection, TRUE, error);
 }
 
 static gboolean
@@ -1707,7 +1309,7 @@ real_complete_connection (NMDevice *device,
 	NMSettingPPPOE *s_pppoe;
 	const GByteArray *setting_mac;
 
-	s_pppoe = (NMSettingPPPOE *) nm_connection_get_setting (connection, NM_TYPE_SETTING_PPPOE);
+	s_pppoe = nm_connection_get_setting_pppoe (connection);
 
 	/* We can't telepathically figure out the service name or username, so if
 	 * those weren't given, we can't complete the connection.
@@ -1725,7 +1327,7 @@ real_complete_connection (NMDevice *device,
 	                           NULL,
 	                           s_pppoe ? FALSE : TRUE); /* No IPv6 by default yet for PPPoE */
 
-	s_wired = (NMSettingWired *) nm_connection_get_setting (connection, NM_TYPE_SETTING_WIRED);
+	s_wired = nm_connection_get_setting_wired (connection);
 	if (!s_wired) {
 		s_wired = (NMSettingWired *) nm_setting_wired_new ();
 		nm_connection_add_setting (connection, NM_SETTING (s_wired));
@@ -1764,7 +1366,7 @@ spec_match_list (NMDevice *device, const GSList *specs)
 	char *hwaddr;
 	gboolean matched;
 
-	hwaddr = nm_ether_ntop ((struct ether_addr *) &priv->perm_hw_addr);
+	hwaddr = nm_utils_hwaddr_ntoa (&priv->perm_hw_addr, ARPHRD_ETHER);
 	matched = nm_match_spec_hwaddr (specs, hwaddr);
 	g_free (hwaddr);
 
@@ -1774,164 +1376,80 @@ spec_match_list (NMDevice *device, const GSList *specs)
 	return matched;
 }
 
-static gboolean
-wired_match_config (NMDevice *self, NMConnection *connection)
-{
-	NMDeviceEthernetPrivate *priv = NM_DEVICE_ETHERNET_GET_PRIVATE (self);
-	NMSettingWired *s_wired;
-	const GByteArray *s_ether;
-	gboolean try_mac = TRUE;
-
-	s_wired = (NMSettingWired *) nm_connection_get_setting (connection, NM_TYPE_SETTING_WIRED);
-	if (!s_wired)
-		return FALSE;
-
-	if (!match_subchans (NM_DEVICE_ETHERNET (self), s_wired, &try_mac))
-		return FALSE;
-
-	/* MAC address check */
-	s_ether = nm_setting_wired_get_mac_address (s_wired);
-	if (try_mac && s_ether && memcmp (s_ether->data, priv->perm_hw_addr, ETH_ALEN))
-		return FALSE;
-
-	return TRUE;
-}
-
-static gboolean
-ip4_match_config (NMDevice *self, NMConnection *connection)
-{
-	NMSettingIP4Config *s_ip4;
-	int i, num;
-	GSList *leases, *iter;
-	NMDHCPManager *dhcp_mgr;
-	const char *method;
-
-	s_ip4 = nm_connection_get_setting_ip4_config (connection);
-	if (!s_ip4)
-		return FALSE;
-
-	/* Get any saved leases that apply to this connection */
-	dhcp_mgr = nm_dhcp_manager_get ();
-	leases = nm_dhcp_manager_get_lease_config (dhcp_mgr,
-	                                           nm_device_get_iface (self),
-	                                           nm_connection_get_uuid (connection));
-	g_object_unref (dhcp_mgr);
-
-	method = nm_setting_ip4_config_get_method (s_ip4);
-	if (!strcmp (method, NM_SETTING_IP4_CONFIG_METHOD_AUTO)) {
-		gboolean found = FALSE;
-
-		/* Find at least one lease's address on the device */
-		for (iter = leases; iter; iter = g_slist_next (iter)) {
-			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;
-			}
-		}
-		g_slist_foreach (leases, (GFunc) g_object_unref, NULL);
-		g_slist_free (leases);
-		return found;
-	} else {
-		/* Maybe the connection used to be DHCP and there are stale leases; ignore them */
-		g_slist_foreach (leases, (GFunc) g_object_unref, NULL);
-		g_slist_free (leases);
-	}
-
-	/* 'shared' and 'link-local' aren't supported methods because 'shared'
-	 * requires too much iptables and dnsmasq state to be reclaimed, and
-	 * avahi-autoipd isn't smart enough to allow the link-local address to be
-	 * determined at any point other than when it was first assigned.
-	 */
-	if (strcmp (method, NM_SETTING_IP4_CONFIG_METHOD_MANUAL))
-		return FALSE;
-
-	/* Everything below for static addressing */
-
-	/* 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++) {
-		NMIP4Address *addr = nm_setting_ip4_config_get_address (s_ip4, i);
-		struct in_addr tmp = { .s_addr = nm_ip4_address_get_address (addr) };
-
-		if (!nm_netlink_find_address (nm_device_get_ip_ifindex (self),
-		                              AF_INET,
-		                              &tmp,
-		                              nm_ip4_address_get_prefix (addr)))
-			return FALSE;
-	}
-
-	/* Success; all the connection's static IP addresses are assigned to the device */
-	return TRUE;
-}
-
 static NMConnection *
 connection_match_config (NMDevice *self, const GSList *connections)
 {
-	GSList *iter;
-	NMSettingConnection *s_con;
+	const GSList *iter;
+	GSList *ether_matches;
+	NMConnection *match;
 
-	for (iter = (GSList *) connections; iter; iter = g_slist_next (iter)) {
+	/* First narrow @connections down to those that match in their
+	 * NMSettingWired configuration.
+	 */
+	ether_matches = NULL;
+	for (iter = connections; iter; iter = iter->next) {
 		NMConnection *candidate = NM_CONNECTION (iter->data);
 
-		s_con = (NMSettingConnection *) nm_connection_get_setting (candidate, NM_TYPE_SETTING_CONNECTION);
-		g_assert (s_con);
-		if (strcmp (nm_setting_connection_get_connection_type (s_con), NM_SETTING_WIRED_SETTING_NAME))
-			continue;
-
 		/* Can't assume 802.1x or PPPoE connections; they have too much state
 		 * that's impossible to get on-the-fly from PPPoE or the supplicant.
 		 */
-		if (   nm_connection_get_setting (candidate, NM_TYPE_SETTING_802_1X)
-		    || nm_connection_get_setting (candidate, NM_TYPE_SETTING_PPPOE))
+		if (   nm_connection_get_setting_802_1x (candidate)
+		    || nm_connection_get_setting_pppoe (candidate))
 			continue;
 
-		if (!wired_match_config (self, candidate))
+		if (!match_ethernet_connection (self, candidate, FALSE, NULL))
 			continue;
 
-		if (!ip4_match_config (self, candidate))
-			continue;
-
-		return candidate;
+		ether_matches = g_slist_prepend (ether_matches, candidate);
 	}
 
-	return NULL;
+	/* Now pass those to the super method, which will check IP config */
+	ether_matches = g_slist_reverse (ether_matches);
+	match = NM_DEVICE_CLASS (nm_device_ethernet_parent_class)->connection_match_config (self, ether_matches);
+	g_slist_free (ether_matches);
+
+	return match;
 }
 
-static void
-dispose (GObject *object)
+static gboolean
+hwaddr_matches (NMDevice *device,
+                NMConnection *connection,
+                const guint8 *other_hwaddr,
+                guint other_hwaddr_len,
+                gboolean fail_if_no_hwaddr)
 {
-	NMDeviceEthernet *self = NM_DEVICE_ETHERNET (object);
-	NMDeviceEthernetPrivate *priv = NM_DEVICE_ETHERNET_GET_PRIVATE (self);
+	NMSettingWired *s_wired;
+	const guint8 *devaddr;
+	const GByteArray *mac = NULL;
+	int devtype;
 
-	if (priv->disposed) {
-		G_OBJECT_CLASS (nm_device_ethernet_parent_class)->dispose (object);
-		return;
-	}
+	devtype = nm_device_wired_get_hwaddr_type (NM_DEVICE_WIRED (device));
+	devaddr = nm_device_wired_get_hwaddr (NM_DEVICE_WIRED (device));
+	g_return_val_if_fail (devaddr != NULL, FALSE);
 
-	priv->disposed = TRUE;
+	s_wired = nm_connection_get_setting_wired (connection);
+	if (s_wired)
+		mac = nm_setting_wired_get_mac_address (s_wired);
 
-	if (priv->link_connected_id) {
-		g_signal_handler_disconnect (priv->monitor, priv->link_connected_id);
-		priv->link_connected_id = 0;
-	}
-	if (priv->link_disconnected_id) {
-		g_signal_handler_disconnect (priv->monitor, priv->link_disconnected_id);
-		priv->link_disconnected_id = 0;
-	}
+	if (mac) {
+		g_return_val_if_fail (mac->len == ETH_ALEN, FALSE);
+		if (other_hwaddr) {
+			g_return_val_if_fail (other_hwaddr_len == ETH_ALEN, FALSE);
+			if (memcmp (mac->data, other_hwaddr, mac->len) == 0)
+				return TRUE;
+		} else if (memcmp (mac->data, devaddr, mac->len) == 0)
+			return TRUE;
+	} else if (fail_if_no_hwaddr == FALSE)
+		return TRUE;
 
-	carrier_action_defer_clear (self);
+	return FALSE;
+}
 
-	if (priv->monitor) {
-		g_object_unref (priv->monitor);
-		priv->monitor = NULL;
-	}
+static void
+dispose (GObject *object)
+{
+	NMDeviceEthernet *self = NM_DEVICE_ETHERNET (object);
+	NMDeviceEthernetPrivate *priv = NM_DEVICE_ETHERNET_GET_PRIVATE (self);
 
 	g_free (priv->subchan1);
 	g_free (priv->subchan2);
@@ -1947,19 +1465,21 @@ get_property (GObject *object, guint prop_id,
 {
 	NMDeviceEthernet *self = NM_DEVICE_ETHERNET (object);
 	NMDeviceEthernetPrivate *priv = NM_DEVICE_ETHERNET_GET_PRIVATE (self);
+	const guint8 *current_addr;
 
 	switch (prop_id) {
 	case PROP_HW_ADDRESS:
-		g_value_take_string (value, nm_ether_ntop ((struct ether_addr *) &priv->hw_addr));
+		current_addr = nm_device_wired_get_hwaddr (NM_DEVICE_WIRED (self));
+		g_value_take_string (value, nm_utils_hwaddr_ntoa (current_addr, ARPHRD_ETHER));
 		break;
 	case PROP_PERM_HW_ADDRESS:
-		g_value_take_string (value, nm_ether_ntop ((struct ether_addr *) &priv->perm_hw_addr));
+		g_value_take_string (value, nm_utils_hwaddr_ntoa (&priv->perm_hw_addr, ARPHRD_ETHER));
 		break;
 	case PROP_SPEED:
-		g_value_set_uint (value, nm_device_ethernet_get_speed (self));
+		g_value_set_uint (value, nm_device_wired_get_speed (NM_DEVICE_WIRED (self)));
 		break;
 	case PROP_CARRIER:
-		g_value_set_boolean (value, priv->carrier);
+		g_value_set_boolean (value, nm_device_wired_get_carrier (NM_DEVICE_WIRED (self)));
 		break;
 	default:
 		G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
@@ -1993,28 +1513,24 @@ nm_device_ethernet_class_init (NMDeviceEthernetClass *klass)
 	object_class->set_property = set_property;
 
 	parent_class->get_generic_capabilities = real_get_generic_capabilities;
-	parent_class->hw_is_up = real_hw_is_up;
-	parent_class->hw_bring_up = real_hw_bring_up;
-	parent_class->hw_take_down = real_hw_take_down;
 	parent_class->is_up = real_is_up;
 	parent_class->bring_up = real_bring_up;
 	parent_class->take_down = real_take_down;
-	parent_class->can_interrupt_activation = real_can_interrupt_activation;
 	parent_class->update_hw_address = real_update_hw_address;
 	parent_class->update_permanent_hw_address = real_update_permanent_hw_address;
 	parent_class->update_initial_hw_address = real_update_initial_hw_address;
 	parent_class->get_best_auto_connection = real_get_best_auto_connection;
-	parent_class->is_available = real_is_available;
 	parent_class->check_connection_compatible = real_check_connection_compatible;
 	parent_class->complete_connection = real_complete_connection;
 
 	parent_class->act_stage1_prepare = real_act_stage1_prepare;
 	parent_class->act_stage2_config = real_act_stage2_config;
 	parent_class->act_stage3_ip4_config_start = real_act_stage3_ip4_config_start;
-	parent_class->act_stage4_get_ip4_config = real_act_stage4_get_ip4_config;
+	parent_class->ip4_config_pre_commit = real_ip4_config_pre_commit;
 	parent_class->deactivate = real_deactivate;
 	parent_class->spec_match_list = spec_match_list;
 	parent_class->connection_match_config = connection_match_config;
+	parent_class->hwaddr_matches = hwaddr_matches;
 
 	/* properties */
 	g_object_class_install_property
diff --git a/src/nm-device-ethernet.h b/src/nm-device-ethernet.h
index b9e2afd4..deb0feca 100644
--- a/src/nm-device-ethernet.h
+++ b/src/nm-device-ethernet.h
@@ -23,9 +23,8 @@
 #define NM_DEVICE_ETHERNET_H
 
 #include <glib-object.h>
-#include <net/ethernet.h>
 
-#include "nm-device.h"
+#include "nm-device-wired.h"
 
 G_BEGIN_DECLS
 
@@ -36,17 +35,24 @@ G_BEGIN_DECLS
 #define NM_IS_DEVICE_ETHERNET_CLASS(klass)	(G_TYPE_CHECK_CLASS_TYPE ((klass),  NM_TYPE_DEVICE_ETHERNET))
 #define NM_DEVICE_ETHERNET_GET_CLASS(obj)	(G_TYPE_INSTANCE_GET_CLASS ((obj),  NM_TYPE_DEVICE_ETHERNET, NMDeviceEthernetClass))
 
+typedef enum
+{
+	NM_ETHERNET_ERROR_CONNECTION_NOT_WIRED = 0, /*< nick=ConnectionNotWired >*/
+	NM_ETHERNET_ERROR_CONNECTION_INVALID,       /*< nick=ConnectionInvalid >*/
+	NM_ETHERNET_ERROR_CONNECTION_INCOMPATIBLE,  /*< nick=ConnectionIncompatible >*/
+} NMEthernetError;
+
 #define NM_DEVICE_ETHERNET_HW_ADDRESS "hw-address"
 #define NM_DEVICE_ETHERNET_PERMANENT_HW_ADDRESS "perm-hw-address"
 #define NM_DEVICE_ETHERNET_SPEED "speed"
 #define NM_DEVICE_ETHERNET_CARRIER "carrier"
 
 typedef struct {
-	NMDevice parent;
+	NMDeviceWired parent;
 } NMDeviceEthernet;
 
 typedef struct {
-	NMDeviceClass parent;
+	NMDeviceWiredClass parent;
 
 	/* Signals */
 	void (*properties_changed) (NMDeviceEthernet *device, GHashTable *properties);
@@ -60,9 +66,6 @@ NMDevice *nm_device_ethernet_new (const char *udi,
                                   const char *iface,
                                   const char *driver);
 
-void nm_device_ethernet_get_address (NMDeviceEthernet *dev,
-                                     struct ether_addr *addr);
-
 G_END_DECLS
 
 #endif	/* NM_DEVICE_ETHERNET_H */
diff --git a/src/nm-device-factory.h b/src/nm-device-factory.h
new file mode 100644
index 00000000..8a4f4467
--- /dev/null
+++ b/src/nm-device-factory.h
@@ -0,0 +1,91 @@
+/* -*- 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) 2007 - 2011 Red Hat, Inc.
+ */
+
+#ifndef NM_DEVICE_FACTORY_H
+#define NM_DEVICE_FACTORY_H
+
+#include <glib.h>
+#include <glib-object.h>
+#include <gudev/gudev.h>
+
+#include "NetworkManager.h"
+
+/* WARNING: this file is private API between NetworkManager and its internal
+ * device plugins.  Its API can change at any time and is not guaranteed to be
+ * stable.  NM and device plugins are distributed together and this API is
+ * not meant to enable third-party plugins.
+ */
+
+/**
+ * nm_device_factory_create_device:
+ * @device: GUdev device object representing the device
+ * @devpath: sysfs path of the device
+ * @ifname: interface name of the device
+ * @driver: driver of the device
+ * @error: error for failure information
+ *
+ * Creates a #NMDevice subclass if the given information represents a device
+ * the factory is capable of creating.  If the information does represent a
+ * device the factory is capable of creating, but the device could not be
+ * created, %NULL should be returned and @error should be set.  If the
+ * factory is not capable of creating a device with the given information
+ * (ie, the factory creates Ethernet devices but the information represents
+ * a WiFi device) it should return %NULL and leave @error untouched.
+ *
+ * Returns: the device object (a subclass of #NMDevice) or %NULL
+ */
+GObject *nm_device_factory_create_device (GUdevDevice *device,
+                                          const char *devpath,
+                                          const char *ifname,
+                                          const char *driver,
+                                          GError **error);
+
+/* Should match nm_device_factory() */
+typedef GObject * (*NMDeviceFactoryCreateFunc) (GUdevDevice *device,
+                                                const char *devpath,
+                                                const char *ifname,
+                                                const char *driver,
+                                                GError **error);
+
+/**
+ * nm_device_factory_get_priority:
+ *
+ * Returns the priority of this plugin.  Higher numbers mean a higher priority.
+ *
+ * Returns: plugin priority
+ */
+guint32 nm_device_factory_get_priority (void);
+
+typedef guint32 (*NMDeviceFactoryPriorityFunc) (void);
+
+/**
+ * nm_device_factory_get_type:
+ *
+ * Returns the type of device this factory can create.  Only one factory for
+ * each type of device is allowed.
+ *
+ * Returns: the %NMDeviceType
+ */
+NMDeviceType nm_device_factory_get_type (void);
+
+typedef NMDeviceType (*NMDeviceFactoryTypeFunc) (void);
+
+#endif /* NM_DEVICE_FACTORY_H */
+
diff --git a/src/nm-device-infiniband.c b/src/nm-device-infiniband.c
new file mode 100644
index 00000000..5e43f060
--- /dev/null
+++ b/src/nm-device-infiniband.c
@@ -0,0 +1,517 @@
+/* -*- 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 2011 Red Hat, Inc.
+ */
+
+#include "config.h"
+
+#include <glib.h>
+#include <glib/gi18n.h>
+
+#include <linux/if_infiniband.h>
+#include <netinet/ether.h>
+
+#include "nm-device-infiniband.h"
+#include "nm-logging.h"
+#include "nm-properties-changed-signal.h"
+#include "nm-utils.h"
+#include "NetworkManagerUtils.h"
+#include "nm-device-private.h"
+#include "nm-enum-types.h"
+
+#include "nm-device-infiniband-glue.h"
+
+
+G_DEFINE_TYPE (NMDeviceInfiniband, nm_device_infiniband, NM_TYPE_DEVICE_WIRED)
+
+#define NM_DEVICE_INFINIBAND_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), NM_TYPE_DEVICE_INFINIBAND, NMDeviceInfinibandPrivate))
+
+#define NM_INFINIBAND_ERROR (nm_infiniband_error_quark ())
+
+typedef struct {
+	int dummy;
+} NMDeviceInfinibandPrivate;
+
+enum {
+	PROPERTIES_CHANGED,
+
+	LAST_SIGNAL
+};
+
+static guint signals[LAST_SIGNAL] = { 0 };
+
+enum {
+	PROP_0,
+	PROP_HW_ADDRESS,
+	PROP_CARRIER,
+
+	LAST_PROP
+};
+
+static GQuark
+nm_infiniband_error_quark (void)
+{
+	static GQuark quark = 0;
+	if (!quark)
+		quark = g_quark_from_static_string ("nm-infiniband-error");
+	return quark;
+}
+
+static GObject*
+constructor (GType type,
+			 guint n_construct_params,
+			 GObjectConstructParam *construct_params)
+{
+	GObject *object;
+	NMDeviceInfinibandPrivate *priv;
+	NMDevice *self;
+
+	object = G_OBJECT_CLASS (nm_device_infiniband_parent_class)->constructor (type,
+	                                                                        n_construct_params,
+	                                                                        construct_params);
+	if (!object)
+		return NULL;
+
+	self = NM_DEVICE (object);
+	priv = NM_DEVICE_INFINIBAND_GET_PRIVATE (self);
+
+	nm_log_dbg (LOGD_HW | LOGD_INFINIBAND, "(%s): kernel ifindex %d",
+	            nm_device_get_iface (NM_DEVICE (self)),
+	            nm_device_get_ifindex (NM_DEVICE (self)));
+
+	return object;
+}
+
+static void
+nm_device_infiniband_init (NMDeviceInfiniband * self)
+{
+}
+
+NMDevice *
+nm_device_infiniband_new (const char *udi,
+						  const char *iface,
+						  const char *driver)
+{
+	g_return_val_if_fail (udi != NULL, NULL);
+	g_return_val_if_fail (iface != NULL, NULL);
+	g_return_val_if_fail (driver != NULL, NULL);
+
+	return (NMDevice *) g_object_new (NM_TYPE_DEVICE_INFINIBAND,
+	                                  NM_DEVICE_UDI, udi,
+	                                  NM_DEVICE_IFACE, iface,
+	                                  NM_DEVICE_DRIVER, driver,
+	                                  NM_DEVICE_TYPE_DESC, "InfiniBand",
+	                                  NM_DEVICE_DEVICE_TYPE, NM_DEVICE_TYPE_INFINIBAND,
+	                                  NULL);
+}
+
+
+static void
+real_update_hw_address (NMDevice *dev)
+{
+	const guint8 *hw_addr;
+	guint8 old_addr[INFINIBAND_ALEN];
+
+	hw_addr = nm_device_wired_get_hwaddr (NM_DEVICE_WIRED (dev));
+	memcpy (old_addr, hw_addr, INFINIBAND_ALEN);
+
+	NM_DEVICE_CLASS (nm_device_infiniband_parent_class)->update_hw_address (dev);
+
+	hw_addr = nm_device_wired_get_hwaddr (NM_DEVICE_WIRED (dev));
+	if (memcmp (old_addr, hw_addr, INFINIBAND_ALEN))
+		g_object_notify (G_OBJECT (dev), NM_DEVICE_INFINIBAND_HW_ADDRESS);
+}
+
+static guint32
+real_get_generic_capabilities (NMDevice *dev)
+{
+	return NM_DEVICE_CAP_CARRIER_DETECT | NM_DEVICE_CAP_NM_SUPPORTED;
+}
+
+static NMConnection *
+real_get_best_auto_connection (NMDevice *dev,
+                               GSList *connections,
+                               char **specific_object)
+{
+	GSList *iter;
+
+	for (iter = connections; iter; iter = g_slist_next (iter)) {
+		NMConnection *connection = NM_CONNECTION (iter->data);
+		NMSettingConnection *s_con;
+		NMSettingInfiniband *s_infiniband;
+
+		s_con = nm_connection_get_setting_connection (connection);
+		g_assert (s_con);
+
+		if (!nm_connection_is_type (connection, NM_SETTING_INFINIBAND_SETTING_NAME))
+			continue;
+		if (!nm_setting_connection_get_autoconnect (s_con))
+			continue;
+
+		s_infiniband = nm_connection_get_setting_infiniband (connection);
+		if (!s_infiniband)
+			continue;
+
+		if (s_infiniband) {
+			const guint8 *hwaddr = nm_device_wired_get_hwaddr (NM_DEVICE_WIRED (dev));
+			const GByteArray *mac;
+
+			mac = nm_setting_infiniband_get_mac_address (s_infiniband);
+			if (mac && memcmp (mac->data, hwaddr, INFINIBAND_ALEN))
+				continue;
+		}
+
+		return connection;
+	}
+	return NULL;
+}
+
+static NMActStageReturn
+real_act_stage1_prepare (NMDevice *dev, NMDeviceStateReason *reason)
+{
+	NMActRequest *req;
+	NMConnection *connection;
+	NMSettingInfiniband *s_infiniband;
+	const char *transport_mode;
+	char *mode_path, *mode_value;
+	gboolean ok;
+
+	g_return_val_if_fail (reason != NULL, NM_ACT_STAGE_RETURN_FAILURE);
+
+	req = nm_device_get_act_request (dev);
+	g_return_val_if_fail (req != NULL, NM_ACT_STAGE_RETURN_FAILURE);
+
+	connection = nm_act_request_get_connection (req);
+	g_assert (connection);
+	s_infiniband = nm_connection_get_setting_infiniband (connection);
+	g_assert (s_infiniband);
+
+	transport_mode = nm_setting_infiniband_get_transport_mode (s_infiniband);
+
+	mode_path = g_strdup_printf ("/sys/class/net/%s/mode", nm_device_get_iface (dev));
+	if (!g_file_test (mode_path, G_FILE_TEST_EXISTS)) {
+		g_free (mode_path);
+
+		if (!strcmp (transport_mode, "datagram"))
+			return NM_ACT_STAGE_RETURN_SUCCESS;
+		else {
+			*reason = NM_DEVICE_STATE_REASON_INFINIBAND_MODE;
+			return NM_ACT_STAGE_RETURN_FAILURE;
+		}
+	}
+
+	mode_value = g_strdup_printf ("%s\n", transport_mode);
+	ok = nm_utils_do_sysctl (mode_path, mode_value);
+	g_free (mode_value);
+	g_free (mode_path);
+
+	if (!ok) {
+		*reason = NM_DEVICE_STATE_REASON_CONFIG_FAILED;
+		return NM_ACT_STAGE_RETURN_FAILURE;
+	}
+
+	return NM_DEVICE_CLASS (nm_device_infiniband_parent_class)->act_stage1_prepare (dev, reason);
+}
+
+static void
+real_ip4_config_pre_commit (NMDevice *self, NMIP4Config *config)
+{
+	NMConnection *connection;
+	NMSettingInfiniband *s_infiniband;
+	guint32 mtu;
+
+	connection = nm_device_get_connection (self);
+	g_assert (connection);
+	s_infiniband = nm_connection_get_setting_infiniband (connection);
+	g_assert (s_infiniband);
+
+	/* MTU override */
+	mtu = nm_setting_infiniband_get_mtu (s_infiniband);
+	if (mtu)
+		nm_ip4_config_set_mtu (config, mtu);
+}
+
+static gboolean
+real_check_connection_compatible (NMDevice *device,
+                                  NMConnection *connection,
+                                  GError **error)
+{
+	NMSettingInfiniband *s_infiniband;
+	const GByteArray *mac;
+
+	if (!nm_connection_is_type (connection, NM_SETTING_INFINIBAND_SETTING_NAME)) {
+		g_set_error (error,
+		             NM_INFINIBAND_ERROR,
+					 NM_INFINIBAND_ERROR_CONNECTION_NOT_INFINIBAND,
+		             "The connection was not an InfiniBand connection.");
+		return FALSE;
+	}
+
+	s_infiniband = nm_connection_get_setting_infiniband (connection);
+	if (!s_infiniband) {
+		g_set_error (error,
+		             NM_INFINIBAND_ERROR, NM_INFINIBAND_ERROR_CONNECTION_INVALID,
+		             "The connection was not a valid infiniband connection.");
+		return FALSE;
+	}
+
+	if (s_infiniband) {
+		const guint8 *hwaddr = nm_device_wired_get_hwaddr (NM_DEVICE_WIRED (device));
+
+		mac = nm_setting_infiniband_get_mac_address (s_infiniband);
+		if (mac && memcmp (mac->data, hwaddr, INFINIBAND_ALEN)) {
+			g_set_error (error,
+			             NM_INFINIBAND_ERROR,
+			             NM_INFINIBAND_ERROR_CONNECTION_INCOMPATIBLE,
+			             "The connection's MAC address did not match this device.");
+			return FALSE;
+		}
+	}
+
+	return TRUE;
+}
+
+static gboolean
+real_complete_connection (NMDevice *device,
+                          NMConnection *connection,
+                          const char *specific_object,
+                          const GSList *existing_connections,
+                          GError **error)
+{
+	NMSettingInfiniband *s_infiniband;
+	const GByteArray *setting_mac;
+	const guint8 *hwaddr;
+
+	nm_utils_complete_generic (connection,
+	                           NM_SETTING_INFINIBAND_SETTING_NAME,
+	                           existing_connections,
+	                           _("InfiniBand connection %d"),
+	                           NULL,
+	                           TRUE);
+
+	s_infiniband = nm_connection_get_setting_infiniband (connection);
+	if (!s_infiniband) {
+		s_infiniband = (NMSettingInfiniband *) nm_setting_infiniband_new ();
+		nm_connection_add_setting (connection, NM_SETTING (s_infiniband));
+	}
+
+	hwaddr = nm_device_wired_get_hwaddr (NM_DEVICE_WIRED (device));
+	setting_mac = nm_setting_infiniband_get_mac_address (s_infiniband);
+	if (setting_mac) {
+		/* Make sure the setting MAC (if any) matches the device's MAC */
+		if (memcmp (setting_mac->data, hwaddr, INFINIBAND_ALEN)) {
+			g_set_error_literal (error,
+			                     NM_SETTING_INFINIBAND_ERROR,
+			                     NM_SETTING_INFINIBAND_ERROR_INVALID_PROPERTY,
+			                     NM_SETTING_INFINIBAND_MAC_ADDRESS);
+			return FALSE;
+		}
+	} else {
+		GByteArray *mac;
+
+		/* Lock the connection to this device by default */
+		mac = g_byte_array_sized_new (INFINIBAND_ALEN);
+		g_byte_array_append (mac, hwaddr, INFINIBAND_ALEN);
+		g_object_set (G_OBJECT (s_infiniband), NM_SETTING_INFINIBAND_MAC_ADDRESS, mac, NULL);
+		g_byte_array_free (mac, TRUE);
+	}
+
+	if (!nm_setting_infiniband_get_transport_mode (s_infiniband))
+		g_object_set (G_OBJECT (s_infiniband), NM_SETTING_INFINIBAND_TRANSPORT_MODE, "datagram", NULL);
+
+	return TRUE;
+}
+
+static gboolean
+spec_match_list (NMDevice *device, const GSList *specs)
+{
+	char *hwaddr;
+	gboolean matched;
+
+	hwaddr = nm_utils_hwaddr_ntoa (nm_device_wired_get_hwaddr (NM_DEVICE_WIRED (device)), ARPHRD_INFINIBAND);
+	matched = nm_match_spec_hwaddr (specs, hwaddr);
+	g_free (hwaddr);
+
+	return matched;
+}
+
+static gboolean
+infiniband_match_config (NMDevice *self, NMConnection *connection)
+{
+	NMSettingInfiniband *s_infiniband;
+	const GByteArray *s_mac;
+
+	s_infiniband = nm_connection_get_setting_infiniband (connection);
+	if (!s_infiniband)
+		return FALSE;
+
+	/* MAC address check */
+	s_mac = nm_setting_infiniband_get_mac_address (s_infiniband);
+	if (s_mac && memcmp (s_mac->data, nm_device_wired_get_hwaddr (NM_DEVICE_WIRED (self)), INFINIBAND_ALEN))
+		return FALSE;
+
+	return TRUE;
+}
+
+static NMConnection *
+connection_match_config (NMDevice *self, const GSList *connections)
+{
+	const GSList *iter;
+	GSList *infiniband_matches;
+	NMConnection *match;
+
+	/* First narrow @connections down to those that match in their
+	 * NMSettingInfiniband configuration.
+	 */
+	infiniband_matches = NULL;
+	for (iter = connections; iter; iter = iter->next) {
+		NMConnection *candidate = NM_CONNECTION (iter->data);
+
+		if (!nm_connection_is_type (candidate, NM_SETTING_INFINIBAND_SETTING_NAME))
+			continue;
+		if (!infiniband_match_config (self, candidate))
+			continue;
+
+		infiniband_matches = g_slist_prepend (infiniband_matches, candidate);
+	}
+
+	/* Now pass those to the super method, which will check IP config */
+	infiniband_matches = g_slist_reverse (infiniband_matches);
+	match = NM_DEVICE_CLASS (nm_device_infiniband_parent_class)->connection_match_config (self, infiniband_matches);
+	g_slist_free (infiniband_matches);
+
+	return match;
+}
+
+static gboolean
+hwaddr_matches (NMDevice *device,
+                NMConnection *connection,
+                const guint8 *other_hwaddr,
+                guint other_hwaddr_len,
+                gboolean fail_if_no_hwaddr)
+{
+	NMSettingInfiniband *s_ib;
+	const guint8 *devaddr;
+	const GByteArray *mac = NULL;
+	int devtype;
+
+	devtype = nm_device_wired_get_hwaddr_type (NM_DEVICE_WIRED (device));
+	devaddr = nm_device_wired_get_hwaddr (NM_DEVICE_WIRED (device));
+	g_return_val_if_fail (devaddr != NULL, FALSE);
+
+	s_ib = nm_connection_get_setting_infiniband (connection);
+	if (s_ib)
+		mac = nm_setting_infiniband_get_mac_address (s_ib);
+
+	if (mac) {
+		g_return_val_if_fail (mac->len == INFINIBAND_ALEN, FALSE);
+		if (other_hwaddr) {
+			g_return_val_if_fail (other_hwaddr_len == INFINIBAND_ALEN, FALSE);
+			if (memcmp (mac->data, other_hwaddr, mac->len) == 0)
+				return TRUE;
+		} else if (memcmp (mac->data, devaddr, mac->len) == 0)
+			return TRUE;
+	} else if (fail_if_no_hwaddr == FALSE)
+		return TRUE;
+
+	return FALSE;
+}
+
+static void
+get_property (GObject *object, guint prop_id,
+              GValue *value, GParamSpec *pspec)
+{
+	const guint8 *current_addr;
+
+	switch (prop_id) {
+	case PROP_HW_ADDRESS:
+		current_addr = nm_device_wired_get_hwaddr (NM_DEVICE_WIRED (object));
+		g_value_take_string (value, nm_utils_hwaddr_ntoa (current_addr, ARPHRD_INFINIBAND));
+		break;
+	case PROP_CARRIER:
+		g_value_set_boolean (value, nm_device_wired_get_carrier (NM_DEVICE_WIRED (object)));
+		break;
+	default:
+		G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+		break;
+	}
+}
+
+static void
+set_property (GObject *object, guint prop_id,
+			  const GValue *value, GParamSpec *pspec)
+{
+	switch (prop_id) {
+	default:
+		G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+		break;
+	}
+}
+
+static void
+nm_device_infiniband_class_init (NMDeviceInfinibandClass *klass)
+{
+	GObjectClass *object_class = G_OBJECT_CLASS (klass);
+	NMDeviceClass *parent_class = NM_DEVICE_CLASS (klass);
+
+	g_type_class_add_private (object_class, sizeof (NMDeviceInfinibandPrivate));
+
+	/* virtual methods */
+	object_class->constructor = constructor;
+	object_class->get_property = get_property;
+	object_class->set_property = set_property;
+
+	parent_class->get_generic_capabilities = real_get_generic_capabilities;
+	parent_class->update_hw_address = real_update_hw_address;
+	parent_class->get_best_auto_connection = real_get_best_auto_connection;
+	parent_class->check_connection_compatible = real_check_connection_compatible;
+	parent_class->complete_connection = real_complete_connection;
+
+	parent_class->act_stage1_prepare = real_act_stage1_prepare;
+	parent_class->ip4_config_pre_commit = real_ip4_config_pre_commit;
+	parent_class->spec_match_list = spec_match_list;
+	parent_class->connection_match_config = connection_match_config;
+	parent_class->hwaddr_matches = hwaddr_matches;
+
+	/* properties */
+	g_object_class_install_property
+		(object_class, PROP_HW_ADDRESS,
+		 g_param_spec_string (NM_DEVICE_INFINIBAND_HW_ADDRESS,
+							  "Active MAC Address",
+							  "Currently set hardware MAC address",
+							  NULL,
+							  G_PARAM_READABLE));
+
+	g_object_class_install_property
+		(object_class, PROP_CARRIER,
+		 g_param_spec_boolean (NM_DEVICE_INFINIBAND_CARRIER,
+							   "Carrier",
+							   "Carrier",
+							   FALSE,
+							   G_PARAM_READABLE));
+
+	/* Signals */
+	signals[PROPERTIES_CHANGED] =
+		nm_properties_changed_signal_new (object_class,
+										  G_STRUCT_OFFSET (NMDeviceInfinibandClass, properties_changed));
+
+	dbus_g_object_type_install_info (G_TYPE_FROM_CLASS (klass),
+									 &dbus_glib_nm_device_infiniband_object_info);
+
+	dbus_g_error_domain_register (NM_INFINIBAND_ERROR, NULL, NM_TYPE_INFINIBAND_ERROR);
+}
diff --git a/src/nm-device-infiniband.h b/src/nm-device-infiniband.h
new file mode 100644
index 00000000..fe88c901
--- /dev/null
+++ b/src/nm-device-infiniband.h
@@ -0,0 +1,66 @@
+/* -*- Mode: C; tab-width: 4; indent-tabs-mode: t; c-basic-offset: 4 -*- */
+/* NetworkManager -- Network link manager
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Copyright 2011 Red Hat, Inc.
+ */
+
+#ifndef NM_DEVICE_INFINIBAND_H
+#define NM_DEVICE_INFINIBAND_H
+
+#include <glib-object.h>
+
+#include "nm-device-wired.h"
+
+G_BEGIN_DECLS
+
+#define NM_TYPE_DEVICE_INFINIBAND			(nm_device_infiniband_get_type ())
+#define NM_DEVICE_INFINIBAND(obj)			(G_TYPE_CHECK_INSTANCE_CAST ((obj), NM_TYPE_DEVICE_INFINIBAND, NMDeviceInfiniband))
+#define NM_DEVICE_INFINIBAND_CLASS(klass)	(G_TYPE_CHECK_CLASS_CAST ((klass),  NM_TYPE_DEVICE_INFINIBAND, NMDeviceInfinibandClass))
+#define NM_IS_DEVICE_INFINIBAND(obj)		(G_TYPE_CHECK_INSTANCE_TYPE ((obj), NM_TYPE_DEVICE_INFINIBAND))
+#define NM_IS_DEVICE_INFINIBAND_CLASS(klass)	(G_TYPE_CHECK_CLASS_TYPE ((klass),  NM_TYPE_DEVICE_INFINIBAND))
+#define NM_DEVICE_INFINIBAND_GET_CLASS(obj)	(G_TYPE_INSTANCE_GET_CLASS ((obj),  NM_TYPE_DEVICE_INFINIBAND, NMDeviceInfinibandClass))
+
+typedef enum {
+	NM_INFINIBAND_ERROR_CONNECTION_NOT_INFINIBAND = 0, /*< nick=ConnectionNotInfiniband >*/
+	NM_INFINIBAND_ERROR_CONNECTION_INVALID,            /*< nick=ConnectionInvalid >*/
+	NM_INFINIBAND_ERROR_CONNECTION_INCOMPATIBLE,       /*< nick=ConnectionIncompatible >*/
+} NMInfinibandError;
+
+#define NM_DEVICE_INFINIBAND_HW_ADDRESS "hw-address"
+#define NM_DEVICE_INFINIBAND_CARRIER "carrier"
+
+typedef struct {
+	NMDeviceWired parent;
+} NMDeviceInfiniband;
+
+typedef struct {
+	NMDeviceWiredClass parent;
+
+	/* Signals */
+	void (*properties_changed) (NMDeviceInfiniband *device, GHashTable *properties);
+} NMDeviceInfinibandClass;
+
+
+GType nm_device_infiniband_get_type (void);
+
+NMDevice *nm_device_infiniband_new (const char *udi,
+									const char *iface,
+									const char *driver);
+
+G_END_DECLS
+
+#endif	/* NM_DEVICE_INFINIBAND_H */
diff --git a/src/nm-device-interface.c b/src/nm-device-interface.c
deleted file mode 100644
index fb471f57..00000000
--- a/src/nm-device-interface.c
+++ /dev/null
@@ -1,433 +0,0 @@
-/* -*- Mode: C; tab-width: 4; indent-tabs-mode: t; c-basic-offset: 4 -*- */
-/* NetworkManager -- Network link manager
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License along
- * with this program; if not, write to the Free Software Foundation, Inc.,
- * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
- *
- * Copyright (C) 2007 - 2008 Novell, Inc.
- * Copyright (C) 2007 - 2010 Red Hat, Inc.
- */
-
-#include <dbus/dbus-glib.h>
-
-#include "nm-marshal.h"
-#include "nm-setting-connection.h"
-#include "nm-device-interface.h"
-#include "nm-logging.h"
-#include "nm-properties-changed-signal.h"
-#include "nm-rfkill.h"
-
-static void impl_device_disconnect (NMDeviceInterface *device,
-                                    DBusGMethodInvocation *context);
-
-#include "nm-device-interface-glue.h"
-
-GQuark
-nm_device_interface_error_quark (void)
-{
-	static GQuark quark = 0;
-	if (!quark)
-		quark = g_quark_from_static_string ("nm-device-interface-error");
-	return quark;
-}
-
-/* This should really be standard. */
-#define ENUM_ENTRY(NAME, DESC) { NAME, "" #NAME "", DESC }
-
-GType
-nm_device_interface_error_get_type (void)
-{
-	static GType etype = 0;
-
-	if (etype == 0) {
-		static const GEnumValue values[] = {
-			/* Connection is already activating. */
-			ENUM_ENTRY (NM_DEVICE_INTERFACE_ERROR_CONNECTION_ACTIVATING, "ConnectionActivating"),
-			/* Connection is invalid for this device. */
-			ENUM_ENTRY (NM_DEVICE_INTERFACE_ERROR_CONNECTION_INVALID, "ConnectionInvalid"),
-			/* Operation could not be performed because the device is not active. */
-			ENUM_ENTRY (NM_DEVICE_INTERFACE_ERROR_NOT_ACTIVE, "NotActive"),
-			{ 0, 0, 0 }
-		};
-		etype = g_enum_register_static ("NMDeviceInterfaceError", values);
-	}
-	return etype;
-}
-
-
-static void
-nm_device_interface_init (gpointer g_iface)
-{
-	GType iface_type = G_TYPE_FROM_INTERFACE (g_iface);
-	static gboolean initialized = FALSE;
-
-	if (initialized)
-		return;
-
-	/* Properties */
-	g_object_interface_install_property
-		(g_iface,
-		 g_param_spec_string (NM_DEVICE_INTERFACE_UDI,
-							  "UDI",
-							  "Unique Device Identifier",
-							  NULL,
-							  G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY));
-
-	g_object_interface_install_property
-		(g_iface,
-		 g_param_spec_string (NM_DEVICE_INTERFACE_IFACE,
-							  "Interface",
-							  "Interface",
-							  NULL,
-							  G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY));
-
-	g_object_interface_install_property
-		(g_iface,
-		 g_param_spec_string (NM_DEVICE_INTERFACE_IP_IFACE,
-		                      "IP Interface",
-		                      "IP Interface",
-		                      NULL,
-		                      G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY));
-
-	g_object_interface_install_property
-		(g_iface,
-		 g_param_spec_string (NM_DEVICE_INTERFACE_DRIVER,
-							  "Driver",
-							  "Driver",
-							  NULL,
-							  G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY));
-	
-	g_object_interface_install_property
-		(g_iface,
-		 g_param_spec_uint (NM_DEVICE_INTERFACE_CAPABILITIES,
-							"Capabilities",
-							"Capabilities",
-							0, G_MAXUINT32, NM_DEVICE_CAP_NONE,
-							G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY));
-
-	g_object_interface_install_property
-		(g_iface,
-		 g_param_spec_uint (NM_DEVICE_INTERFACE_IP4_ADDRESS,
-							"IP4 address",
-							"IP4 address",
-							0, G_MAXUINT32, 0, /* FIXME */
-							G_PARAM_READWRITE));
-
-	g_object_interface_install_property
-		(g_iface,
-		 g_param_spec_boxed (NM_DEVICE_INTERFACE_IP4_CONFIG,
-							  "IP4 Config",
-							  "IP4 Config",
-							  DBUS_TYPE_G_OBJECT_PATH,
-							  G_PARAM_READWRITE));
-
-	g_object_interface_install_property
-		(g_iface,
-		 g_param_spec_boxed (NM_DEVICE_INTERFACE_DHCP4_CONFIG,
-							  "DHCP4 Config",
-							  "DHCP4 Config",
-							  DBUS_TYPE_G_OBJECT_PATH,
-							  G_PARAM_READWRITE));
-
-	g_object_interface_install_property
-		(g_iface,
-		 g_param_spec_boxed (NM_DEVICE_INTERFACE_IP6_CONFIG,
-							  "IP6 Config",
-							  "IP6 Config",
-							  DBUS_TYPE_G_OBJECT_PATH,
-							  G_PARAM_READWRITE));
-
-	g_object_interface_install_property
-		(g_iface,
-		 g_param_spec_boxed (NM_DEVICE_INTERFACE_DHCP6_CONFIG,
-							  "DHCP6 Config",
-							  "DHCP6 Config",
-							  DBUS_TYPE_G_OBJECT_PATH,
-							  G_PARAM_READWRITE));
-
-	g_object_interface_install_property
-		(g_iface,
-		 g_param_spec_uint (NM_DEVICE_INTERFACE_STATE,
-							"State",
-							"State",
-							0, G_MAXUINT32, NM_DEVICE_STATE_UNKNOWN,
-							G_PARAM_READABLE));
-
-	g_object_interface_install_property
-		(g_iface,
-		 g_param_spec_boxed (NM_DEVICE_INTERFACE_ACTIVE_CONNECTION,
-		                     "ActiveConnection",
-		                     "ActiveConnection",
-		                     DBUS_TYPE_G_OBJECT_PATH,
-		                     G_PARAM_READABLE));
-
-	g_object_interface_install_property
-		(g_iface,
-		 g_param_spec_uint (NM_DEVICE_INTERFACE_DEVICE_TYPE,
-							"DeviceType",
-							"DeviceType",
-							0, G_MAXUINT32, NM_DEVICE_TYPE_UNKNOWN,
-							G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY | NM_PROPERTY_PARAM_NO_EXPORT));
-
-	g_object_interface_install_property
-		(g_iface, g_param_spec_boolean (NM_DEVICE_INTERFACE_MANAGED,
-	                                   "Managed",
-	                                   "Managed",
-	                                   FALSE,
-	                                   G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY));
-
-	g_object_interface_install_property
-		(g_iface, g_param_spec_boolean (NM_DEVICE_INTERFACE_FIRMWARE_MISSING,
-	                                   "FirmwareMissing",
-	                                   "Firmware missing",
-	                                   FALSE,
-	                                   G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY));
-
-	g_object_interface_install_property
-		(g_iface,
-		 g_param_spec_string (NM_DEVICE_INTERFACE_TYPE_DESC,
-							  "Type Description",
-							  "Device type description",
-							  NULL,
-							  G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY | NM_PROPERTY_PARAM_NO_EXPORT));
-
-	g_object_interface_install_property
-		(g_iface, g_param_spec_uint (NM_DEVICE_INTERFACE_RFKILL_TYPE,
-	                                 "Rfkill Type",
-	                                 "Type of rfkill switch (if any) supported by this device",
-	                                 RFKILL_TYPE_WLAN,
-	                                 RFKILL_TYPE_MAX,
-	                                 RFKILL_TYPE_UNKNOWN,
-	                                 G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY | NM_PROPERTY_PARAM_NO_EXPORT));
-
-	g_object_interface_install_property
-		(g_iface,
-		 g_param_spec_int (NM_DEVICE_INTERFACE_IFINDEX,
-							"Ifindex",
-							"Ifindex",
-							0, G_MAXINT, 0,
-							G_PARAM_READABLE | NM_PROPERTY_PARAM_NO_EXPORT));
-
-	/* Signals */
-	g_signal_new ("state-changed",
-				  iface_type,
-				  G_SIGNAL_RUN_FIRST,
-				  G_STRUCT_OFFSET (NMDeviceInterface, state_changed),
-				  NULL, NULL,
-				  _nm_marshal_VOID__UINT_UINT_UINT,
-				  G_TYPE_NONE, 3,
-				  G_TYPE_UINT, G_TYPE_UINT, G_TYPE_UINT);
-
-	g_signal_new (NM_DEVICE_INTERFACE_DISCONNECT_REQUEST,
-	              iface_type,
-	              G_SIGNAL_RUN_FIRST,
-	              0, NULL, NULL,
-	              g_cclosure_marshal_VOID__POINTER,
-	              G_TYPE_NONE, 1, G_TYPE_POINTER);
-
-	dbus_g_object_type_install_info (iface_type,
-									 &dbus_glib_nm_device_interface_object_info);
-
-	dbus_g_error_domain_register (NM_DEVICE_INTERFACE_ERROR,
-	                              NULL,
-	                              NM_TYPE_DEVICE_INTERFACE_ERROR);
-
-	initialized = TRUE;
-}
-
-
-GType
-nm_device_interface_get_type (void)
-{
-	static GType device_interface_type = 0;
-
-	if (!device_interface_type) {
-		const GTypeInfo device_interface_info = {
-			sizeof (NMDeviceInterface), /* class_size */
-			nm_device_interface_init,   /* base_init */
-			NULL,		/* base_finalize */
-			NULL,
-			NULL,		/* class_finalize */
-			NULL,		/* class_data */
-			0,
-			0,              /* n_preallocs */
-			NULL
-		};
-
-		device_interface_type = g_type_register_static (G_TYPE_INTERFACE,
-														"NMDeviceInterface",
-														&device_interface_info, 0);
-
-		g_type_interface_add_prerequisite (device_interface_type, G_TYPE_OBJECT);
-	}
-
-	return device_interface_type;
-}
-
-/* FIXME: This should be public and nm_device_get_iface() should be removed. */
-static char *
-nm_device_interface_get_iface (NMDeviceInterface *device)
-{
-	char *iface = NULL;
-
-	g_return_val_if_fail (NM_IS_DEVICE_INTERFACE (device), NULL);
-
-	g_object_get (device, NM_DEVICE_INTERFACE_IFACE, &iface, NULL);
-
-	return iface;
-}
-
-gboolean
-nm_device_interface_check_connection_compatible (NMDeviceInterface *device,
-                                                 NMConnection *connection,
-                                                 GError **error)
-{
-	g_return_val_if_fail (NM_IS_DEVICE_INTERFACE (device), FALSE);
-	g_return_val_if_fail (NM_IS_CONNECTION (connection), FALSE);
-	g_return_val_if_fail (error != NULL, FALSE);
-	g_return_val_if_fail (*error == NULL, FALSE);
-
-	if (NM_DEVICE_INTERFACE_GET_INTERFACE (device)->check_connection_compatible)
-		return NM_DEVICE_INTERFACE_GET_INTERFACE (device)->check_connection_compatible (device, connection, error);
-	return TRUE;
-}
-
-gboolean
-nm_device_interface_activate (NMDeviceInterface *device,
-                              NMActRequest *req,
-                              GError **error)
-{
-	gboolean success;
-	NMConnection *connection;
-	char *iface;
-
-	g_return_val_if_fail (NM_IS_DEVICE_INTERFACE (device), FALSE);
-	g_return_val_if_fail (NM_IS_ACT_REQUEST (req), FALSE);
-
-	connection = nm_act_request_get_connection (req);
-	g_assert (connection);
-
-	iface = nm_device_interface_get_iface (device);
-	nm_log_info (LOGD_DEVICE, "Activation (%s) starting connection '%s'", iface,
-	             nm_connection_get_id (connection));
-	g_free (iface);
-
-	success = NM_DEVICE_INTERFACE_GET_INTERFACE (device)->activate (device, req, error);
-	if (!success)
-		g_assert (*error);
-
-	return success;
-}
-
-gboolean
-nm_device_interface_disconnect (NMDeviceInterface *device,
-                                GError **error)
-{
-	gboolean success = FALSE;
-
-	g_return_val_if_fail (NM_IS_DEVICE_INTERFACE (device), FALSE);
-
-	switch (nm_device_interface_get_state (device)) {
-	case NM_DEVICE_STATE_UNKNOWN:
-	case NM_DEVICE_STATE_UNMANAGED:
-	case NM_DEVICE_STATE_UNAVAILABLE:
-	case NM_DEVICE_STATE_DISCONNECTED:
-		g_set_error_literal (error,
-		                     NM_DEVICE_INTERFACE_ERROR,
-		                     NM_DEVICE_INTERFACE_ERROR_NOT_ACTIVE,
-		                     "Cannot disconnect an inactive device.");
-		break;
-	default:
-		success = NM_DEVICE_INTERFACE_GET_INTERFACE (device)->disconnect (device, error);
-		break;
-	}
-
-	return success;
-}
-
-static void
-impl_device_disconnect (NMDeviceInterface *device,
-                        DBusGMethodInvocation *context)
-{
-	g_signal_emit_by_name (device, NM_DEVICE_INTERFACE_DISCONNECT_REQUEST, context);
-}
-
-void
-nm_device_interface_deactivate (NMDeviceInterface *device, NMDeviceStateReason reason)
-{
-	g_return_if_fail (NM_IS_DEVICE_INTERFACE (device));
-
-	NM_DEVICE_INTERFACE_GET_INTERFACE (device)->deactivate (device, reason);
-}
-
-NMDeviceState
-nm_device_interface_get_state (NMDeviceInterface *device)
-{
-	NMDeviceState state;
-
-	g_object_get (G_OBJECT (device), "state", &state, NULL);
-	return state;
-}
-
-gboolean
-nm_device_interface_spec_match_list (NMDeviceInterface *device,
-                                     const GSList *specs)
-{
-	g_return_val_if_fail (NM_IS_DEVICE_INTERFACE (device), FALSE);
-
-	if (NM_DEVICE_INTERFACE_GET_INTERFACE (device)->spec_match_list)
-		return NM_DEVICE_INTERFACE_GET_INTERFACE (device)->spec_match_list (device, specs);
-	return FALSE;
-}
-
-NMConnection *
-nm_device_interface_connection_match_config (NMDeviceInterface *device,
-                                             const GSList *connections)
-{
-	g_return_val_if_fail (NM_IS_DEVICE_INTERFACE (device), NULL);
-
-	if (NM_DEVICE_INTERFACE_GET_INTERFACE (device)->connection_match_config)
-		return NM_DEVICE_INTERFACE_GET_INTERFACE (device)->connection_match_config (device, connections);
-	return NULL;
-}
-
-gboolean
-nm_device_interface_can_assume_connections (NMDeviceInterface *device)
-{
-	g_return_val_if_fail (NM_IS_DEVICE_INTERFACE (device), FALSE);
-
-	if (NM_DEVICE_INTERFACE_GET_INTERFACE (device)->can_assume_connections)
-		return NM_DEVICE_INTERFACE_GET_INTERFACE (device)->can_assume_connections (device);
-	return FALSE;
-}
-
-void
-nm_device_interface_set_enabled (NMDeviceInterface *device, gboolean enabled)
-{
-	g_return_if_fail (NM_IS_DEVICE_INTERFACE (device));
-
-	if (NM_DEVICE_INTERFACE_GET_INTERFACE (device)->set_enabled)
-		NM_DEVICE_INTERFACE_GET_INTERFACE (device)->set_enabled (device, enabled);
-}
-
-gboolean
-nm_device_interface_get_enabled (NMDeviceInterface *device)
-{
-	g_return_val_if_fail (NM_IS_DEVICE_INTERFACE (device), FALSE);
-
-	if (NM_DEVICE_INTERFACE_GET_INTERFACE (device)->get_enabled)
-		return NM_DEVICE_INTERFACE_GET_INTERFACE (device)->get_enabled (device);
-	return TRUE;
-}
-
diff --git a/src/nm-device-interface.h b/src/nm-device-interface.h
deleted file mode 100644
index 560cdfe5..00000000
--- a/src/nm-device-interface.h
+++ /dev/null
@@ -1,158 +0,0 @@
-/* -*- Mode: C; tab-width: 4; indent-tabs-mode: t; c-basic-offset: 4 -*- */
-/* NetworkManager -- Network link manager
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License along
- * with this program; if not, write to the Free Software Foundation, Inc.,
- * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
- *
- * Copyright (C) 2007 - 2008 Novell, Inc.
- * Copyright (C) 2007 - 2010 Red Hat, Inc.
- */
-
-#ifndef NM_DEVICE_INTERFACE_H
-#define NM_DEVICE_INTERFACE_H
-
-#include <glib-object.h>
-#include "NetworkManager.h"
-#include "nm-connection.h"
-#include "nm-activation-request.h"
-
-#define NM_TYPE_DEVICE_INTERFACE      (nm_device_interface_get_type ())
-#define NM_DEVICE_INTERFACE(obj)      (G_TYPE_CHECK_INSTANCE_CAST ((obj), NM_TYPE_DEVICE_INTERFACE, NMDeviceInterface))
-#define NM_IS_DEVICE_INTERFACE(obj)   (G_TYPE_CHECK_INSTANCE_TYPE ((obj), NM_TYPE_DEVICE_INTERFACE))
-#define NM_DEVICE_INTERFACE_GET_INTERFACE(obj) (G_TYPE_INSTANCE_GET_INTERFACE ((obj), NM_TYPE_DEVICE_INTERFACE, NMDeviceInterface))
-
-#define IS_ACTIVATING_STATE(state) \
-	(state > NM_DEVICE_STATE_DISCONNECTED && state < NM_DEVICE_STATE_ACTIVATED)
-
-typedef enum
-{
-	NM_DEVICE_INTERFACE_ERROR_CONNECTION_ACTIVATING = 0,
-	NM_DEVICE_INTERFACE_ERROR_CONNECTION_INVALID,
-	NM_DEVICE_INTERFACE_ERROR_NOT_ACTIVE,
-} NMDeviceInterfaceError;
-
-#define NM_DEVICE_INTERFACE_ERROR (nm_device_interface_error_quark ())
-#define NM_TYPE_DEVICE_INTERFACE_ERROR (nm_device_interface_error_get_type ()) 
-
-#define NM_DEVICE_INTERFACE_DISCONNECT_REQUEST "disconnect-request"
-
-#define NM_DEVICE_INTERFACE_UDI              "udi"
-#define NM_DEVICE_INTERFACE_IFACE            "interface"
-#define NM_DEVICE_INTERFACE_IP_IFACE         "ip-interface"
-#define NM_DEVICE_INTERFACE_DRIVER           "driver"
-#define NM_DEVICE_INTERFACE_CAPABILITIES     "capabilities"
-#define NM_DEVICE_INTERFACE_IP4_ADDRESS      "ip4-address"
-#define NM_DEVICE_INTERFACE_IP4_CONFIG       "ip4-config"
-#define NM_DEVICE_INTERFACE_DHCP4_CONFIG     "dhcp4-config"
-#define NM_DEVICE_INTERFACE_IP6_CONFIG       "ip6-config"
-#define NM_DEVICE_INTERFACE_DHCP6_CONFIG     "dhcp6-config"
-#define NM_DEVICE_INTERFACE_STATE            "state"
-#define NM_DEVICE_INTERFACE_ACTIVE_CONNECTION "active-connection"
-#define NM_DEVICE_INTERFACE_DEVICE_TYPE      "device-type" /* ugh */
-#define NM_DEVICE_INTERFACE_MANAGED          "managed"
-#define NM_DEVICE_INTERFACE_FIRMWARE_MISSING "firmware-missing"
-#define NM_DEVICE_INTERFACE_TYPE_DESC        "type-desc"    /* Internal only */
-#define NM_DEVICE_INTERFACE_RFKILL_TYPE      "rfkill-type"  /* Internal only */
-#define NM_DEVICE_INTERFACE_IFINDEX          "ifindex"      /* Internal only */
-
-typedef enum {
-	NM_DEVICE_INTERFACE_PROP_FIRST = 0x1000,
-
-	NM_DEVICE_INTERFACE_PROP_UDI = NM_DEVICE_INTERFACE_PROP_FIRST,
-	NM_DEVICE_INTERFACE_PROP_IFACE,
-	NM_DEVICE_INTERFACE_PROP_IP_IFACE,
-	NM_DEVICE_INTERFACE_PROP_DRIVER,
-	NM_DEVICE_INTERFACE_PROP_CAPABILITIES,
-	NM_DEVICE_INTERFACE_PROP_IP4_ADDRESS,
-	NM_DEVICE_INTERFACE_PROP_IP4_CONFIG,
-	NM_DEVICE_INTERFACE_PROP_DHCP4_CONFIG,
-	NM_DEVICE_INTERFACE_PROP_IP6_CONFIG,
-	NM_DEVICE_INTERFACE_PROP_DHCP6_CONFIG,
-	NM_DEVICE_INTERFACE_PROP_STATE,
-	NM_DEVICE_INTERFACE_PROP_ACTIVE_CONNECTION,
-	NM_DEVICE_INTERFACE_PROP_DEVICE_TYPE,
-	NM_DEVICE_INTERFACE_PROP_MANAGED,
-	NM_DEVICE_INTERFACE_PROP_FIRMWARE_MISSING,
-	NM_DEVICE_INTERFACE_PROP_TYPE_DESC,
-	NM_DEVICE_INTERFACE_PROP_RFKILL_TYPE,
-	NM_DEVICE_INTERFACE_PROP_IFINDEX,
-} NMDeviceInterfaceProp;
-
-
-typedef struct _NMDeviceInterface NMDeviceInterface;
-
-struct _NMDeviceInterface {
-	GTypeInterface g_iface;
-
-	/* Methods */
-	gboolean (*check_connection_compatible) (NMDeviceInterface *device,
-	                                         NMConnection *connection,
-	                                         GError **error);
-
-	gboolean (*activate) (NMDeviceInterface *device,
-	                      NMActRequest *req,
-	                      GError **error);
-
-	void (*deactivate) (NMDeviceInterface *device, NMDeviceStateReason reason);
-	gboolean (*disconnect) (NMDeviceInterface *device, GError **error);
-
-	gboolean (*spec_match_list) (NMDeviceInterface *device, const GSList *specs);
-
-	NMConnection * (*connection_match_config) (NMDeviceInterface *device, const GSList *specs);
-
-	gboolean (*can_assume_connections) (NMDeviceInterface *device);
-
-	void (*set_enabled) (NMDeviceInterface *device, gboolean enabled);
-
-	gboolean (*get_enabled) (NMDeviceInterface *device);
-
-	/* Signals */
-	void (*state_changed) (NMDeviceInterface *device,
-	                       NMDeviceState new_state,
-	                       NMDeviceState old_state,
-	                       NMDeviceStateReason reason);
-};
-
-GQuark nm_device_interface_error_quark (void);
-GType nm_device_interface_error_get_type (void);
-
-gboolean nm_device_interface_disconnect (NMDeviceInterface *device, GError **error);
-
-GType nm_device_interface_get_type (void);
-
-gboolean nm_device_interface_check_connection_compatible (NMDeviceInterface *device,
-                                                          NMConnection *connection,
-                                                          GError **error);
-
-gboolean nm_device_interface_activate (NMDeviceInterface *device,
-				       NMActRequest *req,
-				       GError **error);
-
-void nm_device_interface_deactivate (NMDeviceInterface *device, NMDeviceStateReason reason);
-
-NMDeviceState nm_device_interface_get_state (NMDeviceInterface *device);
-
-gboolean nm_device_interface_spec_match_list (NMDeviceInterface *device,
-                                              const GSList *specs);
-
-NMConnection * nm_device_interface_connection_match_config (NMDeviceInterface *device,
-                                                            const GSList *connections);
-
-gboolean nm_device_interface_can_assume_connections (NMDeviceInterface *device);
-
-gboolean nm_device_interface_get_enabled (NMDeviceInterface *device);
-
-void nm_device_interface_set_enabled (NMDeviceInterface *device, gboolean enabled);
-
-#endif /* NM_DEVICE_INTERFACE_H */
diff --git a/src/nm-device-modem.c b/src/nm-device-modem.c
index 076bfa49..7f81e981 100644
--- a/src/nm-device-modem.c
+++ b/src/nm-device-modem.c
@@ -21,7 +21,6 @@
 #include <glib.h>
 
 #include "nm-device-modem.h"
-#include "nm-device-interface.h"
 #include "nm-modem.h"
 #include "nm-modem-cdma.h"
 #include "nm-modem-gsm.h"
@@ -31,10 +30,7 @@
 #include "nm-marshal.h"
 #include "nm-logging.h"
 
-static void device_interface_init (NMDeviceInterface *iface_class);
-
-G_DEFINE_TYPE_EXTENDED (NMDeviceModem, nm_device_modem, NM_TYPE_DEVICE, 0,
-                        G_IMPLEMENT_INTERFACE (NM_TYPE_DEVICE_INTERFACE, device_interface_init))
+G_DEFINE_TYPE (NMDeviceModem, nm_device_modem, NM_TYPE_DEVICE)
 
 #define NM_DEVICE_MODEM_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), NM_TYPE_DEVICE_MODEM, NMDeviceModemPrivate))
 
@@ -60,7 +56,7 @@ enum {
 };
 static guint signals[LAST_SIGNAL] = { 0 };
 
-static void real_set_enabled (NMDeviceInterface *device, gboolean enabled);
+static void real_set_enabled (NMDevice *device, gboolean enabled);
 
 /*****************************************************************************/
 
@@ -69,17 +65,19 @@ ppp_failed (NMModem *modem, NMDeviceStateReason reason, gpointer user_data)
 {
 	NMDevice *device = NM_DEVICE (user_data);
 
-	switch (nm_device_interface_get_state (NM_DEVICE_INTERFACE (device))) {
+	switch (nm_device_get_state (device)) {
 	case NM_DEVICE_STATE_PREPARE:
 	case NM_DEVICE_STATE_CONFIG:
 	case NM_DEVICE_STATE_NEED_AUTH:
-	case NM_DEVICE_STATE_IP_CHECK:
-	case NM_DEVICE_STATE_SECONDARIES:
-	case NM_DEVICE_STATE_ACTIVATED:
 		nm_device_state_changed (device, NM_DEVICE_STATE_FAILED, reason);
 		break;
 	case NM_DEVICE_STATE_IP_CONFIG:
-		if (nm_device_ip_config_should_fail (device, FALSE)) {
+	case NM_DEVICE_STATE_IP_CHECK:
+	case NM_DEVICE_STATE_SECONDARIES:
+	case NM_DEVICE_STATE_ACTIVATED:
+		if (nm_device_activate_ip4_state_in_conf (device))
+			nm_device_activate_schedule_ip4_config_timeout (device);
+		else {
 			nm_device_state_changed (device,
 			                         NM_DEVICE_STATE_FAILED,
 			                         NM_DEVICE_STATE_REASON_IP_CONFIG_UNAVAILABLE);
@@ -99,7 +97,7 @@ modem_prepare_result (NMModem *modem,
 	NMDevice *device = NM_DEVICE (user_data);
 	NMDeviceState state;
 
-	state = nm_device_interface_get_state (NM_DEVICE_INTERFACE (device));
+	state = nm_device_get_state (device);
 	g_return_if_fail (state == NM_DEVICE_STATE_PREPARE);
 
 	if (success)
@@ -140,10 +138,8 @@ modem_ip4_config_result (NMModem *self,
                          gpointer user_data)
 {
 	NMDevice *device = NM_DEVICE (user_data);
-	NMDeviceState state;
 
-	state = nm_device_interface_get_state (NM_DEVICE_INTERFACE (device));
-	g_return_if_fail (state == NM_DEVICE_STATE_IP_CONFIG);
+	g_return_if_fail (nm_device_activate_ip4_state_in_conf (device) == TRUE);
 
 	if (error) {
 		nm_log_warn (LOGD_MB | LOGD_IP4, "retrieving IP4 configuration failed: (%d) %s",
@@ -155,7 +151,7 @@ modem_ip4_config_result (NMModem *self,
 		if (iface)
 			nm_device_set_ip_iface (device, iface);
 
-		nm_device_activate_schedule_stage4_ip4_config_get (device);
+		nm_device_activate_schedule_ip4_config_result (device, config);
 	}
 }
 
@@ -165,7 +161,7 @@ modem_enabled_cb (NMModem *modem, GParamSpec *pspec, gpointer user_data)
 	NMDeviceModem *self = NM_DEVICE_MODEM (user_data);
 	NMDeviceModemPrivate *priv = NM_DEVICE_MODEM_GET_PRIVATE (self);
 
-	real_set_enabled (NM_DEVICE_INTERFACE (self), nm_modem_get_mm_enabled (priv->modem));
+	real_set_enabled (NM_DEVICE (self), nm_modem_get_mm_enabled (priv->modem));
 
 	g_signal_emit (G_OBJECT (self), signals[ENABLE_CHANGED], 0);
 }
@@ -275,7 +271,9 @@ real_act_stage2_config (NMDevice *device, NMDeviceStateReason *reason)
 }
 
 static NMActStageReturn
-real_act_stage3_ip4_config_start (NMDevice *device, NMDeviceStateReason *reason)
+real_act_stage3_ip4_config_start (NMDevice *device,
+                                  NMIP4Config **out_config,
+                                  NMDeviceStateReason *reason)
 {
 	return nm_modem_stage3_ip4_config_start (NM_DEVICE_MODEM_GET_PRIVATE (device)->modem,
 	                                         device,
@@ -284,27 +282,26 @@ real_act_stage3_ip4_config_start (NMDevice *device, NMDeviceStateReason *reason)
 }
 
 static NMActStageReturn
-real_act_stage4_get_ip4_config (NMDevice *device,
-                                NMIP4Config **config,
-                                NMDeviceStateReason *reason)
+real_act_stage3_ip6_config_start (NMDevice *device,
+                                  NMIP6Config **out_config,
+                                  NMDeviceStateReason *reason)
 {
-	return nm_modem_stage4_get_ip4_config (NM_DEVICE_MODEM_GET_PRIVATE (device)->modem,
-	                                       device,
-	                                       NM_DEVICE_CLASS (nm_device_modem_parent_class),
-	                                       config,
-	                                       reason);
+	return nm_modem_stage3_ip6_config_start (NM_DEVICE_MODEM_GET_PRIVATE (device)->modem,
+	                                         device,
+	                                         NM_DEVICE_CLASS (nm_device_modem_parent_class),
+	                                         reason);
 }
 
 /*****************************************************************************/
 
 static gboolean
-real_get_enabled (NMDeviceInterface *device)
+real_get_enabled (NMDevice *device)
 {
 	return nm_modem_get_mm_enabled (NM_DEVICE_MODEM_GET_PRIVATE (device)->modem);
 }
 
 static void
-real_set_enabled (NMDeviceInterface *device, gboolean enabled)
+real_set_enabled (NMDevice *device, gboolean enabled)
 {
 	NMDeviceModem *self = NM_DEVICE_MODEM (device);
 	NMDeviceModemPrivate *priv = NM_DEVICE_MODEM_GET_PRIVATE (self);
@@ -314,7 +311,7 @@ real_set_enabled (NMDeviceInterface *device, gboolean enabled)
 		nm_modem_set_mm_enabled (priv->modem, enabled);
 
 		if (enabled == FALSE) {
-			state = nm_device_interface_get_state (device);
+			state = nm_device_get_state (NM_DEVICE (device));
 			if (state == NM_DEVICE_STATE_ACTIVATED) {
 				nm_device_state_changed (NM_DEVICE (device),
 				                         NM_DEVICE_STATE_DISCONNECTED,
@@ -348,12 +345,12 @@ nm_device_modem_new (NMModem *modem, const char *driver)
 	}
 
 	return (NMDevice *) g_object_new (NM_TYPE_DEVICE_MODEM,
-	                                  NM_DEVICE_INTERFACE_UDI, nm_modem_get_path (modem),
-	                                  NM_DEVICE_INTERFACE_IFACE, nm_modem_get_iface (modem),
-	                                  NM_DEVICE_INTERFACE_DRIVER, driver,
-	                                  NM_DEVICE_INTERFACE_TYPE_DESC, type_desc,
-	                                  NM_DEVICE_INTERFACE_DEVICE_TYPE, NM_DEVICE_TYPE_MODEM,
-	                                  NM_DEVICE_INTERFACE_RFKILL_TYPE, RFKILL_TYPE_WWAN,
+	                                  NM_DEVICE_UDI, nm_modem_get_path (modem),
+	                                  NM_DEVICE_IFACE, nm_modem_get_iface (modem),
+	                                  NM_DEVICE_DRIVER, driver,
+	                                  NM_DEVICE_TYPE_DESC, type_desc,
+	                                  NM_DEVICE_DEVICE_TYPE, NM_DEVICE_TYPE_MODEM,
+	                                  NM_DEVICE_RFKILL_TYPE, RFKILL_TYPE_WWAN,
 	                                  NM_DEVICE_MODEM_MODEM, modem,
 	                                  NM_DEVICE_MODEM_CAPABILITIES, caps,
 	                                  NM_DEVICE_MODEM_CURRENT_CAPABILITIES, caps,
@@ -361,13 +358,6 @@ nm_device_modem_new (NMModem *modem, const char *driver)
 }
 
 static void
-device_interface_init (NMDeviceInterface *iface_class)
-{
-    iface_class->get_enabled = real_get_enabled;
-    iface_class->set_enabled = real_set_enabled;
-}
-
-static void
 nm_device_modem_init (NMDeviceModem *self)
 {
 	g_signal_connect (self, "state-changed", G_CALLBACK (device_state_changed), self);
@@ -469,7 +459,9 @@ nm_device_modem_class_init (NMDeviceModemClass *mclass)
 	device_class->act_stage1_prepare = real_act_stage1_prepare;
 	device_class->act_stage2_config = real_act_stage2_config;
 	device_class->act_stage3_ip4_config_start = real_act_stage3_ip4_config_start;
-	device_class->act_stage4_get_ip4_config = real_act_stage4_get_ip4_config;
+	device_class->act_stage3_ip6_config_start = real_act_stage3_ip6_config_start;
+	device_class->get_enabled = real_get_enabled;
+    device_class->set_enabled = real_set_enabled;
 
 	/* Properties */
 	g_object_class_install_property
diff --git a/src/nm-device-olpc-mesh.c b/src/nm-device-olpc-mesh.c
index ddd5198e..f6390c16 100644
--- a/src/nm-device-olpc-mesh.c
+++ b/src/nm-device-olpc-mesh.c
@@ -31,16 +31,18 @@
 #include <netinet/in.h>
 #include <string.h>
 #include <net/ethernet.h>
-#include <iwlib.h>
+#include <netinet/ether.h>
 #include <sys/stat.h>
 #include <sys/wait.h>
 #include <signal.h>
 #include <unistd.h>
+#include <linux/if.h>
+#include <sys/ioctl.h>
+#include <errno.h>
 
 #include "nm-device.h"
 #include "nm-device-wifi.h"
 #include "nm-device-olpc-mesh.h"
-#include "nm-device-interface.h"
 #include "nm-device-private.h"
 #include "nm-utils.h"
 #include "nm-logging.h"
@@ -51,6 +53,8 @@
 #include "nm-setting-olpc-mesh.h"
 #include "nm-system.h"
 #include "nm-manager.h"
+#include "nm-enum-types.h"
+#include "wifi-utils.h"
 
 /* This is a bug; but we can't really change API now... */
 #include "NetworkManagerVPN.h"
@@ -58,8 +62,6 @@
 
 #include "nm-device-olpc-mesh-glue.h"
 
-static void nm_device_olpc_mesh_set_ssid (NMDeviceOlpcMesh *self, const GByteArray * ssid);
-
 G_DEFINE_TYPE (NMDeviceOlpcMesh, nm_device_olpc_mesh, NM_TYPE_DEVICE)
 
 #define NM_DEVICE_OLPC_MESH_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), NM_TYPE_DEVICE_OLPC_MESH, NMDeviceOlpcMeshPrivate))
@@ -82,15 +84,7 @@ enum {
 
 static guint signals[LAST_SIGNAL] = { 0 };
 
-typedef enum
-{
-	NM_OLPC_MESH_ERROR_CONNECTION_NOT_MESH = 0,
-	NM_OLPC_MESH_ERROR_CONNECTION_INVALID,
-	NM_OLPC_MESH_ERROR_CONNECTION_INCOMPATIBLE,
-} NMOlpcMeshError;
-
 #define NM_OLPC_MESH_ERROR (nm_olpc_mesh_error_quark ())
-#define NM_TYPE_OLPC_MESH_ERROR (nm_olpc_mesh_error_get_type ())
 
 
 struct _NMDeviceOlpcMeshPrivate
@@ -101,8 +95,7 @@ struct _NMDeviceOlpcMeshPrivate
 
 	GByteArray *      ssid;
 
-	gint8			  num_freqs;
-	guint32			  freqs[IW_MAX_FREQUENCIES];
+	WifiData *        wifi_data;
 
 	gboolean          up;
 
@@ -120,29 +113,6 @@ nm_olpc_mesh_error_quark (void)
 	return quark;
 }
 
-/* This should really be standard. */
-#define ENUM_ENTRY(NAME, DESC) { NAME, "" #NAME "", DESC }
-
-static GType
-nm_olpc_mesh_error_get_type (void)
-{
-	static GType etype = 0;
-
-	if (etype == 0) {
-		static const GEnumValue values[] = {
-			/* Connection was not a wireless connection. */
-			ENUM_ENTRY (NM_OLPC_MESH_ERROR_CONNECTION_NOT_MESH, "ConnectionNotMesh"),
-			/* Connection was not a valid wireless connection. */
-			ENUM_ENTRY (NM_OLPC_MESH_ERROR_CONNECTION_INVALID, "ConnectionInvalid"),
-			/* Connection does not apply to this device. */
-			ENUM_ENTRY (NM_OLPC_MESH_ERROR_CONNECTION_INCOMPATIBLE, "ConnectionIncompatible"),
-			{ 0, 0, 0 }
-		};
-		etype = g_enum_register_static ("NMOlpcMeshError", values);
-	}
-	return etype;
-}
-
 static guint32
 real_get_generic_capabilities (NMDevice *dev)
 {
@@ -161,44 +131,6 @@ nm_device_olpc_mesh_init (NMDeviceOlpcMesh * self)
 	memset (&(priv->hw_addr), 0, sizeof (struct ether_addr));
 }
 
-static guint32 iw_freq_to_uint32 (struct iw_freq *freq)
-{
-	if (freq->e == 0) {
-		/* Some drivers report channel not frequency.  Convert to a
-		 * frequency; but this assumes that the device is in b/g mode.
-		 */
-		if ((freq->m >= 1) && (freq->m <= 13))
-			return 2407 + (5 * freq->m);
-		else if (freq->m == 14)
-			return 2484;
-	}
-
-	return (guint32) (((double) freq->m) * pow (10, freq->e) / 1000000);
-}
-
-
-/* Until a new wireless-tools comes out that has the defs and the structure,
- * need to copy them here.
- */
-/* Scan capability flags - in (struct iw_range *)->scan_capa */
-#define NM_IW_SCAN_CAPA_NONE  0x00
-#define NM_IW_SCAN_CAPA_ESSID 0x01
-
-struct iw_range_with_scan_capa
-{
-	guint32 throughput;
-	guint32 min_nwid;
-	guint32 max_nwid;
-	guint16 old_num_channels;
-	guint8  old_num_frequency;
-
-	guint8  scan_capa;
-/* don't need the rest... */
-};
-
-
-
-
 static GObject*
 constructor (GType type,
              guint n_construct_params,
@@ -208,11 +140,6 @@ constructor (GType type,
 	GObjectClass *klass;
 	NMDeviceOlpcMesh *self;
 	NMDeviceOlpcMeshPrivate *priv;
-	const char *iface;
-	int fd;
-	struct iw_range range;
-	struct iwreq wrq;
-	int i;
 
 	klass = G_OBJECT_CLASS (nm_device_olpc_mesh_parent_class);
 	object = klass->constructor (type, n_construct_params, construct_params);
@@ -226,46 +153,19 @@ constructor (GType type,
 	            nm_device_get_iface (NM_DEVICE (self)),
 	            nm_device_get_ifindex (NM_DEVICE (self)));
 
-	iface = nm_device_get_iface (NM_DEVICE (self));
-	fd = socket (PF_INET, SOCK_DGRAM, 0);
-	if (fd < 0)
-		goto error;
-
-	memset (&wrq, 0, sizeof (struct iwreq));
-	memset (&range, 0, sizeof (struct iw_range));
-	strncpy (wrq.ifr_name, iface, IFNAMSIZ);
-	wrq.u.data.pointer = (caddr_t) &range;
-	wrq.u.data.length = sizeof (struct iw_range);
-
-	if (ioctl (fd, SIOCGIWRANGE, &wrq) < 0) {
-		nm_log_info (LOGD_HW | LOGD_WIFI, "(%s): driver WEXT range request failed",
+	priv->wifi_data = wifi_utils_init (nm_device_get_iface (NM_DEVICE (self)),
+	                                   nm_device_get_ifindex (NM_DEVICE (self)),
+	                                   FALSE);
+	if (priv->wifi_data == NULL) {
+		nm_log_warn (LOGD_HW | LOGD_OLPC_MESH, "(%s): failed to initialize WiFi driver",
 		             nm_device_get_iface (NM_DEVICE (self)));
-		goto error;
-	}
-
-	if ((wrq.u.data.length < 300) || (range.we_version_compiled < 21)) {
-		nm_log_info (LOGD_HW | LOGD_WIFI,
-		             "(%s): driver WEXT version too old (got %d, expected >= 21)",
-		             nm_device_get_iface (NM_DEVICE (self)),
-		             range.we_version_compiled);
-		goto error;
+		g_object_unref (object);
+		return NULL;
 	}
 
-	priv->num_freqs = MIN (range.num_frequency, IW_MAX_FREQUENCIES);
-	for (i = 0; i < priv->num_freqs; i++)
-		priv->freqs[i] = iw_freq_to_uint32 (&range.freq[i]);
-
-	close (fd);
-
 	/* shorter timeout for mesh connectivity */
 	nm_device_set_dhcp_timeout (NM_DEVICE (self), 20);
 	return object;
-
-error:
-	if (fd >= 0)
-		close (fd);
-	g_object_unref (object);
-	return NULL;
 }
 
 static gboolean
@@ -331,7 +231,7 @@ real_check_connection_compatible (NMDevice *device,
 	NMSettingConnection *s_con;
 	NMSettingOlpcMesh *s_mesh;
 
-	s_con = NM_SETTING_CONNECTION (nm_connection_get_setting (connection, NM_TYPE_SETTING_CONNECTION));
+	s_con = nm_connection_get_setting_connection (connection);
 	g_assert (s_con);
 
 	if (strcmp (nm_setting_connection_get_connection_type (s_con), NM_SETTING_OLPC_MESH_SETTING_NAME)) {
@@ -341,7 +241,7 @@ real_check_connection_compatible (NMDevice *device,
 		return FALSE;
 	}
 
-	s_mesh = NM_SETTING_OLPC_MESH (nm_connection_get_setting (connection, NM_TYPE_SETTING_OLPC_MESH));
+	s_mesh = nm_connection_get_setting_olpc_mesh (connection);
 	if (!s_mesh) {
 		g_set_error (error,
 		             NM_OLPC_MESH_ERROR, NM_OLPC_MESH_ERROR_CONNECTION_INVALID,
@@ -364,7 +264,7 @@ real_complete_connection (NMDevice *device,
 	NMSettingOlpcMesh *s_mesh;
 	GByteArray *tmp;
 
-	s_mesh = (NMSettingOlpcMesh *) nm_connection_get_setting (connection, NM_TYPE_SETTING_OLPC_MESH);
+	s_mesh = nm_connection_get_setting_olpc_mesh (connection);
 	if (!s_mesh) {
 		s_mesh = (NMSettingOlpcMesh *) nm_setting_olpc_mesh_new ();
 		nm_connection_add_setting (connection, NM_SETTING (s_mesh));
@@ -414,131 +314,6 @@ nm_device_olpc_mesh_get_address (NMDeviceOlpcMesh *self,
 	memcpy (addr, &(priv->hw_addr), sizeof (struct ether_addr));
 }
 
-static int
-create_socket_with_request (NMDevice *self, struct iwreq *req)
-{
-	int sk;
-	const char * iface;
-
-	g_return_val_if_fail (self != NULL, -1);
-
-	sk = socket (AF_INET, SOCK_DGRAM, 0);
-	if (sk == -1) {
-		nm_log_err (LOGD_OLPC_MESH, "Couldn't create socket: %d.", errno);
-		return -1;
-	}
-
-	memset (req, 0, sizeof (struct iwreq));
-	iface = nm_device_get_iface (NM_DEVICE (self));
-	strncpy (req->ifr_name, iface, IFNAMSIZ);
-
-	return sk;
-}
-
-static guint32
-nm_device_olpc_mesh_get_channel (NMDeviceOlpcMesh *self)
-{
-	NMDeviceOlpcMeshPrivate *priv = NM_DEVICE_OLPC_MESH_GET_PRIVATE (self);
-	int sk;
-	struct iwreq req;
-	int ret = 0;
-	int i;
-	guint32 freq;
-
-	sk = create_socket_with_request (NM_DEVICE (self), &req);
-	if (sk == -1)
-		return 0;
-
-	if ((ioctl (sk, SIOCGIWFREQ, &req)) != 0) {
-		nm_log_warn (LOGD_OLPC_MESH, "(%s): failed to get channel (errno: %d)",
-		             nm_device_get_iface (NM_DEVICE (self)), errno);
-		goto out;
-	}
-
-	freq = iw_freq_to_uint32 (&req.u.freq);
-
-	for (i = 0 ; i < priv->num_freqs; i++) {
-		if (freq == priv->freqs[i])
-			break;
-	}
-	if (i < priv->num_freqs)
-		ret = i + 1;
-
-out:
-	if (sk >= 0)
-		close (sk);
-	return ret;
-}
-
-static void
-nm_device_olpc_mesh_set_channel (NMDeviceOlpcMesh *self, guint32 channel)
-{
-	int sk;
-	struct iwreq req;
-
-	if (nm_device_olpc_mesh_get_channel (self) == channel)
-		return;
-
-	sk = create_socket_with_request (NM_DEVICE (self), &req);
-	if (sk < 0)
-		return;
-
-	if (channel > 0) {
-		req.u.freq.flags = IW_FREQ_FIXED;
-		req.u.freq.e = 0;
-		req.u.freq.m = channel;
-	}
-
-	if (ioctl (sk, SIOCSIWFREQ, &req) != 0) {
-		nm_log_warn (LOGD_OLPC_MESH, "(%s): failed to set to channel %d (errno: %d)",
-		             nm_device_get_iface (NM_DEVICE (self)), channel, errno);
-	} else
-		g_object_notify (G_OBJECT (self), NM_DEVICE_OLPC_MESH_ACTIVE_CHANNEL);
-
-	close (sk);
-}
-
-static void
-nm_device_olpc_mesh_set_ssid (NMDeviceOlpcMesh *self, const GByteArray * ssid)
-{
-	int sk;
-	struct iwreq wrq;
-	const char * iface;
-	guint32 len = 0;
-	char buf[IW_ESSID_MAX_SIZE + 1];
-
-	g_return_if_fail (self != NULL);
-
-	sk = socket (AF_INET, SOCK_DGRAM, 0);
-	if (sk == -1) {
-		nm_log_err (LOGD_OLPC_MESH, "Couldn't create socket: %d.", errno);
-		return;
-	}
-
-	iface = nm_device_get_iface (NM_DEVICE (self));
-
-	memset (buf, 0, sizeof (buf));
-	if (ssid) {
-		len = ssid->len;
-		memcpy (buf, ssid->data, MIN (sizeof (buf) - 1, len));
-	}
-	wrq.u.essid.pointer = (caddr_t) buf;
-	wrq.u.essid.length = len;
-	wrq.u.essid.flags = (len > 0) ? 1 : 0; /* 1=enable SSID, 0=disable/any */
-
-	strncpy (wrq.ifr_name, iface, IFNAMSIZ);
-	if (ioctl (sk, SIOCSIWESSID, &wrq) < 0) {
-		if (errno != ENODEV) {
-			nm_log_err (LOGD_OLPC_MESH, "(%s): error setting SSID to '%s': %s",
-			            iface,
-			            ssid ? nm_utils_escape_ssid (ssid->data, ssid->len) : "(null)",
-			            strerror (errno));
-		}
-    }
-
-	close (sk);
-}
-
 /****************************************************************************/
 
 static void
@@ -605,30 +380,38 @@ real_act_stage1_prepare (NMDevice *dev, NMDeviceStateReason *reason)
 	return NM_ACT_STAGE_RETURN_SUCCESS;
 }
 
+static void
+_mesh_set_channel (NMDeviceOlpcMesh *self, guint32 channel)
+{
+	NMDeviceOlpcMeshPrivate *priv = NM_DEVICE_OLPC_MESH_GET_PRIVATE (self);
+
+	if (wifi_utils_get_mesh_channel (priv->wifi_data) != channel) {
+		if (wifi_utils_set_mesh_channel (priv->wifi_data, channel))
+			g_object_notify (G_OBJECT (self), NM_DEVICE_OLPC_MESH_ACTIVE_CHANNEL);
+	}
+}
+
 static NMActStageReturn
 real_act_stage2_config (NMDevice *dev, NMDeviceStateReason *reason)
 {
 	NMDeviceOlpcMesh *self = NM_DEVICE_OLPC_MESH (dev);
+	NMDeviceOlpcMeshPrivate *priv = NM_DEVICE_OLPC_MESH_GET_PRIVATE (self);
 	NMConnection *connection;
 	NMSettingOlpcMesh *s_mesh;
-	NMActRequest *req;
 	guint32 channel;
 	const GByteArray *anycast_addr_array;
 	guint8 *anycast_addr = NULL;
 
-	req = nm_device_get_act_request (dev);
-	g_assert (req);
-
-	connection = nm_act_request_get_connection (req);
+	connection = nm_device_get_connection (dev);
 	g_assert (connection);
 
-	s_mesh = NM_SETTING_OLPC_MESH (nm_connection_get_setting (connection, NM_TYPE_SETTING_OLPC_MESH));
+	s_mesh = nm_connection_get_setting_olpc_mesh (connection);
 	g_assert (s_mesh);
 
 	channel = nm_setting_olpc_mesh_get_channel (s_mesh);
 	if (channel != 0)
-		nm_device_olpc_mesh_set_channel (self, channel);
-	nm_device_olpc_mesh_set_ssid (self, nm_setting_olpc_mesh_get_ssid (s_mesh));
+		_mesh_set_channel (self, channel);
+	wifi_utils_set_mesh_ssid (priv->wifi_data, nm_setting_olpc_mesh_get_ssid (s_mesh));
 
 	anycast_addr_array = nm_setting_olpc_mesh_get_dhcp_anycast_address (s_mesh);
 	if (anycast_addr_array)
@@ -651,6 +434,9 @@ dispose (GObject *object)
 	}
 	priv->dispose_has_run = TRUE;
 
+	if (priv->wifi_data)
+		wifi_utils_deinit (priv->wifi_data);
+
 	device_cleanup (self);
 
 	manager = nm_manager_get ();
@@ -672,7 +458,7 @@ get_property (GObject *object, guint prop_id,
 	switch (prop_id) {
 	case PROP_HW_ADDRESS:
 		nm_device_olpc_mesh_get_address (device, &hw_addr);
-		g_value_take_string (value, nm_ether_ntop (&hw_addr));
+		g_value_take_string (value, nm_utils_hwaddr_ntoa (&hw_addr, ARPHRD_ETHER));
 		break;
 	case PROP_COMPANION:
 		if (priv->companion)
@@ -681,7 +467,7 @@ get_property (GObject *object, guint prop_id,
 			g_value_set_boxed (value, "/");
 		break;
 	case PROP_ACTIVE_CHANNEL:
-		g_value_set_uint (value, nm_device_olpc_mesh_get_channel (device));
+		g_value_set_uint (value, wifi_utils_get_mesh_channel (priv->wifi_data));
 		break;
 	default:
 		G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
@@ -810,9 +596,7 @@ static gboolean
 companion_scan_allowed_cb (NMDeviceWifi *companion, gpointer user_data)
 {
 	NMDeviceOlpcMesh *self = NM_DEVICE_OLPC_MESH (user_data);
-	NMDeviceState state;
-
-	g_object_get (G_OBJECT (self), NM_DEVICE_INTERFACE_STATE, &state, NULL);
+	NMDeviceState state = nm_device_get_state (NM_DEVICE (self));
 
 	/* Don't allow the companion to scan while configuring the mesh interface */
 	return (state < NM_DEVICE_STATE_PREPARE) || (state > NM_DEVICE_STATE_IP_CONFIG);
@@ -822,9 +606,7 @@ static gboolean
 companion_autoconnect_allowed_cb (NMDeviceWifi *companion, gpointer user_data)
 {
 	NMDeviceOlpcMesh *self = NM_DEVICE_OLPC_MESH (user_data);
-	NMDeviceState state;
-
-	g_object_get (G_OBJECT (self), NM_DEVICE_INTERFACE_STATE, &state, NULL);
+	NMDeviceState state = nm_device_get_state (NM_DEVICE (self));
 
 	/* Don't allow the companion to autoconnect while a mesh connection is
 	 * active */
@@ -961,11 +743,11 @@ nm_device_olpc_mesh_new (const char *udi,
 	g_return_val_if_fail (driver != NULL, NULL);
 
 	obj = g_object_new (NM_TYPE_DEVICE_OLPC_MESH,
-	                    NM_DEVICE_INTERFACE_UDI, udi,
-	                    NM_DEVICE_INTERFACE_IFACE, iface,
-	                    NM_DEVICE_INTERFACE_DRIVER, driver,
-	                    NM_DEVICE_INTERFACE_TYPE_DESC, "802.11 OLPC Mesh",
-	                    NM_DEVICE_INTERFACE_DEVICE_TYPE, NM_DEVICE_TYPE_OLPC_MESH,
+	                    NM_DEVICE_UDI, udi,
+	                    NM_DEVICE_IFACE, iface,
+	                    NM_DEVICE_DRIVER, driver,
+	                    NM_DEVICE_TYPE_DESC, "802.11 OLPC Mesh",
+	                    NM_DEVICE_DEVICE_TYPE, NM_DEVICE_TYPE_OLPC_MESH,
 	                    NULL);
 	if (obj == NULL)
 		return NULL;
diff --git a/src/nm-device-olpc-mesh.h b/src/nm-device-olpc-mesh.h
index bcc03e57..9d42ecfa 100644
--- a/src/nm-device-olpc-mesh.h
+++ b/src/nm-device-olpc-mesh.h
@@ -42,6 +42,13 @@ G_BEGIN_DECLS
 #define NM_IS_DEVICE_OLPC_MESH_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass),  NM_TYPE_DEVICE_OLPC_MESH))
 #define NM_DEVICE_OLPC_MESH_GET_CLASS(obj)  (G_TYPE_INSTANCE_GET_CLASS ((obj),  NM_TYPE_DEVICE_OLPC_MESH, NMDeviceOlpcMeshClass))
 
+typedef enum
+{
+	NM_OLPC_MESH_ERROR_CONNECTION_NOT_MESH = 0, /*< nick=ConnectionNotMesh >*/
+	NM_OLPC_MESH_ERROR_CONNECTION_INVALID,      /*< nick=ConnectionInvalid >*/
+	NM_OLPC_MESH_ERROR_CONNECTION_INCOMPATIBLE, /*< nick=ConnectionIncompatible >*/
+} NMOlpcMeshError;
+
 #define NM_DEVICE_OLPC_MESH_HW_ADDRESS     "hw-address"
 #define NM_DEVICE_OLPC_MESH_COMPANION      "companion"
 #define NM_DEVICE_OLPC_MESH_BITRATE        "bitrate"
diff --git a/src/nm-device-private.h b/src/nm-device-private.h
index a7d238b1..9b78db12 100644
--- a/src/nm-device-private.h
+++ b/src/nm-device-private.h
@@ -24,26 +24,47 @@
 
 #include "nm-device.h"
 
+/* This file should only be used by subclasses of NMDevice */
+
+enum NMActStageReturn {
+	NM_ACT_STAGE_RETURN_FAILURE = 0,
+	NM_ACT_STAGE_RETURN_SUCCESS,
+	NM_ACT_STAGE_RETURN_POSTPONE,
+	NM_ACT_STAGE_RETURN_STOP         /* This activation chain is done */
+};
+
 void nm_device_set_ip_iface (NMDevice *self, const char *iface);
 
 void nm_device_activate_schedule_stage3_ip_config_start (NMDevice *device);
 
-void nm_device_state_changed (NMDevice *device,
-                              NMDeviceState state,
-                              NMDeviceStateReason reason);
-
 gboolean nm_device_hw_bring_up (NMDevice *self, gboolean wait, gboolean *no_firmware);
 
 void nm_device_hw_take_down (NMDevice *self, gboolean block);
 
-void nm_device_handle_autoip4_event (NMDevice *self,
-                                     const char *event,
-                                     const char *address);
-
 gboolean nm_device_ip_config_should_fail (NMDevice *self, gboolean ip6);
 
-gboolean nm_device_get_firmware_missing (NMDevice *self);
-
 void nm_device_set_firmware_missing (NMDevice *self, gboolean missing);
 
+guint32 nm_device_get_capabilities (NMDevice *dev);
+guint32 nm_device_get_type_capabilities (NMDevice *dev);
+
+void nm_device_activate_schedule_stage1_device_prepare (NMDevice *device);
+void nm_device_activate_schedule_stage2_device_config (NMDevice *device);
+
+void nm_device_activate_schedule_ip4_config_result(NMDevice *device, NMIP4Config *config);
+void nm_device_activate_schedule_ip4_config_timeout (NMDevice *device);
+
+void nm_device_activate_schedule_ip6_config_result (NMDevice *device, NMIP6Config *config);
+void nm_device_activate_schedule_ip6_config_timeout (NMDevice *device);
+
+gboolean nm_device_activate_ip4_state_in_conf (NMDevice *device);
+gboolean nm_device_activate_ip6_state_in_conf (NMDevice *device);
+
+void nm_device_set_dhcp_timeout (NMDevice *device, guint32 timeout);
+void nm_device_set_dhcp_anycast_address (NMDevice *device, guint8 *addr);
+
+gboolean nm_device_dhcp4_renew (NMDevice *device, gboolean release);
+
+gboolean nm_device_match_ip_config (NMDevice *device, NMConnection *connection);
+
 #endif	/* NM_DEVICE_PRIVATE_H */
diff --git a/src/nm-device-vlan.c b/src/nm-device-vlan.c
new file mode 100644
index 00000000..14be849f
--- /dev/null
+++ b/src/nm-device-vlan.c
@@ -0,0 +1,803 @@
+/* -*- 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 2011 - 2012 Red Hat, Inc.
+ */
+
+#include "config.h"
+
+#include <glib.h>
+#include <glib/gi18n.h>
+
+#include <sys/socket.h>
+#include <linux/if.h>
+#include <netinet/ether.h>
+
+#include "nm-device-vlan.h"
+#include "nm-logging.h"
+#include "nm-properties-changed-signal.h"
+#include "nm-utils.h"
+#include "NetworkManagerUtils.h"
+#include "nm-device-private.h"
+#include "nm-netlink-monitor.h"
+#include "nm-enum-types.h"
+#include "nm-system.h"
+
+#include "nm-device-vlan-glue.h"
+
+
+G_DEFINE_TYPE (NMDeviceVlan, nm_device_vlan, NM_TYPE_DEVICE)
+
+#define NM_DEVICE_VLAN_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), NM_TYPE_DEVICE_VLAN, NMDeviceVlanPrivate))
+
+#define NM_VLAN_ERROR (nm_vlan_error_quark ())
+
+typedef struct {
+	gboolean disposed;
+
+	NMDevice *parent;
+	guint parent_state_id;
+
+	guint vlan_id;
+
+	guint8 hw_addr[NM_UTILS_HWADDR_LEN_MAX];
+	guint hw_addr_len;
+
+	gboolean          carrier;
+	NMNetlinkMonitor *monitor;
+	gulong            link_connected_id;
+	gulong            link_disconnected_id;
+	guint             carrier_action_defer_id;
+} NMDeviceVlanPrivate;
+
+enum {
+	PROPERTIES_CHANGED,
+
+	LAST_SIGNAL
+};
+
+static guint signals[LAST_SIGNAL] = { 0 };
+
+enum {
+	PROP_0,
+	PROP_HW_ADDRESS,
+	PROP_CARRIER,
+	PROP_VLAN_ID,
+
+	LAST_PROP
+};
+
+static void
+set_carrier (NMDeviceVlan *self,
+             const gboolean carrier,
+             const gboolean defer_action);
+
+/******************************************************************/
+
+static GQuark
+nm_vlan_error_quark (void)
+{
+	static GQuark quark = 0;
+	if (!quark)
+		quark = g_quark_from_static_string ("nm-vlan-error");
+	return quark;
+}
+
+/******************************************************************/
+
+static guint32
+real_get_generic_capabilities (NMDevice *dev)
+{
+	/* We assume VLAN interfaces always support carrier detect */
+	return NM_DEVICE_CAP_CARRIER_DETECT | NM_DEVICE_CAP_NM_SUPPORTED;
+}
+
+static gboolean
+get_carrier_sync (NMDeviceVlan *self)
+{
+	NMDeviceVlanPrivate *priv = NM_DEVICE_VLAN_GET_PRIVATE (self);
+	GError *error = NULL;
+	guint32 ifflags = 0;
+
+	/* Get initial link state */
+	if (!nm_netlink_monitor_get_flags_sync (priv->monitor,
+	                                        nm_device_get_ip_ifindex (NM_DEVICE (self)),
+	                                        &ifflags,
+	                                        &error)) {
+		nm_log_warn (LOGD_HW | LOGD_DEVICE,
+		             "(%s): couldn't get carrier state: (%d) %s",
+		             nm_device_get_ip_iface (NM_DEVICE (self)),
+		             error ? error->code : -1,
+		             (error && error->message) ? error->message : "unknown");
+		g_clear_error (&error);
+	}
+
+	return !!(ifflags & IFF_LOWER_UP);
+}
+
+static gboolean
+real_hw_is_up (NMDevice *device)
+{
+	return nm_system_iface_is_up (nm_device_get_ip_ifindex (device));
+}
+
+static gboolean
+real_hw_bring_up (NMDevice *dev, gboolean *no_firmware)
+{
+	gboolean success = FALSE, carrier;
+	guint i = 20;
+
+	while (i-- > 0 && !success) {
+		success = nm_system_iface_set_up (nm_device_get_ip_ifindex (dev), TRUE, no_firmware);
+		g_usleep (50);
+	}
+
+	if (success) {
+		/* Block a bit to make sure the carrier comes on; it's delayed a bit
+		 * after setting the interface up.
+		 */
+		i = 20;
+		while (i-- > 0) {
+			carrier = get_carrier_sync (NM_DEVICE_VLAN (dev));
+			set_carrier (NM_DEVICE_VLAN (dev), carrier, carrier ? FALSE : TRUE);
+			if (carrier)
+				break;
+			g_usleep (100);
+		}
+	}
+	return success;
+}
+
+static void
+real_hw_take_down (NMDevice *dev)
+{
+	nm_system_iface_set_up (nm_device_get_ip_ifindex (dev), FALSE, NULL);
+}
+
+static void
+real_update_hw_address (NMDevice *dev)
+{
+	NMDeviceVlan *self = NM_DEVICE_VLAN (dev);
+	NMDeviceVlanPrivate *priv = NM_DEVICE_VLAN_GET_PRIVATE (self);
+	struct rtnl_link *rtnl;
+	struct nl_addr *addr;
+
+	rtnl = nm_netlink_index_to_rtnl_link (nm_device_get_ip_ifindex (dev));
+	if (!rtnl) {
+		nm_log_err (LOGD_HW | LOGD_DEVICE,
+		            "(%s) failed to read hardware address (error %d)",
+		            nm_device_get_iface (dev), errno);
+		return;
+	}
+
+	addr = rtnl_link_get_addr (rtnl);
+	if (!addr) {
+		nm_log_err (LOGD_HW | LOGD_DEVICE,
+		            "(%s) no hardware address?",
+		            nm_device_get_iface (dev));
+		goto out;
+	}
+
+	if (nl_addr_get_len (addr) > sizeof (priv->hw_addr)) {
+		nm_log_err (LOGD_HW | LOGD_DEVICE,
+		            "(%s) hardware address is wrong length (got %d max %zd)",
+		            nm_device_get_iface (dev),
+		            nl_addr_get_len (addr),
+		            sizeof (priv->hw_addr));
+	} else {
+		priv->hw_addr_len = nl_addr_get_len (addr);
+		memcpy (&priv->hw_addr, nl_addr_get_binary_addr (addr), priv->hw_addr_len);
+		g_object_notify (G_OBJECT (self), NM_DEVICE_VLAN_HW_ADDRESS);
+	}
+
+out:
+	rtnl_link_put (rtnl);
+}
+
+static gboolean
+real_can_interrupt_activation (NMDevice *dev)
+{
+	/* Can interrupt activation if the carrier drops while activating */
+	return NM_DEVICE_VLAN_GET_PRIVATE (dev)->carrier ? FALSE : TRUE;
+}
+
+static gboolean
+real_is_available (NMDevice *dev)
+{
+	return NM_DEVICE_VLAN_GET_PRIVATE (dev)->carrier ? TRUE : FALSE;
+}
+
+/******************************************************************/
+
+static gboolean
+match_parent (NMDeviceVlan *self, const char *parent, GError **error)
+{
+	NMDeviceVlanPrivate *priv = NM_DEVICE_VLAN_GET_PRIVATE (self);
+
+	g_return_val_if_fail (parent != NULL, FALSE);
+
+	if (nm_utils_is_uuid (parent)) {
+		NMActRequest *parent_req;
+		NMConnection *parent_connection;
+
+		/* If the parent is a UUID, the connection matches if our parent
+		 * device has that connection activated.
+		 */
+
+		parent_req = nm_device_get_act_request (priv->parent);
+		if (!parent_req) {
+			g_set_error_literal (error, NM_VLAN_ERROR, NM_VLAN_ERROR_CONNECTION_INVALID,
+			                     "Parent interface not active; could not match UUID");
+			return FALSE;
+		}
+
+		parent_connection = nm_active_connection_get_connection (NM_ACTIVE_CONNECTION (parent_req));
+		if (!parent_connection) {
+			g_set_error_literal (error, NM_VLAN_ERROR, NM_VLAN_ERROR_CONNECTION_INVALID,
+			                     "Parent interface had no connection; could not match UUID");
+			return FALSE;
+		}
+		if (g_strcmp0 (parent, nm_connection_get_uuid (parent_connection)) != 0) {
+			g_set_error_literal (error, NM_VLAN_ERROR, NM_VLAN_ERROR_CONNECTION_INVALID,
+			                     "Parent interface UUID did not match connection UUID");
+			return FALSE;
+		}
+	} else {
+		/* interface name */
+		if (g_strcmp0 (parent, nm_device_get_ip_iface (priv->parent)) != 0) {
+			g_set_error_literal (error, NM_VLAN_ERROR, NM_VLAN_ERROR_CONNECTION_INVALID,
+			                     "Parent interface name did not match connection");
+			return FALSE;
+		}
+	}
+
+	return TRUE;
+}
+
+static gboolean
+match_vlan_connection (NMDeviceVlan *self, NMConnection *connection, GError **error)
+{
+	NMDeviceVlanPrivate *priv = NM_DEVICE_VLAN_GET_PRIVATE (self);
+	NMSettingVlan *s_vlan;
+	const char *parent, *iface = NULL;
+
+	s_vlan = nm_connection_get_setting_vlan (connection);
+	if (!s_vlan) {
+		g_set_error (error, NM_VLAN_ERROR, NM_VLAN_ERROR_CONNECTION_INVALID,
+				     "The connection was not a VLAN connection.");
+		return FALSE;
+	}
+
+	if (nm_setting_vlan_get_id (s_vlan) != priv->vlan_id) {
+		g_set_error (error, NM_VLAN_ERROR, NM_VLAN_ERROR_CONNECTION_INVALID,
+		             "The connection's VLAN ID did not match the device's VLAN ID.");
+		return FALSE;
+	}
+
+	/* Check parent interface; could be an interface name or a UUID */
+	parent = nm_setting_vlan_get_parent (s_vlan);
+	if (parent) {
+		if (!match_parent (self, parent, error))
+			return FALSE;
+	} else {
+		/* Parent could be a MAC address in a hardware-specific setting */
+		if (!nm_device_hwaddr_matches (priv->parent, connection, NULL, 0, TRUE)) {
+			g_set_error (error, NM_VLAN_ERROR, NM_VLAN_ERROR_CONNECTION_INVALID,
+					     "Failed to match the VLAN parent interface via hardware address.");
+			return FALSE;
+		}
+	}
+
+	/* Ensure the interface name matches.  If not specified we assume a match
+	 * since both the parent interface and the VLAN ID matched by the time we
+	 * get here.
+	 */
+	iface = nm_connection_get_virtual_iface_name (connection);
+	if (iface) {
+		if (g_strcmp0 (nm_device_get_ip_iface (NM_DEVICE (self)), iface) != 0) {
+			g_set_error (error, NM_VLAN_ERROR, NM_VLAN_ERROR_CONNECTION_INVALID,
+					     "The VLAN connection virtual interface name did not match.");
+			return FALSE;
+		}
+	}
+
+	return TRUE;
+}
+
+static NMConnection *
+real_get_best_auto_connection (NMDevice *dev,
+                               GSList *connections,
+                               char **specific_object)
+{
+	GSList *iter;
+
+	for (iter = connections; iter; iter = g_slist_next (iter)) {
+		NMConnection *connection = NM_CONNECTION (iter->data);
+		NMSettingConnection *s_con;
+
+		s_con = nm_connection_get_setting_connection (connection);
+		g_assert (s_con);
+		if (   nm_setting_connection_get_autoconnect (s_con)
+		    && match_vlan_connection (NM_DEVICE_VLAN (dev), connection, NULL))
+			return connection;
+	}
+	return NULL;
+}
+
+static gboolean
+real_check_connection_compatible (NMDevice *device,
+                                  NMConnection *connection,
+                                  GError **error)
+{
+	return match_vlan_connection (NM_DEVICE_VLAN (device), connection, error);
+}
+
+static gboolean
+real_complete_connection (NMDevice *device,
+                          NMConnection *connection,
+                          const char *specific_object,
+                          const GSList *existing_connections,
+                          GError **error)
+{
+	NMDeviceVlanPrivate *priv = NM_DEVICE_VLAN_GET_PRIVATE (device);
+	NMSettingVlan *s_vlan;
+
+	nm_utils_complete_generic (connection,
+	                           NM_SETTING_VLAN_SETTING_NAME,
+	                           existing_connections,
+	                           _("VLAN connection %d"),
+	                           NULL,
+	                           TRUE);
+
+	s_vlan = nm_connection_get_setting_vlan (connection);
+	if (!s_vlan) {
+		g_set_error_literal (error, NM_VLAN_ERROR, NM_VLAN_ERROR_CONNECTION_INVALID,
+		                     "A 'vlan' setting is required.");
+		return FALSE;
+	}
+
+	/* If there's no VLAN interface, no parent, and no hardware address in the
+	 * settings, then there's not enough information to complete the setting.
+	 */
+	if (!nm_setting_vlan_get_parent (s_vlan)) {
+		if (!nm_device_hwaddr_matches (priv->parent, connection, NULL, 0, TRUE)) {
+			/* FIXME: put priv->hw_addr into the connection in the appropriate
+			 * hardware-specific setting.
+			 */
+			g_set_error_literal (error, NM_VLAN_ERROR, NM_VLAN_ERROR_CONNECTION_INVALID,
+				                 "The 'vlan' setting had no interface name, parent, or hardware address.");
+			return FALSE;
+		}
+	}
+
+	return TRUE;
+}
+
+static gboolean
+spec_match_list (NMDevice *device, const GSList *specs)
+{
+	NMDeviceVlanPrivate *priv = NM_DEVICE_VLAN_GET_PRIVATE (device);
+	char *hwaddr;
+	gboolean matched;
+	int itype = nm_utils_hwaddr_type (priv->hw_addr_len);
+
+	hwaddr = nm_utils_hwaddr_ntoa (priv->hw_addr, itype);
+	matched = nm_match_spec_hwaddr (specs, hwaddr);
+	g_free (hwaddr);
+
+	return matched;
+}
+
+static gboolean
+vlan_match_config (NMDevice *device, NMConnection *connection)
+{
+	NMDeviceVlanPrivate *priv = NM_DEVICE_VLAN_GET_PRIVATE (device);
+	NMSettingVlan *s_vlan;
+	const char *ifname, *parent;
+	gboolean fail_if_no_hwaddr = FALSE;
+
+	s_vlan = nm_connection_get_setting_vlan (connection);
+	if (!s_vlan)
+		return FALSE;
+
+	/* Interface name */
+	ifname = nm_setting_vlan_get_interface_name (s_vlan);
+	if (g_strcmp0 (ifname, nm_device_get_ip_iface (device)) != 0)
+		return FALSE;
+
+	if (nm_setting_vlan_get_id (s_vlan) != priv->vlan_id)
+		return FALSE;
+
+	parent = nm_setting_vlan_get_parent (s_vlan);
+	if (parent) {
+		if (!match_parent (NM_DEVICE_VLAN (device), parent, NULL))
+			return FALSE;
+	} else {
+		/* If there's no parent and no interface name given, then the only way
+		 * we have to identify the VLAN interface the connection matches is
+		 * a hardware-specific setting's hardware address property, so we want
+		 * to fail the match below if we there is none.
+		 */
+		 if (ifname == NULL)
+		 	fail_if_no_hwaddr = TRUE;
+	}
+
+	/* MAC address check; we ask the parent to check our own MAC address,
+	 * because only the parent knows what kind of NMSetting the MAC
+	 * address will be in.  The VLAN device shouldn't have to know what kind
+	 * of interface the parent is.
+	 */
+	if (!nm_device_hwaddr_matches (priv->parent, connection, priv->hw_addr, priv->hw_addr_len, fail_if_no_hwaddr))
+		return FALSE;
+
+	return TRUE;
+}
+
+static NMConnection *
+connection_match_config (NMDevice *self, const GSList *connections)
+{
+	const GSList *iter;
+
+	/* First narrow @connections down to those that match in their
+	 * NMSettingVlan configuration.
+	 */
+	for (iter = connections; iter; iter = iter->next) {
+		NMConnection *candidate = iter->data;
+
+		if (!nm_connection_is_type (candidate, NM_SETTING_VLAN_SETTING_NAME))
+			continue;
+		if (!vlan_match_config (self, candidate))
+			continue;
+		if (!nm_device_match_ip_config (self, candidate))
+			continue;
+
+		return candidate;
+	}
+	return NULL;
+}
+
+/******************************************************************/
+
+static void
+carrier_action_defer_clear (NMDeviceVlan *self)
+{
+	NMDeviceVlanPrivate *priv = NM_DEVICE_VLAN_GET_PRIVATE (self);
+
+	if (priv->carrier_action_defer_id) {
+		g_source_remove (priv->carrier_action_defer_id);
+		priv->carrier_action_defer_id = 0;
+	}
+}
+
+static gboolean
+carrier_action_defer_cb (gpointer user_data)
+{
+	NMDeviceVlan *self = NM_DEVICE_VLAN (user_data);
+	NMDeviceVlanPrivate *priv = NM_DEVICE_VLAN_GET_PRIVATE (self);
+	NMDeviceState state;
+
+	priv->carrier_action_defer_id = 0;
+
+	state = nm_device_get_state (NM_DEVICE (self));
+	if (state == NM_DEVICE_STATE_UNAVAILABLE) {
+		if (priv->carrier)
+			nm_device_queue_state (NM_DEVICE (self), NM_DEVICE_STATE_DISCONNECTED, NM_DEVICE_STATE_REASON_CARRIER);
+	} else if (state >= NM_DEVICE_STATE_DISCONNECTED) {
+		if (!priv->carrier)
+			nm_device_queue_state (NM_DEVICE (self), NM_DEVICE_STATE_UNAVAILABLE, NM_DEVICE_STATE_REASON_CARRIER);
+	}
+	return FALSE;
+}
+
+static void
+set_carrier (NMDeviceVlan *self,
+             const gboolean carrier,
+             const gboolean defer_action)
+{
+	NMDeviceVlanPrivate *priv = NM_DEVICE_VLAN_GET_PRIVATE (self);
+	NMDeviceState state;
+
+	if (priv->carrier == carrier)
+		return;
+
+	/* Clear any previous deferred action */
+	carrier_action_defer_clear (self);
+
+	priv->carrier = carrier;
+	g_object_notify (G_OBJECT (self), NM_DEVICE_VLAN_CARRIER);
+
+	state = nm_device_get_state (NM_DEVICE (self));
+	nm_log_info (LOGD_HW | LOGD_DEVICE,
+	             "(%s): carrier now %s (device state %d%s)",
+	             nm_device_get_iface (NM_DEVICE (self)),
+	             carrier ? "ON" : "OFF",
+	             state,
+	             defer_action ? ", deferring action for 4 seconds" : "");
+
+	if (defer_action)
+		priv->carrier_action_defer_id = g_timeout_add_seconds (4, carrier_action_defer_cb, self);
+	else
+		carrier_action_defer_cb (self);
+}
+
+static void
+carrier_on (NMNetlinkMonitor *monitor, int idx, NMDevice *device)
+{
+	/* Make sure signal is for us */
+	if (idx == nm_device_get_ifindex (device))
+		set_carrier (NM_DEVICE_VLAN (device), TRUE, FALSE);
+}
+
+static void
+carrier_off (NMNetlinkMonitor *monitor, int idx, NMDevice *device)
+{
+	NMDeviceState state;
+	gboolean defer = FALSE;
+
+	/* Make sure signal is for us */
+	if (idx == nm_device_get_ifindex (device)) {
+		/* Defer carrier-off event actions while connected by a few seconds
+		 * so that tripping over a cable, power-cycling a switch, or breaking
+		 * off the RJ45 locking tab isn't so catastrophic.
+		 */
+		state = nm_device_get_state (device);
+		if (state > NM_DEVICE_STATE_DISCONNECTED)
+			defer = TRUE;
+
+		set_carrier (NM_DEVICE_VLAN (device), FALSE, defer);
+	}
+}
+
+static void
+carrier_watch_init (NMDeviceVlan *self)
+{
+	NMDeviceVlanPrivate *priv = NM_DEVICE_VLAN_GET_PRIVATE (self);
+
+	priv->monitor = nm_netlink_monitor_get ();
+	priv->link_connected_id = g_signal_connect (priv->monitor, "carrier-on",
+	                                            G_CALLBACK (carrier_on),
+	                                            self);
+	priv->link_disconnected_id = g_signal_connect (priv->monitor, "carrier-off",
+	                                               G_CALLBACK (carrier_off),
+	                                               self);
+
+	priv->carrier = get_carrier_sync (NM_DEVICE_VLAN (self));
+
+	nm_log_info (LOGD_HW | LOGD_DEVICE, "(%s): carrier is %s",
+	             nm_device_get_iface (NM_DEVICE (self)),
+	             priv->carrier ? "ON" : "OFF");
+
+	/* Request link state again just in case an error occurred getting the
+	 * initial link state.
+	 */
+	nm_netlink_monitor_request_status (priv->monitor);
+}
+
+/******************************************************************/
+
+static void
+parent_state_changed (NMDevice *parent,
+                      NMDeviceState new_state,
+                      NMDeviceState old_state,
+                      NMDeviceStateReason reason,
+                      gpointer user_data)
+{
+	NMDeviceVlan *self = NM_DEVICE_VLAN (user_data);
+
+	if (new_state < NM_DEVICE_STATE_DISCONNECTED) {
+		/* If the parent becomes unavailable or unmanaged so does the VLAN */
+		nm_device_state_changed (NM_DEVICE (self), new_state, reason);
+	} else if (   new_state == NM_DEVICE_STATE_DISCONNECTED
+	           && old_state < NM_DEVICE_STATE_DISCONNECTED) {
+		/* Mark VLAN interface as available/disconnected when the parent
+		 * becomes available as a result of carrier changes or becoming
+		 * initialized.
+		 */
+		nm_device_state_changed (NM_DEVICE (self), new_state, reason);
+	}
+}
+
+/******************************************************************/
+
+NMDevice *
+nm_device_vlan_new (const char *udi, const char *iface, NMDevice *parent)
+{
+	NMDevice *device;
+
+	g_return_val_if_fail (udi != NULL, NULL);
+	g_return_val_if_fail (iface != NULL, NULL);
+	g_return_val_if_fail (parent != NULL, NULL);
+
+	device = (NMDevice *) g_object_new (NM_TYPE_DEVICE_VLAN,
+	                                    NM_DEVICE_UDI, udi,
+	                                    NM_DEVICE_IFACE, iface,
+	                                    NM_DEVICE_DRIVER, "8021q",
+	                                    NM_DEVICE_TYPE_DESC, "VLAN",
+	                                    NM_DEVICE_DEVICE_TYPE, NM_DEVICE_TYPE_VLAN,
+	                                    NULL);
+	if (device) {
+		NMDeviceVlanPrivate *priv = NM_DEVICE_VLAN_GET_PRIVATE (device);
+		int ifindex = nm_device_get_ifindex (device);
+		int parent_ifindex = -1, itype;
+		int vlan_id;
+
+		itype = nm_system_get_iface_type (ifindex, iface);
+		g_assert (itype == NM_IFACE_TYPE_VLAN);
+
+		if (!nm_system_get_iface_vlan_info (ifindex, &parent_ifindex, &vlan_id)) {
+			nm_log_warn (LOGD_DEVICE, "(%s): failed to get VLAN interface info.", iface);
+			g_object_unref (device);
+			return NULL;
+		}
+		priv->vlan_id = vlan_id;
+
+		if (   parent_ifindex < 0
+		    || parent_ifindex != nm_device_get_ip_ifindex (parent)
+		    || priv->vlan_id < 0) {
+			nm_log_warn (LOGD_DEVICE, "(%s): VLAN parent ifindex (%d) or VLAN ID (%d) invalid.",
+			             iface, parent_ifindex, priv->vlan_id);
+			g_object_unref (device);
+			return NULL;
+		}
+
+		priv->parent = g_object_ref (parent);
+		priv->parent_state_id = g_signal_connect (priv->parent,
+		                                          "state-changed",
+		                                          G_CALLBACK (parent_state_changed),
+		                                          device);
+
+		carrier_watch_init (NM_DEVICE_VLAN (device));
+
+		nm_log_dbg (LOGD_HW | LOGD_ETHER, "(%s): kernel ifindex %d", iface, ifindex);
+		nm_log_info (LOGD_HW | LOGD_ETHER, "(%s): VLAN ID %d with parent %s",
+		             iface, priv->vlan_id, nm_device_get_iface (parent));
+	}
+
+	return device;
+}
+
+static void
+nm_device_vlan_init (NMDeviceVlan * self)
+{
+}
+
+static void
+get_property (GObject *object, guint prop_id,
+              GValue *value, GParamSpec *pspec)
+{
+	NMDeviceVlanPrivate *priv = NM_DEVICE_VLAN_GET_PRIVATE (object);
+	char *hwaddr;
+
+	switch (prop_id) {
+	case PROP_HW_ADDRESS:
+		hwaddr = nm_utils_hwaddr_ntoa (priv->hw_addr, nm_utils_hwaddr_type (priv->hw_addr_len));
+		g_value_take_string (value, hwaddr);
+		break;
+	case PROP_CARRIER:
+		g_value_set_boolean (value, priv->carrier);
+		break;
+	case PROP_VLAN_ID:
+		g_value_set_uint (value, priv->vlan_id);
+		break;
+	default:
+		G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+		break;
+	}
+}
+
+static void
+set_property (GObject *object, guint prop_id,
+			  const GValue *value, GParamSpec *pspec)
+{
+	NMDeviceVlanPrivate *priv = NM_DEVICE_VLAN_GET_PRIVATE (object);
+
+	switch (prop_id) {
+	case PROP_VLAN_ID:
+		priv->vlan_id = g_value_get_uint (value);
+		break;
+	default:
+		G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+		break;
+	}
+}
+
+static void
+dispose (GObject *object)
+{
+	NMDeviceVlan *self = NM_DEVICE_VLAN (object);
+	NMDeviceVlanPrivate *priv = NM_DEVICE_VLAN_GET_PRIVATE (self);
+
+	if (priv->disposed) {
+		G_OBJECT_CLASS (nm_device_vlan_parent_class)->dispose (object);
+		return;
+	}
+	priv->disposed = TRUE;
+
+	if (priv->link_connected_id)
+		g_signal_handler_disconnect (priv->monitor, priv->link_connected_id);
+	if (priv->link_disconnected_id)
+		g_signal_handler_disconnect (priv->monitor, priv->link_disconnected_id);
+	carrier_action_defer_clear (self);
+
+	g_object_unref (priv->monitor);
+
+	g_signal_handler_disconnect (priv->parent, priv->parent_state_id);
+	g_object_unref (priv->parent);
+}
+
+static void
+nm_device_vlan_class_init (NMDeviceVlanClass *klass)
+{
+	GObjectClass *object_class = G_OBJECT_CLASS (klass);
+	NMDeviceClass *parent_class = NM_DEVICE_CLASS (klass);
+
+	g_type_class_add_private (object_class, sizeof (NMDeviceVlanPrivate));
+
+	/* virtual methods */
+	object_class->get_property = get_property;
+	object_class->set_property = set_property;
+	object_class->dispose = dispose;
+
+	parent_class->get_generic_capabilities = real_get_generic_capabilities;
+	parent_class->update_hw_address = real_update_hw_address;
+	parent_class->hw_is_up = real_hw_is_up;
+	parent_class->hw_bring_up = real_hw_bring_up;
+	parent_class->hw_take_down = real_hw_take_down;
+	parent_class->can_interrupt_activation = real_can_interrupt_activation;
+	parent_class->is_available = real_is_available;
+
+	parent_class->get_best_auto_connection = real_get_best_auto_connection;
+	parent_class->check_connection_compatible = real_check_connection_compatible;
+	parent_class->complete_connection = real_complete_connection;
+	parent_class->spec_match_list = spec_match_list;
+	parent_class->connection_match_config = connection_match_config;
+
+	/* properties */
+	g_object_class_install_property
+		(object_class, PROP_HW_ADDRESS,
+		 g_param_spec_string (NM_DEVICE_VLAN_HW_ADDRESS,
+							  "Active MAC Address",
+							  "Currently set hardware MAC address",
+							  NULL,
+							  G_PARAM_READABLE));
+
+	g_object_class_install_property
+		(object_class, PROP_CARRIER,
+		 g_param_spec_boolean (NM_DEVICE_VLAN_CARRIER,
+							   "Carrier",
+							   "Carrier",
+							   FALSE,
+							   G_PARAM_READABLE));
+
+	g_object_class_install_property
+		(object_class, PROP_VLAN_ID,
+		 g_param_spec_uint (NM_DEVICE_VLAN_ID,
+		                    "VLAN ID",
+		                    "VLAN ID",
+		                    0, 4095, 0,
+		                    G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY));
+
+	/* Signals */
+	signals[PROPERTIES_CHANGED] =
+		nm_properties_changed_signal_new (object_class,
+										  G_STRUCT_OFFSET (NMDeviceVlanClass, properties_changed));
+
+	dbus_g_object_type_install_info (G_TYPE_FROM_CLASS (klass),
+									 &dbus_glib_nm_device_vlan_object_info);
+
+	dbus_g_error_domain_register (NM_VLAN_ERROR, NULL, NM_TYPE_VLAN_ERROR);
+}
diff --git a/src/nm-device-vlan.h b/src/nm-device-vlan.h
new file mode 100644
index 00000000..7c5fa24c
--- /dev/null
+++ b/src/nm-device-vlan.h
@@ -0,0 +1,67 @@
+/* -*- 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 2012 Red Hat, Inc.
+ */
+
+#ifndef NM_DEVICE_VLAN_H
+#define NM_DEVICE_VLAN_H
+
+#include <glib-object.h>
+
+#include "nm-device-wired.h"
+
+G_BEGIN_DECLS
+
+#define NM_TYPE_DEVICE_VLAN            (nm_device_vlan_get_type ())
+#define NM_DEVICE_VLAN(obj)            (G_TYPE_CHECK_INSTANCE_CAST ((obj), NM_TYPE_DEVICE_VLAN, NMDeviceVlan))
+#define NM_DEVICE_VLAN_CLASS(klass)    (G_TYPE_CHECK_CLASS_CAST ((klass),  NM_TYPE_DEVICE_VLAN, NMDeviceVlanClass))
+#define NM_IS_DEVICE_VLAN(obj)         (G_TYPE_CHECK_INSTANCE_TYPE ((obj), NM_TYPE_DEVICE_VLAN))
+#define NM_IS_DEVICE_VLAN_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass),  NM_TYPE_DEVICE_VLAN))
+#define NM_DEVICE_VLAN_GET_CLASS(obj)  (G_TYPE_INSTANCE_GET_CLASS ((obj),  NM_TYPE_DEVICE_VLAN, NMDeviceVlanClass))
+
+typedef enum {
+	NM_VLAN_ERROR_CONNECTION_NOT_VLAN = 0, /*< nick=ConnectionNotVlan >*/
+	NM_VLAN_ERROR_CONNECTION_INVALID,      /*< nick=ConnectionInvalid >*/
+	NM_VLAN_ERROR_CONNECTION_INCOMPATIBLE, /*< nick=ConnectionIncompatible >*/
+} NMVlanError;
+
+#define NM_DEVICE_VLAN_HW_ADDRESS "hw-address"
+#define NM_DEVICE_VLAN_CARRIER    "carrier"
+#define NM_DEVICE_VLAN_ID         "vlan-id"
+
+typedef struct {
+	NMDevice parent;
+} NMDeviceVlan;
+
+typedef struct {
+	NMDeviceClass parent;
+
+	/* Signals */
+	void (*properties_changed) (NMDeviceVlan *device, GHashTable *properties);
+} NMDeviceVlanClass;
+
+
+GType nm_device_vlan_get_type (void);
+
+NMDevice *nm_device_vlan_new (const char *udi,
+                              const char *iface,
+                              NMDevice *parent);
+
+G_END_DECLS
+
+#endif	/* NM_DEVICE_VLAN_H */
diff --git a/src/nm-device-wifi.c b/src/nm-device-wifi.c
index 9695c077..ed964a57 100644
--- a/src/nm-device-wifi.c
+++ b/src/nm-device-wifi.c
@@ -15,7 +15,7 @@
  * with this program; if not, write to the Free Software Foundation, Inc.,
  * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
  *
- * Copyright (C) 2005 - 2011 Red Hat, Inc.
+ * Copyright (C) 2005 - 2012 Red Hat, Inc.
  * Copyright (C) 2006 - 2008 Novell, Inc.
  */
 
@@ -25,7 +25,6 @@
 #include <netinet/in.h>
 #include <string.h>
 #include <net/ethernet.h>
-#include <iwlib.h>
 #include <sys/stat.h>
 #include <sys/wait.h>
 #include <signal.h>
@@ -34,11 +33,12 @@
 #include <linux/ethtool.h>
 #include <sys/ioctl.h>
 #include <netinet/ether.h>
+#include <net/if.h>
+#include <errno.h>
 
 #include "nm-glib-compat.h"
 #include "nm-device.h"
 #include "nm-device-wifi.h"
-#include "nm-device-interface.h"
 #include "nm-device-private.h"
 #include "nm-utils.h"
 #include "nm-logging.h"
@@ -57,6 +57,8 @@
 #include "nm-setting-ip6-config.h"
 #include "nm-system.h"
 #include "nm-settings-connection.h"
+#include "nm-enum-types.h"
+#include "wifi-utils.h"
 
 static gboolean impl_device_get_access_points (NMDeviceWifi *device,
                                                GPtrArray **aps,
@@ -72,10 +74,7 @@ static gboolean impl_device_get_access_points (NMDeviceWifi *device,
 
 #define WIRELESS_SECRETS_TRIES "wireless-secrets-tries"
 
-static void device_interface_init (NMDeviceInterface *iface_class);
-
-G_DEFINE_TYPE_EXTENDED (NMDeviceWifi, nm_device_wifi, NM_TYPE_DEVICE, 0,
-                        G_IMPLEMENT_INTERFACE (NM_TYPE_DEVICE_INTERFACE, device_interface_init))
+G_DEFINE_TYPE (NMDeviceWifi, nm_device_wifi, NM_TYPE_DEVICE)
 
 #define NM_DEVICE_WIFI_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), NM_TYPE_DEVICE_WIFI, NMDeviceWifiPrivate))
 
@@ -106,7 +105,7 @@ enum {
 
 static guint signals[LAST_SIGNAL] = { 0 };
 
-#define SUP_SIG_ID_LEN 5
+#define SUP_SIG_ID_LEN 6
 
 typedef struct Supplicant {
 	NMSupplicantManager *mgr;
@@ -132,12 +131,7 @@ struct _NMDeviceWifiPrivate {
 	guint             ipw_rfkill_id;
 	RfKillState       ipw_rfkill_state;
 
-	GByteArray *      ssid;
 	gint8             invalid_strength_counter;
-	iwqual            max_qual;
-
-	gint8             num_freqs;
-	guint32           freqs[IW_MAX_FREQUENCIES];
 
 	GSList *          ap_list;
 	NMAccessPoint *   current_ap;
@@ -147,20 +141,18 @@ struct _NMDeviceWifiPrivate {
 	glong             scheduled_scan_time;
 	guint8            scan_interval; /* seconds */
 	guint             pending_scan_id;
+	guint             scanlist_cull_id;
 
 	Supplicant        supplicant;
+	WifiData *        wifi_data;
 
 	guint32           failed_link_count;
 	guint             periodic_source_id;
 	guint             link_timeout_id;
 
-	/* Static options from driver */
-	guint32           capabilities;
-	gboolean          has_scan_capa_ssid;
+	NMDeviceWifiCapabilities capabilities;
 };
 
-static guint32 nm_device_wifi_get_frequency (NMDeviceWifi *self);
-
 static gboolean request_wireless_scan (gpointer user_data);
 
 static void schedule_scan (NMDeviceWifi *self, gboolean backoff);
@@ -178,9 +170,19 @@ static void supplicant_iface_state_cb (NMSupplicantInterface *iface,
                                        gpointer user_data);
 
 static void supplicant_iface_new_bss_cb (NMSupplicantInterface * iface,
+                                         const char *object_path,
                                          GHashTable *properties,
                                          NMDeviceWifi * self);
 
+static void supplicant_iface_bss_updated_cb (NMSupplicantInterface *iface,
+                                             const char *object_path,
+                                             GHashTable *properties,
+                                             NMDeviceWifi *self);
+
+static void supplicant_iface_bss_removed_cb (NMSupplicantInterface *iface,
+                                             const char *object_path,
+                                             NMDeviceWifi *self);
+
 static void supplicant_iface_scan_done_cb (NMSupplicantInterface * iface,
                                            gboolean success,
                                            NMDeviceWifi * self);
@@ -189,21 +191,11 @@ static void supplicant_iface_notify_scanning_cb (NMSupplicantInterface * iface,
                                                  GParamSpec * pspec,
                                                  NMDeviceWifi * self);
 
-static guint32 nm_device_wifi_get_bitrate (NMDeviceWifi *self);
-
-static void cull_scan_list (NMDeviceWifi *self);
+static void schedule_scanlist_cull (NMDeviceWifi *self);
 
 /*****************************************************************/
 
-typedef enum {
-	NM_WIFI_ERROR_CONNECTION_NOT_WIRELESS = 0,
-	NM_WIFI_ERROR_CONNECTION_INVALID,
-	NM_WIFI_ERROR_CONNECTION_INCOMPATIBLE,
-	NM_WIFI_ERROR_ACCESS_POINT_NOT_FOUND,
-} NMWifiError;
-
 #define NM_WIFI_ERROR (nm_wifi_error_quark ())
-#define NM_TYPE_WIFI_ERROR (nm_wifi_error_get_type ())
 
 static GQuark
 nm_wifi_error_quark (void)
@@ -214,31 +206,6 @@ nm_wifi_error_quark (void)
 	return quark;
 }
 
-/* This should really be standard. */
-#define ENUM_ENTRY(NAME, DESC) { NAME, "" #NAME "", DESC }
-
-static GType
-nm_wifi_error_get_type (void)
-{
-	static GType etype = 0;
-
-	if (etype == 0) {
-		static const GEnumValue values[] = {
-			/* Connection was not a wireless connection. */
-			ENUM_ENTRY (NM_WIFI_ERROR_CONNECTION_NOT_WIRELESS, "ConnectionNotWireless"),
-			/* Connection was not a valid wireless connection. */
-			ENUM_ENTRY (NM_WIFI_ERROR_CONNECTION_INVALID, "ConnectionInvalid"),
-			/* Connection does not apply to this device. */
-			ENUM_ENTRY (NM_WIFI_ERROR_CONNECTION_INCOMPATIBLE, "ConnectionIncompatible"),
-			/* Given access point was not in this device's scan list. */
-			ENUM_ENTRY (NM_WIFI_ERROR_ACCESS_POINT_NOT_FOUND, "AccessPointNotFound"),
-			{ 0, 0, 0 }
-		};
-		etype = g_enum_register_static ("NMWifiError", values);
-	}
-	return etype;
-}
-
 /*****************************************************************/
 
 /* IPW rfkill handling (until 2.6.33) */
@@ -301,319 +268,12 @@ ipw_rfkill_state_work (gpointer user_data)
 
 /*****************************************************************/
 
-/*
- * wireless_qual_to_percent
- *
- * Convert an iw_quality structure from SIOCGIWSTATS into a magical signal
- * strength percentage.
- *
- */
-static int
-wireless_qual_to_percent (const struct iw_quality *qual,
-                          const struct iw_quality *max_qual)
-{
-	int percent = -1;
-	int level_percent = -1;
-
-	g_return_val_if_fail (qual != NULL, -1);
-	g_return_val_if_fail (max_qual != NULL, -1);
-
-	nm_log_dbg (LOGD_WIFI,
-	            "QL: qual %d/%u/0x%X, level %d/%u/0x%X, noise %d/%u/0x%X, updated: 0x%X  ** MAX: qual %d/%u/0x%X, level %d/%u/0x%X, noise %d/%u/0x%X, updated: 0x%X",
-	            (__s8) qual->qual, qual->qual, qual->qual,
-	            (__s8) qual->level, qual->level, qual->level,
-	            (__s8) qual->noise, qual->noise, qual->noise,
-	            qual->updated,
-	            (__s8) max_qual->qual, max_qual->qual, max_qual->qual,
-	            (__s8) max_qual->level, max_qual->level, max_qual->level,
-	            (__s8) max_qual->noise, max_qual->noise, max_qual->noise,
-	            max_qual->updated);
-
-	/* Try using the card's idea of the signal quality first as long as it tells us what the max quality is.
-	 * Drivers that fill in quality values MUST treat them as percentages, ie the "Link Quality" MUST be 
-	 * bounded by 0 and max_qual->qual, and MUST change in a linear fashion.  Within those bounds, drivers
-	 * are free to use whatever they want to calculate "Link Quality".
-	 */
-	if ((max_qual->qual != 0) && !(max_qual->updated & IW_QUAL_QUAL_INVALID) && !(qual->updated & IW_QUAL_QUAL_INVALID))
-		percent = (int)(100 * ((double)qual->qual / (double)max_qual->qual));
-
-	/* If the driver doesn't specify a complete and valid quality, we have two options:
-	 *
-	 * 1) dBm: driver must specify max_qual->level = 0, and have valid values for
-	 *        qual->level and (qual->noise OR max_qual->noise)
-	 * 2) raw RSSI: driver must specify max_qual->level > 0, and have valid values for
-	 *        qual->level and max_qual->level
-	 *
-	 * This is the WEXT spec.  If this interpretation is wrong, I'll fix it.  Otherwise,
-	 * If drivers don't conform to it, they are wrong and need to be fixed.
-	 */
-
-	if (    (max_qual->level == 0) && !(max_qual->updated & IW_QUAL_LEVEL_INVALID)          /* Valid max_qual->level == 0 */
-		&& !(qual->updated & IW_QUAL_LEVEL_INVALID)                                     /* Must have valid qual->level */
-		&& (    ((max_qual->noise > 0) && !(max_qual->updated & IW_QUAL_NOISE_INVALID)) /* Must have valid max_qual->noise */
-			|| ((qual->noise > 0) && !(qual->updated & IW_QUAL_NOISE_INVALID)))     /*    OR valid qual->noise */
-	   ) {
-		/* Absolute power values (dBm) */
-
-		/* Reasonable fallbacks for dumb drivers that don't specify either level. */
-		#define FALLBACK_NOISE_FLOOR_DBM  -90
-		#define FALLBACK_SIGNAL_MAX_DBM   -20
-		int max_level = FALLBACK_SIGNAL_MAX_DBM;
-		int noise = FALLBACK_NOISE_FLOOR_DBM;
-		int level = qual->level - 0x100;
-
-		level = CLAMP (level, FALLBACK_NOISE_FLOOR_DBM, FALLBACK_SIGNAL_MAX_DBM);
-
-		if ((qual->noise > 0) && !(qual->updated & IW_QUAL_NOISE_INVALID))
-			noise = qual->noise - 0x100;
-		else if ((max_qual->noise > 0) && !(max_qual->updated & IW_QUAL_NOISE_INVALID))
-			noise = max_qual->noise - 0x100;
-		noise = CLAMP (noise, FALLBACK_NOISE_FLOOR_DBM, FALLBACK_SIGNAL_MAX_DBM);
-
-		/* A sort of signal-to-noise ratio calculation */
-		level_percent = (int)(100 - 70 *(
-		                                ((double)max_level - (double)level) /
-		                                ((double)max_level - (double)noise)));
-		nm_log_dbg (LOGD_WIFI, "QL1: level_percent is %d.  max_level %d, level %d, noise_floor %d.",
-		            level_percent, max_level, level, noise);
-	} else if (   (max_qual->level != 0)
-	           && !(max_qual->updated & IW_QUAL_LEVEL_INVALID) /* Valid max_qual->level as upper bound */
-	           && !(qual->updated & IW_QUAL_LEVEL_INVALID)) {
-		/* Relative power values (RSSI) */
-
-		int level = qual->level;
-
-		/* Signal level is relavtive (0 -> max_qual->level) */
-		level = CLAMP (level, 0, max_qual->level);
-		level_percent = (int)(100 * ((double)level / (double)max_qual->level));
-		nm_log_dbg (LOGD_WIFI, "QL2: level_percent is %d.  max_level %d, level %d.",
-		            level_percent, max_qual->level, level);
-	} else if (percent == -1) {
-		nm_log_dbg (LOGD_WIFI, "QL: Could not get quality %% value from driver.  Driver is probably buggy.");
-	}
-
-	/* If the quality percent was 0 or doesn't exist, then try to use signal levels instead */
-	if ((percent < 1) && (level_percent >= 0))
-		percent = level_percent;
-
-	nm_log_dbg (LOGD_WIFI, "QL: Final quality percent is %d (%d).",
-	            percent, CLAMP (percent, 0, 100));
-	return (CLAMP (percent, 0, 100));
-}
-
-
-/*
- * nm_device_wifi_update_signal_strength
- *
- * Update the device's idea of the strength of its connection to the
- * current access point.
- *
- */
-static void
-nm_device_wifi_update_signal_strength (NMDeviceWifi *self,
-                                       NMAccessPoint *ap)
-{
-	NMDeviceWifiPrivate *priv = NM_DEVICE_WIFI_GET_PRIVATE (self);
-	const char *iface = nm_device_get_iface (NM_DEVICE (self));
-	int fd, percent = -1;
-
-	fd = socket (PF_INET, SOCK_DGRAM, 0);
-	if (fd >= 0) {
-		struct iwreq wrq;
-		struct iw_statistics stats;
-
-		memset (&stats, 0, sizeof (stats));
-
-		wrq.u.data.pointer = &stats;
-		wrq.u.data.length = sizeof (stats);
-		wrq.u.data.flags = 1;  /* Clear updated flag */
-		strncpy (wrq.ifr_name, iface, IFNAMSIZ);
-
-		if (ioctl (fd, SIOCGIWSTATS, &wrq) == 0)
-			percent = wireless_qual_to_percent (&stats.qual, &priv->max_qual);
-		close (fd);
-	}
-
-	/* Try to smooth out the strength.  Atmel cards, for example, will give no strength
-	 * one second and normal strength the next.
-	 */
-	if (percent >= 0 || ++priv->invalid_strength_counter > 3) {
-		nm_ap_set_strength (ap, (gint8) percent);
-		priv->invalid_strength_counter = 0;
-	}
-}
-
-
-static gboolean
-wireless_get_range (NMDeviceWifi *self,
-                    struct iw_range *range,
-                    guint32 *response_len)
-{
-	int fd, i = 26;
-	gboolean success = FALSE;
-	const char *iface;
-	struct iwreq wrq;
-
-	g_return_val_if_fail (NM_IS_DEVICE_WIFI (self), FALSE);
-	g_return_val_if_fail (range != NULL, FALSE);
-
-	iface = nm_device_get_iface (NM_DEVICE (self));
-
-	fd = socket (PF_INET, SOCK_DGRAM, 0);
-	if (fd < 0) {
-		nm_log_err (LOGD_HW, "(%s): couldn't open control socket.", iface);
-		return FALSE;
-	}
-
-	memset (&wrq, 0, sizeof (struct iwreq));
-	strncpy (wrq.ifr_name, iface, IFNAMSIZ);
-	wrq.u.data.pointer = (caddr_t) range;
-	wrq.u.data.length = sizeof (struct iw_range);
-
-	/* Need to give some drivers time to recover after suspend/resume
-	 * (ex ipw3945 takes a few seconds to talk to its regulatory daemon;
-	 * see rh bz#362421)
-	 */
-	while (i-- > 0) {
-		if (ioctl (fd, SIOCGIWRANGE, &wrq) == 0) {
-			if (response_len)
-				*response_len = wrq.u.data.length;
-			success = TRUE;
-			break;
-		} else if (errno != EAGAIN) {
-			nm_log_err (LOGD_HW | LOGD_WIFI,
-			            "(%s): couldn't get driver range information (%d).",
-			            iface, errno);
-			break;
-		}
-
-		g_usleep (G_USEC_PER_SEC / 4);
-	}
-
-	if (i <= 0) {
-		nm_log_warn (LOGD_HW | LOGD_WIFI,
-		             "(%s): driver took too long to respond to IWRANGE query.",
-		             iface);
-	}
-
-	close (fd);
-	return success;
-}
-
 static guint32
 real_get_generic_capabilities (NMDevice *dev)
 {
-	int fd, err;
-	guint32 caps = NM_DEVICE_CAP_NONE;
-	struct iwreq wrq;
-	const char *iface = nm_device_get_iface (dev);
-
-	fd = socket (PF_INET, SOCK_DGRAM, 0);
-	if (fd < 0) {
-		nm_log_err (LOGD_HW, "(%s): couldn't open control socket.", iface);
-		return NM_DEVICE_CAP_NONE;
-	}
-
-	/* Cards that don't scan aren't supported */
-	memset (&wrq, 0, sizeof (struct iwreq));
-	strncpy (wrq.ifr_name, iface, IFNAMSIZ);
-	err = ioctl (fd, SIOCSIWSCAN, &wrq);
-	close (fd);
-	if ((err < 0) && (errno == EOPNOTSUPP))
-		caps = NM_DEVICE_CAP_NONE;
-	else
-		caps |= NM_DEVICE_CAP_NM_SUPPORTED;
-
-	return caps;
-}
-
-#define WPA_CAPS (NM_WIFI_DEVICE_CAP_CIPHER_TKIP | \
-                  NM_WIFI_DEVICE_CAP_CIPHER_CCMP | \
-                  NM_WIFI_DEVICE_CAP_WPA | \
-                  NM_WIFI_DEVICE_CAP_RSN)
-
-static guint32
-get_wireless_capabilities (NMDeviceWifi *self, iwrange *range)
-{
-	guint32 caps = NM_WIFI_DEVICE_CAP_NONE;
-	const char * iface;
-
-	g_return_val_if_fail (self != NULL, NM_WIFI_DEVICE_CAP_NONE);
-	g_return_val_if_fail (range != NULL, NM_WIFI_DEVICE_CAP_NONE);
-
-	iface = nm_device_get_iface (NM_DEVICE (self));
-
-	/* All drivers should support WEP by default */
-	caps |= NM_WIFI_DEVICE_CAP_CIPHER_WEP40 | NM_WIFI_DEVICE_CAP_CIPHER_WEP104;
-
-	if (range->enc_capa & IW_ENC_CAPA_CIPHER_TKIP)
-		caps |= NM_WIFI_DEVICE_CAP_CIPHER_TKIP;
-
-	if (range->enc_capa & IW_ENC_CAPA_CIPHER_CCMP)
-		caps |= NM_WIFI_DEVICE_CAP_CIPHER_CCMP;
-
-	if (range->enc_capa & IW_ENC_CAPA_WPA)
-		caps |= NM_WIFI_DEVICE_CAP_WPA;
-
-	if (range->enc_capa & IW_ENC_CAPA_WPA2)
-		caps |= NM_WIFI_DEVICE_CAP_RSN;
-
-	/* Check for cipher support but not WPA support */
-	if (    (caps & (NM_WIFI_DEVICE_CAP_CIPHER_TKIP | NM_WIFI_DEVICE_CAP_CIPHER_CCMP))
-	    && !(caps & (NM_WIFI_DEVICE_CAP_WPA | NM_WIFI_DEVICE_CAP_RSN))) {
-		nm_log_warn (LOGD_WIFI, "%s: device supports WPA ciphers but not WPA protocol; "
-		             "WPA unavailable.", iface);
-		caps &= ~WPA_CAPS;
-	}
-
-	/* Check for WPA support but not cipher support */
-	if (    (caps & (NM_WIFI_DEVICE_CAP_WPA | NM_WIFI_DEVICE_CAP_RSN))
-	    && !(caps & (NM_WIFI_DEVICE_CAP_CIPHER_TKIP | NM_WIFI_DEVICE_CAP_CIPHER_CCMP))) {
-		nm_log_warn (LOGD_WIFI, "%s: device supports WPA protocol but not WPA ciphers; "
-		             "WPA unavailable.", iface);
-		caps &= ~WPA_CAPS;
-	}
-
-	return caps;
-}
-
-
-static guint32 iw_freq_to_uint32 (struct iw_freq *freq)
-{
-	if (freq->e == 0) {
-		/* Some drivers report channel not frequency.  Convert to a
-		 * frequency; but this assumes that the device is in b/g mode.
-		 */
-		if ((freq->m >= 1) && (freq->m <= 13))
-			return 2407 + (5 * freq->m);
-		else if (freq->m == 14)
-			return 2484;
-	}
-
-	return (guint32) (((double) freq->m) * pow (10, freq->e) / 1000000);
+	return NM_DEVICE_CAP_NM_SUPPORTED;
 }
 
-
-/* Until a new wireless-tools comes out that has the defs and the structure,
- * need to copy them here.
- */
-/* Scan capability flags - in (struct iw_range *)->scan_capa */
-#define NM_IW_SCAN_CAPA_NONE    0x00
-#define NM_IW_SCAN_CAPA_ESSID   0x01
-
-struct iw_range_with_scan_capa
-{
-	guint32 throughput;
-	guint32 min_nwid;
-	guint32 max_nwid;
-	guint16 old_num_channels;
-	guint8  old_num_frequency;
-
-	guint8  scan_capa;
-/* don't need the rest... */
-};
-
-
 static GObject*
 constructor (GType type,
              guint n_construct_params,
@@ -623,11 +283,6 @@ constructor (GType type,
 	GObjectClass *klass;
 	NMDeviceWifi *self;
 	NMDeviceWifiPrivate *priv;
-	struct iw_range range;
-	struct iw_range_with_scan_capa *scan_capa_range;
-	guint32 response_len = 0;
-	gboolean success;
-	int i;
 
 	klass = G_OBJECT_CLASS (nm_device_wifi_parent_class);
 	object = klass->constructor (type, n_construct_params, construct_params);
@@ -641,52 +296,22 @@ constructor (GType type,
 	            nm_device_get_iface (NM_DEVICE (self)),
 	            nm_device_get_ifindex (NM_DEVICE (self)));
 
-	memset (&range, 0, sizeof (struct iw_range));
-	success = wireless_get_range (NM_DEVICE_WIFI (object), &range, &response_len);
-	if (!success) {
-		nm_log_info (LOGD_HW | LOGD_WIFI, "(%s): driver WEXT range request failed",
+	priv->wifi_data = wifi_utils_init (nm_device_get_iface (NM_DEVICE (self)),
+	                                   nm_device_get_ifindex (NM_DEVICE (self)),
+	                                   TRUE);
+	if (priv->wifi_data == NULL) {
+		nm_log_warn (LOGD_HW | LOGD_WIFI, "(%s): failed to initialize WiFi driver",
 		             nm_device_get_iface (NM_DEVICE (self)));
-		goto error;
-	}
-
-	if ((response_len < 300) || (range.we_version_compiled < 21)) {
-		nm_log_info (LOGD_HW | LOGD_WIFI,
-		             "(%s): driver WEXT version too old (got %d, expected >= 21)",
-		             nm_device_get_iface (NM_DEVICE (self)),
-		             range.we_version_compiled);
-		goto error;
+		g_object_unref (object);
+		return NULL;
 	}
+	priv->capabilities = wifi_utils_get_caps (priv->wifi_data);
 
-	priv->max_qual.qual = range.max_qual.qual;
-	priv->max_qual.level = range.max_qual.level;
-	priv->max_qual.noise = range.max_qual.noise;
-	priv->max_qual.updated = range.max_qual.updated;
-
-	priv->num_freqs = MIN (range.num_frequency, IW_MAX_FREQUENCIES);
-	for (i = 0; i < priv->num_freqs; i++)
-		priv->freqs[i] = iw_freq_to_uint32 (&range.freq[i]);
-
-	/* Check for the ability to scan specific SSIDs.  Until the scan_capa
-	 * field gets added to wireless-tools, need to work around that by casting
-	 * to the custom structure.
-	 */
-	scan_capa_range = (struct iw_range_with_scan_capa *) &range;
-	if (scan_capa_range->scan_capa & NM_IW_SCAN_CAPA_ESSID) {
-		priv->has_scan_capa_ssid = TRUE;
-		nm_log_info (LOGD_HW | LOGD_WIFI,
-		             "(%s): driver supports SSID scans (scan_capa 0x%02X).",
-		             nm_device_get_iface (NM_DEVICE (self)),
-		             scan_capa_range->scan_capa);
-	} else {
-		nm_log_info (LOGD_HW | LOGD_WIFI,
-		             "(%s): driver does not support SSID scans (scan_capa 0x%02X).",
-		             nm_device_get_iface (NM_DEVICE (self)),
-		             scan_capa_range->scan_capa);
+	if (priv->capabilities & NM_WIFI_DEVICE_CAP_AP) {
+		nm_log_warn (LOGD_HW | LOGD_WIFI, "(%s): driver supports Access Point (AP) mode",
+		             nm_device_get_iface (NM_DEVICE (self)));
 	}
 
-	/* 802.11 wireless-specific capabilities */
-	priv->capabilities = get_wireless_capabilities (self, &range);
-
 	/* Connect to the supplicant manager */
 	priv->supplicant.mgr = nm_supplicant_manager_get ();
 	g_assert (priv->supplicant.mgr);
@@ -708,10 +333,6 @@ constructor (GType type,
 	priv->ipw_rfkill_state = nm_device_wifi_get_ipw_rfkill_state (self);
 
 	return object;
-
-error:
-	g_object_unref (object);
-	return NULL;
 }
 
 static gboolean
@@ -748,6 +369,18 @@ supplicant_interface_acquire (NMDeviceWifi *self)
 	priv->supplicant.sig_ids[i++] = id;
 
 	id = g_signal_connect (priv->supplicant.iface,
+	                       NM_SUPPLICANT_INTERFACE_BSS_UPDATED,
+	                       G_CALLBACK (supplicant_iface_bss_updated_cb),
+	                       self);
+	priv->supplicant.sig_ids[i++] = id;
+
+	id = g_signal_connect (priv->supplicant.iface,
+	                       NM_SUPPLICANT_INTERFACE_BSS_REMOVED,
+	                       G_CALLBACK (supplicant_iface_bss_removed_cb),
+	                       self);
+	priv->supplicant.sig_ids[i++] = id;
+
+	id = g_signal_connect (priv->supplicant.iface,
 	                       NM_SUPPLICANT_INTERFACE_SCAN_DONE,
 	                       G_CALLBACK (supplicant_iface_scan_done_cb),
 	                       self);
@@ -808,6 +441,11 @@ supplicant_interface_release (NMDeviceWifi *self)
 	}
 	memset (priv->supplicant.sig_ids, 0, sizeof (priv->supplicant.sig_ids));
 
+	if (priv->scanlist_cull_id) {
+		g_source_remove (priv->scanlist_cull_id);
+		priv->scanlist_cull_id = 0;
+	}
+
 	if (priv->supplicant.iface) {
 		/* Tell the supplicant to disconnect from the current AP */
 		nm_supplicant_interface_disconnect (priv->supplicant.iface);
@@ -817,7 +455,6 @@ supplicant_interface_release (NMDeviceWifi *self)
 	}
 }
 
-
 static NMAccessPoint *
 get_ap_by_path (NMDeviceWifi *self, const char *path)
 {
@@ -825,7 +462,20 @@ get_ap_by_path (NMDeviceWifi *self, const char *path)
 	GSList *iter;
 
 	for (iter = priv->ap_list; iter; iter = g_slist_next (iter)) {
-		if (strcmp (path, nm_ap_get_dbus_path (NM_AP (iter->data))) == 0)
+		if (g_strcmp0 (path, nm_ap_get_dbus_path (NM_AP (iter->data))) == 0)
+			return NM_AP (iter->data);
+	}
+	return NULL;
+}
+
+static NMAccessPoint *
+get_ap_by_supplicant_path (NMDeviceWifi *self, const char *path)
+{
+	NMDeviceWifiPrivate *priv = NM_DEVICE_WIFI_GET_PRIVATE (self);
+	GSList *iter;
+
+	for (iter = priv->ap_list; iter && path; iter = g_slist_next (iter)) {
+		if (g_strcmp0 (path, nm_ap_get_supplicant_path (NM_AP (iter->data))) == 0)
 			return NM_AP (iter->data);
 	}
 	return NULL;
@@ -839,16 +489,16 @@ get_active_ap (NMDeviceWifi *self,
 	NMDeviceWifiPrivate *priv = NM_DEVICE_WIFI_GET_PRIVATE (self);
 	const char *iface = nm_device_get_iface (NM_DEVICE (self));
 	struct ether_addr bssid;
-	const GByteArray *ssid;
+	GByteArray *ssid;
 	GSList *iter;
 	int i = 0;
-	NMAccessPoint *match_nofreq = NULL;
+	NMAccessPoint *match_nofreq = NULL, *active_ap = NULL;
 	gboolean found_a_band = FALSE;
 	gboolean found_bg_band = FALSE;
 	NM80211Mode devmode;
 	guint32 devfreq;
 
-	nm_device_wifi_get_bssid (self, &bssid);
+	wifi_utils_get_bssid (priv->wifi_data, &bssid);
 	nm_log_dbg (LOGD_WIFI, "(%s): active BSSID: %02x:%02x:%02x:%02x:%02x:%02x",
 	            iface,
 	            bssid.ether_addr_octet[0], bssid.ether_addr_octet[1],
@@ -858,15 +508,15 @@ get_active_ap (NMDeviceWifi *self,
 	if (!nm_ethernet_address_is_valid (&bssid))
 		return NULL;
 
-	ssid = nm_device_wifi_get_ssid (self);
+	ssid = wifi_utils_get_ssid (priv->wifi_data);
 	nm_log_dbg (LOGD_WIFI, "(%s): active SSID: %s%s%s",
 	            iface,
 	            ssid ? "'" : "",
 	            ssid ? nm_utils_escape_ssid (ssid->data, ssid->len) : "(none)",
 	            ssid ? "'" : "");
 
-	devmode = nm_device_wifi_get_mode (self);
-	devfreq = nm_device_wifi_get_frequency (self);
+	devmode = wifi_utils_get_mode (priv->wifi_data);
+	devfreq = wifi_utils_get_freq (priv->wifi_data);
 
 	/* When matching hidden APs, do a second pass that ignores the SSID check,
 	 * because NM might not yet know the SSID of the hidden AP in the scan list
@@ -930,7 +580,8 @@ get_active_ap (NMDeviceWifi *self,
 
 			// FIXME: handle security settings here too
 			nm_log_dbg (LOGD_WIFI, "      matched");
-			return ap;
+			active_ap = ap;
+			goto done;
 		}
 	}
 
@@ -943,9 +594,10 @@ get_active_ap (NMDeviceWifi *self,
 	 * is uncommon though, and the frequency check penalizes closed drivers we
 	 * can't fix.  Because we're not total dicks, ignore the frequency condition
 	 * if the associated BSSID/SSID exists only in one band since that's most
-	 * likely the AP we want.
+	 * likely the AP we want.  Sometimes wl.o returns a frequency of 0, so if
+	 * we can't match the AP based on frequency at all, just give up.
 	 */
-	if (match_nofreq && (found_a_band != found_bg_band)) {
+	if (match_nofreq && ((found_a_band != found_bg_band) || (devfreq == 0))) {
 		const struct ether_addr	*ap_bssid = nm_ap_get_address (match_nofreq);
 		const GByteArray *ap_ssid = nm_ap_get_ssid (match_nofreq);
 
@@ -957,11 +609,15 @@ get_active_ap (NMDeviceWifi *self,
 		            ap_bssid->ether_addr_octet[2], ap_bssid->ether_addr_octet[3],
 		            ap_bssid->ether_addr_octet[4], ap_bssid->ether_addr_octet[5]);
 
-		return match_nofreq;
+		active_ap = match_nofreq;
 	}
 
 	nm_log_dbg (LOGD_WIFI, "  No matching AP found.");
-	return NULL;
+
+done:
+	if (ssid)
+		g_byte_array_free (ssid, TRUE);
+	return active_ap;
 }
 
 static void
@@ -1038,7 +694,7 @@ periodic_update (NMDeviceWifi *self)
 {
 	NMDeviceWifiPrivate *priv = NM_DEVICE_WIFI_GET_PRIVATE (self);
 	NMAccessPoint *new_ap;
-	guint32 new_rate;
+	guint32 new_rate, percent;
 
 	/* In IBSS mode, most newer firmware/drivers do "BSS coalescing" where
 	 * multiple IBSS stations using the same SSID will eventually switch to
@@ -1051,7 +707,7 @@ periodic_update (NMDeviceWifi *self)
 	if (priv->current_ap && (nm_ap_get_mode (priv->current_ap) == NM_802_11_MODE_ADHOC)) {
 		struct ether_addr bssid = { {0x0, 0x0, 0x0, 0x0, 0x0, 0x0} };
 
-		nm_device_wifi_get_bssid (self, &bssid);
+		wifi_utils_get_bssid (priv->wifi_data, &bssid);
 		/* 0x02 means "locally administered" and should be OR-ed into
 		 * the first byte of IBSS BSSIDs.
 		 */
@@ -1061,8 +717,16 @@ periodic_update (NMDeviceWifi *self)
 	}
 
 	new_ap = get_active_ap (self, NULL, FALSE);
-	if (new_ap)
-		nm_device_wifi_update_signal_strength (self, new_ap);
+	if (new_ap) {
+		/* Try to smooth out the strength.  Atmel cards, for example, will give no strength
+		 * one second and normal strength the next.
+		 */
+		percent = wifi_utils_get_qual (priv->wifi_data);
+		if (percent >= 0 || ++priv->invalid_strength_counter > 3) {
+			nm_ap_set_strength (new_ap, (gint8) percent);
+			priv->invalid_strength_counter = 0;
+		}
+	}
 
 	if ((new_ap || priv->current_ap) && (new_ap != priv->current_ap)) {
 		const struct ether_addr *new_bssid = NULL;
@@ -1073,13 +737,13 @@ periodic_update (NMDeviceWifi *self)
 
 		if (new_ap) {
 			new_bssid = nm_ap_get_address (new_ap);
-			new_addr = nm_ether_ntop (new_bssid);
+			new_addr = nm_utils_hwaddr_ntoa (new_bssid, ARPHRD_ETHER);
 			new_ssid = nm_ap_get_ssid (new_ap);
 		}
 
 		if (priv->current_ap) {
 			old_bssid = nm_ap_get_address (priv->current_ap);
-			old_addr = nm_ether_ntop (old_bssid);
+			old_addr = nm_utils_hwaddr_ntoa (old_bssid, ARPHRD_ETHER);
 			old_ssid = nm_ap_get_ssid (priv->current_ap);
 		}
 
@@ -1095,7 +759,7 @@ periodic_update (NMDeviceWifi *self)
 		set_current_ap (self, new_ap);
 	}
 
-	new_rate = nm_device_wifi_get_bitrate (self);
+	new_rate = wifi_utils_get_rate (priv->wifi_data);
 	if (new_rate != priv->rate) {
 		priv->rate = new_rate;
 		g_object_notify (G_OBJECT (self), NM_DEVICE_WIFI_BITRATE);
@@ -1305,7 +969,37 @@ real_deactivate (NMDevice *dev)
 	/* Ensure we're in infrastructure mode after deactivation; some devices
 	 * (usually older ones) don't scan well in adhoc mode.
 	 */
-	nm_device_wifi_set_mode (self, NM_802_11_MODE_INFRA);
+	wifi_utils_set_mode (priv->wifi_data, NM_802_11_MODE_INFRA);
+}
+
+static gboolean
+is_adhoc_wpa (NMConnection *connection)
+{
+	NMSettingWireless *s_wifi;
+	NMSettingWirelessSecurity *s_wsec;
+	const char *mode, *key_mgmt;
+
+	/* The kernel doesn't support Ad-Hoc WPA connections well at this time,
+	 * and turns them into open networks.  It's been this way since at least
+	 * 2.6.30 or so; until that's fixed, disable WPA-protected Ad-Hoc networks.
+	 */
+
+	s_wifi = nm_connection_get_setting_wireless (connection);
+	g_return_val_if_fail (s_wifi != NULL, FALSE);
+
+	mode = nm_setting_wireless_get_mode (s_wifi);
+	if (g_strcmp0 (mode, NM_SETTING_WIRELESS_MODE_ADHOC) != 0)
+		return FALSE;
+
+	s_wsec = nm_connection_get_setting_wireless_security (connection);
+	if (!s_wsec)
+		return FALSE;
+
+	key_mgmt = nm_setting_wireless_security_get_key_mgmt (s_wsec);
+	if (g_strcmp0 (key_mgmt, "wpa-none") != 0)
+		return FALSE;
+
+	return TRUE;
 }
 
 static gboolean
@@ -1320,7 +1014,15 @@ real_check_connection_compatible (NMDevice *device,
 	const GByteArray *mac;
 	const GSList *mac_blacklist, *mac_blacklist_iter;
 
-	s_con = NM_SETTING_CONNECTION (nm_connection_get_setting (connection, NM_TYPE_SETTING_CONNECTION));
+	if (is_adhoc_wpa (connection)) {
+		g_set_error_literal (error,
+				             NM_WIFI_ERROR,
+				             NM_WIFI_ERROR_CONNECTION_INCOMPATIBLE,
+				             "WPA Ad-Hoc disabled due to kernel bugs");
+		return FALSE;
+	}
+
+	s_con = nm_connection_get_setting_connection (connection);
 	g_assert (s_con);
 
 	if (strcmp (nm_setting_connection_get_connection_type (s_con), NM_SETTING_WIRELESS_SETTING_NAME)) {
@@ -1330,7 +1032,7 @@ real_check_connection_compatible (NMDevice *device,
 		return FALSE;
 	}
 
-	s_wireless = NM_SETTING_WIRELESS (nm_connection_get_setting (connection, NM_TYPE_SETTING_WIRELESS));
+	s_wireless = nm_connection_get_setting_wireless (connection);
 	if (!s_wireless) {
 		g_set_error (error,
 		             NM_WIFI_ERROR, NM_WIFI_ERROR_CONNECTION_INVALID,
@@ -1525,6 +1227,18 @@ real_complete_connection (NMDevice *device,
 			return FALSE;
 	}
 
+	/* The kernel doesn't support Ad-Hoc WPA connections well at this time,
+	 * and turns them into open networks.  It's been this way since at least
+	 * 2.6.30 or so; until that's fixed, disable WPA-protected Ad-Hoc networks.
+	 */
+	if (is_adhoc_wpa (connection)) {
+		g_set_error_literal (error,
+				             NM_SETTING_WIRELESS_ERROR,
+				             NM_SETTING_WIRELESS_ERROR_INVALID_PROPERTY,
+				             "WPA Ad-Hoc disabled due to kernel bugs");
+		return FALSE;
+	}
+
 	g_assert (ssid);
 	str_ssid = nm_utils_ssid_to_utf8 (ssid);
 	format = g_strdup_printf ("%s %%d", str_ssid);
@@ -1552,8 +1266,11 @@ real_complete_connection (NMDevice *device,
 		GByteArray *mac;
 		const guint8 null_mac[ETH_ALEN] = { 0, 0, 0, 0, 0, 0 };
 
-		/* Lock the connection to this device by default */
-		if (memcmp (priv->perm_hw_addr, null_mac, ETH_ALEN)) {
+		/* Lock the connection to this device by default if it uses a
+		 * permanent MAC address (ie not a 'locally administered' one)
+		 */
+		if (   !(priv->perm_hw_addr[0] & 0x02)
+		    && memcmp (priv->perm_hw_addr, null_mac, ETH_ALEN)) {
 			mac = g_byte_array_sized_new (ETH_ALEN);
 			g_byte_array_append (mac, priv->perm_hw_addr, ETH_ALEN);
 			g_object_set (G_OBJECT (s_wifi), NM_SETTING_WIRELESS_MAC_ADDRESS, mac, NULL);
@@ -1614,7 +1331,7 @@ real_get_best_auto_connection (NMDevice *dev,
 		NMSettingIP4Config *s_ip4;
 		const char *method = NULL;
 
-		s_con = (NMSettingConnection *) nm_connection_get_setting (connection, NM_TYPE_SETTING_CONNECTION);
+		s_con = nm_connection_get_setting_connection (connection);
 		if (s_con == NULL)
 			continue;
 		if (strcmp (nm_setting_connection_get_connection_type (s_con), NM_SETTING_WIRELESS_SETTING_NAME))
@@ -1622,7 +1339,7 @@ real_get_best_auto_connection (NMDevice *dev,
 		if (!nm_setting_connection_get_autoconnect (s_con))
 			continue;
 
-		s_wireless = (NMSettingWireless *) nm_connection_get_setting (connection, NM_TYPE_SETTING_WIRELESS);
+		s_wireless = nm_connection_get_setting_wireless (connection);
 		if (!s_wireless)
 			continue;
 
@@ -1650,7 +1367,7 @@ real_get_best_auto_connection (NMDevice *dev,
 			continue;
 
 		/* Use the connection if it's a shared connection */
-		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)
 			method = nm_setting_ip4_config_get_method (s_ip4);
 
@@ -1725,251 +1442,6 @@ impl_device_get_access_points (NMDeviceWifi *self,
 	return TRUE;
 }
 
-/*
- * nm_device_get_mode
- *
- * Get managed/infrastructure/adhoc mode on a device
- *
- */
-NM80211Mode
-nm_device_wifi_get_mode (NMDeviceWifi *self)
-{
-	int fd;
-	NM80211Mode mode = NM_802_11_MODE_UNKNOWN;
-	const char *iface;
-	struct iwreq wrq;
-
-	g_return_val_if_fail (self != NULL, NM_802_11_MODE_UNKNOWN);
-
-	fd = socket (PF_INET, SOCK_DGRAM, 0);
-	if (fd < 0)
-		goto out;
-
-	memset (&wrq, 0, sizeof (struct iwreq));
-	iface = nm_device_get_iface (NM_DEVICE (self));
-	strncpy (wrq.ifr_name, iface, IFNAMSIZ);
-
-	if (ioctl (fd, SIOCGIWMODE, &wrq) == 0) {
-		switch (wrq.u.mode) {
-		case IW_MODE_ADHOC:
-			mode = NM_802_11_MODE_ADHOC;
-			break;
-		case IW_MODE_INFRA:
-			mode = NM_802_11_MODE_INFRA;
-			break;
-		default:
-			break;
-		}
-	} else {
-		if (errno != ENODEV)
-			nm_log_warn (LOGD_HW | LOGD_WIFI, "(%s): error %d getting card mode", iface, errno);
-	}
-	close (fd);
-
-out:
-	return mode;
-}
-
-
-/*
- * nm_device_wifi_set_mode
- *
- * Set managed/infrastructure/adhoc mode on a device
- *
- */
-gboolean
-nm_device_wifi_set_mode (NMDeviceWifi *self, const NM80211Mode mode)
-{
-	int fd;
-	const char *iface;
-	gboolean success = FALSE;
-	struct iwreq wrq;
-
-	g_return_val_if_fail (self != NULL, FALSE);
-	g_return_val_if_fail ((mode == NM_802_11_MODE_INFRA) || (mode == NM_802_11_MODE_ADHOC), FALSE);
-
-	if (nm_device_wifi_get_mode (self) == mode)
-		return TRUE;
-
-	fd = socket (PF_INET, SOCK_DGRAM, 0);
-	if (fd < 0)
-		goto out;
-
-	memset (&wrq, 0, sizeof (struct iwreq));
-	switch (mode) {
-	case NM_802_11_MODE_ADHOC:
-		wrq.u.mode = IW_MODE_ADHOC;
-		break;
-	case NM_802_11_MODE_INFRA:
-		wrq.u.mode = IW_MODE_INFRA;
-		break;
-	default:
-		goto out;
-	}
-
-	iface = nm_device_get_iface (NM_DEVICE (self));
-	strncpy (wrq.ifr_name, iface, IFNAMSIZ);
-
-	if (ioctl (fd, SIOCSIWMODE, &wrq) < 0) {
-		if (errno != ENODEV)
-			nm_log_err (LOGD_HW | LOGD_WIFI, "(%s): error setting mode %d", iface, mode);
-	} else
-		success = TRUE;
-	close (fd);
-
-out:
-	return success;
-}
-
-
-/*
- * nm_device_wifi_get_frequency
- *
- * Get current frequency
- *
- */
-static guint32
-nm_device_wifi_get_frequency (NMDeviceWifi *self)
-{
-	int fd;
-	guint32 freq = 0;
-	const char *iface;
-	struct iwreq wrq;
-
-	g_return_val_if_fail (self != NULL, 0);
-
-	fd = socket (PF_INET, SOCK_DGRAM, 0);
-	if (fd < 0)
-		return 0;
-
-	memset (&wrq, 0, sizeof (struct iwreq));
-	iface = nm_device_get_iface (NM_DEVICE (self));
-	strncpy (wrq.ifr_name, iface, IFNAMSIZ);
-
-	if (ioctl (fd, SIOCGIWFREQ, &wrq) < 0) {
-		nm_log_warn (LOGD_HW | LOGD_WIFI,
-		             "(%s): error getting frequency: %s",
-		             iface, strerror (errno));
-	} else
-		freq = iw_freq_to_uint32 (&wrq.u.freq);
-
-	close (fd);
-	return freq;
-}
-
-/*
- * nm_device_wifi_get_ssid
- *
- * If a device is wireless, return the ssid that it is attempting
- * to use.
- */
-const GByteArray *
-nm_device_wifi_get_ssid (NMDeviceWifi *self)
-{
-	NMDeviceWifiPrivate *priv;
-	int sk;
-	struct iwreq wrq;
-	char ssid[IW_ESSID_MAX_SIZE + 2];
-	guint32 len;
-
-	g_return_val_if_fail (self != NULL, NULL);
-	priv = NM_DEVICE_WIFI_GET_PRIVATE (self);
-
-	sk = socket (AF_INET, SOCK_DGRAM, 0);
-	if (sk == -1) {
-		nm_log_err (LOGD_HW, "couldn't create socket: %d.", errno);
-		return NULL;
-	}
-
-	memset (ssid, 0, sizeof (ssid));
-	wrq.u.essid.pointer = (caddr_t) &ssid;
-	wrq.u.essid.length = sizeof (ssid);
-	wrq.u.essid.flags = 0;
-	strncpy (wrq.ifr_name, nm_device_get_iface (NM_DEVICE (self)), IFNAMSIZ);
-
-	if (ioctl (sk, SIOCGIWESSID, &wrq) < 0) {
-		nm_log_err (LOGD_HW | LOGD_WIFI, "(%s): couldn't get SSID: %d",
-		            nm_device_get_iface (NM_DEVICE (self)), errno);
-		goto out;
-	}
-
-	if (priv->ssid) {
-		g_byte_array_free (priv->ssid, TRUE);
-		priv->ssid = NULL;
-	}
-
-	len = wrq.u.essid.length;
-	if (!nm_utils_is_empty_ssid ((guint8 *) ssid, len)) {
-		priv->ssid = g_byte_array_sized_new (len);
-		g_byte_array_append (priv->ssid, (const guint8 *) ssid, len);
-	}
-
-out:
-	close (sk);
-	return priv->ssid;
-}
-
-
-/*
- * nm_device_wifi_get_bitrate
- *
- * For wireless devices, get the bitrate to broadcast/receive at.
- * Returned value is rate in Kb/s.
- *
- */
-static guint32
-nm_device_wifi_get_bitrate (NMDeviceWifi *self)
-{
-	int err = -1, fd;
-	struct iwreq wrq;
-
-	g_return_val_if_fail (self != NULL, 0);
-
-	fd = socket (PF_INET, SOCK_DGRAM, 0);
-	if (fd < 0)
-		return 0;
-
-	memset (&wrq, 0, sizeof (wrq));
-	strncpy (wrq.ifr_name, nm_device_get_iface (NM_DEVICE (self)), IFNAMSIZ);
-	err = ioctl (fd, SIOCGIWRATE, &wrq);
-	close (fd);
-
-	return ((err == 0) ? wrq.u.bitrate.value / 1000 : 0);
-}
-
-/*
- * nm_device_get_bssid
- *
- * If a device is wireless, get the access point's ethernet address
- * that the card is associated with.
- */
-void
-nm_device_wifi_get_bssid (NMDeviceWifi *self,
-                          struct ether_addr *bssid)
-{
-	int fd;
-	struct iwreq wrq;
-
-	g_return_if_fail (self != NULL);
-	g_return_if_fail (bssid != NULL);
-
-	memset (bssid, 0, sizeof (struct ether_addr));
-
-	fd = socket (PF_INET, SOCK_DGRAM, 0);
-	if (fd < 0) {
-		nm_log_err (LOGD_WIFI, "failed to open control socket.");
-		return;
-	}
-
-	memset (&wrq, 0, sizeof (wrq));
-	strncpy (wrq.ifr_name, nm_device_get_iface (NM_DEVICE (self)), IFNAMSIZ);
-	if (ioctl (fd, SIOCGIWAP, &wrq) == 0)
-		memcpy (bssid->ether_addr_octet, &(wrq.u.ap_addr.sa_data), ETH_ALEN);
-
-	close (fd);
-}
-
-
 static gboolean
 scanning_allowed (NMDeviceWifi *self)
 {
@@ -2020,7 +1492,7 @@ scanning_allowed (NMDeviceWifi *self)
 
 		/* Don't scan when a shared connection is active; it makes drivers mad */
 		connection = nm_act_request_get_connection (req);
-		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)
 			ip4_method = nm_setting_ip4_config_get_method (s_ip4);
 
@@ -2031,7 +1503,7 @@ scanning_allowed (NMDeviceWifi *self)
 		 * intra-ESS roaming (which requires periodic scanning) isn't being
 		 * used due to the specific AP lock. (bgo #513820)
 		 */
-		s_wifi = (NMSettingWireless *) nm_connection_get_setting (connection, NM_TYPE_SETTING_WIRELESS);
+		s_wifi = nm_connection_get_setting_wireless (connection);
 		g_assert (s_wifi);
 		bssid = nm_setting_wireless_get_bssid (s_wifi);
 		if (bssid && bssid->len == ETH_ALEN)
@@ -2174,15 +1646,10 @@ supplicant_iface_scan_done_cb (NMSupplicantInterface *iface,
 	if (check_scanning_allowed (self))
 		schedule_scan (self, TRUE);
 
-#if 0
-	if (num_results == 0) {
-		/* ensure that old APs get culled, which otherwise only
-		 * happens when there are actual scan results to process.
-		 */
-		cull_scan_list (self);
-		ap_list_dump (self);
-	}
-#endif
+	/* Ensure that old APs get removed, which otherwise only
+	 * happens when there are new BSSes.
+	 */
+	schedule_scanlist_cull (self);
 }
 
 
@@ -2217,9 +1684,7 @@ merge_scanned_ap (NMDeviceWifi *self,
 	gboolean strict_match = TRUE;
 	NMAccessPoint *current_ap = NULL;
 
-	/* Let the manager try to fill in the SSID from seen-bssids lists
-	 * if it can
-	 */
+	/* Let the manager try to fill in the SSID from seen-bssids lists */
 	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)) {
@@ -2252,7 +1717,9 @@ merge_scanned_ap (NMDeviceWifi *self,
 	if (current_ap && nm_ap_get_fake (current_ap))
 		strict_match = FALSE;
 
-	found_ap = nm_ap_match_in_list (merge_ap, priv->ap_list, strict_match);
+	found_ap = get_ap_by_supplicant_path (self, nm_ap_get_supplicant_path (merge_ap));
+	if (!found_ap)
+		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)),
@@ -2261,6 +1728,7 @@ merge_scanned_ap (NMDeviceWifi *self,
 		            merge_ap,
 		            found_ap);
 
+		nm_ap_set_supplicant_path (found_ap, nm_ap_get_supplicant_path (merge_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));
@@ -2289,25 +1757,18 @@ merge_scanned_ap (NMDeviceWifi *self,
 	}
 }
 
-static void
+#define WPAS_REMOVED_TAG "supplicant-removed"
+
+static gboolean
 cull_scan_list (NMDeviceWifi *self)
 {
-	NMDeviceWifiPrivate *priv;
-	GTimeVal cur_time;
+	NMDeviceWifiPrivate *priv = NM_DEVICE_WIFI_GET_PRIVATE (self);
+	GTimeVal now;
 	GSList *outdated_list = NULL;
 	GSList *elt;
-	NMActRequest *req;
-	const char *cur_ap_path = NULL;
 	guint32 removed = 0, total = 0;
 
-	g_return_if_fail (self != NULL);
-	priv = NM_DEVICE_WIFI_GET_PRIVATE (self);
-
-	g_get_current_time (&cur_time);
-
-	req = nm_device_get_act_request (NM_DEVICE (self));
-	if (req)
-		cur_ap_path = nm_act_request_get_specific_object (req);
+	priv->scanlist_cull_id = 0;
 
 	nm_log_dbg (LOGD_WIFI_SCAN, "(%s): checking scan list for outdated APs",
 	            nm_device_get_iface (NM_DEVICE (self)));
@@ -2315,19 +1776,27 @@ cull_scan_list (NMDeviceWifi *self)
 	/* Walk the access point list and remove any access points older than
 	 * three times the inactive scan interval.
 	 */
+	g_get_current_time (&now);
 	for (elt = priv->ap_list; elt; elt = g_slist_next (elt), total++) {
-		NMAccessPoint * ap = NM_AP (elt->data);
-		const glong     ap_time = nm_ap_get_last_seen (ap);
-		gboolean        keep = FALSE;
-		const guint     prune_interval_s = SCAN_INTERVAL_MAX * 3;
+		NMAccessPoint *ap = elt->data;
+		const guint prune_interval_s = SCAN_INTERVAL_MAX * 3;
 
-		/* Don't ever prune the AP we're currently associated with */
-		if (cur_ap_path && !strcmp (cur_ap_path, nm_ap_get_dbus_path (ap)))
-			keep = TRUE;
-		if (nm_ap_get_fake (ap))
-			keep = TRUE;
+		/* Don't cull the associated AP or manually created APs */
+		if (ap == priv->current_ap || nm_ap_get_fake (ap))
+			continue;
+
+		/* Don't cull APs still known to the supplicant.  Since the supplicant
+		 * doesn't yet emit property updates for "last seen" we have to rely
+		 * on changing signal strength for updating "last seen".  But if the
+		 * AP's strength doesn't change we won't get any updates for the AP,
+		 * and we'll end up here even if the AP was still found by the
+		 * supplicant in the last scan.
+		 */
+		if (   nm_ap_get_supplicant_path (ap)
+		    && g_object_get_data (G_OBJECT (ap), WPAS_REMOVED_TAG) == NULL)
+			continue;
 
-		if (!keep && (ap_time + prune_interval_s < cur_time.tv_sec))
+		if (nm_ap_get_last_seen (ap) + prune_interval_s < now.tv_sec)
 			outdated_list = g_slist_append (outdated_list, ap);
 	}
 
@@ -2358,10 +1827,26 @@ cull_scan_list (NMDeviceWifi *self)
 	nm_log_dbg (LOGD_WIFI_SCAN, "(%s): removed %d APs (of %d)",
 	            nm_device_get_iface (NM_DEVICE (self)),
 	            removed, total);
+
+	ap_list_dump (self);
+
+	return FALSE;
+}
+
+static void
+schedule_scanlist_cull (NMDeviceWifi *self)
+{
+	NMDeviceWifiPrivate *priv = NM_DEVICE_WIFI_GET_PRIVATE (self);
+
+	/* Cull the scan list after the last request for it has come in */
+	if (priv->scanlist_cull_id)
+		g_source_remove (priv->scanlist_cull_id);
+	priv->scanlist_cull_id = g_timeout_add_seconds (4, (GSourceFunc) cull_scan_list, self);
 }
 
 static void
 supplicant_iface_new_bss_cb (NMSupplicantInterface *iface,
+                             const char *object_path,
                              GHashTable *properties,
                              NMDeviceWifi *self)
 {
@@ -2377,22 +1862,65 @@ supplicant_iface_new_bss_cb (NMSupplicantInterface *iface,
 	if (state <= NM_DEVICE_STATE_UNAVAILABLE)
 		return;
 
-	ap = nm_ap_new_from_properties (properties);
+	ap = nm_ap_new_from_properties (object_path, properties);
 	if (ap) {
 		nm_ap_dump (ap, "New AP: ");
 
 		/* Add the AP to the device's AP list */
 		merge_scanned_ap (self, ap);
 		g_object_unref (ap);
-
-		/* Remove outdated access points */
-		cull_scan_list (self);
-
-		ap_list_dump (self);
 	} else {
 		nm_log_warn (LOGD_WIFI_SCAN, "(%s): invalid AP properties received",
 		             nm_device_get_iface (NM_DEVICE (self)));
 	}
+
+	/* Remove outdated access points */
+	schedule_scanlist_cull (self);
+}
+
+static void
+supplicant_iface_bss_updated_cb (NMSupplicantInterface *iface,
+                                 const char *object_path,
+                                 GHashTable *properties,
+                                 NMDeviceWifi *self)
+{
+	NMDeviceState state;
+	NMAccessPoint *ap;
+	GTimeVal now;
+
+	g_return_if_fail (self != NULL);
+	g_return_if_fail (object_path != NULL);
+	g_return_if_fail (properties != NULL);
+
+	/* Ignore new APs when unavailable or unamnaged */
+	state = nm_device_get_state (NM_DEVICE (self));
+	if (state <= NM_DEVICE_STATE_UNAVAILABLE)
+		return;
+
+	/* Update the AP's last-seen property */
+	ap = get_ap_by_supplicant_path (self, object_path);
+	if (ap) {
+		g_get_current_time (&now);
+		nm_ap_set_last_seen (ap, now.tv_sec);
+	}
+
+	/* Remove outdated access points */
+	schedule_scanlist_cull (self);
+}
+
+static void
+supplicant_iface_bss_removed_cb (NMSupplicantInterface *iface,
+                                 const char *object_path,
+                                 NMDeviceWifi *self)
+{
+	NMAccessPoint *ap;
+
+	g_return_if_fail (self != NULL);
+	g_return_if_fail (object_path != NULL);
+
+	ap = get_ap_by_supplicant_path (self, object_path);
+	if (ap)
+		g_object_set_data (G_OBJECT (ap), WPAS_REMOVED_TAG, GUINT_TO_POINTER (TRUE));
 }
 
 
@@ -2921,23 +2449,6 @@ remove_supplicant_timeouts (NMDeviceWifi *self)
 	remove_link_timeout (self);
 }
 
-static guint32
-find_supported_frequency (NMDeviceWifi *self, const guint32 *freqs)
-{
-	NMDeviceWifiPrivate *priv = NM_DEVICE_WIFI_GET_PRIVATE (self);
-	int i;
-
-	for (i = 0; i < priv->num_freqs; i++) {
-		while (*freqs) {
-			if (priv->freqs[i] == *freqs)
-				return *freqs;
-			freqs++;
-		}
-	}
-
-	return 0;
-}
-
 static NMSupplicantConfig *
 build_supplicant_config (NMDeviceWifi *self,
                          NMConnection *connection,
@@ -2951,7 +2462,7 @@ build_supplicant_config (NMDeviceWifi *self,
 
 	g_return_val_if_fail (self != NULL, NULL);
 
-	s_wireless = (NMSettingWireless *) nm_connection_get_setting (connection, NM_TYPE_SETTING_WIRELESS);
+	s_wireless = nm_connection_get_setting_wireless (connection);
 	g_return_val_if_fail (s_wireless != NULL, NULL);
 
 	config = nm_supplicant_config_new ();
@@ -2970,9 +2481,9 @@ build_supplicant_config (NMDeviceWifi *self,
 		adhoc_freq = nm_ap_get_freq (ap);
 		if (!adhoc_freq) {
 			if (g_strcmp0 (band, "a") == 0)
-				adhoc_freq = find_supported_frequency (self, a_freqs);
+				adhoc_freq = wifi_utils_find_freq (priv->wifi_data, a_freqs);
 			else
-				adhoc_freq = find_supported_frequency (self, bg_freqs);
+				adhoc_freq = wifi_utils_find_freq (priv->wifi_data, bg_freqs);
 		}
 
 		if (!adhoc_freq) {
@@ -2987,22 +2498,22 @@ build_supplicant_config (NMDeviceWifi *self,
 	                                                s_wireless,
 	                                                nm_ap_get_broadcast (ap),
 	                                                adhoc_freq,
-	                                                priv->has_scan_capa_ssid)) {
+	                                                wifi_utils_can_scan_ssid (priv->wifi_data))) {
 		nm_log_err (LOGD_WIFI, "Couldn't add 802-11-wireless setting to supplicant config.");
 		goto error;
 	}
 
-	s_wireless_sec = (NMSettingWirelessSecurity *) nm_connection_get_setting (connection, NM_TYPE_SETTING_WIRELESS_SECURITY);
+	s_wireless_sec = nm_connection_get_setting_wireless_security (connection);
 	if (s_wireless_sec) {
 		NMSetting8021x *s_8021x;
-		const char *con_path = nm_connection_get_path (connection);
+		const char *con_uuid = nm_connection_get_uuid (connection);
 
-		g_assert (con_path);
-		s_8021x = (NMSetting8021x *) nm_connection_get_setting (connection, NM_TYPE_SETTING_802_1X);
+		g_assert (con_uuid);
+		s_8021x = nm_connection_get_setting_802_1x (connection);
 		if (!nm_supplicant_config_add_setting_wireless_security (config,
 		                                                         s_wireless_sec,
 		                                                         s_8021x,
-		                                                         con_path)) {
+		                                                         con_uuid)) {
 			nm_log_err (LOGD_WIFI, "Couldn't add 802-11-wireless-security setting to "
 			            "supplicant config.");
 			goto error;
@@ -3135,8 +2646,18 @@ real_act_stage1_prepare (NMDevice *dev, NMDeviceStateReason *reason)
 	connection = nm_act_request_get_connection (req);
 	g_return_val_if_fail (connection != NULL, NM_ACT_STAGE_RETURN_FAILURE);
 
+	/* The kernel doesn't support Ad-Hoc WPA connections well at this time,
+	 * and turns them into open networks.  It's been this way since at least
+	 * 2.6.30 or so; until that's fixed, disable WPA-protected Ad-Hoc networks.
+	 */
+	if (is_adhoc_wpa (connection)) {
+		nm_log_warn (LOGD_WIFI, "Ad-Hoc WPA disabled due to kernel bugs");
+		*reason = NM_DEVICE_STATE_REASON_SUPPLICANT_CONFIG_FAILED;
+		return NM_ACT_STAGE_RETURN_FAILURE;
+	}
+
 	/* Set spoof MAC to the interface */
-	s_wireless = (NMSettingWireless *) nm_connection_get_setting (connection, NM_TYPE_SETTING_WIRELESS);
+	s_wireless = nm_connection_get_setting_wireless (connection);
 	g_assert (s_wireless);
 
 	cloned_mac = nm_setting_wireless_get_cloned_mac_address (s_wireless);
@@ -3177,7 +2698,7 @@ real_act_stage1_prepare (NMDevice *dev, NMDeviceStateReason *reason)
 		g_signal_emit (self, signals[ACCESS_POINT_ADDED], 0, ap);
 	}
 
-	nm_act_request_set_specific_object (req, nm_ap_get_dbus_path (ap));
+	nm_active_connection_set_specific_object (NM_ACTIVE_CONNECTION (req), nm_ap_get_dbus_path (ap));
 
 done:
 	set_current_ap (self, ap);
@@ -3212,7 +2733,7 @@ real_act_stage2_config (NMDevice *dev, NMDeviceStateReason *reason)
 	connection = nm_act_request_get_connection (req);
 	g_assert (connection);
 
-	s_wireless = (NMSettingWireless *) nm_connection_get_setting (connection, NM_TYPE_SETTING_WIRELESS);
+	s_wireless = nm_connection_get_setting_wireless (connection);
 	g_assert (s_wireless);
 
 	/* If we need secrets, get them */
@@ -3287,38 +2808,22 @@ out:
 	return ret;
 }
 
-static NMActStageReturn
-real_act_stage4_get_ip4_config (NMDevice *dev,
-                                NMIP4Config **config,
-                                NMDeviceStateReason *reason)
+static void
+real_ip4_config_pre_commit (NMDevice *device, NMIP4Config *config)
 {
-	NMActStageReturn ret = NM_ACT_STAGE_RETURN_FAILURE;
-	NMDeviceClass *parent_class;
-
-	g_return_val_if_fail (config != NULL, NM_ACT_STAGE_RETURN_FAILURE);
-	g_return_val_if_fail (*config == NULL, NM_ACT_STAGE_RETURN_FAILURE);
-
-	/* Chain up to parent */
-	parent_class = NM_DEVICE_CLASS (nm_device_wifi_parent_class);
-	ret = parent_class->act_stage4_get_ip4_config (dev, config, reason);
-
-	if ((ret == NM_ACT_STAGE_RETURN_SUCCESS) && *config) {
-		NMConnection *connection;
-		NMSettingWireless *s_wireless;
-		guint32 mtu;
-
-		connection = nm_act_request_get_connection (nm_device_get_act_request (dev));
-		g_assert (connection);
-		s_wireless = NM_SETTING_WIRELESS (nm_connection_get_setting (connection, NM_TYPE_SETTING_WIRELESS));
-		g_assert (s_wireless);
+	NMConnection *connection;
+	NMSettingWireless *s_wifi;
+	guint32 mtu;
 
-		/* MTU override */
-		mtu = nm_setting_wireless_get_mtu (s_wireless);
-		if (mtu)
-			nm_ip4_config_set_mtu (*config, mtu);
-	}
+	connection = nm_device_get_connection (device);
+	g_assert (connection);
+	s_wifi = nm_connection_get_setting_wireless (connection);
+	g_assert (s_wifi);
 
-	return ret;
+	/* MTU override */
+	mtu = nm_setting_wireless_get_mtu (s_wifi);
+	if (mtu)
+		nm_ip4_config_set_mtu (config, mtu);
 }
 
 static gboolean
@@ -3398,55 +2903,45 @@ handle_ip_config_timeout (NMDeviceWifi *self,
 
 
 static NMActStageReturn
-real_act_stage4_ip4_config_timeout (NMDevice *dev,
-                                    NMIP4Config **config,
-                                    NMDeviceStateReason *reason)
+real_act_stage4_ip4_config_timeout (NMDevice *dev, NMDeviceStateReason *reason)
 {
-	NMActRequest *req;
 	NMConnection *connection;
 	NMSettingIP4Config *s_ip4;
 	gboolean may_fail = FALSE, chain_up = FALSE;
 	NMActStageReturn ret;
 
-	req = nm_device_get_act_request (dev);
-	g_assert (req);
-	connection = nm_act_request_get_connection (req);
+	connection = nm_device_get_connection (dev);
 	g_assert (connection);
 
-	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)
 		may_fail = nm_setting_ip4_config_get_may_fail (s_ip4);
 
 	ret = handle_ip_config_timeout (NM_DEVICE_WIFI (dev), connection, may_fail, &chain_up, reason);
 	if (chain_up)
-		ret = NM_DEVICE_CLASS (nm_device_wifi_parent_class)->act_stage4_ip4_config_timeout (dev, config, reason);
+		ret = NM_DEVICE_CLASS (nm_device_wifi_parent_class)->act_stage4_ip4_config_timeout (dev, reason);
 
 	return ret;
 }
 
 static NMActStageReturn
-real_act_stage4_ip6_config_timeout (NMDevice *dev,
-                                    NMIP6Config **config,
-                                    NMDeviceStateReason *reason)
+real_act_stage4_ip6_config_timeout (NMDevice *dev, NMDeviceStateReason *reason)
 {
-	NMActRequest *req;
 	NMConnection *connection;
 	NMSettingIP6Config *s_ip6;
 	gboolean may_fail = FALSE, chain_up = FALSE;
 	NMActStageReturn ret;
 
-	req = nm_device_get_act_request (dev);
-	g_assert (req);
-	connection = nm_act_request_get_connection (req);
+	connection = nm_device_get_connection (dev);
 	g_assert (connection);
 
-	s_ip6 = (NMSettingIP6Config *) nm_connection_get_setting (connection, NM_TYPE_SETTING_IP6_CONFIG);
+	s_ip6 = nm_connection_get_setting_ip6_config (connection);
 	if (s_ip6)
 		may_fail = nm_setting_ip6_config_get_may_fail (s_ip6);
 
 	ret = handle_ip_config_timeout (NM_DEVICE_WIFI (dev), connection, may_fail, &chain_up, reason);
 	if (chain_up)
-		ret = NM_DEVICE_CLASS (nm_device_wifi_parent_class)->act_stage4_ip6_config_timeout (dev, config, reason);
+		ret = NM_DEVICE_CLASS (nm_device_wifi_parent_class)->act_stage4_ip6_config_timeout (dev, reason);
 
 	return ret;
 }
@@ -3483,13 +2978,13 @@ activation_success_handler (NMDevice *dev)
 	 * But if activation was successful, the card will know the BSSID.  Grab
 	 * the BSSID off the card and fill in the BSSID of the activation AP.
 	 */
-	nm_device_wifi_get_bssid (self, &bssid);
+	wifi_utils_get_bssid (priv->wifi_data, &bssid);
 	if (!nm_ethernet_address_is_valid (nm_ap_get_address (ap)))
 		nm_ap_set_address (ap, &bssid);
 	if (!nm_ap_get_freq (ap))
-		nm_ap_set_freq (ap, nm_device_wifi_get_frequency (self));
+		nm_ap_set_freq (ap, wifi_utils_get_freq (priv->wifi_data));
 	if (!nm_ap_get_max_bitrate (ap))
-		nm_ap_set_max_bitrate (ap, nm_device_wifi_get_bitrate (self));
+		nm_ap_set_max_bitrate (ap, wifi_utils_get_rate (priv->wifi_data));
 
 	tmp_ap = get_active_ap (self, ap, TRUE);
 	if (tmp_ap) {
@@ -3503,7 +2998,8 @@ activation_success_handler (NMDevice *dev)
 		if (!ssid || nm_utils_is_empty_ssid (ssid->data, ssid->len))
 			nm_ap_set_ssid (tmp_ap, nm_ap_get_ssid (ap));
 
-		nm_act_request_set_specific_object (req, nm_ap_get_dbus_path (tmp_ap));
+		nm_active_connection_set_specific_object (NM_ACTIVE_CONNECTION (req),
+		                                          nm_ap_get_dbus_path (tmp_ap));
 
 		priv->ap_list = g_slist_remove (priv->ap_list, ap);
 		g_object_unref (ap);
@@ -3526,13 +3022,9 @@ activation_failure_handler (NMDevice *dev)
 	NMDeviceWifiPrivate *priv = NM_DEVICE_WIFI_GET_PRIVATE (self);
 	NMAccessPoint *ap;
 	const GByteArray * ssid;
-	NMActRequest *req;
 	NMConnection *connection;
 
-	req = nm_device_get_act_request (dev);
-	g_assert (req);
-
-	connection = nm_act_request_get_connection (req);
+	connection = nm_device_get_connection (dev);
 	g_assert (connection);
 
 	/* Clear wireless secrets tries on failure */
@@ -3583,13 +3075,42 @@ spec_match_list (NMDevice *device, const GSList *specs)
 	char *hwaddr;
 	gboolean matched;
 
-	hwaddr = nm_ether_ntop ((struct ether_addr *) &priv->perm_hw_addr);
+	hwaddr = nm_utils_hwaddr_ntoa (&priv->perm_hw_addr, ARPHRD_ETHER);
 	matched = nm_match_spec_hwaddr (specs, hwaddr);
 	g_free (hwaddr);
 
 	return matched;
 }
 
+static gboolean
+hwaddr_matches (NMDevice *device,
+                NMConnection *connection,
+                const guint8 *other_hwaddr,
+                guint other_hwaddr_len,
+                gboolean fail_if_no_hwaddr)
+{
+	NMDeviceWifiPrivate *priv = NM_DEVICE_WIFI_GET_PRIVATE (device);
+	NMSettingWireless *s_wifi;
+	const GByteArray *mac = NULL;
+
+	s_wifi = nm_connection_get_setting_wireless (connection);
+	if (s_wifi)
+		mac = nm_setting_wireless_get_mac_address (s_wifi);
+
+	if (mac) {
+		g_return_val_if_fail (mac->len == ETH_ALEN, FALSE);
+		if (other_hwaddr) {
+			g_return_val_if_fail (other_hwaddr_len == ETH_ALEN, FALSE);
+			if (memcmp (mac->data, other_hwaddr, mac->len) == 0)
+				return TRUE;
+		} else if (memcmp (mac->data, priv->hw_addr, mac->len) == 0)
+			return TRUE;
+	} else if (fail_if_no_hwaddr == FALSE)
+		return TRUE;
+
+	return FALSE;
+}
+
 static void
 device_state_changed (NMDevice *device,
                       NMDeviceState new_state,
@@ -3632,12 +3153,6 @@ device_state_changed (NMDevice *device,
 		 * the device is now ready to use.
 		 */
 		if (priv->enabled && (nm_device_get_firmware_missing (device) == FALSE)) {
-			gboolean success;
-			struct iw_range range;
-
-			/* Wait for some drivers like ipw3945 to come back to life */
-			success = wireless_get_range (self, &range, NULL);
-
 			if (!priv->supplicant.iface)
 				supplicant_interface_acquire (self);
 		}
@@ -3676,13 +3191,13 @@ nm_device_wifi_get_activation_ap (NMDeviceWifi *self)
 	if (!req)
 		return NULL;
 
-	ap_path = nm_act_request_get_specific_object (req);
+	ap_path = nm_active_connection_get_specific_object (NM_ACTIVE_CONNECTION (req));
 
 	return ap_path ? get_ap_by_path (self, ap_path) : NULL;
 }
 
 static void
-real_set_enabled (NMDeviceInterface *device, gboolean enabled)
+real_set_enabled (NMDevice *device, gboolean enabled)
 {
 	NMDeviceWifi *self = NM_DEVICE_WIFI (device);
 	NMDeviceWifiPrivate *priv = NM_DEVICE_WIFI_GET_PRIVATE (self);
@@ -3697,7 +3212,7 @@ real_set_enabled (NMDeviceInterface *device, gboolean enabled)
 	            nm_device_get_iface (NM_DEVICE (device)),
 	            enabled ? "enabled" : "disabled");
 
-	state = nm_device_interface_get_state (NM_DEVICE_INTERFACE (self));
+	state = nm_device_get_state (NM_DEVICE (self));
 	if (state < NM_DEVICE_STATE_UNAVAILABLE) {
 		nm_log_dbg (LOGD_WIFI, "(%s): %s blocked by UNMANAGED state",
 		            enabled ? "enable" : "disable",
@@ -3706,8 +3221,7 @@ real_set_enabled (NMDeviceInterface *device, gboolean enabled)
 	}
 
 	if (enabled) {
-		gboolean no_firmware = FALSE, success;
-		struct iw_range range;
+		gboolean no_firmware = FALSE;
 
 		if (state != NM_DEVICE_STATE_UNAVAILABLE)
 			nm_log_warn (LOGD_CORE, "not in expected unavailable state!");
@@ -3725,9 +3239,6 @@ real_set_enabled (NMDeviceInterface *device, gboolean enabled)
 			return;
 		}
 
-		/* Wait for some drivers like ipw3945 to come back to life */
-		success = wireless_get_range (self, &range, NULL);
-
 		/* Re-initialize the supplicant interface and wait for it to be ready */
 		if (priv->supplicant.iface)
 			supplicant_interface_release (self);
@@ -3755,22 +3266,16 @@ nm_device_wifi_new (const char *udi,
 	g_return_val_if_fail (driver != NULL, NULL);
 
 	return (NMDevice *) g_object_new (NM_TYPE_DEVICE_WIFI,
-	                                  NM_DEVICE_INTERFACE_UDI, udi,
-	                                  NM_DEVICE_INTERFACE_IFACE, iface,
-	                                  NM_DEVICE_INTERFACE_DRIVER, driver,
-	                                  NM_DEVICE_INTERFACE_TYPE_DESC, "802.11 WiFi",
-	                                  NM_DEVICE_INTERFACE_DEVICE_TYPE, NM_DEVICE_TYPE_WIFI,
-	                                  NM_DEVICE_INTERFACE_RFKILL_TYPE, RFKILL_TYPE_WLAN,
+	                                  NM_DEVICE_UDI, udi,
+	                                  NM_DEVICE_IFACE, iface,
+	                                  NM_DEVICE_DRIVER, driver,
+	                                  NM_DEVICE_TYPE_DESC, "802.11 WiFi",
+	                                  NM_DEVICE_DEVICE_TYPE, NM_DEVICE_TYPE_WIFI,
+	                                  NM_DEVICE_RFKILL_TYPE, RFKILL_TYPE_WLAN,
 	                                  NULL);
 }
 
 static void
-device_interface_init (NMDeviceInterface *iface_class)
-{
-    iface_class->set_enabled = real_set_enabled;
-}
-
-static void
 nm_device_wifi_init (NMDeviceWifi * self)
 {
 	g_signal_connect (self, "state-changed", G_CALLBACK (device_state_changed), NULL);
@@ -3802,14 +3307,12 @@ dispose (GObject *object)
 		priv->supplicant.mgr = NULL;
 	}
 
-	if (priv->ssid) {
-		g_byte_array_free (priv->ssid, TRUE);
-		priv->ssid = NULL;
-	}
-
 	set_current_ap (self, NULL);
 	remove_all_aps (self);
 
+	if (priv->wifi_data)
+		wifi_utils_deinit (priv->wifi_data);
+
 	g_free (priv->ipw_rfkill_path);
 	if (priv->ipw_rfkill_id) {
 		g_source_remove (priv->ipw_rfkill_id);
@@ -3828,13 +3331,13 @@ get_property (GObject *object, guint prop_id,
 
 	switch (prop_id) {
 	case PROP_HW_ADDRESS:
-		g_value_take_string (value, nm_ether_ntop ((struct ether_addr *) &priv->hw_addr));
+		g_value_take_string (value, nm_utils_hwaddr_ntoa (&priv->hw_addr, ARPHRD_ETHER));
 		break;
 	case PROP_PERM_HW_ADDRESS:
-		g_value_take_string (value, nm_ether_ntop ((struct ether_addr *) &priv->perm_hw_addr));
+		g_value_take_string (value, nm_utils_hwaddr_ntoa (&priv->perm_hw_addr, ARPHRD_ETHER));
 		break;
 	case PROP_MODE:
-		g_value_set_uint (value, nm_device_wifi_get_mode (device));
+		g_value_set_uint (value, wifi_utils_get_mode (priv->wifi_data));
 		break;
 	case PROP_BITRATE:
 		g_value_set_uint (value, priv->rate);
@@ -3906,15 +3409,17 @@ nm_device_wifi_class_init (NMDeviceWifiClass *klass)
 	parent_class->is_available = real_is_available;
 	parent_class->check_connection_compatible = real_check_connection_compatible;
 	parent_class->complete_connection = real_complete_connection;
+    parent_class->set_enabled = real_set_enabled;
 
 	parent_class->act_stage1_prepare = real_act_stage1_prepare;
 	parent_class->act_stage2_config = real_act_stage2_config;
-	parent_class->act_stage4_get_ip4_config = real_act_stage4_get_ip4_config;
+	parent_class->ip4_config_pre_commit = real_ip4_config_pre_commit;
 	parent_class->act_stage4_ip4_config_timeout = real_act_stage4_ip4_config_timeout;
 	parent_class->act_stage4_ip6_config_timeout = real_act_stage4_ip6_config_timeout;
 	parent_class->deactivate = real_deactivate;
 	parent_class->can_interrupt_activation = real_can_interrupt_activation;
 	parent_class->spec_match_list = spec_match_list;
+	parent_class->hwaddr_matches = hwaddr_matches;
 
 	klass->scanning_allowed = scanning_allowed;
 
diff --git a/src/nm-device-wifi.h b/src/nm-device-wifi.h
index 31ac5ad5..1e665fc3 100644
--- a/src/nm-device-wifi.h
+++ b/src/nm-device-wifi.h
@@ -41,6 +41,12 @@ G_BEGIN_DECLS
 #define NM_IS_DEVICE_WIFI_CLASS(klass)	(G_TYPE_CHECK_CLASS_TYPE ((klass),  NM_TYPE_DEVICE_WIFI))
 #define NM_DEVICE_WIFI_GET_CLASS(obj)	(G_TYPE_INSTANCE_GET_CLASS ((obj),  NM_TYPE_DEVICE_WIFI, NMDeviceWifiClass))
 
+typedef enum {
+	NM_WIFI_ERROR_CONNECTION_NOT_WIRELESS = 0, /*< nick=ConnectionNotWireless >*/
+	NM_WIFI_ERROR_CONNECTION_INVALID,          /*< nick=ConnectionInvalid >*/
+	NM_WIFI_ERROR_CONNECTION_INCOMPATIBLE,     /*< nick=ConnectionIncompatible >*/
+	NM_WIFI_ERROR_ACCESS_POINT_NOT_FOUND,      /*< nick=AccessPointNotFound >*/
+} NMWifiError;
 
 #define NM_DEVICE_WIFI_HW_ADDRESS          "hw-address"
 #define NM_DEVICE_WIFI_PERMANENT_HW_ADDRESS "perm-hw-address"
@@ -88,14 +94,6 @@ NMDevice *nm_device_wifi_new (const char *udi,
 
 void nm_device_wifi_get_address (NMDeviceWifi *dev, struct ether_addr *addr);
 
-void nm_device_wifi_get_bssid (NMDeviceWifi *dev, struct ether_addr *bssid);
-
-const GByteArray * nm_device_wifi_get_ssid (NMDeviceWifi *self);
-
-gboolean nm_device_wifi_set_mode (NMDeviceWifi *self, const NM80211Mode mode);
-
-NM80211Mode nm_device_wifi_get_mode (NMDeviceWifi *self);
-
 NMAccessPoint * nm_device_wifi_get_activation_ap (NMDeviceWifi *self);
 
 RfKillState nm_device_wifi_get_ipw_rfkill_state (NMDeviceWifi *self);
diff --git a/src/nm-device-wired.c b/src/nm-device-wired.c
new file mode 100644
index 00000000..a476faad
--- /dev/null
+++ b/src/nm-device-wired.c
@@ -0,0 +1,595 @@
+/* -*- 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) 2005 - 2012 Red Hat, Inc.
+ * Copyright (C) 2006 - 2008 Novell, Inc.
+ */
+
+#include "config.h"
+#include <glib.h>
+#include <sys/socket.h>
+#include <linux/if.h>
+#include <linux/if_infiniband.h>
+#include <netinet/ether.h>
+#include <linux/sockios.h>
+#include <linux/version.h>
+#include <linux/ethtool.h>
+#include <sys/ioctl.h>
+#include <unistd.h>
+
+#include "nm-device-wired.h"
+#include "nm-device-private.h"
+#include "nm-dhcp-manager.h"
+#include "nm-logging.h"
+#include "nm-netlink-monitor.h"
+#include "nm-netlink-utils.h"
+#include "nm-system.h"
+#include "nm-utils.h"
+#include "NetworkManagerUtils.h"
+
+
+G_DEFINE_TYPE (NMDeviceWired, nm_device_wired, NM_TYPE_DEVICE)
+
+#define NM_DEVICE_WIRED_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), NM_TYPE_DEVICE_WIRED, NMDeviceWiredPrivate))
+
+#define NM_DEVICE_WIRED_LOG_LEVEL(dev) ((nm_device_get_device_type (dev) == NM_DEVICE_TYPE_INFINIBAND) ? LOGD_INFINIBAND : LOGD_ETHER)
+
+typedef struct {
+	guint8              hw_addr[NM_UTILS_HWADDR_LEN_MAX];         /* Currently set MAC address */
+	guint               hw_addr_type;
+	guint               hw_addr_len;
+	gboolean            carrier;
+	guint32             speed;
+
+	NMNetlinkMonitor *  monitor;
+	gulong              link_connected_id;
+	gulong              link_disconnected_id;
+	guint               carrier_action_defer_id;
+
+} NMDeviceWiredPrivate;
+
+
+/* Returns speed in Mb/s */
+static guint32
+ethtool_get_speed (NMDeviceWired *self)
+{
+	int fd;
+	struct ifreq ifr;
+	struct ethtool_cmd edata = {
+		.cmd = ETHTOOL_GSET,
+	};
+	guint32 speed = 0;
+
+	g_return_val_if_fail (self != NULL, 0);
+
+	fd = socket (PF_INET, SOCK_DGRAM, 0);
+	if (fd < 0) {
+		nm_log_warn (LOGD_HW, "couldn't open control socket.");
+		return 0;
+	}
+
+	memset (&ifr, 0, sizeof (struct ifreq));
+	strncpy (ifr.ifr_name, nm_device_get_iface (NM_DEVICE (self)), IFNAMSIZ);
+	ifr.ifr_data = (char *) &edata;
+
+	if (ioctl (fd, SIOCETHTOOL, &ifr) < 0)
+		goto out;
+
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,27)
+	speed = edata.speed;
+#else
+	speed = ethtool_cmd_speed (&edata);
+#endif
+
+	if (speed == G_MAXUINT16 || speed == G_MAXUINT32)
+		speed = 0;
+
+out:
+	close (fd);
+	return speed;
+}
+
+static void
+set_speed (NMDeviceWired *self, const guint32 speed)
+{
+	NMDeviceWiredPrivate *priv;
+
+	g_return_if_fail (NM_IS_DEVICE (self));
+
+	priv = NM_DEVICE_WIRED_GET_PRIVATE (self);
+	if (priv->speed == speed)
+		return;
+
+	priv->speed = speed;
+	g_object_notify (G_OBJECT (self), "speed");
+
+	nm_log_dbg (LOGD_HW | NM_DEVICE_WIRED_LOG_LEVEL (NM_DEVICE (self)),
+	             "(%s): speed is now %d Mb/s",
+	             nm_device_get_iface (NM_DEVICE (self)),
+	             speed);
+}
+
+static void
+carrier_action_defer_clear (NMDeviceWired *self)
+{
+	NMDeviceWiredPrivate *priv = NM_DEVICE_WIRED_GET_PRIVATE (self);
+
+	if (priv->carrier_action_defer_id) {
+		g_source_remove (priv->carrier_action_defer_id);
+		priv->carrier_action_defer_id = 0;
+	}
+}
+
+static gboolean
+carrier_action_defer_cb (gpointer user_data)
+{
+	NMDeviceWired *self = NM_DEVICE_WIRED (user_data);
+	NMDeviceWiredPrivate *priv = NM_DEVICE_WIRED_GET_PRIVATE (self);
+	NMDeviceState state;
+
+	priv->carrier_action_defer_id = 0;
+
+	state = nm_device_get_state (NM_DEVICE (self));
+	if (state == NM_DEVICE_STATE_UNAVAILABLE) {
+		if (priv->carrier)
+			nm_device_queue_state (NM_DEVICE (self), NM_DEVICE_STATE_DISCONNECTED, NM_DEVICE_STATE_REASON_CARRIER);
+	} else if (state >= NM_DEVICE_STATE_DISCONNECTED) {
+		if (!priv->carrier)
+			nm_device_queue_state (NM_DEVICE (self), NM_DEVICE_STATE_UNAVAILABLE, NM_DEVICE_STATE_REASON_CARRIER);
+	}
+
+	return FALSE;
+}
+
+static void
+set_carrier (NMDeviceWired *self,
+             const gboolean carrier,
+             const gboolean defer_action)
+{
+	NMDeviceWiredPrivate *priv;
+	NMDeviceState state;
+
+	g_return_if_fail (NM_IS_DEVICE (self));
+
+	priv = NM_DEVICE_WIRED_GET_PRIVATE (self);
+	if (priv->carrier == carrier)
+		return;
+
+	/* Clear any previous deferred action */
+	carrier_action_defer_clear (self);
+
+	priv->carrier = carrier;
+	g_object_notify (G_OBJECT (self), "carrier");
+
+	state = nm_device_get_state (NM_DEVICE (self));
+	nm_log_info (LOGD_HW | NM_DEVICE_WIRED_LOG_LEVEL (NM_DEVICE (self)),
+	             "(%s): carrier now %s (device state %d%s)",
+	             nm_device_get_iface (NM_DEVICE (self)),
+	             carrier ? "ON" : "OFF",
+	             state,
+	             defer_action ? ", deferring action for 4 seconds" : "");
+
+	if (defer_action)
+		priv->carrier_action_defer_id = g_timeout_add_seconds (4, carrier_action_defer_cb, self);
+	else
+		carrier_action_defer_cb (self);
+}
+
+static void
+carrier_on (NMNetlinkMonitor *monitor,
+            int idx,
+            gpointer user_data)
+{
+	NMDevice *device = NM_DEVICE (user_data);
+	NMDeviceWired *self = NM_DEVICE_WIRED (device);
+	guint32 caps;
+
+	/* Make sure signal is for us */
+	if (idx == nm_device_get_ifindex (device)) {
+		/* Ignore spurious netlink messages */
+		caps = nm_device_get_capabilities (device);
+		if (!(caps & NM_DEVICE_CAP_CARRIER_DETECT))
+			return;
+
+		set_carrier (self, TRUE, FALSE);
+		set_speed (self, ethtool_get_speed (self));
+	}
+}
+
+static void
+carrier_off (NMNetlinkMonitor *monitor,
+             int idx,
+             gpointer user_data)
+{
+	NMDevice *device = NM_DEVICE (user_data);
+	NMDeviceWired *self = NM_DEVICE_WIRED (device);
+	guint32 caps;
+
+	/* Make sure signal is for us */
+	if (idx == nm_device_get_ifindex (device)) {
+		NMDeviceState state;
+		gboolean defer = FALSE;
+
+		/* Ignore spurious netlink messages */
+		caps = nm_device_get_capabilities (device);
+		if (!(caps & NM_DEVICE_CAP_CARRIER_DETECT))
+			return;
+
+		/* Defer carrier-off event actions while connected by a few seconds
+		 * so that tripping over a cable, power-cycling a switch, or breaking
+		 * off the RJ45 locking tab isn't so catastrophic.
+		 */
+		state = nm_device_get_state (device);
+		if (state > NM_DEVICE_STATE_DISCONNECTED)
+			defer = TRUE;
+
+		set_carrier (self, FALSE, defer);
+	}
+}
+
+static gboolean
+get_carrier_sync (NMDeviceWired *self)
+{
+	NMDeviceWiredPrivate *priv = NM_DEVICE_WIRED_GET_PRIVATE (self);
+	GError *error = NULL;
+	guint32 ifflags = 0;
+
+	/* Get initial link state */
+	if (!nm_netlink_monitor_get_flags_sync (priv->monitor,
+	                                        nm_device_get_ip_ifindex (NM_DEVICE (self)),
+	                                        &ifflags,
+	                                        &error)) {
+		nm_log_warn (LOGD_HW | NM_DEVICE_WIRED_LOG_LEVEL (NM_DEVICE (self)),
+		             "(%s): couldn't get carrier state: (%d) %s",
+		             nm_device_get_ip_iface (NM_DEVICE (self)),
+		             error ? error->code : -1,
+		             (error && error->message) ? error->message : "unknown");
+		g_clear_error (&error);
+	}
+
+	return !!(ifflags & IFF_LOWER_UP);
+}
+
+static GObject*
+constructor (GType type,
+			 guint n_construct_params,
+			 GObjectConstructParam *construct_params)
+{
+	GObject *object;
+	NMDeviceWiredPrivate *priv;
+	NMDevice *self;
+	guint32 caps;
+
+	object = G_OBJECT_CLASS (nm_device_wired_parent_class)->constructor (type,
+	                                                                     n_construct_params,
+	                                                                     construct_params);
+	if (!object)
+		return NULL;
+
+	self = NM_DEVICE (object);
+	priv = NM_DEVICE_WIRED_GET_PRIVATE (self);
+
+	nm_log_dbg (LOGD_HW | NM_DEVICE_WIRED_LOG_LEVEL (NM_DEVICE (self)),
+	            "(%s): kernel ifindex %d",
+	            nm_device_get_iface (NM_DEVICE (self)),
+	            nm_device_get_ifindex (NM_DEVICE (self)));
+
+	if (nm_device_get_device_type (self) == NM_DEVICE_TYPE_ETHERNET) {
+		priv->hw_addr_type = ARPHRD_ETHER;
+		priv->hw_addr_len = ETH_ALEN;
+	} else if (nm_device_get_device_type (self) == NM_DEVICE_TYPE_INFINIBAND) {
+		priv->hw_addr_type = ARPHRD_INFINIBAND;
+		priv->hw_addr_len = INFINIBAND_ALEN;
+	} else if (nm_device_get_device_type (self) == NM_DEVICE_TYPE_BOND) {
+		/* We may not know the hardware address type until a slave is added */
+		priv->hw_addr_type = ARPHRD_ETHER;
+		priv->hw_addr_len = ETH_ALEN;
+	} else
+		g_assert_not_reached ();
+
+	caps = nm_device_get_capabilities (self);
+	if (caps & NM_DEVICE_CAP_CARRIER_DETECT) {
+		/* Only listen to netlink for cards that support carrier detect */
+		priv->monitor = nm_netlink_monitor_get ();
+
+		priv->link_connected_id = g_signal_connect (priv->monitor, "carrier-on",
+		                                            G_CALLBACK (carrier_on),
+		                                            self);
+		priv->link_disconnected_id = g_signal_connect (priv->monitor, "carrier-off",
+		                                               G_CALLBACK (carrier_off),
+		                                               self);
+
+		priv->carrier = get_carrier_sync (NM_DEVICE_WIRED (self));
+
+		nm_log_info (LOGD_HW | NM_DEVICE_WIRED_LOG_LEVEL (NM_DEVICE (self)),
+		             "(%s): carrier is %s",
+		             nm_device_get_iface (NM_DEVICE (self)),
+		             priv->carrier ? "ON" : "OFF");
+
+		/* Request link state again just in case an error occurred getting the
+		 * initial link state.
+		 */
+		nm_netlink_monitor_request_status (priv->monitor);
+	} else {
+		nm_log_info (LOGD_HW | NM_DEVICE_WIRED_LOG_LEVEL (NM_DEVICE (self)),
+		             "(%s): driver '%s' does not support carrier detection.",
+		             nm_device_get_iface (self),
+		             nm_device_get_driver (self));
+		priv->carrier = TRUE;
+	}
+
+	return object;
+}
+
+static void
+nm_device_wired_init (NMDeviceWired * self)
+{
+}
+
+static gboolean
+real_hw_is_up (NMDevice *device)
+{
+	return nm_system_iface_is_up (nm_device_get_ip_ifindex (device));
+}
+
+static gboolean
+real_hw_bring_up (NMDevice *dev, gboolean *no_firmware)
+{
+	gboolean success, carrier;
+
+	success = nm_system_iface_set_up (nm_device_get_ip_ifindex (dev), TRUE, no_firmware);
+	if (success) {
+		carrier = get_carrier_sync (NM_DEVICE_WIRED (dev));
+		set_carrier (NM_DEVICE_WIRED (dev), carrier, carrier ? FALSE : TRUE);
+	}
+	return success;
+}
+
+static void
+real_hw_take_down (NMDevice *dev)
+{
+	nm_system_iface_set_up (nm_device_get_ip_ifindex (dev), FALSE, NULL);
+}
+
+static void
+real_update_hw_address (NMDevice *dev)
+{
+	NMDeviceWired *self = NM_DEVICE_WIRED (dev);
+	NMDeviceWiredPrivate *priv = NM_DEVICE_WIRED_GET_PRIVATE (self);
+	struct rtnl_link *rtnl;
+	struct nl_addr *addr;
+
+	rtnl = nm_netlink_index_to_rtnl_link (nm_device_get_ip_ifindex (dev));
+	if (!rtnl) {
+		nm_log_err (LOGD_HW | NM_DEVICE_WIRED_LOG_LEVEL (dev),
+		            "(%s) failed to read hardware address (error %d)",
+		            nm_device_get_iface (dev), errno);
+		return;
+	}
+
+	addr = rtnl_link_get_addr (rtnl);
+	if (!addr) {
+		nm_log_err (LOGD_HW | NM_DEVICE_WIRED_LOG_LEVEL (dev),
+		            "(%s) no hardware address?",
+		            nm_device_get_iface (dev));
+		rtnl_link_put (rtnl);
+		return;
+	}
+
+	if (nl_addr_get_len (addr) != priv->hw_addr_len) {
+		nm_log_err (LOGD_HW | NM_DEVICE_WIRED_LOG_LEVEL (dev),
+		            "(%s) hardware address is wrong length (expected %d got %d)",
+		            nm_device_get_iface (dev),
+		            priv->hw_addr_len, nl_addr_get_len (addr));
+	} else {
+		memcpy (&priv->hw_addr, nl_addr_get_binary_addr (addr),
+				priv->hw_addr_len);
+	}
+
+	rtnl_link_put (rtnl);
+}
+
+static gboolean
+real_can_interrupt_activation (NMDevice *dev)
+{
+	NMDeviceWired *self = NM_DEVICE_WIRED (dev);
+	gboolean interrupt = FALSE;
+
+	/* Devices that support carrier detect can interrupt activation
+	 * if the link becomes inactive.
+	 */
+	if (nm_device_get_capabilities (dev) & NM_DEVICE_CAP_CARRIER_DETECT) {
+		if (NM_DEVICE_WIRED_GET_PRIVATE (self)->carrier == FALSE)
+			interrupt = TRUE;
+	}
+	return interrupt;
+}
+
+static gboolean
+real_is_available (NMDevice *dev)
+{
+	NMDeviceWired *self = NM_DEVICE_WIRED (dev);
+
+	/* Can't do anything if there isn't a carrier */
+	if (!NM_DEVICE_WIRED_GET_PRIVATE (self)->carrier)
+		return FALSE;
+
+	return TRUE;
+}
+
+static NMConnection *
+connection_match_config (NMDevice *self, const GSList *connections)
+{
+	const GSList *iter;
+
+	for (iter = connections; iter; iter = iter->next) {
+		NMConnection *candidate = NM_CONNECTION (iter->data);
+
+		if (!nm_device_match_ip_config (self, candidate))
+			continue;
+
+		return candidate;
+	}
+
+	return NULL;
+}
+
+static void
+dispose (GObject *object)
+{
+	NMDeviceWired *self = NM_DEVICE_WIRED (object);
+	NMDeviceWiredPrivate *priv = NM_DEVICE_WIRED_GET_PRIVATE (self);
+
+	if (priv->link_connected_id) {
+		g_signal_handler_disconnect (priv->monitor, priv->link_connected_id);
+		priv->link_connected_id = 0;
+	}
+	if (priv->link_disconnected_id) {
+		g_signal_handler_disconnect (priv->monitor, priv->link_disconnected_id);
+		priv->link_disconnected_id = 0;
+	}
+
+	carrier_action_defer_clear (self);
+
+	if (priv->monitor) {
+		g_object_unref (priv->monitor);
+		priv->monitor = NULL;
+	}
+
+	G_OBJECT_CLASS (nm_device_wired_parent_class)->dispose (object);
+}
+
+static void
+nm_device_wired_class_init (NMDeviceWiredClass *klass)
+{
+	GObjectClass *object_class = G_OBJECT_CLASS (klass);
+	NMDeviceClass *parent_class = NM_DEVICE_CLASS (klass);
+
+	g_type_class_add_private (object_class, sizeof (NMDeviceWiredPrivate));
+
+	/* virtual methods */
+	object_class->constructor = constructor;
+	object_class->dispose = dispose;
+
+	parent_class->hw_is_up = real_hw_is_up;
+	parent_class->hw_bring_up = real_hw_bring_up;
+	parent_class->hw_take_down = real_hw_take_down;
+	parent_class->can_interrupt_activation = real_can_interrupt_activation;
+	parent_class->update_hw_address = real_update_hw_address;
+	parent_class->is_available = real_is_available;
+	parent_class->connection_match_config = connection_match_config;
+}
+
+/**
+ * nm_device_wired_get_hwaddr:
+ * @dev: an #NMDeviceWired
+ *
+ * Get a device's hardware address
+ *
+ * Returns: (transfer none): @dev's hardware address
+ */
+const guint8 *
+nm_device_wired_get_hwaddr (NMDeviceWired *dev)
+{
+	NMDeviceWiredPrivate *priv;
+
+	g_return_val_if_fail (dev != NULL, NULL);
+
+	priv = NM_DEVICE_WIRED_GET_PRIVATE (dev);
+	return priv->hw_addr;
+}
+
+/**
+ * nm_device_wired_set_hwaddr:
+ * @dev: an #NMDeviceWired
+ * @addr: the new hardware address, @addrlen bytes in length
+ * @addrlen: the length in bytes of @addr
+ *
+ * Sets the device's hardware address.
+ */
+void
+nm_device_wired_set_hwaddr (NMDeviceWired *dev,
+                            const guint8 *addr,
+                            guint addrlen)
+{
+	NMDeviceWiredPrivate *priv;
+
+	g_return_if_fail (dev != NULL);
+	g_return_if_fail (addr != NULL);
+
+	priv = NM_DEVICE_WIRED_GET_PRIVATE (dev);
+	g_return_if_fail (addrlen == priv->hw_addr_len);
+
+	memcpy (priv->hw_addr, addr, priv->hw_addr_len);
+}
+
+/**
+ * nm_device_wired_get_hwaddr_type:
+ * @dev: an #NMDeviceWired
+ *
+ * Get the type of a device's hardware address
+ *
+ * Returns: the type of @dev's hardware address
+ */
+int
+nm_device_wired_get_hwaddr_type (NMDeviceWired *dev)
+{
+	NMDeviceWiredPrivate *priv;
+
+	g_return_val_if_fail (dev != NULL, -1);
+
+	priv = NM_DEVICE_WIRED_GET_PRIVATE (dev);
+	return priv->hw_addr_type;
+}
+
+/**
+ * nm_device_wired_get_carrier:
+ * @dev: an #NMDeviceWired
+ *
+ * Get @dev's carrier status
+ *
+ * Return value: @dev's carrier
+ */
+gboolean
+nm_device_wired_get_carrier (NMDeviceWired *dev)
+{
+	NMDeviceWiredPrivate *priv;
+
+	g_return_val_if_fail (dev != NULL, FALSE);
+
+	priv = NM_DEVICE_WIRED_GET_PRIVATE (dev);
+	return priv->carrier;
+}
+
+/**
+ * nm_device_wired_get_speed:
+ * @dev: an #NMDeviceWired
+ *
+ * Get @dev's speed
+ *
+ * Return value: @dev's speed in Mb/s
+ */
+guint32
+nm_device_wired_get_speed (NMDeviceWired *dev)
+{
+	NMDeviceWiredPrivate *priv;
+
+	g_return_val_if_fail (dev != NULL, 0);
+
+	priv = NM_DEVICE_WIRED_GET_PRIVATE (dev);
+	return priv->speed;
+}
diff --git a/src/nm-device-wired.h b/src/nm-device-wired.h
new file mode 100644
index 00000000..3180ee45
--- /dev/null
+++ b/src/nm-device-wired.h
@@ -0,0 +1,59 @@
+/* -*- 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) 2005 - 2012 Red Hat, Inc.
+ * Copyright (C) 2006 - 2008 Novell, Inc.
+ */
+
+#ifndef NM_DEVICE_WIRED_H
+#define NM_DEVICE_WIRED_H
+
+#include <glib-object.h>
+
+#include "nm-device.h"
+
+G_BEGIN_DECLS
+
+#define NM_TYPE_DEVICE_WIRED			(nm_device_wired_get_type ())
+#define NM_DEVICE_WIRED(obj)			(G_TYPE_CHECK_INSTANCE_CAST ((obj), NM_TYPE_DEVICE_WIRED, NMDeviceWired))
+#define NM_DEVICE_WIRED_CLASS(klass)	(G_TYPE_CHECK_CLASS_CAST ((klass),  NM_TYPE_DEVICE_WIRED, NMDeviceWiredClass))
+#define NM_IS_DEVICE_WIRED(obj)		(G_TYPE_CHECK_INSTANCE_TYPE ((obj), NM_TYPE_DEVICE_WIRED))
+#define NM_IS_DEVICE_WIRED_CLASS(klass)	(G_TYPE_CHECK_CLASS_TYPE ((klass),  NM_TYPE_DEVICE_WIRED))
+#define NM_DEVICE_WIRED_GET_CLASS(obj)	(G_TYPE_INSTANCE_GET_CLASS ((obj),  NM_TYPE_DEVICE_WIRED, NMDeviceWiredClass))
+
+typedef struct {
+	NMDevice parent;
+} NMDeviceWired;
+
+typedef struct {
+	NMDeviceClass parent;
+
+} NMDeviceWiredClass;
+
+GType nm_device_wired_get_type (void);
+
+const guint8 *nm_device_wired_get_hwaddr      (NMDeviceWired *dev);
+void          nm_device_wired_set_hwaddr      (NMDeviceWired *dev,
+                                               const guint8 *addr,
+                                               guint addrlen);
+int           nm_device_wired_get_hwaddr_type (NMDeviceWired *dev);
+gboolean      nm_device_wired_get_carrier     (NMDeviceWired *dev);
+guint32       nm_device_wired_get_speed       (NMDeviceWired *dev);
+
+G_END_DECLS
+
+#endif	/* NM_DEVICE_WIRED_H */
diff --git a/src/nm-device.c b/src/nm-device.c
index 95f07e44..1dc94ee9 100644
--- a/src/nm-device.c
+++ b/src/nm-device.c
@@ -15,7 +15,7 @@
  * with this program; if not, write to the Free Software Foundation, Inc.,
  * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
  *
- * Copyright (C) 2005 - 2011 Red Hat, Inc.
+ * Copyright (C) 2005 - 2012 Red Hat, Inc.
  * Copyright (C) 2006 - 2008 Novell, Inc.
  */
 
@@ -36,9 +36,9 @@
 #include <linux/if.h>
 
 #include "nm-glib-compat.h"
-#include "nm-device-interface.h"
 #include "nm-device.h"
 #include "nm-device-private.h"
+#include "backends/nm-backend.h"
 #include "NetworkManagerUtils.h"
 #include "nm-system.h"
 #include "nm-dhcp-manager.h"
@@ -57,31 +57,91 @@
 #include "nm-ip6-manager.h"
 #include "nm-marshal.h"
 #include "nm-rfkill.h"
+#include "nm-firewall-manager.h"
+#include "nm-properties-changed-signal.h"
+#include "nm-enum-types.h"
+#include "nm-settings-connection.h"
 
-#define NM_ACT_REQUEST_IP4_CONFIG "nm-act-request-ip4-config"
-#define NM_ACT_REQUEST_IP6_CONFIG "nm-act-request-ip6-config"
+static void impl_device_disconnect (NMDevice *device, DBusGMethodInvocation *context);
 
-static void device_interface_init (NMDeviceInterface *device_interface_class);
+#include "nm-device-interface-glue.h"
 
-G_DEFINE_TYPE_EXTENDED (NMDevice, nm_device, G_TYPE_OBJECT, G_TYPE_FLAG_ABSTRACT,
-						G_IMPLEMENT_INTERFACE (NM_TYPE_DEVICE_INTERFACE, device_interface_init))
+#define PENDING_IP4_CONFIG "pending-ip4-config"
+#define PENDING_IP6_CONFIG "pending-ip6-config"
+
+#define DBUS_G_TYPE_UINT_STRUCT (dbus_g_type_get_struct ("GValueArray", G_TYPE_UINT, G_TYPE_UINT, G_TYPE_INVALID))
+
+/***********************************************************/
+#define NM_DEVICE_ERROR (nm_device_error_quark ())
+
+static GQuark
+nm_device_error_quark (void)
+{
+	static GQuark quark = 0;
+	if (!quark)
+		quark = g_quark_from_static_string ("nm-device-error");
+	return quark;
+}
+
+/***********************************************************/
 
 enum {
+	STATE_CHANGED,
+	DISCONNECT_REQUEST,
 	AUTOCONNECT_ALLOWED,
 	LAST_SIGNAL,
 };
-
 static guint signals[LAST_SIGNAL] = { 0 };
 
+enum {
+	PROP_0,
+	PROP_UDI,
+	PROP_IFACE,
+	PROP_IP_IFACE,
+	PROP_DRIVER,
+	PROP_CAPABILITIES,
+	PROP_IP4_ADDRESS,
+	PROP_IP4_CONFIG,
+	PROP_DHCP4_CONFIG,
+	PROP_IP6_CONFIG,
+	PROP_DHCP6_CONFIG,
+	PROP_STATE,
+	PROP_STATE_REASON,
+	PROP_ACTIVE_CONNECTION,
+	PROP_DEVICE_TYPE,
+	PROP_MANAGED,
+	PROP_FIRMWARE_MISSING,
+	PROP_TYPE_DESC,
+	PROP_RFKILL_TYPE,
+	PROP_IFINDEX,
+	LAST_PROP
+};
+
+/***********************************************************/
+
+G_DEFINE_ABSTRACT_TYPE (NMDevice, nm_device, G_TYPE_OBJECT)
+
 #define NM_DEVICE_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), NM_TYPE_DEVICE, NMDevicePrivate))
 
+typedef enum {
+	IP_NONE = 0,
+	IP_CONF,
+	IP_DONE
+} IpState;
+
+typedef struct {
+	NMDeviceState state;
+	NMDeviceStateReason reason;
+	guint id;
+} QueuedState;
+
 typedef struct {
 	gboolean disposed;
 	gboolean initialized;
 
 	NMDeviceState state;
-	guint         failed_to_disconnected_id;
-	guint         unavailable_to_disconnected_id;
+	NMDeviceStateReason state_reason;
+	QueuedState   queued_state;
 
 	char *        udi;
 	char *        path;
@@ -104,12 +164,11 @@ typedef struct {
 	gpointer        act_source_func;
 	guint           act_source6_id;
 	gpointer        act_source6_func;
+	guint           act_dep_result_id;
+	guint           act_dep_timeout_id;
 	gulong          secrets_updated_id;
 	gulong          secrets_failed_id;
 
-	gboolean        ip4_ready;
-	gboolean        ip6_ready;
-
 	/* Generic DHCP stuff */
 	NMDHCPManager * dhcp_manager;
 	guint32         dhcp_timeout;
@@ -117,6 +176,7 @@ typedef struct {
 
 	/* IP4 configuration info */
 	NMIP4Config *   ip4_config;			/* Config from DHCP, PPP, or system config files */
+	IpState         ip4_state;
 	NMDHCPClient *  dhcp4_client;
 	gulong          dhcp4_state_sigid;
 	gulong          dhcp4_timeout_sigid;
@@ -126,45 +186,47 @@ typedef struct {
 	NMDnsMasqManager *dnsmasq_manager;
 	gulong            dnsmasq_state_id;
 
+	/* Firewall Manager */
+	NMFirewallManager *fw_manager;
+	DBusGProxyCall    *fw_call;
+
 	/* avahi-autoipd stuff */
 	GPid    aipd_pid;
 	guint   aipd_watch;
 	guint   aipd_timeout;
-	guint32 aipd_addr;
 
 	/* IP6 configuration info */
 	NMIP6Config *  ip6_config;
+	IpState        ip6_state;
+
 	NMIP6Manager * ip6_manager;
 	gulong         ip6_addrconf_sigid;
 	gulong         ip6_config_changed_sigid;
 	gboolean       ip6_waiting_for_config;
+	/* IP6 config from autoconf */
+	NMIP6Config *  ac_ip6_config;
 
 	char *         ip6_accept_ra_path;
-	guint32        ip6_accept_ra_save;
+	gint32         ip6_accept_ra_save;
+
+	/* IPv6 privacy extensions (RFC4941) */
+	char *         ip6_privacy_tempaddr_path;
+	gint32         ip6_privacy_tempaddr_save;
 
 	NMDHCPClient *  dhcp6_client;
 	guint32         dhcp6_mode;
 	gulong          dhcp6_state_sigid;
 	gulong          dhcp6_timeout_sigid;
 	NMDHCP6Config * dhcp6_config;
+	/* IP6 config from DHCP */
+	NMIP6Config *   dhcp6_ip6_config;
 
 	/* inhibit autoconnect feature */
 	gboolean	autoconnect_inhibit;
-} NMDevicePrivate;
-
-static gboolean check_connection_compatible (NMDeviceInterface *device,
-                                             NMConnection *connection,
-                                             GError **error);
-static gboolean nm_device_activate (NMDeviceInterface *device,
-                                    NMActRequest *req,
-                                    GError **error);
-static void nm_device_deactivate (NMDeviceInterface *device, NMDeviceStateReason reason);
-static gboolean device_disconnect (NMDeviceInterface *device, GError **error);
-static gboolean spec_match_list (NMDeviceInterface *device, const GSList *specs);
-static NMConnection *connection_match_config (NMDeviceInterface *device, const GSList *connections);
-static gboolean can_assume_connections (NMDeviceInterface *device);
 
-static void nm_device_activate_schedule_stage5_ip_config_commit (NMDevice *self, int family);
+	/* master interface for bridge, bond, vlan, etc */
+	NMDevice *	master;
+} NMDevicePrivate;
 
 static void nm_device_take_down (NMDevice *dev, gboolean wait, NMDeviceStateReason reason);
 
@@ -180,32 +242,12 @@ static gboolean nm_device_set_ip6_config (NMDevice *dev,
                                           gboolean assumed,
                                           NMDeviceStateReason *reason);
 
-static NMActStageReturn dhcp6_start (NMDevice *self,
-                                     NMConnection *connection,
-                                     guint32 dhcp_opt,
-                                     NMDeviceStateReason *reason);
+static gboolean nm_device_activate_ip6_config_commit (gpointer user_data);
 
-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)
-{
-	/* interface implementation */
-	device_interface_class->check_connection_compatible = check_connection_compatible;
-	device_interface_class->activate = nm_device_activate;
-	device_interface_class->deactivate = nm_device_deactivate;
-	device_interface_class->disconnect = device_disconnect;
-	device_interface_class->spec_match_list = spec_match_list;
-	device_interface_class->connection_match_config = connection_match_config;
-	device_interface_class->can_assume_connections = can_assume_connections;
-}
-
-
 static void
 nm_device_init (NMDevice *self)
 {
@@ -214,6 +256,7 @@ nm_device_init (NMDevice *self)
 	priv->type = NM_DEVICE_TYPE_UNKNOWN;
 	priv->capabilities = NM_DEVICE_CAP_NONE;
 	priv->state = NM_DEVICE_STATE_UNMANAGED;
+	priv->state_reason = NM_DEVICE_STATE_REASON_NONE;
 	priv->dhcp_timeout = 0;
 	priv->rfkill_type = RFKILL_TYPE_UNKNOWN;
 }
@@ -245,14 +288,50 @@ update_accept_ra_save (NMDevice *self)
 
 	/* Grab the original value of "accept_ra" so we can restore it when NM exits */
 	priv->ip6_accept_ra_path = new_path;
-	if (!nm_utils_get_proc_sys_net_value (priv->ip6_accept_ra_path,
-	                                      ip_iface,
-	                                      &priv->ip6_accept_ra_save)) {
+	if (!nm_utils_get_proc_sys_net_value_with_bounds (priv->ip6_accept_ra_path,
+	                                                  ip_iface,
+	                                                  &priv->ip6_accept_ra_save,
+	                                                  0, 1)) {
 		g_free (priv->ip6_accept_ra_path);
 		priv->ip6_accept_ra_path = NULL;
 	}
 }
 
+static void
+update_ip6_privacy_save (NMDevice *self)
+{
+	NMDevicePrivate *priv;
+	const char *ip_iface;
+	char *new_path;
+
+	g_return_if_fail (self != NULL);
+	g_return_if_fail (NM_IS_DEVICE (self));
+
+	priv = NM_DEVICE_GET_PRIVATE (self);
+	ip_iface = nm_device_get_ip_iface (self);
+
+	new_path = g_strdup_printf ("/proc/sys/net/ipv6/conf/%s/use_tempaddr", ip_iface);
+	g_assert (new_path);
+
+	if (priv->ip6_privacy_tempaddr_path) {
+		/* If the IP iface is different from before, use the new value */
+		if (!strcmp (new_path, priv->ip6_privacy_tempaddr_path)) {
+			g_free (new_path);
+			return;
+		}
+		g_free (priv->ip6_privacy_tempaddr_path);
+	}
+
+	/* Grab the original value of "use_tempaddr" so we can restore it when NM exits */
+	priv->ip6_privacy_tempaddr_path = new_path;
+	if (!nm_utils_get_proc_sys_net_value (priv->ip6_privacy_tempaddr_path,
+	                                      ip_iface,
+	                                      &priv->ip6_privacy_tempaddr_save)) {
+		g_free (priv->ip6_privacy_tempaddr_path);
+		priv->ip6_privacy_tempaddr_path = NULL;
+	}
+}
+
 static GObject*
 constructor (GType type,
 			 guint n_construct_params,
@@ -287,18 +366,12 @@ constructor (GType type,
 		goto error;
 	}
 
-	if (NM_DEVICE_GET_CLASS (dev)->update_hw_address)
-		NM_DEVICE_GET_CLASS (dev)->update_hw_address (dev);
-
-	if (NM_DEVICE_GET_CLASS (dev)->update_permanent_hw_address)
-		NM_DEVICE_GET_CLASS (dev)->update_permanent_hw_address (dev);
-
-	if (NM_DEVICE_GET_CLASS (dev)->update_initial_hw_address)
-		NM_DEVICE_GET_CLASS (dev)->update_initial_hw_address (dev);
-
 	priv->dhcp_manager = nm_dhcp_manager_get ();
 
+	priv->fw_manager = nm_firewall_manager_get ();
+
 	update_accept_ra_save (dev);
+	update_ip6_privacy_save (dev);
 
 	priv->initialized = TRUE;
 	return object;
@@ -308,6 +381,24 @@ error:
 	return NULL;
 }
 
+static void
+constructed (GObject *object)
+{
+	NMDevice *dev = NM_DEVICE (object);
+
+	if (NM_DEVICE_GET_CLASS (dev)->update_hw_address)
+		NM_DEVICE_GET_CLASS (dev)->update_hw_address (dev);
+
+	if (NM_DEVICE_GET_CLASS (dev)->update_permanent_hw_address)
+		NM_DEVICE_GET_CLASS (dev)->update_permanent_hw_address (dev);
+
+	if (NM_DEVICE_GET_CLASS (dev)->update_initial_hw_address)
+		NM_DEVICE_GET_CLASS (dev)->update_initial_hw_address (dev);
+
+	if (G_OBJECT_CLASS (nm_device_parent_class)->constructed)
+		G_OBJECT_CLASS (nm_device_parent_class)->constructed (object);
+}
+
 static gboolean
 nm_device_hw_is_up (NMDevice *self)
 {
@@ -412,14 +503,14 @@ nm_device_set_ip_iface (NMDevice *self, const char *iface)
 	priv->ip_iface = g_strdup (iface);
 	if (priv->ip_iface) {
 		priv->ip_ifindex = nm_netlink_iface_to_index (priv->ip_iface);
-		if (!priv->ip_ifindex) {
+		if (priv->ip_ifindex < 0) {
 			nm_log_warn (LOGD_HW, "(%s): failed to look up interface index", iface);
 		}
 	}
 
 	/* Emit change notification */
 	if (g_strcmp0 (old_ip_iface, priv->ip_iface))
-		g_object_notify (G_OBJECT (self), NM_DEVICE_INTERFACE_IP_IFACE);
+		g_object_notify (G_OBJECT (self), NM_DEVICE_IP_IFACE);
 	g_free (old_ip_iface);
 }
 
@@ -494,6 +585,51 @@ nm_device_get_type_desc (NMDevice *self)
 	return NM_DEVICE_GET_PRIVATE (self)->type_desc;
 }
 
+/**
+ * nm_device_enslave_slave:
+ * @dev: the master device
+ * @slave: the slave device to enslave
+ *
+ * If @dev is capable of enslaving other devices (ie it's a bridge, bond, etc)
+ * then this function enslaves @slave.
+ *
+ * Returns: %TRUE on success, %FALSE on failure or if this device cannot enslave
+ *  other devices.
+ */
+gboolean
+nm_device_enslave_slave (NMDevice *dev, NMDevice *slave)
+{
+	g_return_val_if_fail (dev != NULL, FALSE);
+	g_return_val_if_fail (slave != NULL, FALSE);
+	g_return_val_if_fail (nm_device_get_state (slave) >= NM_DEVICE_STATE_DISCONNECTED, FALSE);
+
+	if (NM_DEVICE_GET_CLASS (dev)->enslave_slave)
+		return NM_DEVICE_GET_CLASS (dev)->enslave_slave (dev, slave);
+	return FALSE;
+}
+
+/**
+ * nm_device_release_slave:
+ * @dev: the master device
+ * @slave: the slave device to release
+ *
+ * If @dev is capable of enslaving other devices (ie it's a bridge, bond, etc)
+ * then this function releases the previously enslaved @slave.
+ *
+ * Returns: %TRUE on success, %FALSE on failure, if this device cannot enslave
+ *  other devices, or if @slave was never enslaved.
+ */
+gboolean
+nm_device_release_slave (NMDevice *dev, NMDevice *slave)
+{
+	g_return_val_if_fail (dev != NULL, FALSE);
+	g_return_val_if_fail (slave != NULL, FALSE);
+
+	if (NM_DEVICE_GET_CLASS (dev)->release_slave)
+		return NM_DEVICE_GET_CLASS (dev)->release_slave (dev, slave);
+	return FALSE;
+}
+
 /*
  * nm_device_get_act_request
  *
@@ -508,6 +644,13 @@ nm_device_get_act_request (NMDevice *self)
 	return NM_DEVICE_GET_PRIVATE (self)->act_request;
 }
 
+NMConnection *
+nm_device_get_connection (NMDevice *self)
+{
+	NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE (self);
+
+	return priv->act_request ? nm_act_request_get_connection (priv->act_request) : NULL;
+}
 
 gboolean
 nm_device_is_available (NMDevice *self)
@@ -522,6 +665,36 @@ nm_device_is_available (NMDevice *self)
 	return TRUE;
 }
 
+gboolean
+nm_device_get_enabled (NMDevice *self)
+{
+	g_return_val_if_fail (self != NULL, FALSE);
+	g_return_val_if_fail (NM_IS_DEVICE (self), FALSE);
+
+	if (NM_DEVICE_GET_CLASS (self)->get_enabled)
+		return NM_DEVICE_GET_CLASS (self)->get_enabled (self);
+	return TRUE;
+}
+
+void
+nm_device_set_enabled (NMDevice *self, gboolean enabled)
+{
+	g_return_if_fail (self != NULL);
+	g_return_if_fail (NM_IS_DEVICE (self));
+
+	if (NM_DEVICE_GET_CLASS (self)->set_enabled)
+		NM_DEVICE_GET_CLASS (self)->set_enabled (self, enabled);
+}
+
+RfKillType
+nm_device_get_rfkill_type (NMDevice *self)
+{
+	g_return_val_if_fail (self != NULL, FALSE);
+	g_return_val_if_fail (NM_IS_DEVICE (self), FALSE);
+
+	return NM_DEVICE_GET_PRIVATE (self)->rfkill_type;
+}
+
 static gboolean
 autoconnect_allowed_accumulator (GSignalInvocationHint *ihint,
                                  GValue *return_accu,
@@ -589,9 +762,7 @@ nm_device_complete_connection (NMDevice *self,
 	g_return_val_if_fail (connection != NULL, FALSE);
 
 	if (!NM_DEVICE_GET_CLASS (self)->complete_connection) {
-		g_set_error (error,
-		             NM_DEVICE_INTERFACE_ERROR,
-		             NM_DEVICE_INTERFACE_ERROR_CONNECTION_INVALID,
+		g_set_error (error, NM_DEVICE_ERROR, NM_DEVICE_ERROR_CONNECTION_INVALID,
 		             "Device class %s had no complete_connection method",
 		             G_OBJECT_TYPE_NAME (self));
 		return FALSE;
@@ -605,9 +776,41 @@ nm_device_complete_connection (NMDevice *self,
 	if (success)
 		success = nm_connection_verify (connection, error);
 
+	/* If ip6-privacy is unknown, enable it with temporary address preferred */
+	if (success) {
+		NMSettingIP6Config *s_ip6 = nm_connection_get_setting_ip6_config (connection);
+		if (s_ip6 && nm_setting_ip6_config_get_ip6_privacy (s_ip6) == NM_SETTING_IP6_CONFIG_PRIVACY_UNKNOWN)
+			g_object_set (s_ip6, NM_SETTING_IP6_CONFIG_IP6_PRIVACY,
+			              NM_SETTING_IP6_CONFIG_PRIVACY_PREFER_TEMP_ADDR, NULL);
+	}
+
 	return success;
 }
 
+gboolean
+nm_device_check_connection_compatible (NMDevice *device,
+                                       NMConnection *connection,
+                                       GError **error)
+{
+	g_return_val_if_fail (device != NULL, FALSE);
+	g_return_val_if_fail (NM_IS_DEVICE (device), FALSE);
+	g_return_val_if_fail (connection != NULL, FALSE);
+	g_return_val_if_fail (NM_IS_CONNECTION (connection), FALSE);
+
+	if (NM_DEVICE_GET_CLASS (device)->check_connection_compatible)
+		return NM_DEVICE_GET_CLASS (device)->check_connection_compatible (device, connection, error);
+	return TRUE;
+}
+
+gboolean
+nm_device_can_assume_connections (NMDevice *device)
+{
+	g_return_val_if_fail (device != NULL, FALSE);
+	g_return_val_if_fail (NM_IS_DEVICE (device), FALSE);
+
+	return !!NM_DEVICE_GET_CLASS (device)->connection_match_config;
+}
+
 static void
 dnsmasq_state_changed_cb (NMDnsMasqManager *manager, guint32 status, gpointer user_data)
 {
@@ -679,25 +882,22 @@ activation_source_schedule (NMDevice *self, GSourceFunc func, int family)
 gboolean
 nm_device_ip_config_should_fail (NMDevice *self, gboolean ip6)
 {
-	NMActRequest *req;
 	NMConnection *connection;
 	NMSettingIP4Config *s_ip4;
 	NMSettingIP6Config *s_ip6;
 
 	g_return_val_if_fail (self != NULL, TRUE);
 
-	req = nm_device_get_act_request (self);
-	g_assert (req);
-	connection = nm_act_request_get_connection (req);
+	connection = nm_device_get_connection (self);
 	g_assert (connection);
 
 	/* Fail the connection if the failed IP method is required to complete */
 	if (ip6) {
-		s_ip6 = (NMSettingIP6Config *) nm_connection_get_setting (connection, NM_TYPE_SETTING_IP6_CONFIG);
+		s_ip6 = nm_connection_get_setting_ip6_config (connection);
 		if (s_ip6 && !nm_setting_ip6_config_get_may_fail (s_ip6))
 			return TRUE;
 	} else {
-		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 && !nm_setting_ip4_config_get_may_fail (s_ip4))
 			return TRUE;
 	}
@@ -705,185 +905,48 @@ nm_device_ip_config_should_fail (NMDevice *self, gboolean ip6)
 	return FALSE;
 }
 
-static void
-ip6_addrconf_complete (NMIP6Manager *ip6_manager,
-                       int ifindex,
-                       guint dhcp_opts,
-                       gboolean success,
-                       gpointer user_data)
-{
-	NMDevice *self = NM_DEVICE (user_data);
-	NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE (self);
-	NMActRequest *req;
-	NMConnection *connection;
-	NMActStageReturn ret;
-	NMDeviceStateReason reason = NM_DEVICE_STATE_REASON_NONE;
-	NMDeviceState state;
-
-	if (ifindex != nm_device_get_ip_ifindex (self))
-		return;
-	req = nm_device_get_act_request (self);
-	if (!req)
-		return;
-	connection = nm_act_request_get_connection (req);
-	g_assert (connection);
-
-	if (!priv->ip6_waiting_for_config)
-		return;
-
-	priv->ip6_waiting_for_config = FALSE;
-
-	if (!success) {
-		nm_device_activate_schedule_stage4_ip6_config_timeout (self);
-		return;
-	}
-
-	priv->dhcp6_mode = dhcp_opts;
-
-	/* If addrconf is all that's required, we're done */
-	if (priv->dhcp6_mode == IP6_DHCP_OPT_NONE) {
-		nm_device_activate_schedule_stage4_ip6_config_get (self);
-		return;
-	}
-
-	/* If the router said to use DHCP for managed or otherconf, do it */
-
-	/* Don't re-start DHCPv6 if it's already in progress */
-	state = nm_device_interface_get_state (NM_DEVICE_INTERFACE (self));
-	if ((state != NM_DEVICE_STATE_IP_CONFIG) || priv->dhcp6_client)
-		return;
-
-	nm_log_info (LOGD_DEVICE | LOGD_DHCP6,
-	             "Activation (%s) Stage 3 of 5 (IP Configure Start) starting DHCPv6"
-	             " as requested by IPv6 router...",
-	             priv->iface);
-
-	ret = dhcp6_start (self, connection, priv->dhcp6_mode, &reason);
-	switch (ret) {
-	case NM_ACT_STAGE_RETURN_SUCCESS:
-		/* Shouldn't get this, but handle it anyway */
-		g_warn_if_reached ();
-		nm_device_activate_schedule_stage4_ip6_config_get (self);
-		break;
-	case NM_ACT_STAGE_RETURN_POSTPONE:
-		/* Success; wait for DHCPv6 to complete */
-		break;
-	default:
-		nm_device_state_changed (self, NM_DEVICE_STATE_FAILED, reason);
-		break;
-	}
-}
-
-static void
-ip6_config_changed (NMIP6Manager *ip6_manager,
-                    int ifindex,
-                    guint dhcp_opts,
-                    gboolean success,
-                    gpointer user_data)
-{
-	NMDevice *self = NM_DEVICE (user_data);
-
-	if (ifindex != nm_device_get_ip_ifindex (self))
-		return;
-	if (!nm_device_get_act_request (self))
-		return;
-
-	/* FIXME: re-run DHCPv6 here to get any new nameservers or whatever */
-
-	if (!success && (nm_device_get_state (self) == NM_DEVICE_STATE_ACTIVATED)) {
-		nm_device_state_changed (self,
-		                         NM_DEVICE_STATE_FAILED,
-		                         NM_DEVICE_STATE_REASON_IP_CONFIG_UNAVAILABLE);
-		return;
-	}
-
-	nm_device_activate_schedule_stage4_ip6_config_get (self);
-}
-
 static gboolean
 ip6_method_matches (NMConnection *connection, const char *match)
 {
 	NMSettingIP6Config *s_ip6;
 	const char *method = NULL;
 
-	s_ip6 = (NMSettingIP6Config *) nm_connection_get_setting (connection, NM_TYPE_SETTING_IP6_CONFIG);
+	s_ip6 = nm_connection_get_setting_ip6_config (connection);
 	if (s_ip6) {
 		method = nm_setting_ip6_config_get_method (s_ip6);
 		g_assert (method);
 	}
 
-	/* Treat missing IP6 setting as IGNORE */
-	if (!s_ip6 && !strcmp (match, NM_SETTING_IP6_CONFIG_METHOD_IGNORE))
+	/* Treat missing IP6 setting as AUTO */
+	if (!s_ip6 && !strcmp (match, NM_SETTING_IP6_CONFIG_METHOD_AUTO))
 		return TRUE;
 
 	return method && !strcmp (method, match);
 }
 
-static gboolean
-addrconf6_setup (NMDevice *self)
+static NMActStageReturn
+real_act_stage1_prepare (NMDevice *self, NMDeviceStateReason *reason)
 {
-	NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE (self);
 	NMActRequest *req;
-	NMConnection *connection;
-	NMSettingIP6Config *s_ip6;
-	gboolean success;
+	NMActiveConnection *master_ac;
+	NMDevice *master;
+	NMActStageReturn ret = NM_ACT_STAGE_RETURN_SUCCESS;
 
 	req = nm_device_get_act_request (self);
 	g_assert (req);
-	connection = nm_act_request_get_connection (req);
-	g_assert (connection);
-
-	if (!priv->ip6_manager) {
-		priv->ip6_manager = nm_ip6_manager_get ();
-		priv->ip6_addrconf_sigid = g_signal_connect (priv->ip6_manager,
-		                                             "addrconf-complete",
-		                                             G_CALLBACK (ip6_addrconf_complete),
-		                                             self);
-		priv->ip6_config_changed_sigid = g_signal_connect (priv->ip6_manager,
-		                                                   "config-changed",
-		                                                   G_CALLBACK (ip6_config_changed),
-		                                                   self);
-	}
-
-	s_ip6 = (NMSettingIP6Config *) nm_connection_get_setting (connection, NM_TYPE_SETTING_IP6_CONFIG);
-	success = nm_ip6_manager_prepare_interface (priv->ip6_manager,
-	                                            nm_device_get_ip_ifindex (self),
-	                                            s_ip6,
-	                                            priv->ip6_accept_ra_path);
-	if (success)
-		priv->ip6_waiting_for_config = TRUE;
-
-	return success;
-}
-
-static void
-addrconf6_cleanup (NMDevice *self)
-{
-	NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE (self);
 
-	if (!priv->ip6_manager)
-		return;
+	/* If the interface is going to be a slave, let the master enslave it here */
+	master_ac = nm_act_request_get_dependency (req);
+	if (master_ac && NM_IS_ACT_REQUEST (master_ac)) {
+		/* FIXME: handle VPNs here too */
 
-	if (priv->ip6_addrconf_sigid) {
-		g_signal_handler_disconnect (priv->ip6_manager,
-		                             priv->ip6_addrconf_sigid);
-		priv->ip6_addrconf_sigid = 0;
-	}
-	if (priv->ip6_config_changed_sigid) {
-		g_signal_handler_disconnect (priv->ip6_manager,
-		                             priv->ip6_config_changed_sigid);
-		priv->ip6_config_changed_sigid = 0;
+		master = NM_DEVICE (nm_act_request_get_device (NM_ACT_REQUEST (master_ac)));
+		g_assert (master);
+		if (!nm_device_enslave_slave (master, self))
+			ret = NM_ACT_STAGE_RETURN_FAILURE;
 	}
 
-	nm_ip6_manager_cancel_addrconf (priv->ip6_manager, nm_device_get_ip_ifindex (self));
-	g_object_unref (priv->ip6_manager);
-	priv->ip6_manager = NULL;
-}
-
-static NMActStageReturn
-real_act_stage1_prepare (NMDevice *self, NMDeviceStateReason *reason)
-{
-	return NM_ACT_STAGE_RETURN_SUCCESS;
+	return ret;
 }
 
 /*
@@ -904,7 +967,12 @@ nm_device_activate_stage1_device_prepare (gpointer user_data)
 	/* Clear the activation source ID now that this stage has run */
 	activation_source_clear (self, FALSE, 0);
 
-	priv->ip4_ready = priv->ip6_ready = FALSE;
+	if (priv->act_dep_timeout_id) {
+		g_source_remove (priv->act_dep_timeout_id);
+		priv->act_dep_timeout_id = 0;
+	}
+
+	priv->ip4_state = priv->ip6_state = IP_NONE;
 
 	iface = nm_device_get_iface (self);
 	nm_log_info (LOGD_DEVICE, "Activation (%s) Stage 1 of 5 (Device Prepare) started...", iface);
@@ -1029,6 +1097,9 @@ nm_device_activate_schedule_stage2_device_config (NMDevice *self)
 	         nm_device_get_iface (self));
 }
 
+/*********************************************/
+/* avahi-autoipd stuff */
+
 static void
 aipd_timeout_remove (NMDevice *self)
 {
@@ -1062,28 +1133,20 @@ aipd_cleanup (NMDevice *self)
 	}
 
 	aipd_timeout_remove (self);
-
-	priv->aipd_addr = 0;
 }
 
 static NMIP4Config *
-aipd_get_ip4_config (NMDevice *self, NMDeviceStateReason *reason)
+aipd_get_ip4_config (NMDevice *self, struct in_addr lla)
 {
-	NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE (self);
 	NMIP4Config *config = NULL;
 	NMIP4Address *addr;
 	NMIP4Route *route;
 
-	g_return_val_if_fail (priv->aipd_addr > 0, NULL);
-
 	config = nm_ip4_config_new ();
-	if (!config) {
-		*reason = NM_DEVICE_STATE_REASON_IP_CONFIG_UNAVAILABLE;
-		return NULL;
-	}
+	g_assert (config);
 
 	addr = nm_ip4_address_new ();
-	nm_ip4_address_set_address (addr, (guint32) priv->aipd_addr);
+	nm_ip4_address_set_address (addr, (guint32) lla.s_addr);
 	nm_ip4_address_set_prefix (addr, 16);
 	nm_ip4_config_take_address (config, addr);
 
@@ -1098,35 +1161,19 @@ aipd_get_ip4_config (NMDevice *self, NMDeviceStateReason *reason)
 	return config;	
 }
 
-static gboolean
-handle_autoip_change (NMDevice *self, NMDeviceStateReason *reason)
+static void
+autoip_changed (NMDevice *self,
+                NMIP4Config *config,
+                NMSettingIP4Config *s_ip4)
 {
-	NMActRequest *req;
-	NMConnection *connection;
-	NMIP4Config *config;
-
-	g_return_val_if_fail (reason != NULL, FALSE);
-
-	config = aipd_get_ip4_config (self, reason);
-	if (!config) {
-		nm_log_err (LOGD_AUTOIP4, "failed to get autoip config for rebind");
-		return FALSE;
-	}
-
-	req = nm_device_get_act_request (self);
-	g_assert (req);
-	connection = nm_act_request_get_connection (req);
-	g_assert (connection);
-
-	g_object_set_data (G_OBJECT (req), NM_ACT_REQUEST_IP4_CONFIG, config);
+	NMDeviceStateReason reason = NM_DEVICE_STATE_REASON_NONE;
 
-	if (!nm_device_set_ip4_config (self, config, FALSE, reason)) {
+	nm_utils_merge_ip4_config (config, s_ip4);
+	if (!nm_device_set_ip4_config (self, config, FALSE, &reason)) {
 		nm_log_err (LOGD_AUTOIP4, "(%s): failed to update IP4 config in response to autoip event.",
-		            nm_device_get_iface (self));
-		return FALSE;
+			        nm_device_get_iface (self));
+		nm_device_state_changed (self, NM_DEVICE_STATE_FAILED, reason);
 	}
-
-	return TRUE;
 }
 
 #define IPV4LL_NETWORK (htonl (0xA9FE0000L))
@@ -1138,74 +1185,62 @@ nm_device_handle_autoip4_event (NMDevice *self,
                                 const char *address)
 {
 	NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE (self);
-	NMActRequest *req;
 	NMConnection *connection = NULL;
 	NMSettingIP4Config *s_ip4 = NULL;
-	NMDeviceState state;
 	const char *iface, *method = NULL;
 
 	g_return_if_fail (event != NULL);
 
-	req = nm_device_get_act_request (self);
-	if (!req)
+	if (priv->act_request == NULL)
 		return;
 
-	connection = nm_act_request_get_connection (req);
-	if (!connection)
-		return;
+	connection = nm_act_request_get_connection (priv->act_request);
+	g_assert (connection);
 
 	/* Ignore if the connection isn't an AutoIP connection */
-	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)
 		method = nm_setting_ip4_config_get_method (s_ip4);
 
-	if (!s_ip4 || !method || strcmp (method, NM_SETTING_IP4_CONFIG_METHOD_LINK_LOCAL))
+	if (g_strcmp0 (method, NM_SETTING_IP4_CONFIG_METHOD_LINK_LOCAL) != 0)
 		return;
 
 	iface = nm_device_get_iface (self);
-	state = nm_device_get_state (self);
 
 	if (strcmp (event, "BIND") == 0) {
-		struct in_addr ip;
-		NMDeviceStateReason reason = NM_DEVICE_STATE_REASON_NONE;
+		struct in_addr lla;
+		NMIP4Config *config;
 
-		if (inet_pton (AF_INET, address, &ip) <= 0) {
+		if (inet_pton (AF_INET, address, &lla) <= 0) {
 			nm_log_err (LOGD_AUTOIP4, "(%s): invalid address %s received from avahi-autoipd.",
 			            iface, address);
 			nm_device_state_changed (self, NM_DEVICE_STATE_FAILED, NM_DEVICE_STATE_REASON_AUTOIP_ERROR);
 			return;
 		}
 
-		if ((ip.s_addr & IPV4LL_NETMASK) != IPV4LL_NETWORK) {
+		if ((lla.s_addr & IPV4LL_NETMASK) != IPV4LL_NETWORK) {
 			nm_log_err (LOGD_AUTOIP4, "(%s): invalid address %s received from avahi-autoipd (not link-local).",
 			            iface, address);
 			nm_device_state_changed (self, NM_DEVICE_STATE_FAILED, NM_DEVICE_STATE_REASON_AUTOIP_ERROR);
 			return;
 		}
 
-		switch (state) {
-		case NM_DEVICE_STATE_IP_CONFIG:
-			if (priv->aipd_addr) {
-				nm_log_warn (LOGD_AUTOIP4, "(%s): already have autoip address!", iface);
-				return;
-			}
+		config = aipd_get_ip4_config (self, lla);
+		if (config == NULL) {
+			nm_log_err (LOGD_AUTOIP4, "failed to get autoip config");
+			nm_device_state_changed (self, NM_DEVICE_STATE_FAILED, NM_DEVICE_STATE_REASON_IP_CONFIG_UNAVAILABLE);
+			return;
+		}
 
-			priv->aipd_addr = ip.s_addr;
+		if (priv->ip4_state == IP_CONF) {
 			aipd_timeout_remove (self);
-			nm_device_activate_schedule_stage4_ip4_config_get (self);
-			break;
-		case NM_DEVICE_STATE_IP_CHECK:
-		case NM_DEVICE_STATE_SECONDARIES:
-		case NM_DEVICE_STATE_ACTIVATED:
-			priv->aipd_addr = ip.s_addr;
-			if (!handle_autoip_change (self, &reason))
-				nm_device_state_changed (self, NM_DEVICE_STATE_FAILED, reason);
-			break;
-		default:
-			nm_log_warn (LOGD_AUTOIP4, "(%s): unexpected avahi-autoip event %s for %s.",
-			            iface, event, address);
-			break;
-		}
+			nm_device_activate_schedule_ip4_config_result (self, config);
+		} else if (priv->ip4_state == IP_DONE) {
+			autoip_changed (self, config, s_ip4);
+		} else
+			g_assert_not_reached ();
+
+		g_object_unref (config);
 	} else {
 		nm_log_warn (LOGD_AUTOIP4, "(%s): autoip address %s no longer valid because '%s'.",
 		            iface, address, event);
@@ -1255,15 +1290,14 @@ aipd_timeout_cb (gpointer user_data)
 	NMDevice *self = NM_DEVICE (user_data);
 	NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE (self);
 
-	if (!priv->aipd_timeout)
-		return FALSE;
-	priv->aipd_timeout = 0;
-
-	nm_log_info (LOGD_AUTOIP4, "(%s): avahi-autoipd timed out.", nm_device_get_iface (self));
-	aipd_cleanup (self);
+	if (priv->aipd_timeout) {
+		nm_log_info (LOGD_AUTOIP4, "(%s): avahi-autoipd timed out.", nm_device_get_iface (self));
+		priv->aipd_timeout = 0;
+		aipd_cleanup (self);
 
-	if (nm_device_get_state (self) == NM_DEVICE_STATE_IP_CONFIG)
-		nm_device_activate_schedule_stage4_ip4_config_timeout (self);
+		if (priv->ip4_state == IP_CONF)
+			nm_device_activate_schedule_ip4_config_timeout (self);
+	}
 
 	return FALSE;
 }
@@ -1279,12 +1313,12 @@ aipd_child_setup (gpointer user_data G_GNUC_UNUSED)
 	setpgid (pid, pid);
 }
 
-static gboolean
-aipd_exec (NMDevice *self, GError **error)
+static NMActStageReturn
+aipd_start (NMDevice *self, NMDeviceStateReason *reason)
 {
 	NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE (self);
+	const char *iface = nm_device_get_iface (self);
 	char *argv[6], *cmdline;
-	gboolean success = FALSE;
 	const char **aipd_binary = NULL;
 	static const char *aipd_paths[] = {
 		"/usr/sbin/avahi-autoipd",
@@ -1292,6 +1326,7 @@ aipd_exec (NMDevice *self, GError **error)
 		NULL
 	};
 	int i = 0;
+	GError *error = NULL;
 
 	aipd_cleanup (self);
 
@@ -1304,8 +1339,11 @@ aipd_exec (NMDevice *self, GError **error)
 	}
 
 	if (!*aipd_binary) {
-		g_set_error (error, 0, 0, "%s", "couldn't find avahi-autoipd");
-		return FALSE;
+		nm_log_warn (LOGD_DEVICE | LOGD_AUTOIP4,
+		             "Activation (%s) Stage 3 of 5 (IP Configure Start) failed"
+		             " to start avahi-autoipd: not found", iface);
+		*reason = NM_DEVICE_STATE_REASON_AUTOIP_START_FAILED;
+		return NM_ACT_STAGE_RETURN_FAILURE;
 	}
 
 	argv[i++] = (char *) (*aipd_binary);
@@ -1317,13 +1355,24 @@ aipd_exec (NMDevice *self, GError **error)
 	argv[i++] = NULL;
 
 	cmdline = g_strjoinv (" ", argv);
-	nm_log_dbg(LOGD_AUTOIP4, "running: %s", cmdline);
+	nm_log_dbg (LOGD_AUTOIP4, "running: %s", cmdline);
 	g_free (cmdline);
 
-	success = g_spawn_async ("/", argv, NULL, G_SPAWN_DO_NOT_REAP_CHILD,
-	                         &aipd_child_setup, NULL, &(priv->aipd_pid), error);
-	if (!success)
-		return FALSE;
+	if (!g_spawn_async ("/", argv, NULL, G_SPAWN_DO_NOT_REAP_CHILD,
+	                    &aipd_child_setup, NULL, &(priv->aipd_pid), &error)) {
+		nm_log_warn (LOGD_DEVICE | LOGD_AUTOIP4,
+		             "Activation (%s) Stage 3 of 5 (IP Configure Start) failed"
+		             " to start avahi-autoipd: %s",
+		             iface,
+		             error && error->message ? error->message : "(unknown)");
+		g_clear_error (&error);
+		aipd_cleanup (self);
+		return NM_ACT_STAGE_RETURN_FAILURE;
+	}
+
+	nm_log_info (LOGD_DEVICE | LOGD_AUTOIP4,
+	             "Activation (%s) Stage 3 of 5 (IP Configure Start) started"
+	             " avahi-autoipd...", iface);
 
 	/* Monitor the child process so we know when it dies */
 	priv->aipd_watch = g_child_watch_add (priv->aipd_pid, aipd_watch_cb, self);
@@ -1331,9 +1380,12 @@ aipd_exec (NMDevice *self, GError **error)
 	/* Start a timeout to bound the address attempt */
 	priv->aipd_timeout = g_timeout_add_seconds (20, aipd_timeout_cb, self);
 
-	return TRUE;
+	return NM_ACT_STAGE_RETURN_POSTPONE;
 }
 
+/*********************************************/
+/* DHCPv4 stuff */
+
 static void
 dhcp4_add_option_cb (gpointer key, gpointer value, gpointer user_data)
 {
@@ -1343,156 +1395,95 @@ dhcp4_add_option_cb (gpointer key, gpointer value, gpointer user_data)
 }
 
 static void
-dhcp6_add_option_cb (gpointer key, gpointer value, gpointer user_data)
+dhcp4_lease_change (NMDevice *device, NMIP4Config *config)
 {
-	nm_dhcp6_config_add_option (NM_DHCP6_CONFIG (user_data),
-	                            (const char *) key,
-	                            (const char *) value);
-}
-
-static void
-handle_dhcp_lease_change (NMDevice *device, gboolean ipv6)
-{
-	NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE (device);
-	NMIP4Config *ip4_config;
-	NMSettingIP4Config *s_ip4;
-	NMIP6Config *ip6_config;
-	NMSettingIP6Config *s_ip6;
 	NMConnection *connection;
-	NMActRequest *req;
 	NMDeviceStateReason reason = NM_DEVICE_STATE_REASON_NONE;
-	gboolean assumed;
 
-	req = nm_device_get_act_request (device);
-	g_assert (req);
-	connection = nm_act_request_get_connection (req);
+	if (config == NULL) {
+		nm_log_warn (LOGD_DHCP4, "(%s): failed to get DHCPv4 config for rebind",
+		             nm_device_get_ip_iface (device));
+		nm_device_state_changed (device, NM_DEVICE_STATE_FAILED, NM_DEVICE_STATE_REASON_IP_CONFIG_EXPIRED);
+		return;
+	}
+
+	connection = nm_device_get_connection (device);
 	g_assert (connection);
-	assumed = nm_act_request_get_assumed (req);
-
-	if (ipv6) {
-		ip6_config = nm_dhcp_client_get_ip6_config (priv->dhcp6_client, FALSE);
-		if (!ip6_config) {
-			nm_log_warn (LOGD_DHCP6, "(%s): failed to get DHCPv6 config for rebind",
-			             nm_device_get_ip_iface (device));
-			nm_device_state_changed (device, NM_DEVICE_STATE_FAILED, NM_DEVICE_STATE_REASON_IP_CONFIG_EXPIRED);
-			return;
-		}
 
-		s_ip6 = NM_SETTING_IP6_CONFIG (nm_connection_get_setting (connection, NM_TYPE_SETTING_IP6_CONFIG));
-		nm_utils_merge_ip6_config (ip6_config, s_ip6);
+	/* Merge with user overrides */
+	nm_utils_merge_ip4_config (config, nm_connection_get_setting_ip4_config (connection));
 
-		g_object_set_data (G_OBJECT (req), NM_ACT_REQUEST_IP6_CONFIG, ip6_config);
+	if (!nm_device_set_ip4_config (device, config, FALSE, &reason)) {
+		nm_log_warn (LOGD_DHCP6, "(%s): failed to update IPv4 config in response to DHCP event.",
+		             nm_device_get_ip_iface (device));
+		nm_device_state_changed (device, NM_DEVICE_STATE_FAILED, reason);
+		return;
+	}
 
-		if (nm_device_set_ip6_config (device, ip6_config, assumed, &reason)) {
-			nm_dhcp6_config_reset (priv->dhcp6_config);
-			nm_dhcp_client_foreach_option (priv->dhcp6_client,
-			                               dhcp6_add_option_cb,
-			                               priv->dhcp6_config);
-			nm_utils_call_dispatcher ("dhcp6-change", connection, device, NULL, NULL, NULL);
-		} else {
-			nm_log_warn (LOGD_DHCP6, "(%s): failed to update IPv6 config in response to DHCP event.",
-			             nm_device_get_ip_iface (device));
-			nm_device_state_changed (device, NM_DEVICE_STATE_FAILED, reason);
-		}
-	} else {
-		ip4_config = nm_dhcp_client_get_ip4_config (priv->dhcp4_client, FALSE);
-		if (!ip4_config) {
-			nm_log_warn (LOGD_DHCP6, "(%s): failed to get DHCPv4 config for rebind",
-			             nm_device_get_ip_iface (device));
-			nm_device_state_changed (device, NM_DEVICE_STATE_FAILED, NM_DEVICE_STATE_REASON_IP_CONFIG_EXPIRED);
-			return;
-		}
+	/* Notify dispatcher scripts of new DHCP4 config */
+	nm_utils_call_dispatcher ("dhcp4-change", connection, device, NULL, NULL, NULL);
+}
 
-		s_ip4 = NM_SETTING_IP4_CONFIG (nm_connection_get_setting (connection, NM_TYPE_SETTING_IP4_CONFIG));
-		nm_utils_merge_ip4_config (ip4_config, s_ip4);
+static void
+dhcp4_fail (NMDevice *device, gboolean timeout)
+{
+	NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE (device);
 
-		g_object_set_data (G_OBJECT (req), NM_ACT_REQUEST_IP4_CONFIG, ip4_config);
+	nm_dhcp4_config_reset (priv->dhcp4_config);
 
-		if (nm_device_set_ip4_config (device, ip4_config, assumed, &reason)) {
-			nm_dhcp4_config_reset (priv->dhcp4_config);
-			nm_dhcp_client_foreach_option (priv->dhcp4_client,
-			                               dhcp4_add_option_cb,
-			                               priv->dhcp4_config);
-			nm_utils_call_dispatcher ("dhcp4-change", connection, device, NULL, NULL, NULL);
-		} else {
-			nm_log_warn (LOGD_DHCP6, "(%s): failed to update IPv4 config in response to DHCP event.",
-			             nm_device_get_ip_iface (device));
-			nm_device_state_changed (device, NM_DEVICE_STATE_FAILED, reason);
-		}
-	}
+	if (timeout || (priv->ip4_state == IP_CONF))
+		nm_device_activate_schedule_ip4_config_timeout (device);
+	else if (priv->ip4_state == IP_DONE)
+		nm_device_state_changed (device, NM_DEVICE_STATE_FAILED, NM_DEVICE_STATE_REASON_IP_CONFIG_EXPIRED);
 }
 
 static void
-dhcp_state_changed (NMDHCPClient *client,
-					NMDHCPState state,
-					gpointer user_data)
+dhcp4_state_changed (NMDHCPClient *client,
+                     NMDHCPState state,
+                     gpointer user_data)
 {
 	NMDevice *device = NM_DEVICE (user_data);
 	NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE (device);
 	NMDeviceState dev_state;
-	gboolean ipv6;
+	NMIP4Config *config;
 
-	ipv6 = nm_dhcp_client_get_ipv6 (client);
-	dev_state = nm_device_get_state (device);
+	g_return_if_fail (nm_dhcp_client_get_ipv6 (client) == FALSE);
 
-	if (ipv6) {
-		nm_log_dbg (LOGD_DHCP6, "(%s): new DHCPv6 client state %d",
-		            nm_device_get_iface (device), dev_state);
-	} else {
-		nm_log_dbg (LOGD_DHCP4, "(%s): new DHCPv4 client state %d",
-		            nm_device_get_iface (device), dev_state);
-	}
+	nm_log_dbg (LOGD_DHCP4, "(%s): new DHCPv4 client state %d",
+	            nm_device_get_iface (device), state);
+
+	dev_state = nm_device_get_state (device);
 
 	switch (state) {
 	case DHC_BOUND4:     /* lease obtained */
-	case DHC_BOUND6:
 	case DHC_RENEW4:     /* lease renewed */
-	case DHC_RENEW6:     /* lease renewed */
 	case DHC_REBOOT:     /* have valid lease, but now obtained a different one */
 	case DHC_REBIND4:    /* new, different lease */
-	case DHC_REBIND6:    /* new, different lease */
-		if (dev_state == NM_DEVICE_STATE_IP_CONFIG) {
-			if (ipv6)
-				nm_device_activate_schedule_stage4_ip6_config_get (device);
-			else
-				nm_device_activate_schedule_stage4_ip4_config_get (device);
-		} else if (dev_state == NM_DEVICE_STATE_ACTIVATED)
-			handle_dhcp_lease_change (device, ipv6);
-		break;
-	case DHC_TIMEOUT: /* timed out contacting DHCP server */
-		if (ipv6) {
-			nm_dhcp6_config_reset (priv->dhcp6_config);
-			if (nm_device_get_state (device) == NM_DEVICE_STATE_IP_CONFIG)
-				nm_device_activate_schedule_stage4_ip6_config_timeout (device);
-		} else {
+		config = nm_dhcp_client_get_ip4_config (priv->dhcp4_client, FALSE);
+		if (priv->ip4_state == IP_CONF)
+			nm_device_activate_schedule_ip4_config_result (device, config);
+		else if (priv->ip4_state == IP_DONE)
+			dhcp4_lease_change (device, config);
+
+		if (config) {
+			/* Update the DHCP4 config object with new DHCP options */
 			nm_dhcp4_config_reset (priv->dhcp4_config);
-			if (nm_device_get_state (device) == NM_DEVICE_STATE_IP_CONFIG)
-				nm_device_activate_schedule_stage4_ip4_config_timeout (device);
+			nm_dhcp_client_foreach_option (priv->dhcp4_client,
+			                               dhcp4_add_option_cb,
+			                               priv->dhcp4_config);
+			g_object_notify (G_OBJECT (device), NM_DEVICE_DHCP4_CONFIG);
+
+			g_object_unref (config);
 		}
 		break;
+	case DHC_TIMEOUT: /* timed out contacting DHCP server */
+		dhcp4_fail (device, TRUE);
+		break;
 	case DHC_END: /* dhclient exited normally */
-		/* In IPv6 info-only mode, the client doesn't handle leases so it
-		 * may exit right after getting a response from the server.  That's
-		 * normal.  In that case we just ignore the exit.
-		 */
-		if (ipv6 && (priv->dhcp6_mode == IP6_DHCP_OPT_OTHERCONF))
-			break;
-		/* Otherwise, fall through */
 	case DHC_FAIL: /* all attempts to contact server timed out, sleeping */
 	case DHC_ABEND: /* dhclient exited abnormally */
-		if (ipv6)
-			nm_dhcp6_config_reset (priv->dhcp6_config);
-		else
-			nm_dhcp4_config_reset (priv->dhcp4_config);
-
 		/* dhclient quit and can't get/renew a lease; so kill the connection */
-		if (nm_device_get_state (device) == NM_DEVICE_STATE_IP_CONFIG) {
-			if (ipv6)
-				nm_device_activate_schedule_stage4_ip6_config_timeout (device);
-			else
-				nm_device_activate_schedule_stage4_ip4_config_timeout (device);
-		} else if (nm_device_get_state (device) == NM_DEVICE_STATE_ACTIVATED)
-			nm_device_state_changed (device, NM_DEVICE_STATE_FAILED, NM_DEVICE_STATE_REASON_IP_CONFIG_EXPIRED);
+		dhcp4_fail (device, FALSE);
 		break;
 	default:
 		break;
@@ -1500,21 +1491,15 @@ dhcp_state_changed (NMDHCPClient *client,
 }
 
 static void
-dhcp_timeout (NMDHCPClient *client, gpointer user_data)
+dhcp4_timeout (NMDHCPClient *client, gpointer user_data)
 {
 	NMDevice *device = NM_DEVICE (user_data);
 
-	if (!nm_device_get_act_request (device))
-		return;
+	g_return_if_fail (nm_device_get_act_request (device) != NULL);
+	g_return_if_fail (nm_dhcp_client_get_ipv6 (client) == FALSE);
 
 	nm_dhcp_client_stop (client, FALSE);
-
-	if (nm_device_get_state (device) == NM_DEVICE_STATE_IP_CONFIG) {
-		if (nm_dhcp_client_get_ipv6 (client))
-			nm_device_activate_schedule_stage4_ip6_config_timeout (device);
-		else
-			nm_device_activate_schedule_stage4_ip4_config_timeout (device);
-	}
+	dhcp4_fail (device, TRUE);
 }
 
 static NMActStageReturn
@@ -1526,7 +1511,7 @@ dhcp4_start (NMDevice *self,
 	NMSettingIP4Config *s_ip4;
 	guint8 *anycast = NULL;
 
-	s_ip4 = (NMSettingIP4Config *) nm_connection_get_setting (connection, NM_TYPE_SETTING_IP4_CONFIG);
+	s_ip4 = nm_connection_get_setting_ip4_config (connection);
 
 	if (priv->dhcp_anycast_address)
 		anycast = priv->dhcp_anycast_address->data;
@@ -1551,11 +1536,11 @@ dhcp4_start (NMDevice *self,
 
 	priv->dhcp4_state_sigid = g_signal_connect (priv->dhcp4_client,
 	                                            "state-changed",
-	                                            G_CALLBACK (dhcp_state_changed),
+	                                            G_CALLBACK (dhcp4_state_changed),
 	                                            self);
 	priv->dhcp4_timeout_sigid = g_signal_connect (priv->dhcp4_client,
 	                                              "timeout",
-	                                              G_CALLBACK (dhcp_timeout),
+	                                              G_CALLBACK (dhcp4_timeout),
 	                                              self);
 
 	/* DHCP devices will be notified by the DHCP manager when stuff happens */
@@ -1568,7 +1553,6 @@ nm_device_dhcp4_renew (NMDevice *self, gboolean release)
 	NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE (self);
 	NMActStageReturn ret;
 	NMDeviceStateReason reason;
-	NMActRequest *req;
 	NMConnection *connection;
 
 	g_return_val_if_fail (priv->dhcp4_client != NULL, FALSE);
@@ -1579,9 +1563,7 @@ nm_device_dhcp4_renew (NMDevice *self, gboolean release)
 	/* Terminate old DHCP instance and release the old lease */
 	dhcp4_cleanup (self, TRUE, release);
 
-	req = nm_device_get_act_request (self);
-	g_assert (req);
-	connection = nm_act_request_get_connection (req);
+	connection = nm_device_get_connection (self);
 	g_assert (connection);
 
 	/* Start DHCP again on the interface */
@@ -1590,63 +1572,315 @@ nm_device_dhcp4_renew (NMDevice *self, gboolean release)
 	return (ret != NM_ACT_STAGE_RETURN_FAILURE);
 }
 
+/*********************************************/
+
+static GHashTable *shared_ips = NULL;
+
+static void
+release_shared_ip (gpointer data)
+{
+	g_hash_table_remove (shared_ips, data);
+}
+
+static guint32
+reserve_shared_ip (void)
+{
+	guint32 start = (guint32) ntohl (0x0a2a0001); /* 10.42.0.1 */
+	guint32 count = 0;
+
+	while (g_hash_table_lookup (shared_ips, GUINT_TO_POINTER (start + count))) {
+		count += ntohl (0x100);
+		if (count > ntohl (0xFE00)) {
+			nm_log_err (LOGD_SHARING, "ran out of shared IP addresses!");
+			return 0;
+		}
+	}
+
+	g_hash_table_insert (shared_ips, GUINT_TO_POINTER (start + count), GUINT_TO_POINTER (TRUE));
+	return start + count;
+}
+
+static NMIP4Config *
+shared4_new_config (NMDevice *self, NMDeviceStateReason *reason)
+{
+	NMIP4Config *config = NULL;
+	NMIP4Address *addr;
+	guint32 tmp_addr;
+
+	g_return_val_if_fail (self != NULL, NULL);
+
+	if (G_UNLIKELY (shared_ips == NULL))
+		shared_ips = g_hash_table_new (g_direct_hash, g_direct_equal);
+
+	tmp_addr = reserve_shared_ip ();
+	if (!tmp_addr) {
+		*reason = NM_DEVICE_STATE_REASON_IP_CONFIG_UNAVAILABLE;
+		return NULL;
+	}
+
+	config = nm_ip4_config_new ();
+	addr = nm_ip4_address_new ();
+	nm_ip4_address_set_address (addr, tmp_addr);
+	nm_ip4_address_set_prefix (addr, 24);
+	nm_ip4_config_take_address (config, addr);
+
+	/* Remove the address lock when the object gets disposed */
+	g_object_set_data_full (G_OBJECT (config), "shared-ip",
+	                        GUINT_TO_POINTER (tmp_addr), release_shared_ip);
+
+	return config;
+}
+
+/*********************************************/
+
 static NMActStageReturn
-real_act_stage3_ip4_config_start (NMDevice *self, NMDeviceStateReason *reason)
+real_act_stage3_ip4_config_start (NMDevice *self,
+                                  NMIP4Config **out_config,
+                                  NMDeviceStateReason *reason)
 {
 	NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE (self);
 	NMConnection *connection;
 	NMSettingIP4Config *s_ip4;
-	NMActRequest *req;
-	NMActStageReturn ret = NM_ACT_STAGE_RETURN_SUCCESS;
-	const char *method = NULL;
-	int ifindex;
+	NMActStageReturn ret = NM_ACT_STAGE_RETURN_FAILURE;
+	const char *method = NM_SETTING_IP4_CONFIG_METHOD_AUTO;
 
 	g_return_val_if_fail (reason != NULL, NM_ACT_STAGE_RETURN_FAILURE);
 
-	/* Make sure the interface is up before trying to do anything with it */
-	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);
-
-	s_ip4 = (NMSettingIP4Config *) nm_connection_get_setting (connection, NM_TYPE_SETTING_IP4_CONFIG);
+	connection = nm_device_get_connection (self);
+	g_assert (connection);
 
 	/* If we did not receive IP4 configuration information, default to DHCP */
+	s_ip4 = nm_connection_get_setting_ip4_config (connection);
 	if (s_ip4)
 		method = nm_setting_ip4_config_get_method (s_ip4);
+	else if (nm_connection_is_type (connection, NM_SETTING_BOND_SETTING_NAME))
+		method = NM_SETTING_IP4_CONFIG_METHOD_DISABLED;
 
-	if (!s_ip4 || !method || !strcmp (method, NM_SETTING_IP4_CONFIG_METHOD_AUTO)) {
+	/* Start IPv4 addressing based on the method requested */
+	if (strcmp (method, NM_SETTING_IP4_CONFIG_METHOD_AUTO) == 0)
 		ret = dhcp4_start (self, connection, reason);
-	} else if (s_ip4 && !strcmp (method, NM_SETTING_IP4_CONFIG_METHOD_LINK_LOCAL)) {
-		GError *error = NULL;
-		const char *iface = nm_device_get_iface (self);
-
-		/* Start avahi-autoipd */
-		if (aipd_exec (self, &error)) {
-			nm_log_info (LOGD_DEVICE | LOGD_AUTOIP4,
-			             "Activation (%s) Stage 3 of 5 (IP Configure Start) started"
-			             " avahi-autoipd...", iface);
-			ret = NM_ACT_STAGE_RETURN_POSTPONE;
-		} else {
-			nm_log_info (LOGD_DEVICE | LOGD_AUTOIP4,
-			             "Activation (%s) Stage 3 of 5 (IP Configure Start) failed"
-			             " to start avahi-autoipd: %s", iface, error->message);
-			g_error_free (error);
-			aipd_cleanup (self);
-			*reason = NM_DEVICE_STATE_REASON_AUTOIP_START_FAILED;
+	else if (strcmp (method, NM_SETTING_IP4_CONFIG_METHOD_LINK_LOCAL) == 0)
+		ret = aipd_start (self, reason);
+	else if (strcmp (method, NM_SETTING_IP4_CONFIG_METHOD_MANUAL) == 0) {
+		/* Use only IPv4 config from the connection data */
+		*out_config = nm_ip4_config_new ();
+		g_assert (*out_config);
+		ret = NM_ACT_STAGE_RETURN_SUCCESS;
+	} else if (strcmp (method, NM_SETTING_IP4_CONFIG_METHOD_SHARED) == 0) {
+		*out_config = shared4_new_config (self, reason);
+		if (*out_config) {
+			priv->dnsmasq_manager = nm_dnsmasq_manager_new (nm_device_get_ip_iface (self));
+			ret = NM_ACT_STAGE_RETURN_SUCCESS;
+		} else
 			ret = NM_ACT_STAGE_RETURN_FAILURE;
-		}
 	} else if (s_ip4 && !strcmp (method, NM_SETTING_IP4_CONFIG_METHOD_DISABLED)) {
 		/* Nothing to do... */
-		priv->ip4_ready = TRUE;
 		ret = NM_ACT_STAGE_RETURN_STOP;
+	} else {
+		nm_log_warn (LOGD_IP4, "(%s): unhandled IPv4 config method; will fail",
+		             nm_device_get_ip_iface (self));
 	}
 
 	return ret;
 }
 
+/*********************************************/
+/* DHCPv6 stuff */
+
+static void
+dhcp6_add_option_cb (gpointer key, gpointer value, gpointer user_data)
+{
+	nm_dhcp6_config_add_option (NM_DHCP6_CONFIG (user_data),
+	                            (const char *) key,
+	                            (const char *) value);
+}
+
+static void
+merge_ip6_configs (NMIP6Config *dst, NMIP6Config *src)
+{
+	guint32 i;
+
+	g_return_if_fail (src != NULL);
+	g_return_if_fail (dst != NULL);
+
+	/* addresses */
+	for (i = 0; i < nm_ip6_config_get_num_addresses (src); i++)
+		nm_ip6_config_add_address (dst, nm_ip6_config_get_address (src, i));
+
+	/* ptp address; only replace if src doesn't have one */
+	if (!nm_ip6_config_get_ptp_address (dst))
+		nm_ip6_config_set_ptp_address (dst, nm_ip6_config_get_ptp_address (src));
+
+	/* nameservers */
+	for (i = 0; i < nm_ip6_config_get_num_nameservers (src); i++)
+		nm_ip6_config_add_nameserver (dst, nm_ip6_config_get_nameserver (src, i));
+
+	/* routes */
+	for (i = 0; i < nm_ip6_config_get_num_routes (src); i++)
+		nm_ip6_config_add_route (dst, nm_ip6_config_get_route (src, i));
+
+	/* domains */
+	for (i = 0; i < nm_ip6_config_get_num_domains (src); i++)
+		nm_ip6_config_add_domain (dst, nm_ip6_config_get_domain (src, i));
+
+	/* dns searches */
+	for (i = 0; i < nm_ip6_config_get_num_searches (src); i++)
+		nm_ip6_config_add_search (dst, nm_ip6_config_get_search (src, i));
+
+	if (!nm_ip6_config_get_mss (dst))
+		nm_ip6_config_set_mss (dst, nm_ip6_config_get_mss (src));
+}
+
+static gboolean
+ip6_config_merge_and_apply (NMDevice *self,
+                            NMIP6Config *src_config,
+                            NMDeviceStateReason *out_reason)
+{
+	NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE (self);
+	NMConnection *connection;
+	gboolean assumed, success;
+	NMIP6Config *composite;
+
+	connection = nm_device_get_connection (self);
+	g_assert (connection);
+
+	/* If no config was passed in, create a new one */
+	composite = nm_ip6_config_new ();
+	g_assert (composite);
+
+	/* Merge in the given config first, if any */
+	if (src_config)
+		merge_ip6_configs (composite, src_config);
+
+	/* Merge RA and DHCPv6 configs into the composite config */
+	if (priv->ac_ip6_config && (src_config != priv->ac_ip6_config))
+		merge_ip6_configs (composite, priv->ac_ip6_config);
+	if (priv->dhcp6_ip6_config && (src_config != priv->dhcp6_ip6_config))
+		merge_ip6_configs (composite, priv->dhcp6_ip6_config);
+
+	/* Merge user overrides into the composite config */
+	nm_utils_merge_ip6_config (composite, nm_connection_get_setting_ip6_config (connection));
+
+	assumed = nm_act_request_get_assumed (priv->act_request);
+	success = nm_device_set_ip6_config (self, composite, assumed, out_reason);
+	g_object_unref (composite);
+	return success;
+}
+
+static void
+dhcp6_lease_change (NMDevice *device)
+{
+	NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE (device);
+	NMConnection *connection;
+	NMDeviceStateReason reason = NM_DEVICE_STATE_REASON_NONE;
+
+	if (priv->dhcp6_ip6_config == NULL) {
+		nm_log_warn (LOGD_DHCP6, "(%s): failed to get DHCPv6 config for rebind",
+		             nm_device_get_ip_iface (device));
+		nm_device_state_changed (device, NM_DEVICE_STATE_FAILED, NM_DEVICE_STATE_REASON_IP_CONFIG_EXPIRED);
+		return;
+	}
+
+	g_assert (priv->dhcp6_client);  /* sanity check */
+
+	connection = nm_device_get_connection (device);
+	g_assert (connection);
+
+	/* Apply the updated config */
+	if (ip6_config_merge_and_apply (device, NULL, &reason) == FALSE) {
+		nm_log_warn (LOGD_DHCP6, "(%s): failed to update IPv6 config in response to DHCP event.",
+		             nm_device_get_ip_iface (device));
+		nm_device_state_changed (device, NM_DEVICE_STATE_FAILED, reason);
+	} else {
+		/* Notify dispatcher scripts of new DHCPv6 config */
+		nm_utils_call_dispatcher ("dhcp6-change", connection, device, NULL, NULL, NULL);
+	}
+}
+
+static void
+dhcp6_fail (NMDevice *device, gboolean timeout)
+{
+	NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE (device);
+
+	nm_dhcp6_config_reset (priv->dhcp6_config);
+
+	if (timeout || (priv->ip6_state == IP_CONF))
+		nm_device_activate_schedule_ip6_config_timeout (device);
+	else if (priv->ip6_state == IP_DONE)
+		nm_device_state_changed (device, NM_DEVICE_STATE_FAILED, NM_DEVICE_STATE_REASON_IP_CONFIG_EXPIRED);
+}
+
+static void
+dhcp6_state_changed (NMDHCPClient *client,
+                     NMDHCPState state,
+                     gpointer user_data)
+{
+	NMDevice *device = NM_DEVICE (user_data);
+	NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE (device);
+	NMDeviceState dev_state;
+
+	g_return_if_fail (nm_dhcp_client_get_ipv6 (client) == TRUE);
+
+	nm_log_dbg (LOGD_DHCP6, "(%s): new DHCPv6 client state %d",
+	            nm_device_get_iface (device), state);
+
+	dev_state = nm_device_get_state (device);
+
+	switch (state) {
+	case DHC_BOUND6:
+	case DHC_RENEW6:     /* lease renewed */
+	case DHC_REBOOT:     /* have valid lease, but now obtained a different one */
+	case DHC_REBIND6:    /* new, different lease */
+		if (priv->dhcp6_ip6_config)
+			g_object_unref (priv->dhcp6_ip6_config);
+		priv->dhcp6_ip6_config = nm_dhcp_client_get_ip6_config (priv->dhcp6_client, FALSE);
+		if (priv->ip6_state == IP_CONF)
+			nm_device_activate_schedule_ip6_config_result (device, priv->dhcp6_ip6_config);
+		else if (priv->ip6_state == IP_DONE)
+			dhcp6_lease_change (device);
+
+		if (priv->dhcp6_ip6_config) {
+			/* Update the DHCP6 config object with new DHCP options */
+			nm_dhcp6_config_reset (priv->dhcp6_config);
+			nm_dhcp_client_foreach_option (priv->dhcp6_client,
+			                               dhcp6_add_option_cb,
+			                               priv->dhcp6_config);
+			g_object_notify (G_OBJECT (device), NM_DEVICE_DHCP6_CONFIG);
+		}
+		break;
+	case DHC_TIMEOUT: /* timed out contacting DHCP server */
+		dhcp6_fail (device, TRUE);
+		break;
+	case DHC_END: /* dhclient exited normally */
+		/* In IPv6 info-only mode, the client doesn't handle leases so it
+		 * may exit right after getting a response from the server.  That's
+		 * normal.  In that case we just ignore the exit.
+		 */
+		if (priv->dhcp6_mode == IP6_DHCP_OPT_OTHERCONF)
+			break;
+		/* Otherwise, fall through */
+	case DHC_FAIL: /* all attempts to contact server timed out, sleeping */
+	case DHC_ABEND: /* dhclient exited abnormally */
+		/* dhclient quit and can't get/renew a lease; so kill the connection */
+		dhcp6_fail (device, FALSE);
+		break;
+	default:
+		break;
+	}
+}
+
+static void
+dhcp6_timeout (NMDHCPClient *client, gpointer user_data)
+{
+	NMDevice *device = NM_DEVICE (user_data);
+
+	g_return_if_fail (nm_device_get_act_request (device) != NULL);
+	g_return_if_fail (nm_dhcp_client_get_ipv6 (client) == TRUE);
+
+	nm_dhcp_client_stop (client, FALSE);
+	dhcp6_fail (device, TRUE);
+}
+
 static NMActStageReturn
 dhcp6_start (NMDevice *self,
              NMConnection *connection,
@@ -1656,17 +1890,12 @@ dhcp6_start (NMDevice *self,
 	NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE (self);
 	NMActStageReturn ret = NM_ACT_STAGE_RETURN_FAILURE;
 	guint8 *anycast = NULL;
-	NMSettingIP6Config *s_ip6;
 	const char *ip_iface;
 	const struct in6_addr dest = { { { 0xFF,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 } } };
 	int err;
 
 	if (!connection) {
-		NMActRequest *req;
-
-		req = nm_device_get_act_request (self);
-		g_assert (req);
-		connection = nm_act_request_get_connection (req);
+		connection = nm_device_get_connection (self);
 		g_assert (connection);
 	}
 
@@ -1680,6 +1909,12 @@ dhcp6_start (NMDevice *self,
 		g_object_unref (priv->dhcp6_config);
 	priv->dhcp6_config = nm_dhcp6_config_new ();
 
+	g_warn_if_fail (priv->dhcp6_ip6_config == NULL);
+	if (priv->dhcp6_ip6_config) {
+		g_object_unref (priv->dhcp6_ip6_config);
+		priv->dhcp6_ip6_config = NULL;
+	}
+
 	/* DHCPv6 communicates with the DHCPv6 server via two multicast addresses,
 	 * ff02::1:2 (link-scope) and ff05::1:3 (site-scope).  Make sure we have
 	 * a multicast route (ff00::/8) for client <-> server communication.
@@ -1692,24 +1927,22 @@ dhcp6_start (NMDevice *self,
 		            priv->ip_iface ? priv->ip_iface : priv->iface, nl_geterror (err));
 	}
 
-	s_ip6 = (NMSettingIP6Config *) nm_connection_get_setting (connection, NM_TYPE_SETTING_IP6_CONFIG);
-
 	ip_iface = nm_device_get_ip_iface (self);
 	priv->dhcp6_client = nm_dhcp_manager_start_ip6 (priv->dhcp_manager,
 	                                                ip_iface,
 	                                                nm_connection_get_uuid (connection),
-	                                                s_ip6,
+	                                                nm_connection_get_setting_ip6_config (connection),
 	                                                priv->dhcp_timeout,
 	                                                anycast,
 	                                                (dhcp_opt == IP6_DHCP_OPT_OTHERCONF) ? TRUE : FALSE);
 	if (priv->dhcp6_client) {
 		priv->dhcp6_state_sigid = g_signal_connect (priv->dhcp6_client,
 		                                            "state-changed",
-		                                            G_CALLBACK (dhcp_state_changed),
+		                                            G_CALLBACK (dhcp6_state_changed),
 		                                            self);
 		priv->dhcp6_timeout_sigid = g_signal_connect (priv->dhcp6_client,
 		                                              "timeout",
-		                                              G_CALLBACK (dhcp_timeout),
+		                                              G_CALLBACK (dhcp6_timeout),
 		                                              self);
 
 		/* DHCP devices will be notified by the DHCP manager when stuff happens */
@@ -1722,36 +1955,215 @@ dhcp6_start (NMDevice *self,
 	return ret;
 }
 
+/******************************************/
+
+static void
+ip6_addrconf_complete (NMIP6Manager *ip6_manager,
+                       int ifindex,
+                       guint dhcp_opts,
+                       gboolean success,
+                       gpointer user_data)
+{
+	NMDevice *self = NM_DEVICE (user_data);
+	NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE (self);
+	NMConnection *connection;
+	NMActStageReturn ret;
+	NMDeviceStateReason reason = NM_DEVICE_STATE_REASON_NONE;
+
+	if (ifindex != nm_device_get_ip_ifindex (self))
+		return;
+	g_return_if_fail (priv->act_request != NULL);
+	connection = nm_device_get_connection (self);
+	g_assert (connection);
+
+	if (!priv->ip6_waiting_for_config)
+		return;
+
+	priv->ip6_waiting_for_config = FALSE;
+
+	if (!success) {
+		nm_device_activate_schedule_ip6_config_timeout (self);
+		return;
+	}
+
+	priv->dhcp6_mode = dhcp_opts;
+
+	/* If addrconf is all that's required, we're done */
+	if (priv->dhcp6_mode == IP6_DHCP_OPT_NONE) {
+		priv->ac_ip6_config = nm_ip6_manager_get_ip6_config (ip6_manager, ifindex);
+		nm_device_activate_schedule_ip6_config_result (self, priv->ac_ip6_config);
+		return;
+	}
+
+	/* If the router said to use DHCP for managed or otherconf, do it */
+
+	/* Don't re-start DHCPv6 if it's already in progress */
+	if (priv->ip6_state != IP_CONF)
+		return;
+
+	nm_log_info (LOGD_DEVICE | LOGD_DHCP6,
+	             "Activation (%s) Stage 3 of 5 (IP Configure Start) starting DHCPv6"
+	             " as requested by IPv6 router...",
+	             priv->iface);
+
+	ret = dhcp6_start (self, connection, priv->dhcp6_mode, &reason);
+	switch (ret) {
+	case NM_ACT_STAGE_RETURN_SUCCESS:
+		/* Shouldn't get this, but handle it anyway */
+		g_warn_if_reached ();
+		priv->ac_ip6_config = nm_ip6_manager_get_ip6_config (ip6_manager, ifindex);
+		nm_device_activate_schedule_ip6_config_result (self, priv->ac_ip6_config);
+		break;
+	case NM_ACT_STAGE_RETURN_POSTPONE:
+		/* Cache acquired autoconf config and wait for DHCPv6 to complete */
+		priv->ac_ip6_config = nm_ip6_manager_get_ip6_config (ip6_manager, ifindex);
+		break;
+	default:
+		nm_device_state_changed (self, NM_DEVICE_STATE_FAILED, reason);
+		break;
+	}
+}
+
+static void
+ip6_config_changed (NMIP6Manager *ip6_manager,
+                    int ifindex,
+                    guint dhcp_opts,
+                    gboolean success,
+                    gpointer user_data)
+{
+	NMDevice *self = NM_DEVICE (user_data);
+	NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE (self);
+	NMDeviceStateReason reason = NM_DEVICE_STATE_REASON_NONE;
+
+	if (ifindex != nm_device_get_ip_ifindex (self))
+		return;
+	g_return_if_fail (priv->act_request != NULL);
+
+	/* If autoconf failed and IPv6 previously succeeded, fail */
+	if (!success && (priv->ip6_state == IP_DONE)) {
+		nm_device_state_changed (self,
+		                         NM_DEVICE_STATE_FAILED,
+		                         NM_DEVICE_STATE_REASON_IP_CONFIG_UNAVAILABLE);
+		return;
+	}
+
+	/* FIXME: re-run DHCPv6 here to get any new nameservers or whatever */
+
+	if (priv->ac_ip6_config)
+		g_object_unref (priv->ac_ip6_config);
+	priv->ac_ip6_config = nm_ip6_manager_get_ip6_config (ip6_manager, ifindex);
+
+	if (ip6_config_merge_and_apply (self, NULL, &reason) == FALSE) {
+		nm_log_warn (LOGD_DHCP6, "(%s): failed to update IPv6 config in response to Router Advertisement.",
+		             nm_device_get_ip_iface (self));
+		nm_device_state_changed (self, NM_DEVICE_STATE_FAILED, reason);
+	}
+}
+
+static gboolean
+addrconf6_start (NMDevice *self)
+{
+	NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE (self);
+	NMConnection *connection;
+	gboolean success;
+
+	connection = nm_device_get_connection (self);
+	g_assert (connection);
+
+	g_warn_if_fail (priv->ac_ip6_config == NULL);
+	if (priv->ac_ip6_config) {
+		g_object_unref (priv->ac_ip6_config);
+		priv->ac_ip6_config = NULL;
+	}
+
+	if (!priv->ip6_manager) {
+		priv->ip6_manager = nm_ip6_manager_get ();
+		priv->ip6_addrconf_sigid = g_signal_connect (priv->ip6_manager,
+		                                             "addrconf-complete",
+		                                             G_CALLBACK (ip6_addrconf_complete),
+		                                             self);
+		priv->ip6_config_changed_sigid = g_signal_connect (priv->ip6_manager,
+		                                                   "config-changed",
+		                                                   G_CALLBACK (ip6_config_changed),
+		                                                   self);
+	}
+
+	success = nm_ip6_manager_prepare_interface (priv->ip6_manager,
+	                                            nm_device_get_ip_ifindex (self),
+	                                            nm_connection_get_setting_ip6_config (connection),
+	                                            priv->ip6_accept_ra_path);
+	if (success) {
+		priv->ip6_waiting_for_config = TRUE;
+		nm_ip6_manager_begin_addrconf (priv->ip6_manager, nm_device_get_ip_ifindex (self));
+	}
+
+	return success;
+}
+
+static void
+addrconf6_cleanup (NMDevice *self)
+{
+	NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE (self);
+
+	if (priv->ac_ip6_config) {
+		g_object_unref (priv->ac_ip6_config);
+		priv->ac_ip6_config = NULL;
+	}
+
+	if (!priv->ip6_manager)
+		return;
+
+	if (priv->ip6_addrconf_sigid) {
+		g_signal_handler_disconnect (priv->ip6_manager,
+		                             priv->ip6_addrconf_sigid);
+		priv->ip6_addrconf_sigid = 0;
+	}
+	if (priv->ip6_config_changed_sigid) {
+		g_signal_handler_disconnect (priv->ip6_manager,
+		                             priv->ip6_config_changed_sigid);
+		priv->ip6_config_changed_sigid = 0;
+	}
+
+	nm_ip6_manager_cancel_addrconf (priv->ip6_manager, nm_device_get_ip_ifindex (self));
+	g_object_unref (priv->ip6_manager);
+	priv->ip6_manager = NULL;
+}
+
+/******************************************/
+
 static NMActStageReturn
-real_act_stage3_ip6_config_start (NMDevice *self, NMDeviceStateReason *reason)
+real_act_stage3_ip6_config_start (NMDevice *self,
+                                  NMIP6Config **out_config,
+                                  NMDeviceStateReason *reason)
 {
 	NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE (self);
 	const char *ip_iface;
 	NMActStageReturn ret = NM_ACT_STAGE_RETURN_FAILURE;
-	NMActRequest *req;
 	NMConnection *connection;
+	NMSettingIP6Config *s_ip6;
+	int conf_use_tempaddr;
+	NMSettingIP6ConfigPrivacy ip6_privacy = NM_SETTING_IP6_CONFIG_PRIVACY_UNKNOWN;
+	const char *ip6_privacy_str = "0\n";
 
 	g_return_val_if_fail (reason != NULL, NM_ACT_STAGE_RETURN_FAILURE);
 
-	req = nm_device_get_act_request (self);
-	g_assert (req);
-	connection = nm_act_request_get_connection (req);
+	connection = nm_device_get_connection (self);
 	g_assert (connection);
 
 	ip_iface = nm_device_get_ip_iface (self);
 
 	update_accept_ra_save (self);
+	update_ip6_privacy_save (self);
 
 	priv->dhcp6_mode = IP6_DHCP_OPT_NONE;
 
 	if (   ip6_method_matches (connection, NM_SETTING_IP6_CONFIG_METHOD_AUTO)
 	    || ip6_method_matches (connection, NM_SETTING_IP6_CONFIG_METHOD_LINK_LOCAL)) {
-		if (!addrconf6_setup (self)) {
+		if (!addrconf6_start (self)) {
 			*reason = NM_DEVICE_STATE_REASON_IP_CONFIG_UNAVAILABLE;
-			goto out;
-		}
-		nm_ip6_manager_begin_addrconf (priv->ip6_manager, nm_device_get_ip_ifindex (self));
-		ret = NM_ACT_STAGE_RETURN_POSTPONE;
+			ret = NM_ACT_STAGE_RETURN_FAILURE;
+		} else
+			ret = NM_ACT_STAGE_RETURN_POSTPONE;
 	} else if (ip6_method_matches (connection, NM_SETTING_IP6_CONFIG_METHOD_DHCP)) {
 		/* Router advertisements shouldn't be used in pure DHCP mode */
 		if (priv->ip6_accept_ra_path)
@@ -1765,19 +2177,52 @@ real_act_stage3_ip6_config_start (NMDevice *self, NMDeviceStateReason *reason)
 			nm_utils_do_sysctl (priv->ip6_accept_ra_path,
 			                    priv->ip6_accept_ra_save ? "1\n" : "0\n");
 		}
-
-		priv->ip6_ready = TRUE;
 		ret = NM_ACT_STAGE_RETURN_STOP;
 	} else if (ip6_method_matches (connection, NM_SETTING_IP6_CONFIG_METHOD_MANUAL)) {
+		/* New blank config */
+		*out_config = nm_ip6_config_new ();
+		g_assert (*out_config);
+
 		/* Router advertisements shouldn't be used in manual mode */
 		if (priv->ip6_accept_ra_path)
 			nm_utils_do_sysctl (priv->ip6_accept_ra_path, "0\n");
 		ret = NM_ACT_STAGE_RETURN_SUCCESS;
+	} else {
+		nm_log_warn (LOGD_IP6, "(%s): unhandled IPv6 config method; will fail",
+		             nm_device_get_ip_iface (self));
 	}
 
 	/* Other methods (shared) aren't implemented yet */
 
-out:
+	/* Enable/disable IPv6 Privacy Extensions.
+	 * If a global value is configured by sysadmin (e.g. /etc/sysctl.conf),
+	 * use that value instead of per-connection value.
+	 */
+	conf_use_tempaddr = nm_backend_ipv6_use_tempaddr ();
+	if (conf_use_tempaddr >= 0)
+		ip6_privacy = conf_use_tempaddr;
+	else {
+		s_ip6 = nm_connection_get_setting_ip6_config (connection);
+		if (s_ip6)
+			ip6_privacy = nm_setting_ip6_config_get_ip6_privacy (s_ip6);
+	}
+	ip6_privacy = CLAMP (ip6_privacy, NM_SETTING_IP6_CONFIG_PRIVACY_UNKNOWN, NM_SETTING_IP6_CONFIG_PRIVACY_PREFER_TEMP_ADDR);
+
+	switch (ip6_privacy) {
+	case NM_SETTING_IP6_CONFIG_PRIVACY_UNKNOWN:
+	case NM_SETTING_IP6_CONFIG_PRIVACY_DISABLED:
+		ip6_privacy_str = "0\n";
+	break;
+	case NM_SETTING_IP6_CONFIG_PRIVACY_PREFER_PUBLIC_ADDR:
+		ip6_privacy_str = "1\n";
+	break;
+	case NM_SETTING_IP6_CONFIG_PRIVACY_PREFER_TEMP_ADDR:
+		ip6_privacy_str = "2\n";
+	break;
+	}
+	if (priv->ip6_privacy_tempaddr_path)
+		nm_utils_do_sysctl (priv->ip6_privacy_tempaddr_path, ip6_privacy_str);
+
 	return ret;
 }
 
@@ -1792,9 +2237,13 @@ static gboolean
 nm_device_activate_stage3_ip_config_start (gpointer user_data)
 {
 	NMDevice *self = NM_DEVICE (user_data);
+	NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE (self);
 	const char *iface;
 	NMActStageReturn ret;
 	NMDeviceStateReason reason = NM_DEVICE_STATE_REASON_NONE;
+	NMIP4Config *ip4_config = NULL;
+	NMIP6Config *ip6_config = NULL;
+	int ifindex;
 
 	/* Clear the activation source ID now that this stage has run */
 	activation_source_clear (self, FALSE, 0);
@@ -1803,271 +2252,119 @@ nm_device_activate_stage3_ip_config_start (gpointer user_data)
 	nm_log_info (LOGD_DEVICE, "Activation (%s) Stage 3 of 5 (IP Configure Start) started...", iface);
 	nm_device_state_changed (self, NM_DEVICE_STATE_IP_CONFIG, NM_DEVICE_STATE_REASON_NONE);
 
-	ret = NM_DEVICE_GET_CLASS (self)->act_stage3_ip4_config_start (self, &reason);
-	if (ret == NM_ACT_STAGE_RETURN_SUCCESS)
-		nm_device_activate_schedule_stage4_ip4_config_get (self);
-	else if (ret == NM_ACT_STAGE_RETURN_FAILURE) {
+	/* Make sure the interface is up before trying to do anything with it */
+	ifindex = nm_device_get_ip_ifindex (self);
+	if ((ifindex > 0) && (nm_system_iface_is_up (ifindex) == FALSE))
+		nm_system_iface_set_up (ifindex, TRUE, NULL);
+
+	priv->ip4_state = priv->ip6_state = IP_CONF;
+
+	ret = NM_DEVICE_GET_CLASS (self)->act_stage3_ip4_config_start (self, &ip4_config, &reason);
+	if (ret == NM_ACT_STAGE_RETURN_SUCCESS) {
+		g_assert (ip4_config);
+		nm_device_activate_schedule_ip4_config_result (self, ip4_config);
+		g_object_unref (ip4_config);
+	} else if (ret == NM_ACT_STAGE_RETURN_FAILURE) {
 		nm_device_state_changed (self, NM_DEVICE_STATE_FAILED, reason);
 		goto out;
 	} else if (ret == NM_ACT_STAGE_RETURN_STOP) {
 		/* Nothing to do */
+		priv->ip4_state = IP_DONE;
 	} else
 		g_assert (ret == NM_ACT_STAGE_RETURN_POSTPONE);
 
-	ret = NM_DEVICE_GET_CLASS (self)->act_stage3_ip6_config_start (self, &reason);
-	if (ret == NM_ACT_STAGE_RETURN_SUCCESS)
-		nm_device_activate_schedule_stage4_ip6_config_get (self);
-	else if (ret == NM_ACT_STAGE_RETURN_FAILURE) {
+	ret = NM_DEVICE_GET_CLASS (self)->act_stage3_ip6_config_start (self, &ip6_config, &reason);
+	if (ret == NM_ACT_STAGE_RETURN_SUCCESS) {
+		g_assert (ip6_config);
+		nm_device_activate_schedule_ip6_config_result (self, ip6_config);
+		g_object_unref (ip6_config);
+	} else if (ret == NM_ACT_STAGE_RETURN_FAILURE) {
 		nm_device_state_changed (self, NM_DEVICE_STATE_FAILED, reason);
 		goto out;
 	} else if (ret == NM_ACT_STAGE_RETURN_STOP) {
 		/* Nothing to do */
+		priv->ip6_state = IP_DONE;
 	} else
 		g_assert (ret == NM_ACT_STAGE_RETURN_POSTPONE);
 
 out:
 	nm_log_info (LOGD_DEVICE, "Activation (%s) Stage 3 of 5 (IP Configure Start) complete.", iface);
-	return FALSE;
-}
-
 
-/*
- * nm_device_activate_schedule_stage3_ip_config_start
- *
- * Schedule IP configuration start
- */
-void
-nm_device_activate_schedule_stage3_ip_config_start (NMDevice *self)
-{
-	NMDevicePrivate *priv;
-
-	g_return_if_fail (NM_IS_DEVICE (self));
-
-	priv = NM_DEVICE_GET_PRIVATE (self);
-	g_return_if_fail (priv->act_request);
-
-	activation_source_schedule (self, nm_device_activate_stage3_ip_config_start, 0);
-
-	nm_log_info (LOGD_DEVICE, "Activation (%s) Stage 3 of 5 (IP Configure Start) scheduled.",
-	             nm_device_get_iface (self));
-}
-
-static GHashTable *shared_ips = NULL;
-
-static void
-release_shared_ip (gpointer data)
-{
-	g_hash_table_remove (shared_ips, data);
-}
-
-static guint32
-reserve_shared_ip (void)
-{
-	guint32 start = (guint32) ntohl (0x0a2a0001); /* 10.42.0.1 */
-	guint32 count = 0;
-
-	while (g_hash_table_lookup (shared_ips, GUINT_TO_POINTER (start + count))) {
-		count += ntohl (0x100);
-		if (count > ntohl (0xFE00)) {
-			nm_log_err (LOGD_SHARING, "ran out of shared IP addresses!");
-			return 0;
-		}
-	}
-
-	g_hash_table_insert (shared_ips, GUINT_TO_POINTER (start + count), GUINT_TO_POINTER (TRUE));
-	return start + count;
-}
-
-static NMIP4Config *
-nm_device_new_ip4_shared_config (NMDevice *self, NMDeviceStateReason *reason)
-{
-	NMIP4Config *config = NULL;
-	NMIP4Address *addr;
-	guint32 tmp_addr;
-
-	g_return_val_if_fail (self != NULL, NULL);
-
-	if (G_UNLIKELY (shared_ips == NULL))
-		shared_ips = g_hash_table_new (g_direct_hash, g_direct_equal);
-
-	tmp_addr = reserve_shared_ip ();
-	if (!tmp_addr) {
-		*reason = NM_DEVICE_STATE_REASON_IP_CONFIG_UNAVAILABLE;
-		return NULL;
+	/* Handle interfaces (bond slaves, etc) that won't have any IP config; they
+	 * need to move to ACTIVATED.
+	 */
+	if (priv->ip4_state == IP_DONE && priv->ip6_state == IP_DONE) {
+		/* FIXME: call layer2 stuff to set MTU? */
+		nm_device_state_changed (self, NM_DEVICE_STATE_ACTIVATED, NM_DEVICE_STATE_REASON_NONE);
 	}
 
-	config = nm_ip4_config_new ();
-	addr = nm_ip4_address_new ();
-	nm_ip4_address_set_address (addr, tmp_addr);
-	nm_ip4_address_set_prefix (addr, 24);
-	nm_ip4_config_take_address (config, addr);
-
-	/* Remove the address lock when the object gets disposed */
-	g_object_set_data_full (G_OBJECT (config), "shared-ip",
-	                        GUINT_TO_POINTER (tmp_addr), release_shared_ip);
-
-	return config;
+	return FALSE;
 }
 
-static NMActStageReturn
-real_act_stage4_get_ip4_config (NMDevice *self,
-                                NMIP4Config **config,
-                                NMDeviceStateReason *reason)
-{
-	NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE (self);
-	NMActStageReturn ret = NM_ACT_STAGE_RETURN_FAILURE;
-	NMConnection *connection;
-	NMSettingIP4Config *s_ip4;
-	const char *ip_iface;
-
-	g_return_val_if_fail (config != NULL, NM_ACT_STAGE_RETURN_FAILURE);
-	g_return_val_if_fail (*config == NULL, NM_ACT_STAGE_RETURN_FAILURE);
-	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);
-
-	connection = nm_act_request_get_connection (nm_device_get_act_request (self));
-	g_assert (connection);
-
-	s_ip4 = (NMSettingIP4Config *) nm_connection_get_setting (connection, NM_TYPE_SETTING_IP4_CONFIG);
 
-	if (priv->dhcp4_client) {
-		/* DHCP */
-		*config = nm_dhcp_client_get_ip4_config (priv->dhcp4_client, FALSE);
-		if (*config) {
-			/* Merge user-defined overrides into the IP4Config to be applied */
-			nm_utils_merge_ip4_config (*config, s_ip4);
-
-			nm_dhcp4_config_reset (priv->dhcp4_config);
-			nm_dhcp_client_foreach_option (priv->dhcp4_client,
-			                               dhcp4_add_option_cb,
-			                               priv->dhcp4_config);
-
-			/* Notify of new DHCP4 config */
-			g_object_notify (G_OBJECT (self), NM_DEVICE_INTERFACE_DHCP4_CONFIG);
-		} else
-			*reason = NM_DEVICE_STATE_REASON_DHCP_ERROR;
-	} else {
-		/* Not DHCP */
-		const char *method;
-
-		g_assert (s_ip4);
-
-		method = nm_setting_ip4_config_get_method (s_ip4);
-		g_assert (method);
-
-		if (!strcmp (method, NM_SETTING_IP4_CONFIG_METHOD_LINK_LOCAL)) {
-			*config = aipd_get_ip4_config (self, reason);
-		} else if (!strcmp (method, NM_SETTING_IP4_CONFIG_METHOD_MANUAL)) {
-			*config = nm_ip4_config_new ();
-			if (*config) {
-				/* Merge user-defined overrides into the IP4Config to be applied */
-				nm_utils_merge_ip4_config (*config, s_ip4);
-			} else
-				*reason = NM_DEVICE_STATE_REASON_IP_CONFIG_UNAVAILABLE;
-		} else if (!strcmp (method, NM_SETTING_IP4_CONFIG_METHOD_SHARED)) {
-			*config = nm_device_new_ip4_shared_config (self, reason);
-			if (*config)
-				priv->dnsmasq_manager = nm_dnsmasq_manager_new (ip_iface);
-		} else if (!strcmp (method, NM_SETTING_IP4_CONFIG_METHOD_DISABLED))
-			ret = NM_ACT_STAGE_RETURN_SUCCESS;
-	}
-
-	if (!*config) {
-		/* Make sure device is up even if config fails */
-		nm_device_bring_up (self, FALSE, NULL);
-	} else
-		ret = NM_ACT_STAGE_RETURN_SUCCESS;
-
-	return ret;
-}
-
-/*
- * nm_device_activate_stage4_ip4_config_get
- *
- * Retrieve the correct IPv4 config.
- *
- */
-static gboolean
-nm_device_activate_stage4_ip4_config_get (gpointer user_data)
+static void
+fw_add_to_zone_cb (GError *error, gpointer user_data)
 {
 	NMDevice *self = NM_DEVICE (user_data);
-	NMIP4Config *ip4_config = NULL;
-	NMActStageReturn ret;
-	const char *iface = NULL;
-	NMDeviceStateReason reason = NM_DEVICE_STATE_REASON_NONE;
+	NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE (self);
 
-	/* Clear the activation source ID now that this stage has run */
-	activation_source_clear (self, FALSE, AF_INET);
+	priv->fw_call = NULL;
 
-	iface = nm_device_get_iface (self);
-	nm_log_info (LOGD_DEVICE | LOGD_IP4,
-	             "Activation (%s) Stage 4 of 5 (IP4 Configure Get) started...",
-	             iface);
-
-	ret = NM_DEVICE_GET_CLASS (self)->act_stage4_get_ip4_config (self, &ip4_config, &reason);
-	if (ret == NM_ACT_STAGE_RETURN_POSTPONE)
-		goto out;
-	else if (!ip4_config || (ret == NM_ACT_STAGE_RETURN_FAILURE)) {
-		nm_device_state_changed (self, NM_DEVICE_STATE_FAILED, reason);
-		goto out;
+	if (error) {
+		/* FIXME: fail the device activation? */
 	}
-	g_assert (ret == NM_ACT_STAGE_RETURN_SUCCESS);	
-
-	g_object_set_data (G_OBJECT (nm_device_get_act_request (self)),
-					   NM_ACT_REQUEST_IP4_CONFIG, ip4_config);
 
-	nm_device_activate_schedule_stage5_ip_config_commit (self, AF_INET);
+	activation_source_schedule (self, nm_device_activate_stage3_ip_config_start, 0);
 
-out:
-	nm_log_info (LOGD_DEVICE | LOGD_IP4,
-	             "Activation (%s) Stage 4 of 5 (IP4 Configure Get) complete.",
-	             iface);
-	return FALSE;
+	nm_log_info (LOGD_DEVICE, "Activation (%s) Stage 3 of 5 (IP Configure Start) scheduled.",
+	             nm_device_get_iface (self));
 }
 
-
 /*
- * nm_device_activate_schedule_stage4_ip4_config_get
- *
- * Schedule creation of the IPv4 config
+ * nm_device_activate_schedule_stage3_ip_config_start
  *
+ * Schedule IP configuration start
  */
 void
-nm_device_activate_schedule_stage4_ip4_config_get (NMDevice *self)
+nm_device_activate_schedule_stage3_ip_config_start (NMDevice *self)
 {
 	NMDevicePrivate *priv;
+	NMConnection *connection;
+	NMSettingConnection *s_con = NULL;
+	NMDeviceState state;
+	const char *zone;
 
 	g_return_if_fail (NM_IS_DEVICE (self));
 
 	priv = NM_DEVICE_GET_PRIVATE (self);
 	g_return_if_fail (priv->act_request);
 
-	activation_source_schedule (self, nm_device_activate_stage4_ip4_config_get, AF_INET);
+	state = nm_device_get_state (self);
+	g_warn_if_fail (state >= NM_DEVICE_STATE_PREPARE && state <= NM_DEVICE_STATE_NEED_AUTH);
 
-	nm_log_info (LOGD_DEVICE | LOGD_IP4,
-	             "Activation (%s) Stage 4 of 5 (IP4 Configure Get) scheduled...",
-	             nm_device_get_iface (self));
-}
+	/* Add the interface to the specified firewall zone */
+	connection = nm_device_get_connection (self);
+	g_assert (connection);
+	s_con = nm_connection_get_setting_connection (connection);
 
+	zone = nm_setting_connection_get_zone (s_con);
+	nm_log_dbg (LOGD_DEVICE, "Activation (%s) setting firewall zone '%s'",
+	            nm_device_get_iface (self), zone ? zone : "default");
+	priv->fw_call = nm_firewall_manager_add_or_change_zone (priv->fw_manager,
+	                                                        nm_device_get_ip_iface (self),
+	                                                        zone,
+	                                                        TRUE,
+	                                                        fw_add_to_zone_cb,
+	                                                        self);
+}
 
 static NMActStageReturn
-real_act_stage4_ip4_config_timeout (NMDevice *self,
-									NMIP4Config **config,
-									NMDeviceStateReason *reason)
+real_act_stage4_ip4_config_timeout (NMDevice *self, NMDeviceStateReason *reason)
 {
-	g_return_val_if_fail (config != NULL, NM_ACT_STAGE_RETURN_FAILURE);
-	g_return_val_if_fail (*config == NULL, NM_ACT_STAGE_RETURN_FAILURE);
-
-	/* Notify of invalid DHCP4 config object */
-	g_object_notify (G_OBJECT (self), NM_DEVICE_INTERFACE_DHCP4_CONFIG);
-
 	if (nm_device_ip_config_should_fail (self, FALSE)) {
 		*reason = NM_DEVICE_STATE_REASON_IP_CONFIG_UNAVAILABLE;
 		return NM_ACT_STAGE_RETURN_FAILURE;
 	}
-
 	return NM_ACT_STAGE_RETURN_SUCCESS;
 }
 
@@ -2079,10 +2376,10 @@ real_act_stage4_ip4_config_timeout (NMDevice *self,
  *
  */
 static gboolean
-nm_device_activate_stage4_ip4_config_timeout (gpointer user_data)
+nm_device_activate_ip4_config_timeout (gpointer user_data)
 {
 	NMDevice *self = NM_DEVICE (user_data);
-	NMIP4Config *ip4_config = NULL;
+	NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE (self);
 	const char *iface;
 	NMActStageReturn ret = NM_ACT_STAGE_RETURN_FAILURE;
 	NMDeviceStateReason reason = NM_DEVICE_STATE_REASON_NONE;
@@ -2092,10 +2389,10 @@ nm_device_activate_stage4_ip4_config_timeout (gpointer user_data)
 
 	iface = nm_device_get_iface (self);
 	nm_log_info (LOGD_DEVICE | LOGD_IP4,
-	             "Activation (%s) Stage 4 of 5 (IP4 Configure Timeout) started...",
+	             "Activation (%s) Stage 4 of 5 (IPv4 Configure Timeout) started...",
 	             iface);
 
-	ret = NM_DEVICE_GET_CLASS (self)->act_stage4_ip4_config_timeout (self, &ip4_config, &reason);
+	ret = NM_DEVICE_GET_CLASS (self)->act_stage4_ip4_config_timeout (self, &reason);
 	if (ret == NM_ACT_STAGE_RETURN_POSTPONE)
 		goto out;
 	else if (ret == NM_ACT_STAGE_RETURN_FAILURE) {
@@ -2104,29 +2401,31 @@ nm_device_activate_stage4_ip4_config_timeout (gpointer user_data)
 	}
 	g_assert (ret == NM_ACT_STAGE_RETURN_SUCCESS);	
 
-	if (ip4_config) {
-		g_object_set_data (G_OBJECT (nm_device_get_act_request (self)),
-						   NM_ACT_REQUEST_IP4_CONFIG, ip4_config);
-	}
+	priv->ip4_state = IP_DONE;
 
-	nm_device_activate_schedule_stage5_ip_config_commit (self, AF_INET);
+	/* If IPv4 failed and IPv6 failed, the activation fails */
+	if ((priv->ip6_state == IP_DONE) && (priv->ip6_config == NULL)) {
+		nm_device_state_changed (self,
+				                 NM_DEVICE_STATE_FAILED,
+				                 NM_DEVICE_STATE_REASON_IP_CONFIG_UNAVAILABLE);
+	}
 
 out:
 	nm_log_info (LOGD_DEVICE | LOGD_IP4,
-	             "Activation (%s) Stage 4 of 5 (IP4 Configure Timeout) complete.",
+	             "Activation (%s) Stage 4 of 5 (IPv4 Configure Timeout) complete.",
 	             iface);
 	return FALSE;
 }
 
 
 /*
- * nm_device_activate_schedule_stage4_ip4_config_timeout
+ * nm_device_activate_schedule_ip4_config_timeout
  *
  * Deal with a timeout of the IPv4 configuration
  *
  */
 void
-nm_device_activate_schedule_stage4_ip4_config_timeout (NMDevice *self)
+nm_device_activate_schedule_ip4_config_timeout (NMDevice *self)
 {
 	NMDevicePrivate *priv;
 
@@ -2135,214 +2434,17 @@ nm_device_activate_schedule_stage4_ip4_config_timeout (NMDevice *self)
 	priv = NM_DEVICE_GET_PRIVATE (self);
 	g_return_if_fail (priv->act_request);
 
-	activation_source_schedule (self, nm_device_activate_stage4_ip4_config_timeout, AF_INET);
+	activation_source_schedule (self, nm_device_activate_ip4_config_timeout, AF_INET);
 
 	nm_log_info (LOGD_DEVICE | LOGD_IP4,
-	             "Activation (%s) Stage 4 of 5 (IP4 Configure Timeout) scheduled...",
+	             "Activation (%s) Stage 4 of 5 (IPv4 Configure Timeout) scheduled...",
 	             nm_device_get_iface (self));
 }
 
-static void
-merge_dhcp_config_to_master (NMIP6Config *dst, NMIP6Config *src)
-{
-	guint32 i;
-
-	g_return_if_fail (src != NULL);
-	g_return_if_fail (dst != NULL);
-
-	/* addresses */
-	for (i = 0; i < nm_ip6_config_get_num_addresses (src); i++)
-		nm_ip6_config_add_address (dst, nm_ip6_config_get_address (src, i));
-
-	/* ptp address; only replace if src doesn't have one */
-	if (!nm_ip6_config_get_ptp_address (dst))
-		nm_ip6_config_set_ptp_address (dst, nm_ip6_config_get_ptp_address (src));
-
-	/* nameservers */
-	for (i = 0; i < nm_ip6_config_get_num_nameservers (src); i++)
-		nm_ip6_config_add_nameserver (dst, nm_ip6_config_get_nameserver (src, i));
-
-	/* routes */
-	for (i = 0; i < nm_ip6_config_get_num_routes (src); i++)
-		nm_ip6_config_add_route (dst, nm_ip6_config_get_route (src, i));
-
-	/* domains */
-	for (i = 0; i < nm_ip6_config_get_num_domains (src); i++)
-		nm_ip6_config_add_domain (dst, nm_ip6_config_get_domain (src, i));
-
-	/* dns searches */
-	for (i = 0; i < nm_ip6_config_get_num_searches (src); i++)
-		nm_ip6_config_add_search (dst, nm_ip6_config_get_search (src, i));
-
-	if (!nm_ip6_config_get_mss (dst))
-		nm_ip6_config_set_mss (dst, nm_ip6_config_get_mss (src));
-}
 
 static NMActStageReturn
-real_act_stage4_get_ip6_config (NMDevice *self,
-                                NMIP6Config **config,
-                                NMDeviceStateReason *reason)
-{
-	NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE (self);
-	NMConnection *connection;
-	NMSettingIP6Config *s_ip6;
-	const char *ip_iface;
-
-	g_return_val_if_fail (config != NULL, NM_ACT_STAGE_RETURN_FAILURE);
-	g_return_val_if_fail (*config == NULL, NM_ACT_STAGE_RETURN_FAILURE);
-	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);
-
-	connection = nm_act_request_get_connection (nm_device_get_act_request (self));
-	g_assert (connection);
-
-	if (   ip6_method_matches (connection, NM_SETTING_IP6_CONFIG_METHOD_AUTO)
-	    || ip6_method_matches (connection, NM_SETTING_IP6_CONFIG_METHOD_LINK_LOCAL)) {
-		*config = nm_ip6_manager_get_ip6_config (priv->ip6_manager,
-		                                         nm_device_get_ip_ifindex (self));
-		if (!*config) {
-			*reason = NM_DEVICE_STATE_REASON_IP_CONFIG_UNAVAILABLE;
-			goto out;
-		}
-	} else if (ip6_method_matches (connection, NM_SETTING_IP6_CONFIG_METHOD_MANUAL)) {
-		*config = nm_ip6_config_new ();
-		if (!*config) {
-			*reason = NM_DEVICE_STATE_REASON_IP_CONFIG_UNAVAILABLE;
-			goto out;
-		}
-	} else if (ip6_method_matches (connection, NM_SETTING_IP6_CONFIG_METHOD_DHCP))
-		g_assert (priv->dhcp6_client);  /* sanity check */
-
-	/* Autoconf might have triggered DHCPv6 too */
-	if (priv->dhcp6_client) {
-		NMIP6Config *dhcp;
-
-		dhcp = nm_dhcp_client_get_ip6_config (priv->dhcp6_client, FALSE);
-		if (!dhcp) {
-			*reason = NM_DEVICE_STATE_REASON_DHCP_ERROR;
-			goto out;
-		}
-
-		/* For "managed" and DHCP-only setups, we use only the DHCP-supplied
-		 * IPv6 config.  But when autoconf is enabled, we have to merge the
-		 * autoconf config and the DHCP-supplied config, then merge the
-		 * user's overrides from the connection to get the final configuration
-		 * that gets applied to the device.
-		 */
-		if (*config) {
-			/* Merge autoconf and DHCP configs */
-			merge_dhcp_config_to_master (*config, dhcp);
-			g_object_unref (dhcp);
-			dhcp = NULL;
-		} else {
-			*config = dhcp;
-		}
-
-		/* Copy the new DHCPv6 configuration into the DHCP config object that's
-		 * exported over D-Bus to clients.
-		 */
-		nm_dhcp6_config_reset (priv->dhcp6_config);
-		nm_dhcp_client_foreach_option (priv->dhcp6_client,
-		                               dhcp6_add_option_cb,
-		                               priv->dhcp6_config);
-
-		/* Notify of new DHCP6 config */
-		g_object_notify (G_OBJECT (self), NM_DEVICE_INTERFACE_DHCP6_CONFIG);
-	}
-
-	/* Merge user-defined overrides into the IP6Config to be applied */
-	if (*config) {
-		s_ip6 = (NMSettingIP6Config *) nm_connection_get_setting (connection, NM_TYPE_SETTING_IP6_CONFIG);
-		nm_utils_merge_ip6_config (*config, s_ip6);
-	}
-
-out:
-	return *config ? NM_ACT_STAGE_RETURN_SUCCESS : NM_ACT_STAGE_RETURN_FAILURE;
-}
-
-/*
- * nm_device_activate_stage4_ip6_config_get
- *
- * Retrieve the correct IPv6 config.
- *
- */
-static gboolean
-nm_device_activate_stage4_ip6_config_get (gpointer user_data)
+real_act_stage4_ip6_config_timeout (NMDevice *self, NMDeviceStateReason *reason)
 {
-	NMDevice *self = NM_DEVICE (user_data);
-	NMIP6Config *ip6_config = NULL;
-	NMActStageReturn ret;
-	const char *iface = NULL;
-	NMDeviceStateReason reason = NM_DEVICE_STATE_REASON_NONE;
-
-	/* Clear the activation source ID now that this stage has run */
-	activation_source_clear (self, FALSE, AF_INET6);
-
-	iface = nm_device_get_iface (self);
-	nm_log_info (LOGD_DEVICE | LOGD_IP6,
-	             "Activation (%s) Stage 4 of 5 (IP6 Configure Get) started...",
-	             iface);
-
-	ret = NM_DEVICE_GET_CLASS (self)->act_stage4_get_ip6_config (self, &ip6_config, &reason);
-	if (ret == NM_ACT_STAGE_RETURN_POSTPONE)
-		goto out;
-	else if (ret == NM_ACT_STAGE_RETURN_FAILURE)
-	{
-		nm_device_state_changed (self, NM_DEVICE_STATE_FAILED, reason);
-		goto out;
-	}
-	g_assert (ret == NM_ACT_STAGE_RETURN_SUCCESS);
-
-	g_object_set_data (G_OBJECT (nm_device_get_act_request (self)),
-					   NM_ACT_REQUEST_IP6_CONFIG, ip6_config);
-
-	nm_device_activate_schedule_stage5_ip_config_commit (self, AF_INET6);
-
-out:
-	nm_log_info (LOGD_DEVICE | LOGD_IP6,
-	             "Activation (%s) Stage 4 of 5 (IP6 Configure Get) complete.",
-	             iface);
-	return FALSE;
-}
-
-
-/*
- * nm_device_activate_schedule_stage4_ip6_config_get
- *
- * Schedule creation of the IPv6 config
- *
- */
-void
-nm_device_activate_schedule_stage4_ip6_config_get (NMDevice *self)
-{
-	NMDevicePrivate *priv;
-
-	g_return_if_fail (NM_IS_DEVICE (self));
-
-	priv = NM_DEVICE_GET_PRIVATE (self);
-	g_return_if_fail (priv->act_request);
-
-	activation_source_schedule (self, nm_device_activate_stage4_ip6_config_get, AF_INET6);
-
-	nm_log_info (LOGD_DEVICE | LOGD_IP6,
-	             "Activation (%s) Stage 4 of 5 (IP6 Configure Get) scheduled...",
-	             nm_device_get_iface (self));
-}
-
-
-static NMActStageReturn
-real_act_stage4_ip6_config_timeout (NMDevice *self,
-									NMIP6Config **config,
-									NMDeviceStateReason *reason)
-{
-	g_return_val_if_fail (config != NULL, NM_ACT_STAGE_RETURN_FAILURE);
-	g_return_val_if_fail (*config == NULL, NM_ACT_STAGE_RETURN_FAILURE);
-
-	/* Notify of invalid DHCP4 config object */
-	g_object_notify (G_OBJECT (self), NM_DEVICE_INTERFACE_DHCP6_CONFIG);
-
 	if (nm_device_ip_config_should_fail (self, TRUE)) {
 		*reason = NM_DEVICE_STATE_REASON_IP_CONFIG_UNAVAILABLE;
 		return NM_ACT_STAGE_RETURN_FAILURE;
@@ -2353,16 +2455,16 @@ real_act_stage4_ip6_config_timeout (NMDevice *self,
 
 
 /*
- * nm_device_activate_stage4_ip6_config_timeout
+ * nm_device_activate_ip6_config_timeout
  *
  * Time out on retrieving the IPv6 config.
  *
  */
 static gboolean
-nm_device_activate_stage4_ip6_config_timeout (gpointer user_data)
+nm_device_activate_ip6_config_timeout (gpointer user_data)
 {
 	NMDevice *self = NM_DEVICE (user_data);
-	NMIP6Config *ip6_config = NULL;
+	NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE (self);
 	const char *iface;
 	NMActStageReturn ret = NM_ACT_STAGE_RETURN_FAILURE;
 	NMDeviceStateReason reason = NM_DEVICE_STATE_REASON_NONE;
@@ -2372,10 +2474,10 @@ nm_device_activate_stage4_ip6_config_timeout (gpointer user_data)
 
 	iface = nm_device_get_iface (self);
 	nm_log_info (LOGD_DEVICE | LOGD_IP6,
-	             "Activation (%s) Stage 4 of 5 (IP6 Configure Timeout) started...",
+	             "Activation (%s) Stage 4 of 5 (IPv6 Configure Timeout) started...",
 	             iface);
 
-	ret = NM_DEVICE_GET_CLASS (self)->act_stage4_ip6_config_timeout (self, &ip6_config, &reason);
+	ret = NM_DEVICE_GET_CLASS (self)->act_stage4_ip6_config_timeout (self, &reason);
 	if (ret == NM_ACT_STAGE_RETURN_POSTPONE)
 		goto out;
 	else if (ret == NM_ACT_STAGE_RETURN_FAILURE) {
@@ -2384,29 +2486,31 @@ nm_device_activate_stage4_ip6_config_timeout (gpointer user_data)
 	}
 	g_assert (ret == NM_ACT_STAGE_RETURN_SUCCESS);
 
-	if (ip6_config) {
-		g_object_set_data (G_OBJECT (nm_device_get_act_request (self)),
-						   NM_ACT_REQUEST_IP6_CONFIG, ip6_config);
-	}
+	priv->ip6_state = IP_DONE;
 
-	nm_device_activate_schedule_stage5_ip_config_commit (self, AF_INET6);
+	/* If IPv6 failed and IPv4 failed, the activation fails */
+	if ((priv->ip4_state == IP_DONE) && (priv->ip4_config == NULL)) {
+		nm_device_state_changed (self,
+				                 NM_DEVICE_STATE_FAILED,
+				                 NM_DEVICE_STATE_REASON_IP_CONFIG_UNAVAILABLE);
+	}
 
 out:
 	nm_log_info (LOGD_DEVICE | LOGD_IP6,
-	             "Activation (%s) Stage 4 of 5 (IP6 Configure Timeout) complete.",
+	             "Activation (%s) Stage 4 of 5 (IPv6 Configure Timeout) complete.",
 	             iface);
 	return FALSE;
 }
 
 
 /*
- * nm_device_activate_schedule_stage4_ip6_config_timeout
+ * nm_device_activate_schedule_ip6_config_timeout
  *
  * Deal with a timeout of the IPv6 configuration
  *
  */
 void
-nm_device_activate_schedule_stage4_ip6_config_timeout (NMDevice *self)
+nm_device_activate_schedule_ip6_config_timeout (NMDevice *self)
 {
 	NMDevicePrivate *priv;
 
@@ -2415,10 +2519,10 @@ nm_device_activate_schedule_stage4_ip6_config_timeout (NMDevice *self)
 	priv = NM_DEVICE_GET_PRIVATE (self);
 	g_return_if_fail (priv->act_request);
 
-	activation_source_schedule (self, nm_device_activate_stage4_ip6_config_timeout, AF_INET6);
+	activation_source_schedule (self, nm_device_activate_ip6_config_timeout, AF_INET6);
 
 	nm_log_info (LOGD_DEVICE | LOGD_IP6,
-	             "Activation (%s) Stage 4 of 5 (IP6 Configure Timeout) scheduled...",
+	             "Activation (%s) Stage 4 of 5 (IPv6 Configure Timeout) scheduled...",
 	             nm_device_get_iface (self));
 }
 
@@ -2483,7 +2587,7 @@ add_share_rule (NMActRequest *req, const char *table, const char *fmt, ...)
 }
 
 static gboolean
-start_sharing (NMDevice *self)
+start_sharing (NMDevice *self, NMIP4Config *config)
 {
 	NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE (self);
 	NMActRequest *req;
@@ -2491,17 +2595,14 @@ start_sharing (NMDevice *self)
 	char str_addr[INET_ADDRSTRLEN + 1];
 	char str_mask[INET_ADDRSTRLEN + 1];
 	guint32 netmask, network;
-	NMIP4Config *ip4_config;
 	NMIP4Address *ip4_addr;
 	const char *ip_iface;
 
-	ip_iface = nm_device_get_ip_iface (self);
+	g_return_val_if_fail (config != NULL, FALSE);
 
-	ip4_config = nm_device_get_ip4_config (self);
-	if (!ip4_config)
-		return FALSE;
+	ip_iface = nm_device_get_ip_iface (self);
 
-	ip4_addr = nm_ip4_config_get_address (ip4_config, 0);
+	ip4_addr = nm_ip4_config_get_address (config, 0);
 	if (!ip4_addr || !nm_ip4_address_get_address (ip4_addr))
 		return FALSE;
 
@@ -2532,7 +2633,7 @@ start_sharing (NMDevice *self)
 
 	nm_act_request_set_shared (req, TRUE);
 
-	if (!nm_dnsmasq_manager_start (priv->dnsmasq_manager, ip4_config, &error)) {
+	if (!nm_dnsmasq_manager_start (priv->dnsmasq_manager, config, &error)) {
 		nm_log_err (LOGD_SHARING, "(%s/%s): failed to start dnsmasq: %s",
 		            nm_device_get_iface (self), ip_iface, error->message);
 		g_error_free (error);
@@ -2546,114 +2647,86 @@ start_sharing (NMDevice *self)
 	return TRUE;
 }
 
-/*
- * nm_device_activate_stage5_ip_config_commit
- *
- * Commit the IP config on the device
- *
- */
 static gboolean
-nm_device_activate_stage5_ip_config_commit (gpointer user_data)
+nm_device_activate_ip4_config_commit (gpointer user_data)
 {
 	NMDevice *self = NM_DEVICE (user_data);
 	NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE (self);
-	NMActRequest *act_request;
-	NMIP4Config *ip4_config = NULL;
-	NMIP6Config *ip6_config = NULL;
+	NMActRequest *req;
+	NMIP4Config *config = NULL;
 	const char *iface, *method = NULL;
 	NMConnection *connection;
 	NMSettingIP4Config *s_ip4;
 	NMDeviceStateReason reason = NM_DEVICE_STATE_REASON_NONE;
 	gboolean assumed;
-
-	/* Get the new IP4 and IP6 configs; since this stage gets rerun
-	 * when automatic configuration changes (DHCP lease renewal, new
-	 * IPv6 router advertisement, etc), it's possible that only one of
-	 * them will be set.
-	 */
-	act_request = nm_device_get_act_request (self);
-
-	ip4_config = g_object_get_data (G_OBJECT (act_request),
-									NM_ACT_REQUEST_IP4_CONFIG);
-	g_object_set_data (G_OBJECT (act_request),
-					   NM_ACT_REQUEST_IP4_CONFIG, NULL);
-
-	ip6_config = g_object_get_data (G_OBJECT (act_request),
-									NM_ACT_REQUEST_IP6_CONFIG);
-	g_object_set_data (G_OBJECT (act_request),
-					   NM_ACT_REQUEST_IP6_CONFIG, NULL);
+	int ifindex;
 
 	/* Clear the activation source ID now that this stage has run */
-	activation_source_clear (self, FALSE, 0);
+	activation_source_clear (self, FALSE, AF_INET);
 
 	iface = nm_device_get_iface (self);
-	nm_log_info (LOGD_DEVICE, "Activation (%s) Stage 5 of 5 (IP Configure Commit) started...",
+	nm_log_info (LOGD_DEVICE, "Activation (%s) Stage 5 of 5 (IPv4 Commit) started...",
 	             iface);
 
-	assumed = nm_act_request_get_assumed (priv->act_request);
+	req = nm_device_get_act_request (self);
+	g_assert (req);
+	connection = nm_act_request_get_connection (req);
+	g_assert (connection);
 
-	if (!ip6_config && !ip4_config) {
-		nm_log_info (LOGD_DEVICE,
-		             "Activation (%s) Stage 5 of 5 (IP Configure Commit) failed (no IP configuration found)",
-				     iface);
-		nm_device_state_changed (self,
-		                         NM_DEVICE_STATE_FAILED,
-		                         NM_DEVICE_STATE_REASON_IP_CONFIG_UNAVAILABLE);
-		goto out;
-	}
+	config = g_object_get_data (G_OBJECT (req), PENDING_IP4_CONFIG);
+	g_assert (config);
 
-	if (ip4_config && !nm_device_set_ip4_config (self, ip4_config, assumed, &reason)) {
-		nm_device_state_changed (self, NM_DEVICE_STATE_FAILED, reason);
-		goto out;
-	}
+	/* Make sure the interface is up again just because */
+	ifindex = nm_device_get_ip_ifindex (self);
+	if ((ifindex > 0) && (nm_system_iface_is_up (ifindex) == FALSE))
+		nm_system_iface_set_up (ifindex, TRUE, NULL);
 
-	if (ip6_config && !nm_device_set_ip6_config (self, ip6_config, assumed, &reason)) {
-		nm_log_info (LOGD_DEVICE | LOGD_IP6,
-		             "Activation (%s) Stage 5 of 5 (IP Configure Commit) IPv6 failed",
-				     iface);
+	/* Allow setting MTU etc */
+	if (NM_DEVICE_GET_CLASS (self)->ip4_config_pre_commit)
+		NM_DEVICE_GET_CLASS (self)->ip4_config_pre_commit (self, config);
+
+	/* Merge with user overrides */
+	nm_utils_merge_ip4_config (config, nm_connection_get_setting_ip4_config (connection));
+
+	assumed = nm_act_request_get_assumed (priv->act_request);
+	if (!nm_device_set_ip4_config (self, config, assumed, &reason)) {
+		nm_log_info (LOGD_DEVICE | LOGD_IP4,
+			         "Activation (%s) Stage 5 of 5 (IPv4 Commit) failed",
+					 iface);
 		nm_device_state_changed (self, NM_DEVICE_STATE_FAILED, reason);
 		goto out;
 	}
 
-	connection = nm_act_request_get_connection (nm_device_get_act_request (self));
-
-	if (ip4_config) {
-		s_ip4 = (NMSettingIP4Config *) nm_connection_get_setting (connection, NM_TYPE_SETTING_IP4_CONFIG);
-		if (s_ip4)
-			method = nm_setting_ip4_config_get_method (s_ip4);
+	/* Start IPv4 sharing if we need it */
+	s_ip4 = nm_connection_get_setting_ip4_config (connection);
+	if (s_ip4)
+		method = nm_setting_ip4_config_get_method (s_ip4);
 
-		if (s_ip4 && !strcmp (method, NM_SETTING_IP4_CONFIG_METHOD_SHARED)) {
-			if (!start_sharing (self)) {
-				nm_log_warn (LOGD_SHARING, "Activation (%s) Stage 5 of 5 (IP Configure Commit) start sharing failed.", iface);
-				nm_device_state_changed (self, NM_DEVICE_STATE_FAILED, NM_DEVICE_STATE_REASON_SHARED_START_FAILED);
-				goto out;
-			}
+	if (g_strcmp0 (method, NM_SETTING_IP4_CONFIG_METHOD_SHARED) == 0) {
+		if (!start_sharing (self, config)) {
+			nm_log_warn (LOGD_SHARING, "Activation (%s) Stage 5 of 5 (IPv4 Commit) start sharing failed.", iface);
+			nm_device_state_changed (self, NM_DEVICE_STATE_FAILED, NM_DEVICE_STATE_REASON_SHARED_START_FAILED);
+			goto out;
 		}
 	}
 
-	nm_device_state_changed (self, NM_DEVICE_STATE_ACTIVATED, NM_DEVICE_STATE_REASON_NONE);
+	/* Enter the ACTIVATED state if this is the first method to complete */
+	priv->ip4_state = IP_DONE;
+	if (nm_device_get_state (self) == NM_DEVICE_STATE_IP_CONFIG)
+		nm_device_state_changed (self, NM_DEVICE_STATE_ACTIVATED, NM_DEVICE_STATE_REASON_NONE);
 
 out:
-	nm_log_info (LOGD_DEVICE, "Activation (%s) Stage 5 of 5 (IP Configure Commit) complete.",
+	nm_log_info (LOGD_DEVICE, "Activation (%s) Stage 5 of 5 (IPv4 Commit) complete.",
 	             iface);
 
-	/* Balance IP config creation; device takes ownership in set_ip*_config() */
-	if (ip4_config)
-		g_object_unref (ip4_config);
-	if (ip6_config)
-		g_object_unref (ip6_config);
+	/* Balance IP config creation; nm_device_set_ip4_config() takes a reference */
+	g_object_set_data (G_OBJECT (req), PENDING_IP4_CONFIG, NULL);
 
 	return FALSE;
 }
 
-
-/*
- * nm_device_activate_schedule_stage5_ip_config_commit
- *
- * Schedule commit of the IP config
- */
-static void
-nm_device_activate_schedule_stage5_ip_config_commit (NMDevice *self, int family)
+void
+nm_device_activate_schedule_ip4_config_result (NMDevice *self, NMIP4Config *config)
 {
 	NMDevicePrivate *priv;
 
@@ -2662,26 +2735,121 @@ nm_device_activate_schedule_stage5_ip_config_commit (NMDevice *self, int family)
 	priv = NM_DEVICE_GET_PRIVATE (self);
 	g_return_if_fail (priv->act_request);
 
-	if (family == AF_INET)
-		priv->ip4_ready = TRUE;
-	else if (family == AF_INET6)
-		priv->ip6_ready = TRUE;
+	if (config == NULL) {
+		nm_device_state_changed (self, NM_DEVICE_STATE_FAILED, NM_DEVICE_STATE_REASON_IP_CONFIG_UNAVAILABLE);
+		return;
+	}
 
-	/* Note that these are only set FALSE at stage3, so once you've
-	 * made it all the way through activation once, you can jump back
-	 * into stage4 (eg, for a DHCP lease change) and not worry about
-	 * needing both IPv4 and IPv6 to complete.
-	 */
-	if (!priv->ip4_ready || !priv->ip6_ready)
+	g_object_set_data_full (G_OBJECT (priv->act_request),
+	                        PENDING_IP4_CONFIG,
+	                        g_object_ref (config),
+	                        g_object_unref);
+
+	activation_source_schedule (self, nm_device_activate_ip4_config_commit, AF_INET);
+
+	nm_log_info (LOGD_DEVICE | LOGD_IP4,
+		         "Activation (%s) Stage 5 of 5 (IPv4 Configure Commit) scheduled...",
+		         nm_device_get_iface (self));
+}
+
+gboolean
+nm_device_activate_ip4_state_in_conf (NMDevice *self)
+{
+	g_return_val_if_fail (self != NULL, FALSE);
+	return NM_DEVICE_GET_PRIVATE (self)->ip4_state == IP_CONF;
+}
+
+static gboolean
+nm_device_activate_ip6_config_commit (gpointer user_data)
+{
+	NMDevice *self = NM_DEVICE (user_data);
+	NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE (self);
+	NMActRequest *req;
+	NMIP6Config *config = NULL;
+	const char *iface;
+	NMConnection *connection;
+	NMDeviceStateReason reason = NM_DEVICE_STATE_REASON_NONE;
+	int ifindex;
+
+	/* Clear the activation source ID now that this stage has run */
+	activation_source_clear (self, FALSE, AF_INET6);
+
+	iface = nm_device_get_iface (self);
+	nm_log_info (LOGD_DEVICE, "Activation (%s) Stage 5 of 5 (IPv6 Commit) started...",
+	             iface);
+
+	req = nm_device_get_act_request (self);
+	g_assert (req);
+	connection = nm_act_request_get_connection (req);
+	g_assert (connection);
+
+	config = g_object_get_data (G_OBJECT (req), PENDING_IP6_CONFIG);
+	g_assert (config);
+
+	/* Make sure the interface is up again just because */
+	ifindex = nm_device_get_ip_ifindex (self);
+	if ((ifindex > 0) && (nm_system_iface_is_up (ifindex) == FALSE))
+		nm_system_iface_set_up (ifindex, TRUE, NULL);
+
+	/* Allow setting MTU etc */
+	if (NM_DEVICE_GET_CLASS (self)->ip6_config_pre_commit)
+		NM_DEVICE_GET_CLASS (self)->ip6_config_pre_commit (self, config);
+
+	if (ip6_config_merge_and_apply (self, config, &reason)) {
+		/* Enter the ACTIVATED state if this is the first method to complete */
+		priv->ip6_state = IP_DONE;
+		if (nm_device_get_state (self) == NM_DEVICE_STATE_IP_CONFIG)
+			nm_device_state_changed (self, NM_DEVICE_STATE_ACTIVATED, NM_DEVICE_STATE_REASON_NONE);
+	} else {
+		nm_log_info (LOGD_DEVICE | LOGD_IP6,
+			         "Activation (%s) Stage 5 of 5 (IPv6 Commit) failed",
+					 iface);
+		nm_device_state_changed (self, NM_DEVICE_STATE_FAILED, reason);
+	}
+
+	nm_log_info (LOGD_DEVICE, "Activation (%s) Stage 5 of 5 (IPv6 Commit) complete.",
+	             iface);
+
+	/* Balance IP config creation; nm_device_set_ip6_config() takes a reference */
+	g_object_set_data (G_OBJECT (req), PENDING_IP6_CONFIG, NULL);
+
+	return FALSE;
+}
+
+void
+nm_device_activate_schedule_ip6_config_result (NMDevice *self, NMIP6Config *config)
+{
+	NMDevicePrivate *priv;
+
+	g_return_if_fail (NM_IS_DEVICE (self));
+
+	priv = NM_DEVICE_GET_PRIVATE (self);
+	g_return_if_fail (priv->act_request);
+
+	if (config == NULL) {
+		nm_device_state_changed (self, NM_DEVICE_STATE_FAILED, NM_DEVICE_STATE_REASON_IP_CONFIG_UNAVAILABLE);
 		return;
+	}
 
-	activation_source_schedule (self, nm_device_activate_stage5_ip_config_commit, 0);
+	/* Save the pending config */
+	g_object_set_data_full (G_OBJECT (priv->act_request),
+	                        PENDING_IP6_CONFIG,
+	                        g_object_ref (config),
+	                        g_object_unref);
 
-	nm_log_info (LOGD_DEVICE,
-	             "Activation (%s) Stage 5 of 5 (IP Configure Commit) scheduled...",
-	             nm_device_get_iface (self));
+	activation_source_schedule (self, nm_device_activate_ip6_config_commit, AF_INET6);
+
+	nm_log_info (LOGD_DEVICE | LOGD_IP4,
+		         "Activation (%s) Stage 5 of 5 (IPv6 Commit) scheduled...",
+		         nm_device_get_iface (self));
 }
 
+gboolean
+nm_device_activate_ip6_state_in_conf (NMDevice *self)
+{
+	g_return_val_if_fail (self != NULL, FALSE);
+	return NM_DEVICE_GET_PRIVATE (self)->ip6_state == IP_CONF;
+}
 
 static void
 clear_act_request (NMDevice *self)
@@ -2707,29 +2875,23 @@ clear_act_request (NMDevice *self)
 		priv->secrets_failed_id = 0;
 	}
 
-	nm_act_request_set_default (priv->act_request, FALSE);
+	nm_active_connection_set_default (NM_ACTIVE_CONNECTION (priv->act_request), FALSE);
 
 	g_object_unref (priv->act_request);
 	priv->act_request = NULL;
 }
 
 static void
-delayed_transitions_clear (NMDevice *self)
+queued_state_clear (NMDevice *self)
 {
 	NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE (self);
 
-	if (priv->failed_to_disconnected_id) {
-		nm_log_dbg (LOGD_DEVICE, "(%s): clearing failed->disconnected transition",
-		            nm_device_get_iface (self));
-		g_source_remove (priv->failed_to_disconnected_id);
-		priv->failed_to_disconnected_id = 0;
-	}
-	if (priv->unavailable_to_disconnected_id) {
-		nm_log_dbg (LOGD_DEVICE, "(%s): clearing unavailable->disconnected transition",
-		            nm_device_get_iface (self));
-		g_source_remove (priv->unavailable_to_disconnected_id);
-		priv->unavailable_to_disconnected_id = 0;
+	if (priv->queued_state.id) {
+		nm_log_dbg (LOGD_DEVICE, "(%s): clearing queued state transition (id %d)",
+		            nm_device_get_iface (self), priv->queued_state.id);
+		g_source_remove (priv->queued_state.id);
 	}
+	memset (&priv->queued_state, 0, sizeof (priv->queued_state));
 }
 
 static void
@@ -2738,7 +2900,7 @@ dhcp4_cleanup (NMDevice *self, gboolean stop, gboolean release)
 	NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE (self);
 
 	if (priv->dhcp4_config) {
-		g_object_notify (G_OBJECT (self), NM_DEVICE_INTERFACE_DHCP4_CONFIG);
+		g_object_notify (G_OBJECT (self), NM_DEVICE_DHCP4_CONFIG);
 		g_object_unref (priv->dhcp4_config);
 		priv->dhcp4_config = NULL;
 	}
@@ -2770,8 +2932,13 @@ dhcp6_cleanup (NMDevice *self, gboolean stop, gboolean release)
 
 	priv->dhcp6_mode = IP6_DHCP_OPT_NONE;
 
+	if (priv->dhcp6_ip6_config) {
+		g_object_unref (priv->dhcp6_ip6_config);
+		priv->dhcp6_ip6_config = NULL;
+	}
+
 	if (priv->dhcp6_config) {
-		g_object_notify (G_OBJECT (self), NM_DEVICE_INTERFACE_DHCP6_CONFIG);
+		g_object_notify (G_OBJECT (self), NM_DEVICE_DHCP6_CONFIG);
 		g_object_unref (priv->dhcp6_config);
 		priv->dhcp6_config = NULL;
 	}
@@ -2813,6 +2980,32 @@ dnsmasq_cleanup (NMDevice *self)
 	priv->dnsmasq_manager = NULL;
 }
 
+static void
+_update_ip4_address (NMDevice *self)
+{
+	NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE (self);
+	struct ifreq req;
+	guint32 new_address;
+	int fd;
+
+	g_return_if_fail (self  != NULL);
+
+	fd = socket (PF_INET, SOCK_DGRAM, 0);
+	if (fd < 0) {
+		nm_log_err (LOGD_IP4, "couldn't open control socket.");
+		return;
+	}
+
+	memset (&req, 0, sizeof (struct ifreq));
+	strncpy (req.ifr_name, nm_device_get_ip_iface (self), IFNAMSIZ);
+	if (ioctl (fd, SIOCGIFADDR, &req) == 0) {
+		new_address = ((struct sockaddr_in *)(&req.ifr_addr))->sin_addr.s_addr;
+		if (new_address != priv->ip4_address)
+			priv->ip4_address = new_address;
+	}
+	close (fd);
+}
+
 /*
  * nm_device_deactivate
  *
@@ -2820,29 +3013,58 @@ dnsmasq_cleanup (NMDevice *self)
  *
  */
 static void
-nm_device_deactivate (NMDeviceInterface *device, NMDeviceStateReason reason)
+nm_device_deactivate (NMDevice *self, NMDeviceStateReason reason)
 {
-	NMDevice *self = NM_DEVICE (device);
-	NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE (self);
+	NMDevicePrivate *priv;
 	NMDeviceStateReason ignored = NM_DEVICE_STATE_REASON_NONE;
+	NMConnection *connection = NULL;
+	NMSettingConnection *s_con = NULL;
 	gboolean tried_ipv6 = FALSE;
 	int ifindex, family;
 
 	g_return_if_fail (self != NULL);
+	g_return_if_fail (NM_IS_DEVICE (self));
 
 	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 */
+	priv = NM_DEVICE_GET_PRIVATE (self);
 	if (priv->ip6_manager || priv->ip6_config)
 		tried_ipv6 = TRUE;
 
+	/* Clean up when device was deactivated during call to firewall */
+	if (priv->fw_call) {
+		nm_firewall_manager_cancel_call (priv->fw_manager, priv->fw_call);
+		priv->fw_call = NULL;
+	}
+
+	if (priv->act_request)
+		connection = nm_act_request_get_connection (priv->act_request);
+	if (connection) {
+		s_con = nm_connection_get_setting_connection (connection);
+		nm_firewall_manager_remove_from_zone (priv->fw_manager,
+		                                      nm_device_get_ip_iface (self),
+		                                      nm_setting_connection_get_zone (s_con));
+	}
+
 	/* Break the activation chain */
 	activation_source_clear (self, TRUE, AF_INET);
 	activation_source_clear (self, TRUE, AF_INET6);
 
-	/* Clear any delayed transitions */
-	delayed_transitions_clear (self);
+	if (priv->act_dep_result_id) {
+		g_source_remove (priv->act_dep_result_id);
+		priv->act_dep_result_id = 0;
+	}
+	if (priv->act_dep_timeout_id) {
+		g_source_remove (priv->act_dep_timeout_id);
+		priv->act_dep_timeout_id = 0;
+	}
+
+	/* Clear any queued transitions */
+	queued_state_clear (self);
+
+	priv->ip4_state = priv->ip6_state = IP_NONE;
 
 	dhcp4_cleanup (self, TRUE, FALSE);
 	dhcp6_cleanup (self, TRUE, FALSE);
@@ -2856,6 +3078,10 @@ nm_device_deactivate (NMDeviceInterface *device, NMDeviceStateReason reason)
 	if (priv->ip6_accept_ra_path)
 		nm_utils_do_sysctl (priv->ip6_accept_ra_path, "0\n");
 
+	/* Turn off IPv6 privacy extensions */
+	if (priv->ip6_privacy_tempaddr_path)
+		nm_utils_do_sysctl (priv->ip6_privacy_tempaddr_path, "0\n");
+
 	/* Call device type-specific deactivation */
 	if (NM_DEVICE_GET_CLASS (self)->deactivate)
 		NM_DEVICE_GET_CLASS (self)->deactivate (self);
@@ -2866,46 +3092,119 @@ nm_device_deactivate (NMDeviceInterface *device, NMDeviceStateReason reason)
 	/* Take out any entries in the routing table and any IP address the device had. */
 	ifindex = nm_device_get_ip_ifindex (self);
 	family = tried_ipv6 ? AF_UNSPEC : AF_INET;
-	nm_system_iface_flush_routes (ifindex, family);
-	nm_system_iface_flush_addresses (ifindex, family);
-	nm_device_update_ip4_address (self);	
+	if (ifindex >= 0) {
+		nm_system_iface_flush_routes (ifindex, family);
+		nm_system_iface_flush_addresses (ifindex, family);
+	}
+	_update_ip4_address (self);
 
 	/* Clean up nameservers and addresses */
 	nm_device_set_ip4_config (self, NULL, FALSE, &ignored);
 	nm_device_set_ip6_config (self, NULL, FALSE, &ignored);
 }
 
-static gboolean
-device_disconnect (NMDeviceInterface *device,
-                   GError **error)
+gboolean
+nm_device_disconnect (NMDevice *device, GError **error)
 {
-	NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE (NM_DEVICE (device));
+	NMDevicePrivate *priv;
+
+	g_return_val_if_fail (device != NULL, FALSE);
+	g_return_val_if_fail (NM_IS_DEVICE (device), FALSE);
+
+	priv = NM_DEVICE_GET_PRIVATE (device);
+	if (priv->state <= NM_DEVICE_STATE_DISCONNECTED) {
+		g_set_error_literal (error, NM_DEVICE_ERROR, NM_DEVICE_ERROR_NOT_ACTIVE,
+		                     "Cannot disconnect an inactive device.");
+		return FALSE;
+	}
 
 	priv->autoconnect_inhibit = TRUE;	
-	nm_device_state_changed (NM_DEVICE (device), NM_DEVICE_STATE_DISCONNECTED, NM_DEVICE_STATE_REASON_USER_REQUESTED);
+	nm_device_state_changed (device,
+	                         NM_DEVICE_STATE_DISCONNECTED,
+	                         NM_DEVICE_STATE_REASON_USER_REQUESTED);
 	return TRUE;
 }
 
+static void
+impl_device_disconnect (NMDevice *device, DBusGMethodInvocation *context)
+{
+	g_signal_emit (device, signals[DISCONNECT_REQUEST], 0, context);
+}
+
 static gboolean
-check_connection_compatible (NMDeviceInterface *dev_iface,
-                             NMConnection *connection,
-                             GError **error)
+act_dep_timeout_cb (gpointer user_data)
 {
-	NMDeviceClass *klass = NM_DEVICE_GET_CLASS (NM_DEVICE (dev_iface));
+	NMDevice *self = NM_DEVICE (user_data);
+	NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE (self);
+	NMConnection *connection;
 
-	if (klass->check_connection_compatible)
-		return klass->check_connection_compatible (NM_DEVICE (dev_iface), connection, error);
+	connection = nm_active_connection_get_connection (NM_ACTIVE_CONNECTION (priv->act_request));
+	nm_log_warn (LOGD_DEVICE,
+	             "Activation (%s) connection '%s' dependency timed out",
+	             nm_device_get_iface (self),
+	             nm_connection_get_id (connection));
 
-	return TRUE;
+	nm_device_queue_state (self, NM_DEVICE_STATE_FAILED, NM_DEVICE_STATE_REASON_DEPENDENCY_FAILED);
+	return FALSE;
 }
 
-static gboolean
-nm_device_activate (NMDeviceInterface *device,
-                    NMActRequest *req,
-                    GError **error)
+static void
+act_dep_result_cb (NMActRequest *req,
+                   NMActRequestDependencyResult result,
+                   NMDevice *self)
 {
-	NMDevice *self = NM_DEVICE (device);
 	NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE (self);
+	NMConnection *connection;
+
+	connection = nm_active_connection_get_connection (NM_ACTIVE_CONNECTION (priv->act_request));
+
+	switch (result) {
+	case NM_ACT_REQUEST_DEP_RESULT_FAILED:
+		g_source_remove (priv->act_dep_result_id);
+		priv->act_dep_result_id = 0;
+
+		nm_log_warn (LOGD_DEVICE,
+			         "Activation (%s) connection '%s' dependency failed",
+			         nm_device_get_iface (self),
+			         nm_connection_get_id (connection));
+		nm_device_queue_state (self, NM_DEVICE_STATE_FAILED, NM_DEVICE_STATE_REASON_DEPENDENCY_FAILED);
+		break;
+	case NM_ACT_REQUEST_DEP_RESULT_READY:
+		g_warn_if_fail (priv->state == NM_DEVICE_STATE_PREPARE);
+		if (priv->state == NM_DEVICE_STATE_PREPARE) {
+			nm_log_info (LOGD_DEVICE,
+					     "Activation (%s) connection '%s' dependency ready, continuing activation",
+					     nm_device_get_iface (self),
+					     nm_connection_get_id (connection));
+			nm_device_activate_schedule_stage1_device_prepare (self);
+		}
+		break;
+	case NM_ACT_REQUEST_DEP_RESULT_WAIT:
+	default:
+		g_assert_not_reached ();
+		break;
+	}
+}
+
+gboolean
+nm_device_activate (NMDevice *self, NMActRequest *req, GError **error)
+{
+	NMDevicePrivate *priv;
+	NMConnection *connection;
+
+	g_return_val_if_fail (self != NULL, FALSE);
+	g_return_val_if_fail (NM_IS_DEVICE (self), FALSE);
+	g_return_val_if_fail (req != NULL, FALSE);
+	g_return_val_if_fail (NM_IS_ACT_REQUEST (req), FALSE);
+
+	priv = NM_DEVICE_GET_PRIVATE (self);
+
+	connection = nm_act_request_get_connection (req);
+	g_assert (connection);
+
+	nm_log_info (LOGD_DEVICE, "Activation (%s) starting connection '%s'",
+	             nm_device_get_iface (self),
+	             nm_connection_get_id (connection));
 
 	/* Make sure this connection isn't activated already, or in the process of
 	 * being activated.
@@ -2916,9 +3215,7 @@ nm_device_activate (NMDeviceInterface *device,
 		NMConnection *current = nm_act_request_get_connection (priv->act_request);
 
 		if (new == current) {
-			g_set_error_literal (error,
-			                     NM_DEVICE_INTERFACE_ERROR,
-			                     NM_DEVICE_INTERFACE_ERROR_CONNECTION_ACTIVATING,
+			g_set_error_literal (error, NM_DEVICE_ERROR, NM_DEVICE_ERROR_CONNECTION_ACTIVATING,
 			                     "Connection is already activating");
 			return FALSE;
 		}
@@ -2927,13 +3224,44 @@ nm_device_activate (NMDeviceInterface *device,
 	priv->act_request = g_object_ref (req);
 
 	if (!nm_act_request_get_assumed (req)) {
+		NMActiveConnection *dep_ac;
+		NMConnection *dep_con;
+
 		/* HACK: update the state a bit early to avoid a race between the 
 		 * scheduled stage1 handler and nm_policy_device_change_check() thinking
 		 * that the activation request isn't deferred because the deferred bit
 		 * gets cleared a bit too early, when the connection becomes valid.
 		 */
 		nm_device_state_changed (self, NM_DEVICE_STATE_PREPARE, NM_DEVICE_STATE_REASON_NONE);
-		nm_device_activate_schedule_stage1_device_prepare (self);
+
+		/* Handle any dependencies this connection might have */
+		switch (nm_act_request_get_dependency_result (priv->act_request)) {
+		case NM_ACT_REQUEST_DEP_RESULT_FAILED:
+			nm_device_queue_state (self, NM_DEVICE_STATE_FAILED, NM_DEVICE_STATE_REASON_DEPENDENCY_FAILED);
+			break;
+		case NM_ACT_REQUEST_DEP_RESULT_WAIT:
+			dep_ac = nm_act_request_get_dependency (priv->act_request);
+			g_assert (dep_ac);
+			dep_con = nm_active_connection_get_connection (dep_ac);
+			g_assert (dep_con);
+			nm_log_info (LOGD_DEVICE, "Activation (%s) connection '%s' waiting on dependency '%s'",
+						 nm_device_get_iface (self),
+						 nm_connection_get_id (connection),
+						 nm_connection_get_id (dep_con));
+
+			priv->act_dep_result_id = g_signal_connect (priv->act_request,
+					                                    NM_ACT_REQUEST_DEPENDENCY_RESULT,
+					                                    G_CALLBACK (act_dep_result_cb),
+					                                    self);
+			priv->act_dep_timeout_id = g_timeout_add_seconds (60, act_dep_timeout_cb, self);
+			break;
+		default:
+			g_warn_if_reached ();
+			/* fall through */
+		case NM_ACT_REQUEST_DEP_RESULT_READY:
+			nm_device_activate_schedule_stage1_device_prepare (self);
+			break;
+		}
 	} else {
 		/* If it's an assumed connection, let the device subclass short-circuit
 		 * the normal connection process and just copy its IP configs from the
@@ -3062,56 +3390,16 @@ nm_device_set_ip4_config (NMDevice *self,
 			/* Add the DNS information to the DNS manager */
 			nm_dns_manager_add_ip4_config (dns_mgr, ip_iface, new_config, NM_DNS_IP_CONFIG_TYPE_DEFAULT);
 
-			nm_device_update_ip4_address (self);
+			_update_ip4_address (self);
 		}
 	}
 	g_object_unref (dns_mgr);
 
-	g_object_notify (G_OBJECT (self), NM_DEVICE_INTERFACE_IP4_CONFIG);
+	g_object_notify (G_OBJECT (self), NM_DEVICE_IP4_CONFIG);
 
 	return success;
 }
 
-/*
- * nm_device_get_ip4_address
- *
- * Get a device's IPv4 address
- *
- */
-guint32
-nm_device_get_ip4_address (NMDevice *self)
-{
-	g_return_val_if_fail (self != NULL, 0);
-
-	return NM_DEVICE_GET_PRIVATE (self)->ip4_address;
-}
-
-
-void
-nm_device_update_ip4_address (NMDevice *self)
-{
-	struct ifreq req;
-	guint32 new_address;
-	int fd;
-	
-	g_return_if_fail (self  != NULL);
-
-	fd = socket (PF_INET, SOCK_DGRAM, 0);
-	if (fd < 0) {
-		nm_log_err (LOGD_IP4, "couldn't open control socket.");
-		return;
-	}
-
-	memset (&req, 0, sizeof (struct ifreq));
-	strncpy (req.ifr_name, nm_device_get_ip_iface (self), IFNAMSIZ);
-	if (ioctl (fd, SIOCGIFADDR, &req) == 0) {
-		new_address = ((struct sockaddr_in *)(&req.ifr_addr))->sin_addr.s_addr;
-		if (new_address != nm_device_get_ip4_address (self))
-			NM_DEVICE_GET_PRIVATE (self)->ip4_address = new_address;
-	}
-	close (fd);
-}
-
 static gboolean
 nm_device_set_ip6_config (NMDevice *self,
                           NMIP6Config *new_config,
@@ -3170,7 +3458,7 @@ nm_device_set_ip6_config (NMDevice *self,
 	}
 	g_object_unref (dns_mgr);
 
-	g_object_notify (G_OBJECT (self), NM_DEVICE_INTERFACE_IP6_CONFIG);
+	g_object_notify (G_OBJECT (self), NM_DEVICE_IP6_CONFIG);
 
 	return success;
 }
@@ -3237,7 +3525,7 @@ out:
 	if (NM_DEVICE_GET_CLASS (self)->update_hw_address)
 		NM_DEVICE_GET_CLASS (self)->update_hw_address (self);
 
-	nm_device_update_ip4_address (self);
+	_update_ip4_address (self);
 	return TRUE;
 }
 
@@ -3288,7 +3576,7 @@ nm_device_take_down (NMDevice *self, gboolean block, NMDeviceStateReason reason)
 	g_return_if_fail (NM_IS_DEVICE (self));
 
 	if (nm_device_get_act_request (self))
-		nm_device_interface_deactivate (NM_DEVICE_INTERFACE (self), reason);
+		nm_device_deactivate (self, reason);
 
 	if (nm_device_is_up (self)) {
 		nm_log_info (LOGD_HW, "(%s): cleaning up...", nm_device_get_iface (self));
@@ -3315,20 +3603,19 @@ dispose (GObject *object)
 	/* Don't down can-assume-connection capable devices that are activated with
 	 * a connection that can be assumed.
 	 */
-	if (   nm_device_interface_can_assume_connections (NM_DEVICE_INTERFACE (self))
-	    && (nm_device_get_state (self) == NM_DEVICE_STATE_ACTIVATED)) {
+	if (nm_device_can_assume_connections (self) && (priv->state == NM_DEVICE_STATE_ACTIVATED)) {
 		NMConnection *connection;
 	    NMSettingIP4Config *s_ip4 = NULL;
 		const char *method = NULL;
 
-		connection = nm_act_request_get_connection (priv->act_request);
+		connection = nm_device_get_connection (self);
 		if (connection) {
 
 			/* Only static or DHCP IPv4 connections can be left up.
 			 * All IPv6 connections can be left up, so we don't have
 			 * to check that.
 			 */
-			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)
 				method = nm_setting_ip4_config_get_method (s_ip4);
 			if (   !method
@@ -3338,8 +3625,8 @@ dispose (GObject *object)
 		}
 	}
 
-	/* Clear any delayed transitions */
-	delayed_transitions_clear (self);
+	/* Clear any queued transitions */
+	queued_state_clear (self);
 
 	/* Clean up and stop DHCP */
 	dhcp4_cleanup (self, take_down, FALSE);
@@ -3362,6 +3649,15 @@ dispose (GObject *object)
 	}
 	g_free (priv->ip6_accept_ra_path);
 
+	/* reset the saved use_tempaddr value */
+	if (priv->ip6_privacy_tempaddr_path) {
+		char tmp[16];
+
+		snprintf (tmp, sizeof (tmp), "%d\n", priv->ip6_privacy_tempaddr_save);
+		nm_utils_do_sysctl (priv->ip6_privacy_tempaddr_path, tmp);
+	}
+	g_free (priv->ip6_privacy_tempaddr_path);
+
 	activation_source_clear (self, TRUE, AF_INET);
 	activation_source_clear (self, TRUE, AF_INET6);
 
@@ -3380,6 +3676,9 @@ finalize (GObject *object)
 	if (priv->dhcp_manager)
 		g_object_unref (priv->dhcp_manager);
 
+	if (priv->fw_manager)
+		g_object_unref (priv->fw_manager);
+
 	g_free (priv->udi);
 	g_free (priv->iface);
 	g_free (priv->ip_iface);
@@ -3399,11 +3698,15 @@ set_property (GObject *object, guint prop_id,
 	NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE (object);
  
 	switch (prop_id) {
-	case NM_DEVICE_INTERFACE_PROP_UDI:
-		/* construct-only */
+	case PROP_UDI:
+		/* Only virtual interfaces can set UDI post-construction */
+		if (priv->initialized)
+			g_return_if_fail (nm_system_get_iface_type (priv->ifindex, NULL) != NM_IFACE_TYPE_UNSPEC);
+
+		g_free (priv->udi);
 		priv->udi = g_strdup (g_value_get_string (value));
 		break;
-	case NM_DEVICE_INTERFACE_PROP_IFACE:
+	case PROP_IFACE:
 		g_free (priv->iface);
 		priv->ifindex = 0;
 		priv->iface = g_value_dup_string (value);
@@ -3414,32 +3717,32 @@ set_property (GObject *object, guint prop_id,
 			}
 		}
 		break;
-	case NM_DEVICE_INTERFACE_PROP_IP_IFACE:
+	case PROP_IP_IFACE:
 		break;
-	case NM_DEVICE_INTERFACE_PROP_DRIVER:
+	case PROP_DRIVER:
 		priv->driver = g_strdup (g_value_get_string (value));
 		break;
-	case NM_DEVICE_INTERFACE_PROP_CAPABILITIES:
+	case PROP_CAPABILITIES:
 		priv->capabilities = g_value_get_uint (value);
 		break;
-	case NM_DEVICE_INTERFACE_PROP_IP4_ADDRESS:
+	case PROP_IP4_ADDRESS:
 		priv->ip4_address = g_value_get_uint (value);
 		break;
-	case NM_DEVICE_INTERFACE_PROP_MANAGED:
+	case PROP_MANAGED:
 		priv->managed = g_value_get_boolean (value);
 		break;
-	case NM_DEVICE_INTERFACE_PROP_FIRMWARE_MISSING:
+	case PROP_FIRMWARE_MISSING:
 		priv->firmware_missing = g_value_get_boolean (value);
 		break;
-	case NM_DEVICE_INTERFACE_PROP_DEVICE_TYPE:
+	case PROP_DEVICE_TYPE:
 		g_return_if_fail (priv->type == NM_DEVICE_TYPE_UNKNOWN);
 		priv->type = g_value_get_uint (value);
 		break;
-	case NM_DEVICE_INTERFACE_PROP_TYPE_DESC:
+	case PROP_TYPE_DESC:
 		g_free (priv->type_desc);
 		priv->type_desc = g_value_dup_string (value);
 		break;
-	case NM_DEVICE_INTERFACE_PROP_RFKILL_TYPE:
+	case PROP_RFKILL_TYPE:
 		priv->rfkill_type = g_value_get_uint (value);
 		break;
 	default:
@@ -3466,75 +3769,83 @@ get_property (GObject *object, guint prop_id,
 	state = nm_device_get_state (self);
 
 	switch (prop_id) {
-	case NM_DEVICE_INTERFACE_PROP_UDI:
+	case PROP_UDI:
 		g_value_set_string (value, priv->udi);
 		break;
-	case NM_DEVICE_INTERFACE_PROP_IFACE:
+	case PROP_IFACE:
 		g_value_set_string (value, priv->iface);
 		break;
-	case NM_DEVICE_INTERFACE_PROP_IP_IFACE:
+	case PROP_IP_IFACE:
 		if (_is_connected (state))
 			g_value_set_string (value, nm_device_get_ip_iface (self));
 		else
 			g_value_set_string (value, NULL);
 		break;
-	case NM_DEVICE_INTERFACE_PROP_IFINDEX:
+	case PROP_IFINDEX:
 		g_value_set_int (value, priv->ifindex);
 		break;
-	case NM_DEVICE_INTERFACE_PROP_DRIVER:
+	case PROP_DRIVER:
 		g_value_set_string (value, priv->driver);
 		break;
-	case NM_DEVICE_INTERFACE_PROP_CAPABILITIES:
+	case PROP_CAPABILITIES:
 		g_value_set_uint (value, priv->capabilities);
 		break;
-	case NM_DEVICE_INTERFACE_PROP_IP4_ADDRESS:
+	case PROP_IP4_ADDRESS:
 		g_value_set_uint (value, priv->ip4_address);
 		break;
-	case NM_DEVICE_INTERFACE_PROP_IP4_CONFIG:
+	case PROP_IP4_CONFIG:
 		if (_is_connected (state) && priv->ip4_config)
 			g_value_set_boxed (value, nm_ip4_config_get_dbus_path (priv->ip4_config));
 		else
 			g_value_set_boxed (value, "/");
 		break;
-	case NM_DEVICE_INTERFACE_PROP_DHCP4_CONFIG:
+	case PROP_DHCP4_CONFIG:
 		if (_is_connected (state) && priv->dhcp4_client)
 			g_value_set_boxed (value, nm_dhcp4_config_get_dbus_path (priv->dhcp4_config));
 		else
 			g_value_set_boxed (value, "/");
 		break;
-	case NM_DEVICE_INTERFACE_PROP_IP6_CONFIG:
+	case PROP_IP6_CONFIG:
 		if (_is_connected (state) && priv->ip6_config)
 			g_value_set_boxed (value, nm_ip6_config_get_dbus_path (priv->ip6_config));
 		else
 			g_value_set_boxed (value, "/");
 		break;
-	case NM_DEVICE_INTERFACE_PROP_DHCP6_CONFIG:
+	case PROP_DHCP6_CONFIG:
 		if (_is_connected (state) && priv->dhcp6_client)
 			g_value_set_boxed (value, nm_dhcp6_config_get_dbus_path (priv->dhcp6_config));
 		else
 			g_value_set_boxed (value, "/");
 		break;
-	case NM_DEVICE_INTERFACE_PROP_STATE:
+	case PROP_STATE:
 		g_value_set_uint (value, priv->state);
 		break;
-	case NM_DEVICE_INTERFACE_PROP_ACTIVE_CONNECTION:
+	case PROP_STATE_REASON:
+		g_value_set_boxed (value,
+			dbus_g_type_specialized_construct (DBUS_G_TYPE_UINT_STRUCT));
+		dbus_g_type_struct_set (value,
+		                        0, priv->state,
+		                        1, priv->state_reason,
+		                        G_MAXUINT);
+		break;
+	case PROP_ACTIVE_CONNECTION:
 		if (priv->act_request)
-			ac_path = nm_act_request_get_active_connection_path (priv->act_request);
+			ac_path = nm_active_connection_get_path (NM_ACTIVE_CONNECTION (priv->act_request));
 		g_value_set_boxed (value, ac_path ? ac_path : "/");
 		break;
-	case NM_DEVICE_INTERFACE_PROP_DEVICE_TYPE:
+	case PROP_DEVICE_TYPE:
 		g_value_set_uint (value, priv->type);
 		break;
-	case NM_DEVICE_INTERFACE_PROP_MANAGED:
+	case PROP_MANAGED:
 		g_value_set_boolean (value, priv->managed);
 		break;
-	case NM_DEVICE_INTERFACE_PROP_FIRMWARE_MISSING:
+	case PROP_FIRMWARE_MISSING:
 		g_value_set_boolean (value, priv->firmware_missing);
 		break;
-	case NM_DEVICE_INTERFACE_PROP_TYPE_DESC:
+	case PROP_TYPE_DESC:
 		g_value_set_string (value, priv->type_desc);
 		break;
-	case NM_DEVICE_INTERFACE_PROP_RFKILL_TYPE:
+	case PROP_RFKILL_TYPE:
 		g_value_set_uint (value, priv->rfkill_type);
 		break;
 	default:
@@ -3557,6 +3868,7 @@ nm_device_class_init (NMDeviceClass *klass)
 	object_class->set_property = set_property;
 	object_class->get_property = get_property;
 	object_class->constructor = constructor;
+	object_class->constructed = constructed;
 
 	klass->get_type_capabilities = real_get_type_capabilities;
 	klass->get_generic_capabilities = real_get_generic_capabilities;
@@ -3564,84 +3876,180 @@ nm_device_class_init (NMDeviceClass *klass)
 	klass->act_stage2_config = real_act_stage2_config;
 	klass->act_stage3_ip4_config_start = real_act_stage3_ip4_config_start;
 	klass->act_stage3_ip6_config_start = real_act_stage3_ip6_config_start;
-	klass->act_stage4_get_ip4_config = real_act_stage4_get_ip4_config;
-	klass->act_stage4_get_ip6_config = real_act_stage4_get_ip6_config;
 	klass->act_stage4_ip4_config_timeout = real_act_stage4_ip4_config_timeout;
 	klass->act_stage4_ip6_config_timeout = real_act_stage4_ip6_config_timeout;
 
 	/* Properties */
-
-	g_object_class_override_property (object_class,
-									  NM_DEVICE_INTERFACE_PROP_UDI,
-									  NM_DEVICE_INTERFACE_UDI);
-
-	g_object_class_override_property (object_class,
-									  NM_DEVICE_INTERFACE_PROP_IFACE,
-									  NM_DEVICE_INTERFACE_IFACE);
-
-	g_object_class_override_property (object_class,
-	                                  NM_DEVICE_INTERFACE_PROP_IP_IFACE,
-	                                  NM_DEVICE_INTERFACE_IP_IFACE);
-
-	g_object_class_override_property (object_class,
-	                                  NM_DEVICE_INTERFACE_PROP_IFINDEX,
-	                                  NM_DEVICE_INTERFACE_IFINDEX);
-
-	g_object_class_override_property (object_class,
-									  NM_DEVICE_INTERFACE_PROP_DRIVER,
-									  NM_DEVICE_INTERFACE_DRIVER);
-
-	g_object_class_override_property (object_class,
-									  NM_DEVICE_INTERFACE_PROP_CAPABILITIES,
-									  NM_DEVICE_INTERFACE_CAPABILITIES);
-
-	g_object_class_override_property (object_class,
-									  NM_DEVICE_INTERFACE_PROP_IP4_ADDRESS,
-									  NM_DEVICE_INTERFACE_IP4_ADDRESS);
-
-	g_object_class_override_property (object_class,
-									  NM_DEVICE_INTERFACE_PROP_IP4_CONFIG,
-									  NM_DEVICE_INTERFACE_IP4_CONFIG);
-
-	g_object_class_override_property (object_class,
-									  NM_DEVICE_INTERFACE_PROP_DHCP4_CONFIG,
-									  NM_DEVICE_INTERFACE_DHCP4_CONFIG);
-
-	g_object_class_override_property (object_class,
-									  NM_DEVICE_INTERFACE_PROP_IP6_CONFIG,
-									  NM_DEVICE_INTERFACE_IP6_CONFIG);
-
-	g_object_class_override_property (object_class,
-	                                  NM_DEVICE_INTERFACE_PROP_DHCP6_CONFIG,
-	                                  NM_DEVICE_INTERFACE_DHCP6_CONFIG);
-
-	g_object_class_override_property (object_class,
-									  NM_DEVICE_INTERFACE_PROP_STATE,
-									  NM_DEVICE_INTERFACE_STATE);
-
-	g_object_class_override_property (object_class,
-	                                  NM_DEVICE_INTERFACE_PROP_ACTIVE_CONNECTION,
-	                                  NM_DEVICE_INTERFACE_ACTIVE_CONNECTION);
-
-	g_object_class_override_property (object_class,
-									  NM_DEVICE_INTERFACE_PROP_DEVICE_TYPE,
-									  NM_DEVICE_INTERFACE_DEVICE_TYPE);
-
-	g_object_class_override_property (object_class,
-									  NM_DEVICE_INTERFACE_PROP_MANAGED,
-									  NM_DEVICE_INTERFACE_MANAGED);
-
-	g_object_class_override_property (object_class,
-									  NM_DEVICE_INTERFACE_PROP_FIRMWARE_MISSING,
-									  NM_DEVICE_INTERFACE_FIRMWARE_MISSING);
-
-	g_object_class_override_property (object_class,
-									  NM_DEVICE_INTERFACE_PROP_TYPE_DESC,
-									  NM_DEVICE_INTERFACE_TYPE_DESC);
-
-	g_object_class_override_property (object_class,
-	                                  NM_DEVICE_INTERFACE_PROP_RFKILL_TYPE,
-	                                  NM_DEVICE_INTERFACE_RFKILL_TYPE);
+	g_object_class_install_property
+		(object_class, PROP_UDI,
+		 g_param_spec_string (NM_DEVICE_UDI,
+		                      "UDI",
+		                      "Unique Device Identifier",
+		                      NULL,
+		                      G_PARAM_READWRITE | G_PARAM_CONSTRUCT));
+
+	g_object_class_install_property
+		(object_class, PROP_IFACE,
+		 g_param_spec_string (NM_DEVICE_IFACE,
+		                      "Interface",
+		                      "Interface",
+		                      NULL,
+		                      G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY));
+
+	g_object_class_install_property
+		(object_class, PROP_IP_IFACE,
+		 g_param_spec_string (NM_DEVICE_IP_IFACE,
+		                      "IP Interface",
+		                      "IP Interface",
+		                      NULL,
+		                      G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY));
+
+	g_object_class_install_property
+		(object_class, PROP_DRIVER,
+		 g_param_spec_string (NM_DEVICE_DRIVER,
+		                      "Driver",
+		                      "Driver",
+		                      NULL,
+		                      G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY));
+
+	g_object_class_install_property
+		(object_class, PROP_CAPABILITIES,
+		 g_param_spec_uint (NM_DEVICE_CAPABILITIES,
+		                    "Capabilities",
+		                    "Capabilities",
+		                    0, G_MAXUINT32, NM_DEVICE_CAP_NONE,
+		                    G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY));
+
+	g_object_class_install_property
+		(object_class, PROP_IP4_ADDRESS,
+		 g_param_spec_uint (NM_DEVICE_IP4_ADDRESS,
+		                    "IP4 address",
+		                    "IP4 address",
+		                    0, G_MAXUINT32, 0, /* FIXME */
+		                    G_PARAM_READWRITE));
+
+	g_object_class_install_property
+		(object_class, PROP_IP4_CONFIG,
+		 g_param_spec_boxed (NM_DEVICE_IP4_CONFIG,
+		                     "IP4 Config",
+		                     "IP4 Config",
+		                     DBUS_TYPE_G_OBJECT_PATH,
+		                     G_PARAM_READWRITE));
+
+	g_object_class_install_property
+		(object_class, PROP_DHCP4_CONFIG,
+		 g_param_spec_boxed (NM_DEVICE_DHCP4_CONFIG,
+		                     "DHCP4 Config",
+		                     "DHCP4 Config",
+		                     DBUS_TYPE_G_OBJECT_PATH,
+		                     G_PARAM_READWRITE));
+
+	g_object_class_install_property
+		(object_class, PROP_IP6_CONFIG,
+		 g_param_spec_boxed (NM_DEVICE_IP6_CONFIG,
+		                     "IP6 Config",
+		                     "IP6 Config",
+		                     DBUS_TYPE_G_OBJECT_PATH,
+		                     G_PARAM_READWRITE));
+
+	g_object_class_install_property
+		(object_class, PROP_DHCP6_CONFIG,
+		 g_param_spec_boxed (NM_DEVICE_DHCP6_CONFIG,
+		                     "DHCP6 Config",
+		                     "DHCP6 Config",
+		                     DBUS_TYPE_G_OBJECT_PATH,
+		                     G_PARAM_READWRITE));
+
+	g_object_class_install_property
+		(object_class, PROP_STATE,
+		 g_param_spec_uint (NM_DEVICE_STATE,
+		                    "State",
+		                    "State",
+		                    0, G_MAXUINT32, NM_DEVICE_STATE_UNKNOWN,
+		                    G_PARAM_READABLE));
+	g_object_class_install_property
+		(object_class, PROP_STATE_REASON,
+		 g_param_spec_boxed (NM_DEVICE_STATE_REASON,
+		                     "StateReason",
+		                     "StateReason",
+		                     DBUS_G_TYPE_UINT_STRUCT,
+		                     G_PARAM_READABLE));
+
+	g_object_class_install_property
+		(object_class, PROP_ACTIVE_CONNECTION,
+		 g_param_spec_boxed (NM_DEVICE_ACTIVE_CONNECTION,
+		                     "ActiveConnection",
+		                     "ActiveConnection",
+		                     DBUS_TYPE_G_OBJECT_PATH,
+		                     G_PARAM_READABLE));
+
+	g_object_class_install_property
+		(object_class, PROP_DEVICE_TYPE,
+		 g_param_spec_uint (NM_DEVICE_DEVICE_TYPE,
+		                    "DeviceType",
+		                    "DeviceType",
+		                    0, G_MAXUINT32, NM_DEVICE_TYPE_UNKNOWN,
+		                    G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY | NM_PROPERTY_PARAM_NO_EXPORT));
+
+	g_object_class_install_property
+		(object_class, PROP_MANAGED,
+		 g_param_spec_boolean (NM_DEVICE_MANAGED,
+		                       "Managed",
+		                       "Managed",
+		                       FALSE,
+		                       G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY));
+
+	g_object_class_install_property
+		(object_class, PROP_FIRMWARE_MISSING,
+		 g_param_spec_boolean (NM_DEVICE_FIRMWARE_MISSING,
+		                       "FirmwareMissing",
+		                       "Firmware missing",
+		                       FALSE,
+		                       G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY));
+
+	g_object_class_install_property
+		(object_class, PROP_TYPE_DESC,
+		 g_param_spec_string (NM_DEVICE_TYPE_DESC,
+		                      "Type Description",
+		                      "Device type description",
+		                      NULL,
+		                      G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY | NM_PROPERTY_PARAM_NO_EXPORT));
+
+	g_object_class_install_property
+		(object_class, PROP_RFKILL_TYPE,
+		 g_param_spec_uint (NM_DEVICE_RFKILL_TYPE,
+		                    "Rfkill Type",
+		                    "Type of rfkill switch (if any) supported by this device",
+		                    RFKILL_TYPE_WLAN,
+		                    RFKILL_TYPE_MAX,
+		                    RFKILL_TYPE_UNKNOWN,
+		                    G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY | NM_PROPERTY_PARAM_NO_EXPORT));
+
+	g_object_class_install_property
+		(object_class, PROP_IFINDEX,
+		 g_param_spec_int (NM_DEVICE_IFINDEX,
+		                   "Ifindex",
+		                   "Ifindex",
+		                   0, G_MAXINT, 0,
+		                   G_PARAM_READABLE | NM_PROPERTY_PARAM_NO_EXPORT));
+
+	/* Signals */
+	signals[STATE_CHANGED] =
+		g_signal_new ("state-changed",
+		              G_OBJECT_CLASS_TYPE (object_class),
+		              G_SIGNAL_RUN_FIRST,
+		              0, NULL, NULL,
+		              _nm_marshal_VOID__UINT_UINT_UINT,
+		              G_TYPE_NONE, 3,
+		              G_TYPE_UINT, G_TYPE_UINT, G_TYPE_UINT);
+
+	signals[DISCONNECT_REQUEST] =
+		g_signal_new (NM_DEVICE_DISCONNECT_REQUEST,
+		              G_OBJECT_CLASS_TYPE (object_class),
+		              G_SIGNAL_RUN_FIRST,
+		              0, NULL, NULL,
+		              g_cclosure_marshal_VOID__POINTER,
+		              G_TYPE_NONE, 1, G_TYPE_POINTER);
 
 	signals[AUTOCONNECT_ALLOWED] =
 		g_signal_new ("autoconnect-allowed",
@@ -3651,32 +4059,11 @@ nm_device_class_init (NMDeviceClass *klass)
 		              autoconnect_allowed_accumulator, NULL,
 		              _nm_marshal_BOOLEAN__VOID,
 		              G_TYPE_BOOLEAN, 0);
-}
-
-static gboolean
-failed_to_disconnected (gpointer user_data)
-{
-	NMDevice *self = NM_DEVICE (user_data);
-	NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE (self);
-
-	nm_log_dbg (LOGD_DEVICE, "(%s): running failed->disconnected transition",
-	            nm_device_get_iface (self));
-	priv->failed_to_disconnected_id = 0;
-	nm_device_state_changed (self, NM_DEVICE_STATE_DISCONNECTED, NM_DEVICE_STATE_REASON_NONE);
-	return FALSE;
-}
 
-static gboolean
-unavailable_to_disconnected (gpointer user_data)
-{
-	NMDevice *self = NM_DEVICE (user_data);
-	NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE (self);
+	dbus_g_object_type_install_info (G_TYPE_FROM_CLASS (klass),
+	                                 &dbus_glib_nm_device_interface_object_info);
 
-	nm_log_dbg (LOGD_DEVICE, "(%s): running unavailable->disconnected transition",
-	            nm_device_get_iface (self));
-	priv->unavailable_to_disconnected_id = 0;
-	nm_device_state_changed (self, NM_DEVICE_STATE_DISCONNECTED, NM_DEVICE_STATE_REASON_NONE);
-	return FALSE;
+	dbus_g_error_domain_register (NM_DEVICE_ERROR, NULL, NM_TYPE_DEVICE_ERROR);
 }
 
 void
@@ -3690,7 +4077,7 @@ nm_device_set_firmware_missing (NMDevice *self, gboolean new_missing)
 	priv = NM_DEVICE_GET_PRIVATE (self);
 	if (priv->firmware_missing != new_missing) {
 		priv->firmware_missing = new_missing;
-		g_object_notify (G_OBJECT (self), NM_DEVICE_INTERFACE_FIRMWARE_MISSING);
+		g_object_notify (G_OBJECT (self), NM_DEVICE_FIRMWARE_MISSING);
 	}
 }
 
@@ -3826,6 +4213,18 @@ reason_to_string (NMDeviceStateReason reason)
 		return "modem-not-found";
 	case NM_DEVICE_STATE_REASON_BT_FAILED:
 		return "bluetooth-failed";
+	case NM_DEVICE_STATE_REASON_GSM_SIM_NOT_INSERTED:
+		return "gsm-sim-not-inserted";
+	case NM_DEVICE_STATE_REASON_GSM_SIM_PIN_REQUIRED:
+		return "gsm-sim-pin-required";
+	case NM_DEVICE_STATE_REASON_GSM_SIM_PUK_REQUIRED:
+		return "gsm-sim-puk-required";
+	case NM_DEVICE_STATE_REASON_GSM_SIM_WRONG:
+		return "gsm-sim-wrong";
+	case NM_DEVICE_STATE_REASON_INFINIBAND_MODE:
+		return "infiniband-mode";
+	case NM_DEVICE_STATE_REASON_DEPENDENCY_FAILED:
+		return "dependency-failed";
 	default:
 		break;
 	}
@@ -3854,6 +4253,7 @@ nm_device_state_changed (NMDevice *device,
 
 	old_state = priv->state;
 	priv->state = state;
+	priv->state_reason = reason;
 
 	nm_log_info (LOGD_DEVICE, "(%s): device state change: %s -> %s (reason '%s') [%d %d %d]",
 	             nm_device_get_iface (device),
@@ -3864,12 +4264,21 @@ nm_device_state_changed (NMDevice *device,
 	             state,
 	             reason);
 
-	/* Clear any delayed transitions */
-	delayed_transitions_clear (device);
+	/* Clear any queued transitions */
+	queued_state_clear (device);
 
 	/* Cache the activation request for the dispatcher */
 	req = priv->act_request ? g_object_ref (priv->act_request) : NULL;
 
+	/* Update connection timestamps; do this before possibly deactivating the
+	 * device since that will clear the activation request and thus the
+	 * connection, which we need.
+	 */
+	if (state == NM_DEVICE_STATE_ACTIVATED || old_state == NM_DEVICE_STATE_ACTIVATED) {
+		nm_settings_connection_update_timestamp (NM_SETTINGS_CONNECTION (nm_act_request_get_connection (req)),
+		                                         (guint64) time (NULL), TRUE);
+	}
+
 	/* Handle the new state here; but anything that could trigger
 	 * another state change should be done below.
 	 */
@@ -3891,18 +4300,19 @@ nm_device_state_changed (NMDevice *device,
 		 * assuming the device's existing connection.
 		 */
 		if (reason != NM_DEVICE_STATE_REASON_CONNECTION_ASSUMED)
-			nm_device_interface_deactivate (NM_DEVICE_INTERFACE (device), reason);
+			nm_device_deactivate (device, reason);
 		break;
 	case NM_DEVICE_STATE_DISCONNECTED:
 		if (old_state != NM_DEVICE_STATE_UNAVAILABLE)
-			nm_device_interface_deactivate (NM_DEVICE_INTERFACE (device), reason);
+			nm_device_deactivate (device, reason);
 		break;
 	default:
 		priv->autoconnect_inhibit = FALSE;
 		break;
 	}
 
-	g_object_notify (G_OBJECT (device), NM_DEVICE_INTERFACE_STATE);
+	g_object_notify (G_OBJECT (device), NM_DEVICE_STATE);
+	g_object_notify (G_OBJECT (device), NM_DEVICE_STATE_REASON);
 	g_signal_emit_by_name (device, "state-changed", state, old_state, reason);
 
 	/* Post-process the event after internal notification */
@@ -3918,7 +4328,7 @@ nm_device_state_changed (NMDevice *device,
 		if (nm_device_is_available (device)) {
 			nm_log_dbg (LOGD_DEVICE, "(%s): device is available, will transition to DISCONNECTED",
 			            nm_device_get_iface (device));
-			priv->unavailable_to_disconnected_id = g_idle_add (unavailable_to_disconnected, device);
+			nm_device_queue_state (device, NM_DEVICE_STATE_DISCONNECTED, NM_DEVICE_STATE_REASON_NONE);
 		} else {
 			nm_log_dbg (LOGD_DEVICE, "(%s): device not yet available for transition to DISCONNECTED",
 			            nm_device_get_iface (device));
@@ -3935,7 +4345,7 @@ nm_device_state_changed (NMDevice *device,
 		 * immediately because we can't change states again from the state
 		 * handler for a variety of reasons.
 		 */
-		priv->failed_to_disconnected_id = g_idle_add (failed_to_disconnected, device);
+		nm_device_queue_state (device, NM_DEVICE_STATE_DISCONNECTED, NM_DEVICE_STATE_REASON_NONE);
 		break;
 	default:
 		break;
@@ -3949,6 +4359,51 @@ nm_device_state_changed (NMDevice *device,
 		g_object_unref (req);
 }
 
+static gboolean
+queued_set_state (gpointer user_data)
+{
+	NMDevice *self = NM_DEVICE (user_data);
+	NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE (self);
+
+	if (priv->queued_state.id) {
+		nm_log_dbg (LOGD_DEVICE, "(%s): running queued state change to %s (id %d)",
+			        nm_device_get_iface (self),
+			        state_to_string (priv->queued_state.state),
+			        priv->queued_state.id);
+		priv->queued_state.id = 0;
+		nm_device_state_changed (self, priv->queued_state.state, priv->queued_state.reason);
+	}
+	queued_state_clear (self);
+	return FALSE;
+}
+
+void
+nm_device_queue_state (NMDevice *self,
+                       NMDeviceState state,
+                       NMDeviceStateReason reason)
+{
+	NMDevicePrivate *priv;
+
+	g_return_if_fail (self != NULL);
+	g_return_if_fail (NM_IS_DEVICE (self));
+
+	priv = NM_DEVICE_GET_PRIVATE (self);
+
+	/* We should only ever have one delayed state transition at a time */
+	if (priv->queued_state.id) {
+		g_warn_if_fail (priv->queued_state.id == 0);
+		queued_state_clear (self);
+	}
+
+	priv->queued_state.state = state;
+	priv->queued_state.reason = reason;
+	priv->queued_state.id = g_idle_add (queued_set_state, self);
+
+	nm_log_dbg (LOGD_DEVICE, "(%s): queued state change to %s (id %d)",
+	            nm_device_get_iface (self), state_to_string (state),
+	            priv->queued_state.id);
+}
+
 NMDeviceState
 nm_device_get_state (NMDevice *device)
 {
@@ -3983,7 +4438,7 @@ nm_device_set_managed (NMDevice *device,
 	             nm_device_get_iface (device),
 	             managed ? "managed" : "unmanaged");
 
-	g_object_notify (G_OBJECT (device), NM_DEVICE_INTERFACE_MANAGED);
+	g_object_notify (G_OBJECT (device), NM_DEVICE_MANAGED);
 
 	/* If now managed, jump to unavailable */
 	if (managed)
@@ -3992,36 +4447,156 @@ nm_device_set_managed (NMDevice *device,
 		nm_device_state_changed (device, NM_DEVICE_STATE_UNMANAGED, reason);
 }
 
+gboolean
+nm_device_spec_match_list (NMDevice *device, const GSList *specs)
+{
+	g_return_val_if_fail (device != NULL, FALSE);
+	g_return_val_if_fail (NM_IS_DEVICE (device), FALSE);
+
+	if (NM_DEVICE_GET_CLASS (device)->spec_match_list)
+		return NM_DEVICE_GET_CLASS (device)->spec_match_list (device, specs);
+	return FALSE;
+}
+
 static gboolean
-spec_match_list (NMDeviceInterface *device, const GSList *specs)
+ip4_match_config (NMDevice *self, NMConnection *connection)
 {
-	NMDevice *self;
+	NMSettingIP4Config *s_ip4;
+	int i, num;
+	GSList *leases, *iter;
+	NMDHCPManager *dhcp_mgr;
+	const char *method;
 
-	g_return_val_if_fail (device != NULL, FALSE);
+	s_ip4 = nm_connection_get_setting_ip4_config (connection);
+	if (!s_ip4)
+		return FALSE;
 
-	self = NM_DEVICE (device);
-	if (NM_DEVICE_GET_CLASS (self)->spec_match_list)
-		return NM_DEVICE_GET_CLASS (self)->spec_match_list (self, specs);
+	/* Get any saved leases that apply to this connection */
+	dhcp_mgr = nm_dhcp_manager_get ();
+	leases = nm_dhcp_manager_get_lease_config (dhcp_mgr,
+	                                           nm_device_get_iface (self),
+	                                           nm_connection_get_uuid (connection));
+	g_object_unref (dhcp_mgr);
+
+	method = nm_setting_ip4_config_get_method (s_ip4);
+	if (!strcmp (method, NM_SETTING_IP4_CONFIG_METHOD_AUTO)) {
+		gboolean found = FALSE;
+
+		/* Find at least one lease's address on the device */
+		for (iter = leases; iter; iter = g_slist_next (iter)) {
+			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;
+			}
+		}
+		g_slist_foreach (leases, (GFunc) g_object_unref, NULL);
+		g_slist_free (leases);
+		return found;
+	} else {
+		/* Maybe the connection used to be DHCP and there are stale leases; ignore them */
+		g_slist_foreach (leases, (GFunc) g_object_unref, NULL);
+		g_slist_free (leases);
+	}
 
-	return FALSE;
+	if (!strcmp (method, NM_SETTING_IP4_CONFIG_METHOD_DISABLED)) {
+		// FIXME: Enforce no ipv4 addresses?
+		return TRUE;
+	}
+
+	/* 'shared' and 'link-local' aren't supported methods because 'shared'
+	 * requires too much iptables and dnsmasq state to be reclaimed, and
+	 * avahi-autoipd isn't smart enough to allow the link-local address to be
+	 * determined at any point other than when it was first assigned.
+	 */
+	if (strcmp (method, NM_SETTING_IP4_CONFIG_METHOD_MANUAL))
+		return FALSE;
+
+	/* Everything below for static addressing */
+
+	/* 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++) {
+		NMIP4Address *addr = nm_setting_ip4_config_get_address (s_ip4, i);
+		struct in_addr tmp = { .s_addr = nm_ip4_address_get_address (addr) };
+
+		if (!nm_netlink_find_address (nm_device_get_ip_ifindex (self),
+		                              AF_INET,
+		                              &tmp,
+		                              nm_ip4_address_get_prefix (addr)))
+			return FALSE;
+	}
+
+	/* Success; all the connection's static IP addresses are assigned to the device */
+	return TRUE;
 }
 
-static NMConnection *
-connection_match_config (NMDeviceInterface *device, const GSList *connections)
+gboolean
+nm_device_match_ip_config (NMDevice *device, NMConnection *connection)
+{
+	if (!ip4_match_config (device, connection))
+		return FALSE;
+
+	/* FIXME: match IPv6 config */
+
+	return TRUE;
+}
+
+NMConnection *
+nm_device_connection_match_config (NMDevice *device, const GSList *connections)
 {
 	g_return_val_if_fail (device != NULL, NULL);
+	g_return_val_if_fail (NM_IS_DEVICE (device), NULL);
 
 	if (NM_DEVICE_GET_CLASS (device)->connection_match_config)
 		return NM_DEVICE_GET_CLASS (device)->connection_match_config (NM_DEVICE (device), connections);
 	return NULL;
 }
 
-static gboolean
-can_assume_connections (NMDeviceInterface *device)
+/**
+ * nm_device_hwaddr_matches:
+ * @device: the device to use when matching the hardware address
+ * @connection: the connection which supplies the hardware address
+ * @other_hwaddr: if given, use this address instead of the device's actual
+ *   hardware address
+ * @other_hwaddr_len: length in bytes of @other_hwaddr
+ * @fail_if_no_hwaddr: whether to fail the match if @connection does not contain
+ *   a hardware address
+ *
+ * Matches a the devices hardware address (or @other_hwaddr if given) against
+ * the hardware-specific setting in @connection.  Allows for device-agnostic
+ * hardware address matching without having to know the internal details of
+ * the connection and which settings are used by each device subclass.
+ *
+ * Returns: %TRUE if the @device 's hardware address or @other_hwaddr matches
+ *  a hardware address in a hardware-specific setting in @connection
+ */
+gboolean
+nm_device_hwaddr_matches (NMDevice *device,
+                          NMConnection *connection,
+                          const guint8 *other_hwaddr,
+                          guint other_hwaddr_len,
+                          gboolean fail_if_no_hwaddr)
 {
 	g_return_val_if_fail (device != NULL, FALSE);
-
-	return !!NM_DEVICE_GET_CLASS (device)->connection_match_config;
+	g_return_val_if_fail (NM_IS_DEVICE (device), FALSE);
+	if (other_hwaddr)
+		g_return_val_if_fail (other_hwaddr_len > 0, FALSE);
+
+	if (NM_DEVICE_GET_CLASS (device)->hwaddr_matches) {
+		return NM_DEVICE_GET_CLASS (device)->hwaddr_matches (device,
+		                                                     connection,
+		                                                     other_hwaddr,
+		                                                     other_hwaddr_len,
+		                                                     fail_if_no_hwaddr);
+	}
+	return FALSE;
 }
 
 void
diff --git a/src/nm-device.h b/src/nm-device.h
index 1d080eda..bf76ecb5 100644
--- a/src/nm-device.h
+++ b/src/nm-device.h
@@ -33,14 +33,31 @@
 #include "nm-dhcp4-config.h"
 #include "nm-dhcp6-config.h"
 #include "nm-connection.h"
-
-typedef enum NMActStageReturn
-{
-	NM_ACT_STAGE_RETURN_FAILURE = 0,
-	NM_ACT_STAGE_RETURN_SUCCESS,
-	NM_ACT_STAGE_RETURN_POSTPONE,
-	NM_ACT_STAGE_RETURN_STOP         /* This activation chain is done */
-} NMActStageReturn;
+#include "nm-rfkill.h"
+
+/* Properties */
+#define NM_DEVICE_UDI              "udi"
+#define NM_DEVICE_IFACE            "interface"
+#define NM_DEVICE_IP_IFACE         "ip-interface"
+#define NM_DEVICE_DRIVER           "driver"
+#define NM_DEVICE_CAPABILITIES     "capabilities"
+#define NM_DEVICE_IP4_ADDRESS      "ip4-address"
+#define NM_DEVICE_IP4_CONFIG       "ip4-config"
+#define NM_DEVICE_DHCP4_CONFIG     "dhcp4-config"
+#define NM_DEVICE_IP6_CONFIG       "ip6-config"
+#define NM_DEVICE_DHCP6_CONFIG     "dhcp6-config"
+#define NM_DEVICE_STATE            "state"
+#define NM_DEVICE_STATE_REASON     "state-reason"
+#define NM_DEVICE_ACTIVE_CONNECTION "active-connection"
+#define NM_DEVICE_DEVICE_TYPE      "device-type" /* ugh */
+#define NM_DEVICE_MANAGED          "managed"
+#define NM_DEVICE_FIRMWARE_MISSING "firmware-missing"
+#define NM_DEVICE_TYPE_DESC        "type-desc"    /* Internal only */
+#define NM_DEVICE_RFKILL_TYPE      "rfkill-type"  /* Internal only */
+#define NM_DEVICE_IFINDEX          "ifindex"      /* Internal only */
+
+/* Internal signal */
+#define NM_DEVICE_DISCONNECT_REQUEST "disconnect-request"
 
 
 G_BEGIN_DECLS
@@ -52,6 +69,14 @@ G_BEGIN_DECLS
 #define NM_IS_DEVICE_CLASS(klass)	(G_TYPE_CHECK_CLASS_TYPE ((klass),  NM_TYPE_DEVICE))
 #define NM_DEVICE_GET_CLASS(obj)	(G_TYPE_INSTANCE_GET_CLASS ((obj),  NM_TYPE_DEVICE, NMDeviceClass))
 
+typedef enum NMActStageReturn NMActStageReturn;
+
+typedef enum {
+	NM_DEVICE_ERROR_CONNECTION_ACTIVATING = 0, /*< nick=ConnectionActivating >*/
+	NM_DEVICE_ERROR_CONNECTION_INVALID,        /*< nick=ConnectionInvalid >*/
+	NM_DEVICE_ERROR_NOT_ACTIVE,                /*< nick=NotActive >*/
+} NMDeviceError;
+
 typedef struct {
 	GObject parent;
 } NMDevice;
@@ -59,6 +84,11 @@ typedef struct {
 typedef struct {
 	GObjectClass parent;
 
+	void (*state_changed) (NMDevice *device,
+	                       NMDeviceState new_state,
+	                       NMDeviceState old_state,
+	                       NMDeviceStateReason reason);
+
 	/* Hardware state, ie IFF_UP */
 	gboolean        (*hw_is_up)      (NMDevice *self);
 	gboolean        (*hw_bring_up)   (NMDevice *self, gboolean *no_firmware);
@@ -80,6 +110,10 @@ typedef struct {
 
 	gboolean	(* is_available) (NMDevice *self);
 
+	gboolean    (* get_enabled) (NMDevice *self);
+
+	void        (* set_enabled) (NMDevice *self, gboolean enabled);
+
 	NMConnection * (* get_best_auto_connection) (NMDevice *self,
 	                                             GSList *connections,
 	                                             char **specific_object);
@@ -99,21 +133,20 @@ typedef struct {
 	NMActStageReturn	(* act_stage2_config)	(NMDevice *self,
 	                                             NMDeviceStateReason *reason);
 	NMActStageReturn	(* act_stage3_ip4_config_start) (NMDevice *self,
+														 NMIP4Config **out_config,
 														 NMDeviceStateReason *reason);
 	NMActStageReturn	(* act_stage3_ip6_config_start) (NMDevice *self,
+														 NMIP6Config **out_config,
 														 NMDeviceStateReason *reason);
-	NMActStageReturn	(* act_stage4_get_ip4_config)	(NMDevice *self,
-														 NMIP4Config **config,
-	                                                     NMDeviceStateReason *reason);
-	NMActStageReturn	(* act_stage4_get_ip6_config)	(NMDevice *self,
-														 NMIP6Config **config,
-	                                                     NMDeviceStateReason *reason);
 	NMActStageReturn	(* act_stage4_ip4_config_timeout)	(NMDevice *self,
-	                                                         NMIP4Config **config,
 	                                                         NMDeviceStateReason *reason);
 	NMActStageReturn	(* act_stage4_ip6_config_timeout)	(NMDevice *self,
-	                                                         NMIP6Config **config,
 	                                                         NMDeviceStateReason *reason);
+
+	/* Called right before IP config is set; use for setting MTU etc */
+	void                (* ip4_config_pre_commit) (NMDevice *self, NMIP4Config *config);
+	void                (* ip6_config_pre_commit) (NMDevice *self, NMIP6Config *config);
+
 	void			(* deactivate)			(NMDevice *self);
 
 	gboolean		(* can_interrupt_activation)		(NMDevice *self);
@@ -121,6 +154,18 @@ typedef struct {
 	gboolean        (* spec_match_list)     (NMDevice *self, const GSList *specs);
 
 	NMConnection *  (* connection_match_config) (NMDevice *self, const GSList *connections);
+
+	gboolean        (* hwaddr_matches) (NMDevice *self,
+	                                    NMConnection *connection,
+	                                    const guint8 *other_hwaddr,
+	                                    guint other_hwaddr_len,
+	                                    gboolean fail_if_no_hwaddr);
+
+	gboolean        (* enslave_slave) (NMDevice *self,
+	                                   NMDevice *slave);
+
+	gboolean        (* release_slave) (NMDevice *self,
+	                                   NMDevice *slave);
 } NMDeviceClass;
 
 
@@ -136,25 +181,21 @@ const char *	nm_device_get_ip_iface	(NMDevice *dev);
 int             nm_device_get_ip_ifindex(NMDevice *dev);
 const char *	nm_device_get_driver	(NMDevice *dev);
 const char *	nm_device_get_type_desc (NMDevice *dev);
-
 NMDeviceType	nm_device_get_device_type	(NMDevice *dev);
-guint32		nm_device_get_capabilities	(NMDevice *dev);
-guint32		nm_device_get_type_capabilities	(NMDevice *dev);
 
 int			nm_device_get_priority (NMDevice *dev);
 
-guint32			nm_device_get_ip4_address	(NMDevice *dev);
-void				nm_device_update_ip4_address	(NMDevice *dev);
-
 NMDHCP4Config * nm_device_get_dhcp4_config (NMDevice *dev);
 NMDHCP6Config * nm_device_get_dhcp6_config (NMDevice *dev);
 
 NMIP4Config *	nm_device_get_ip4_config	(NMDevice *dev);
 NMIP6Config *	nm_device_get_ip6_config	(NMDevice *dev);
 
-void *		nm_device_get_system_config_data	(NMDevice *dev);
+gboolean        nm_device_enslave_slave     (NMDevice *dev, NMDevice *slave);
+gboolean        nm_device_release_slave     (NMDevice *dev, NMDevice *slave);
 
 NMActRequest *	nm_device_get_act_request	(NMDevice *dev);
+NMConnection *  nm_device_get_connection	(NMDevice *dev);
 
 gboolean		nm_device_is_available (NMDevice *dev);
 
@@ -168,29 +209,59 @@ gboolean nm_device_complete_connection (NMDevice *device,
                                         const GSList *existing_connection,
                                         GError **error);
 
-void			nm_device_activate_schedule_stage1_device_prepare		(NMDevice *device);
-void			nm_device_activate_schedule_stage2_device_config		(NMDevice *device);
-void			nm_device_activate_schedule_stage4_ip4_config_get		(NMDevice *device);
-void			nm_device_activate_schedule_stage4_ip4_config_timeout	(NMDevice *device);
-void			nm_device_activate_schedule_stage4_ip6_config_get		(NMDevice *device);
-void			nm_device_activate_schedule_stage4_ip6_config_timeout	(NMDevice *device);
+gboolean nm_device_check_connection_compatible (NMDevice *device,
+                                                NMConnection *connection,
+                                                GError **error);
+
+gboolean nm_device_can_assume_connections (NMDevice *device);
+
+NMConnection * nm_device_connection_match_config (NMDevice *device,
+                                                  const GSList *connections);
+
+gboolean nm_device_hwaddr_matches (NMDevice *device,
+                                   NMConnection *connection,
+                                   const guint8 *other_hwaddr,
+                                   guint other_hwaddr_len,
+                                   gboolean fail_if_no_hwaddr);
+
+gboolean nm_device_spec_match_list (NMDevice *device, const GSList *specs);
+
 gboolean		nm_device_is_activating		(NMDevice *dev);
 gboolean		nm_device_can_interrupt_activation		(NMDevice *self);
 gboolean		nm_device_autoconnect_allowed	(NMDevice *self);
 
 NMDeviceState nm_device_get_state (NMDevice *device);
 
+gboolean nm_device_get_enabled (NMDevice *device);
+
+void nm_device_set_enabled (NMDevice *device, gboolean enabled);
+
+RfKillType nm_device_get_rfkill_type (NMDevice *device);
+
 gboolean nm_device_get_managed (NMDevice *device);
 void nm_device_set_managed (NMDevice *device,
                             gboolean managed,
                             NMDeviceStateReason reason);
 
-void nm_device_set_dhcp_timeout (NMDevice *device, guint32 timeout);
-void nm_device_set_dhcp_anycast_address (NMDevice *device, guint8 *addr);
-
 void nm_device_clear_autoconnect_inhibit (NMDevice *device);
 
-gboolean nm_device_dhcp4_renew (NMDevice *device, gboolean release);
+void nm_device_handle_autoip4_event (NMDevice *self,
+                                     const char *event,
+                                     const char *address);
+
+void nm_device_state_changed (NMDevice *device,
+                              NMDeviceState state,
+                              NMDeviceStateReason reason);
+
+void nm_device_queue_state   (NMDevice *self,
+                              NMDeviceState state,
+                              NMDeviceStateReason reason);
+
+gboolean nm_device_get_firmware_missing (NMDevice *self);
+
+gboolean nm_device_activate (NMDevice *device, NMActRequest *req, GError **error);
+
+gboolean nm_device_disconnect (NMDevice *device, GError **error);
 
 G_END_DECLS
 
diff --git a/src/nm-ip6-config.c b/src/nm-ip6-config.c
index 2f231638..f06e4069 100644
--- a/src/nm-ip6-config.c
+++ b/src/nm-ip6-config.c
@@ -71,7 +71,7 @@ enum {
 
 
 static struct nl_addr *
-nm_utils_ip6_addr_to_nl_addr (const struct in6_addr *ip6_addr)
+nm_utils_ip6_addr_to_nl_addr (const struct in6_addr *ip6_addr, guint prefix)
 {
 	struct nl_addr * nla = NULL;
 
@@ -79,6 +79,8 @@ nm_utils_ip6_addr_to_nl_addr (const struct in6_addr *ip6_addr)
 		return NULL;
 	nl_addr_set_family (nla, AF_INET6);
 	nl_addr_set_binary_addr (nla, (struct in6_addr *)ip6_addr, sizeof (struct in6_addr));
+	if (prefix)
+		nl_addr_set_prefixlen (nla, prefix);
 
 	return nla;
 }
@@ -428,14 +430,16 @@ nm_ip6_config_set_never_default (NMIP6Config *config, gboolean never_default)
 
 /* libnl convenience/conversion functions */
 
-static int ip6_addr_to_rtnl_local (const struct in6_addr *ip6_address, struct rtnl_addr *addr)
+static int ip6_addr_to_rtnl_local (const struct in6_addr *ip6_address,
+                                   struct rtnl_addr *addr,
+                                   guint prefix)
 {
 	struct nl_addr * local = NULL;
 	int err = 0;
 
 	g_return_val_if_fail (addr != NULL, -1);
 
-	local = nm_utils_ip6_addr_to_nl_addr (ip6_address);
+	local = nm_utils_ip6_addr_to_nl_addr (ip6_address, prefix);
 	err = rtnl_addr_set_local (addr, local);
 	nl_addr_put (local);
 
@@ -449,7 +453,7 @@ static int ip6_addr_to_rtnl_peer (const struct in6_addr *ip6_address, struct rtn
 
 	g_return_val_if_fail (addr != NULL, -1);
 
-	peer = nm_utils_ip6_addr_to_nl_addr (ip6_address);
+	peer = nm_utils_ip6_addr_to_nl_addr (ip6_address, 0);
 	err = rtnl_addr_set_peer (addr, peer);
 	nl_addr_put (peer);
 
@@ -472,8 +476,11 @@ nm_ip6_config_to_rtnl_addr (NMIP6Config *config, guint32 i, guint32 flags)
 	if (!(addr = rtnl_addr_alloc()))
 		return NULL;
 
-	if (flags & NM_RTNL_ADDR_ADDR)
-		success = (ip6_addr_to_rtnl_local (nm_ip6_address_get_address (config_addr), addr) >= 0);
+	if (flags & NM_RTNL_ADDR_ADDR) {
+		success = (ip6_addr_to_rtnl_local (nm_ip6_address_get_address (config_addr),
+		                                   addr,
+		                                   nm_ip6_address_get_prefix (config_addr)) >= 0);
+	}
 
 	if (flags & NM_RTNL_ADDR_PTP_ADDR)
 		success = (ip6_addr_to_rtnl_peer (&priv->ptp_address, addr) >= 0);
diff --git a/src/nm-manager-auth.c b/src/nm-manager-auth.c
index beed65ab..d797032b 100644
--- a/src/nm-manager-auth.c
+++ b/src/nm-manager-auth.c
@@ -541,7 +541,7 @@ nm_auth_uid_in_acl (NMConnection *connection,
 	g_return_val_if_fail (connection != NULL, FALSE);
 	g_return_val_if_fail (smon != NULL, FALSE);
 
-	s_con = NM_SETTING_CONNECTION (nm_connection_get_setting (connection, NM_TYPE_SETTING_CONNECTION));
+	s_con = nm_connection_get_setting_connection (connection);
 	g_assert (s_con);
 
 	/* Reject the request if the request comes from no session at all */
diff --git a/src/nm-manager.c b/src/nm-manager.c
index 475344a5..7c812bdc 100644
--- a/src/nm-manager.c
+++ b/src/nm-manager.c
@@ -16,16 +16,18 @@
  * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
  *
  * Copyright (C) 2007 - 2009 Novell, Inc.
- * Copyright (C) 2007 - 2011 Red Hat, Inc.
+ * Copyright (C) 2007 - 2012 Red Hat, Inc.
  */
 
 #include <config.h>
 
 #include <netinet/ether.h>
-#include <unistd.h>
 #include <fcntl.h>
 #include <errno.h>
 #include <string.h>
+#include <unistd.h>
+#include <sys/types.h>
+#include <sys/stat.h>
 #include <dbus/dbus-glib-lowlevel.h>
 #include <dbus/dbus-glib.h>
 #include <gio/gio.h>
@@ -38,15 +40,14 @@
 #include "nm-vpn-manager.h"
 #include "nm-modem-manager.h"
 #include "nm-device-bt.h"
-#include "nm-device-interface.h"
-#include "nm-device-private.h"
+#include "nm-device.h"
 #include "nm-device-ethernet.h"
 #include "nm-device-wifi.h"
 #include "nm-device-olpc-mesh.h"
-#if WITH_WIMAX
-#include "nm-device-wimax.h"
-#endif
 #include "nm-device-modem.h"
+#include "nm-device-infiniband.h"
+#include "nm-device-bond.h"
+#include "nm-device-vlan.h"
 #include "nm-system.h"
 #include "nm-properties-changed-signal.h"
 #include "nm-setting-bluetooth.h"
@@ -64,6 +65,14 @@
 #include "nm-manager-auth.h"
 #include "NetworkManagerUtils.h"
 #include "nm-utils.h"
+#include "nm-device-factory.h"
+#include "wifi-utils.h"
+#include "nm-enum-types.h"
+
+#if WITH_CONCHECK
+#include "nm-connectivity.h"
+#endif
+
 
 #define NM_AUTOIP_DBUS_SERVICE "org.freedesktop.nm_avahi_autoipd"
 #define NM_AUTOIP_DBUS_IFACE   "org.freedesktop.nm_avahi_autoipd"
@@ -117,15 +126,6 @@ static gboolean impl_manager_set_logging (NMManager *manager,
 
 #include "nm-manager-glue.h"
 
-static void udev_device_added_cb (NMUdevManager *udev_mgr,
-                                  GUdevDevice *device,
-                                  NMDeviceCreatorFn creator_fn,
-                                  gpointer user_data);
-
-static void udev_device_removed_cb (NMUdevManager *udev_mgr,
-                                    GUdevDevice *device,
-                                    gpointer user_data);
-
 static void bluez_manager_bdaddr_added_cb (NMBluezManager *bluez_mgr,
 					   const char *bdaddr,
 					   const char *name,
@@ -144,14 +144,15 @@ static void add_device (NMManager *self, NMDevice *device);
 
 static void hostname_provider_init (NMHostnameProvider *provider_class);
 
-static const char *internal_activate_device (NMManager *manager,
-                                             NMDevice *device,
-                                             NMConnection *connection,
-                                             const char *specific_object,
-                                             gboolean user_requested,
-                                             gulong sender_uid,
-                                             gboolean assumed,
-                                             GError **error);
+static NMActiveConnection *internal_activate_device (NMManager *manager,
+                                                     NMDevice *device,
+                                                     NMConnection *connection,
+                                                     const char *specific_object,
+                                                     gboolean user_requested,
+                                                     gulong sender_uid,
+                                                     gboolean assumed,
+                                                     NMActiveConnection *master,
+                                                     GError **error);
 
 static NMDevice *find_device_by_ip_iface (NMManager *self, const gchar *iface);
 
@@ -200,11 +201,17 @@ typedef struct {
 
 	GSList *devices;
 	NMState state;
+#if WITH_CONCHECK
+	NMConnectivity *connectivity;
+#endif
 
 	NMDBusManager *dbus_mgr;
 	NMUdevManager *udev_mgr;
 	NMBluezManager *bluez_mgr;
 
+	/* List of NMDeviceFactoryFunc pointers sorted in priority order */
+	GSList *factories;
+
 	NMSettings *settings;
 	char *hostname;
 
@@ -277,20 +284,7 @@ enum {
 
 /************************************************************************/
 
-typedef enum {
-	NM_MANAGER_ERROR_UNKNOWN_CONNECTION = 0,
-	NM_MANAGER_ERROR_UNKNOWN_DEVICE,
-	NM_MANAGER_ERROR_UNMANAGED_DEVICE,
-	NM_MANAGER_ERROR_SYSTEM_CONNECTION,
-	NM_MANAGER_ERROR_PERMISSION_DENIED,
-	NM_MANAGER_ERROR_CONNECTION_NOT_ACTIVE,
-	NM_MANAGER_ERROR_ALREADY_ASLEEP_OR_AWAKE,
-	NM_MANAGER_ERROR_ALREADY_ENABLED_OR_DISABLED,
-	NM_MANAGER_ERROR_UNSUPPORTED_CONNECTION_TYPE,
-} NMManagerError;
-
 #define NM_MANAGER_ERROR (nm_manager_error_quark ())
-#define NM_TYPE_MANAGER_ERROR (nm_manager_error_get_type ()) 
 
 static GQuark
 nm_manager_error_quark (void)
@@ -301,41 +295,6 @@ nm_manager_error_quark (void)
 	return quark;
 }
 
-/* This should really be standard. */
-#define ENUM_ENTRY(NAME, DESC) { NAME, "" #NAME "", DESC }
-
-static GType
-nm_manager_error_get_type (void)
-{
-	static GType etype = 0;
-
-	if (etype == 0) {
-		static const GEnumValue values[] = {
-			/* Connection was not provided by any known settings service. */
-			ENUM_ENTRY (NM_MANAGER_ERROR_UNKNOWN_CONNECTION, "UnknownConnection"),
-			/* Unknown device. */
-			ENUM_ENTRY (NM_MANAGER_ERROR_UNKNOWN_DEVICE, "UnknownDevice"),
-			/* Unmanaged device. */
-			ENUM_ENTRY (NM_MANAGER_ERROR_UNMANAGED_DEVICE, "UnmanagedDevice"),
-			/* Connection was superceded by a system connection. */
-			ENUM_ENTRY (NM_MANAGER_ERROR_SYSTEM_CONNECTION, "SystemConnection"),
-			/* User does not have the permission to activate this connection. */
-			ENUM_ENTRY (NM_MANAGER_ERROR_PERMISSION_DENIED, "PermissionDenied"),
-			/* The connection was not active. */
-			ENUM_ENTRY (NM_MANAGER_ERROR_CONNECTION_NOT_ACTIVE, "ConnectionNotActive"),
-			/* The manager is already in the requested sleep state */
-			ENUM_ENTRY (NM_MANAGER_ERROR_ALREADY_ASLEEP_OR_AWAKE, "AlreadyAsleepOrAwake"),
-			/* The manager is already in the requested enabled/disabled state */
-			ENUM_ENTRY (NM_MANAGER_ERROR_ALREADY_ENABLED_OR_DISABLED, "AlreadyEnabledOrDisabled"),
-			/* The requested operation is unsupported for this type of connection */
-			ENUM_ENTRY (NM_MANAGER_ERROR_UNSUPPORTED_CONNECTION_TYPE, "UnsupportedConnectionType"),
-			{ 0, 0, 0 },
-		};
-		etype = g_enum_register_static ("NMManagerError", values);
-	}
-	return etype;
-}
-
 /************************************************************************/
 
 static NMDevice *
@@ -366,6 +325,24 @@ nm_manager_get_device_by_path (NMManager *manager, const char *path)
 	return NULL;
 }
 
+NMDevice *
+nm_manager_get_device_by_master (NMManager *manager, const char *master, const char *driver)
+{
+	GSList *iter;
+
+	g_return_val_if_fail (master != NULL, NULL);
+
+	for (iter = NM_MANAGER_GET_PRIVATE (manager)->devices; iter; iter = iter->next) {
+		NMDevice *device = NM_DEVICE (iter->data);
+
+		if (!strcmp (nm_device_get_iface (device), master) &&
+		    (!driver || !strcmp (nm_device_get_driver (device), driver)))
+			return device;
+	}
+
+	return NULL;
+}
+
 static gboolean
 manager_sleeping (NMManager *self)
 {
@@ -385,7 +362,7 @@ vpn_manager_connection_activated_cb (NMVPNManager *manager,
 {
 	/* Update timestamp for the VPN connection */
 	nm_settings_connection_update_timestamp (NM_SETTINGS_CONNECTION (nm_vpn_connection_get_connection (vpn)),
-	                                         (guint64) time (NULL));
+	                                         (guint64) time (NULL), TRUE);
 }
 
 static void
@@ -422,7 +399,7 @@ modem_added (NMModemManager *modem_manager,
 
 	/* Give Bluetooth DUN devices first chance to claim the modem */
 	for (iter = priv->devices; iter; iter = g_slist_next (iter)) {
-		if (NM_IS_DEVICE_BT (iter->data)) {
+		if (nm_device_get_device_type (iter->data) == NM_DEVICE_TYPE_BT) {
 			if (nm_device_bt_modem_added (NM_DEVICE_BT (iter->data), modem, driver))
 				return;
 		}
@@ -462,8 +439,12 @@ nm_manager_update_state (NMManager *manager)
 			NMDeviceState state = nm_device_get_state (dev);
 
 			if (state == NM_DEVICE_STATE_ACTIVATED) {
-				/* FIXME: handle local-only and site too */
 				new_state = NM_STATE_CONNECTED_GLOBAL;
+#if WITH_CONCHECK
+				/* Connectivity check might have a better idea */
+				if (nm_connectivity_get_connected (priv->connectivity) == FALSE)
+					new_state = NM_STATE_CONNECTED_SITE;
+#endif
 				break;
 			}
 
@@ -491,7 +472,10 @@ manager_device_state_changed (NMDevice *device,
                               NMDeviceStateReason reason,
                               gpointer user_data)
 {
-	NMManager *manager = NM_MANAGER (user_data);
+	NMManager *self = NM_MANAGER (user_data);
+#if WITH_CONCHECK
+	NMManagerPrivate *priv = NM_MANAGER_GET_PRIVATE (self);
+#endif
 
 	switch (new_state) {
 	case NM_DEVICE_STATE_UNMANAGED:
@@ -499,22 +483,30 @@ manager_device_state_changed (NMDevice *device,
 	case NM_DEVICE_STATE_DISCONNECTED:
 	case NM_DEVICE_STATE_PREPARE:
 	case NM_DEVICE_STATE_FAILED:
-		g_object_notify (G_OBJECT (manager), NM_MANAGER_ACTIVE_CONNECTIONS);
+		g_object_notify (G_OBJECT (self), NM_MANAGER_ACTIVE_CONNECTIONS);
 		break;
 	default:
 		break;
 	}
 
-	nm_manager_update_state (manager);
-
-	if (new_state == NM_DEVICE_STATE_ACTIVATED) {
-		NMActRequest *req;
+	nm_manager_update_state (self);
 
-		req = nm_device_get_act_request (device);
-		if (req)
-			nm_settings_connection_update_timestamp (NM_SETTINGS_CONNECTION (nm_act_request_get_connection (req)),
-			                                         (guint64) time (NULL));
+#if WITH_CONCHECK
+	if (priv->state >= NM_STATE_CONNECTED_LOCAL) {
+		if (old_state == NM_DEVICE_STATE_ACTIVATED || new_state == NM_DEVICE_STATE_ACTIVATED) {
+			/* Still connected, but a device activated or deactivated; make sure
+			 * we still have connectivity on the other activated devices.
+			 */
+			nm_log_dbg (LOGD_CORE, "(%s): triggered connectivity check due to state change",
+			            nm_device_get_iface (device));
+			nm_connectivity_start_check (priv->connectivity);
+		}
+	} else {
+		/* Cannot be connected if no devices are activated */
+		nm_log_dbg (LOGD_CORE, "stopping connectivity checks");
+		nm_connectivity_stop_check (priv->connectivity);
 	}
+#endif
 }
 
 /* Removes a device from a device list; returns the start of the new device list */
@@ -535,7 +527,7 @@ remove_one_device (NMManager *manager,
 		 * connections get torn down and the interface is deactivated.
 		 */
 
-		if (   !nm_device_interface_can_assume_connections (NM_DEVICE_INTERFACE (device))
+		if (   !nm_device_can_assume_connections (device)
 		    || (nm_device_get_state (device) != NM_DEVICE_STATE_ACTIVATED)
 		    || !quitting)
 			nm_device_set_managed (device, FALSE, NM_DEVICE_STATE_REASON_REMOVED);
@@ -562,7 +554,7 @@ modem_removed (NMModemManager *modem_manager,
 
 	/* Give Bluetooth DUN devices first chance to handle the modem removal */
 	for (iter = priv->devices; iter; iter = g_slist_next (iter)) {
-		if (NM_IS_DEVICE_BT (iter->data)) {
+		if (nm_device_get_device_type (iter->data) == NM_DEVICE_TYPE_BT) {
 			if (nm_device_bt_modem_removed (NM_DEVICE_BT (iter->data), modem))
 				return;
 		}
@@ -639,11 +631,11 @@ might_be_vpn (NMConnection *connection)
 	NMSettingConnection *s_con;
 	const char *ctype = NULL;
 
-	if (nm_connection_get_setting (connection, NM_TYPE_SETTING_VPN))
+	if (nm_connection_get_setting_vpn (connection))
 		return TRUE;
 
 	/* Make sure it's not a VPN, which we can't autocomplete yet */
-	s_con = (NMSettingConnection *) nm_connection_get_setting (connection, NM_TYPE_SETTING_CONNECTION);
+	s_con = nm_connection_get_setting_connection (connection);
 	if (s_con)
 		ctype = nm_setting_connection_get_connection_type (s_con);
 
@@ -655,7 +647,7 @@ try_complete_vpn (NMConnection *connection, GSList *existing, GError **error)
 {
 	g_assert (might_be_vpn (connection) == TRUE);
 
-	if (!nm_connection_get_setting (connection, NM_TYPE_SETTING_VPN)) {
+	if (!nm_connection_get_setting_vpn (connection)) {
 		g_set_error_literal (error,
 			                 NM_MANAGER_ERROR,
 			                 NM_MANAGER_ERROR_UNSUPPORTED_CONNECTION_TYPE,
@@ -741,13 +733,14 @@ pending_activation_new (NMManager *manager,
 	pending->context = context;
 	pending->callback = callback;
 
-	pending->device_path = g_strdup (device_path);
 	pending->connection_path = g_strdup (connection_path);
 	pending->connection = connection;
 
 	/* "/" is special-cased to NULL to get through D-Bus */
 	if (specific_object_path && strcmp (specific_object_path, "/"))
 		pending->specific_object_path = g_strdup (specific_object_path);
+	if (device_path && strcmp (device_path, "/"))
+		pending->device_path = g_strdup (device_path);
 
 	return pending;
 }
@@ -862,19 +855,21 @@ pending_activation_check_authorized (PendingActivation *pending,
 static void
 pending_activation_destroy (PendingActivation *pending,
                             GError *error,
-                            const char *ac_path)
+                            NMActiveConnection *ac)
 {
 	g_return_if_fail (pending != NULL);
 
 	if (error)
 		dbus_g_method_return_error (pending->context, error);
-	else if (ac_path) {
+	else if (ac) {
 		if (pending->connection) {
 			dbus_g_method_return (pending->context,
 			                      pending->connection_path,
-			                      ac_path);
-		} else
-			dbus_g_method_return (pending->context, ac_path);
+			                      nm_active_connection_get_path (ac));
+		} else {
+			dbus_g_method_return (pending->context,
+			                      nm_active_connection_get_path (ac));
+		}
 	}
 
 	g_free (pending->connection_path);
@@ -909,7 +904,7 @@ get_active_connections (NMManager *manager, NMConnection *filter)
 			continue;
 
 		if (!filter || (nm_act_request_get_connection (req) == filter)) {
-			path = nm_act_request_get_active_connection_path (req);
+			path = nm_active_connection_get_path (NM_ACTIVE_CONNECTION (req));
 			g_ptr_array_add (active, g_strdup (path));
 		}
 	}
@@ -924,12 +919,274 @@ get_active_connections (NMManager *manager, NMConnection *filter)
 /* Settings stuff via NMSettings                                   */
 /*******************************************************************/
 
+static NMDevice *
+get_device_from_hwaddr (NMManager *self, NMConnection *connection)
+{
+	NMManagerPrivate *priv = NM_MANAGER_GET_PRIVATE (self);
+	GSList *iter;
+
+	for (iter = priv->devices; iter; iter = g_slist_next (iter)) {
+		if (nm_device_hwaddr_matches (NM_DEVICE (iter->data), connection, NULL, 0, TRUE))
+			return iter->data;
+	}
+	return NULL;
+}
+
+static NMDevice*
+find_vlan_parent (NMManager *self,
+                  NMConnection *connection,
+                  gboolean check_hwaddr)
+{
+	NMManagerPrivate *priv = NM_MANAGER_GET_PRIVATE (self);
+	NMSettingVlan *s_vlan;
+	NMConnection *parent_connection;
+	const char *parent_iface;
+	NMDevice *parent = NULL;
+	GSList *iter;
+
+	/* The 'parent' property could be either an interface name, a connection
+	 * UUID, or even given by the MAC address of the connection's ethernet,
+	 * InfiniBand, or WiFi setting.
+	 */
+	s_vlan = nm_connection_get_setting_vlan (connection);
+	g_return_val_if_fail (s_vlan != NULL, NULL);
+
+	parent_iface = nm_setting_vlan_get_parent (s_vlan);
+	if (parent_iface) {
+		parent = find_device_by_ip_iface (self, parent_iface);
+		if (parent)
+			return parent;
+
+		if (nm_utils_is_uuid (parent_iface)) {
+			/* Try as a connection UUID */
+			parent_connection = (NMConnection *) nm_settings_get_connection_by_uuid (priv->settings, parent_iface);
+			if (parent_connection) {
+				/* Check if the parent connection is activated on some device already */
+				for (iter = priv->devices; iter; iter = g_slist_next (iter)) {
+					NMActRequest *req;
+					NMConnection *candidate;
+
+					req = nm_device_get_act_request (NM_DEVICE (iter->data));
+					if (req) {
+						candidate = nm_active_connection_get_connection (NM_ACTIVE_CONNECTION (req));
+						if (candidate == parent_connection)
+							return parent;
+					}
+				}
+
+				/* Check the hardware address of the parent connection */
+				if (check_hwaddr)
+					return get_device_from_hwaddr (self, parent_connection);
+			}
+			return NULL;
+		}
+	}
+
+	/* Try the hardware address from the VLAN connection's hardware setting */
+	if (check_hwaddr)
+		return get_device_from_hwaddr (self, connection);
+
+	return NULL;
+}
+
+/**
+ * get_virtual_iface_name:
+ * @self: the #NMManager
+ * @connection: the #NMConnection representing a virtual interface
+ * @out_parent: on success, the parent device if any
+ *
+ * Given @connection, returns the interface name that the connection
+ * would represent.  If the interface name is not given by the connection,
+ * this may require constructing it based on information in the connection
+ * and existing network interfaces.
+ *
+ * Returns: the expected interface name (caller takes ownership), or %NULL
+ */
+static char *
+get_virtual_iface_name (NMManager *self,
+                        NMConnection *connection,
+                        NMDevice **out_parent)
+{
+	char *vname = NULL;
+	NMDevice *parent = NULL;
+
+	if (out_parent)
+		*out_parent = NULL;
+
+	if (nm_connection_is_type (connection, NM_SETTING_BOND_SETTING_NAME))
+		return g_strdup (nm_connection_get_virtual_iface_name (connection));
+
+	if (nm_connection_is_type (connection, NM_SETTING_VLAN_SETTING_NAME)) {
+		NMSettingVlan *s_vlan;
+		const char *ifname;
+
+		s_vlan = nm_connection_get_setting_vlan (connection);
+		g_return_val_if_fail (s_vlan != NULL, NULL);
+
+		parent = find_vlan_parent (self, connection, TRUE);
+		if (parent) {
+			/* If the connection doesn't specify the interface name for the VLAN
+			 * device, we create one for it using the VLAN ID and the parent
+			 * interface's name.
+			 */
+			ifname = nm_connection_get_virtual_iface_name (connection);
+			if (ifname)
+				vname = g_strdup (ifname);
+			else {
+				vname = nm_utils_new_vlan_name (nm_device_get_ip_iface (parent),
+				                                nm_setting_vlan_get_id (s_vlan));
+			}
+			if (out_parent)
+				*out_parent = parent;
+		}
+	}
+
+	return vname;
+}
+
+static gboolean
+connection_needs_virtual_device (NMConnection *connection)
+{
+	if (nm_connection_is_type (connection, NM_SETTING_BOND_SETTING_NAME))
+		return TRUE;
+	if (nm_connection_is_type (connection, NM_SETTING_VLAN_SETTING_NAME))
+		return TRUE;
+
+	return FALSE;
+}
+
+static char *
+get_virtual_iface_placeholder_udi (void)
+{
+	static guint32 id = 0;
+
+	return g_strdup_printf ("/virtual/device/placeholder/%d", id++);
+}
+
+/**
+ * system_create_virtual_device:
+ * @self: the #NMManager
+ * @connection: the connection which might require a virtual device
+ *
+ * If @connection requires a virtual device and one does not yet exist for it,
+ * creates that device.
+ *
+ * Returns: the #NMDevice if successfully created, NULL if not
+ */
+static NMDevice *
+system_create_virtual_device (NMManager *self, NMConnection *connection)
+{
+	NMManagerPrivate *priv = NM_MANAGER_GET_PRIVATE (self);
+	GSList *iter;
+	char *iface = NULL, *udi;
+	NMDevice *device = NULL, *parent = NULL;
+
+	iface = get_virtual_iface_name (self, connection, &parent);
+	if (!iface) {
+		nm_log_warn (LOGD_DEVICE, "(%s) failed to determine virtual interface name",
+		             nm_connection_get_id (connection));
+		return NULL;
+	}
+
+	/* Make sure we didn't create a device for this connection already */
+	for (iter = priv->devices; iter; iter = g_slist_next (iter)) {
+		NMDevice *candidate = iter->data;
+		GError *error = NULL;
+
+		if (   g_strcmp0 (nm_device_get_iface (candidate), iface) == 0
+		    || nm_device_check_connection_compatible (candidate, connection, &error)) {
+			g_clear_error (&error);
+			goto out;
+		}
+		g_clear_error (&error);
+	}
+
+	if (nm_connection_is_type (connection, NM_SETTING_BOND_SETTING_NAME)) {
+		if (!nm_system_add_bonding_master (iface)) {
+			nm_log_warn (LOGD_DEVICE, "(%s): failed to add bonding master interface for '%s'",
+			             iface, nm_connection_get_id (connection));
+			goto out;
+		}
+
+		udi = get_virtual_iface_placeholder_udi ();
+		device = nm_device_bond_new (udi, iface);
+		g_free (udi);
+	} else if (nm_connection_is_type (connection, NM_SETTING_VLAN_SETTING_NAME)) {
+		g_return_val_if_fail (parent != NULL, FALSE);
+
+		if (!nm_system_add_vlan_iface (connection, iface, nm_device_get_ip_ifindex (parent))) {
+			nm_log_warn (LOGD_DEVICE, "(%s): failed to add VLAN interface for '%s'",
+			             iface, nm_connection_get_id (connection));
+			goto out;
+		}
+		udi = get_virtual_iface_placeholder_udi ();
+		device = nm_device_vlan_new (udi, iface, parent);
+		g_free (udi);
+	}
+
+	if (device)
+		add_device (self, device);
+
+out:
+	g_free (iface);
+	return device;
+}
+
 static void
-connections_changed (NMSettings *settings,
+system_create_virtual_devices (NMManager *self)
+{
+	NMManagerPrivate *priv = NM_MANAGER_GET_PRIVATE (self);
+	GSList *iter, *connections;
+
+	nm_log_dbg (LOGD_CORE, "creating virtual devices...");
+
+	connections = nm_settings_get_connections (priv->settings);
+	for (iter = connections; iter; iter = g_slist_next (iter)) {
+		NMConnection *connection = iter->data;
+		NMSettingConnection *s_con = nm_connection_get_setting_connection (connection);
+
+		g_assert (s_con);
+		if (connection_needs_virtual_device (connection)) {
+			/* We only create a virtual interface if the connection can autoconnect */
+			if (nm_setting_connection_get_autoconnect (s_con))
+				system_create_virtual_device (self, connection);
+		}
+	}
+	g_slist_free (connections);
+}
+
+static void
+connection_added (NMSettings *settings,
+                  NMSettingsConnection *connection,
+                  NMManager *manager)
+{
+	bluez_manager_resync_devices (manager);
+
+	if (connection_needs_virtual_device (NM_CONNECTION (connection)))
+		system_create_virtual_device (manager, NM_CONNECTION (connection));
+}
+
+static void
+connection_changed (NMSettings *settings,
                      NMSettingsConnection *connection,
                      NMManager *manager)
 {
 	bluez_manager_resync_devices (manager);
+
+	/* FIXME: Some virtual devices may need to be updated in the future. */
+}
+
+static void
+connection_removed (NMSettings *settings,
+                    NMSettingsConnection *connection,
+                    NMManager *manager)
+{
+	bluez_manager_resync_devices (manager);
+
+	/*
+	 * Do not delete existing virtual devices to keep connectivity up.
+	 * Virtual devices are reused when NetworkManager is restarted.
+	 */
 }
 
 static void
@@ -946,7 +1203,7 @@ system_unmanaged_devices_changed_cb (NMSettings *settings,
 		NMDevice *device = NM_DEVICE (iter->data);
 		gboolean managed;
 
-		managed = !nm_device_interface_spec_match_list (NM_DEVICE_INTERFACE (device), unmanaged_specs);
+		managed = !nm_device_spec_match_list (device, unmanaged_specs);
 		nm_device_set_managed (device,
 		                       managed,
 		                       managed ? NM_DEVICE_STATE_REASON_NOW_MANAGED :
@@ -1072,20 +1329,19 @@ manager_update_radio_enabled (NMManager *self,
 
 	/* enable/disable wireless devices as required */
 	for (iter = priv->devices; iter; iter = iter->next) {
-		RfKillType devtype = RFKILL_TYPE_UNKNOWN;
+		NMDevice *device = NM_DEVICE (iter->data);
 
-		g_object_get (G_OBJECT (iter->data), NM_DEVICE_INTERFACE_RFKILL_TYPE, &devtype, NULL);
-		if (devtype == rstate->rtype) {
+		if (nm_device_get_rfkill_type (device) == rstate->rtype) {
 			nm_log_dbg (LOGD_RFKILL, "(%s): setting radio %s",
-			            nm_device_get_iface (NM_DEVICE (iter->data)),
+			            nm_device_get_iface (device),
 			            enabled ? "enabled" : "disabled");
-			nm_device_interface_set_enabled (NM_DEVICE_INTERFACE (iter->data), enabled);
+			nm_device_set_enabled (device, enabled);
 		}
 	}
 }
 
 static void
-manager_hidden_ap_found (NMDeviceInterface *device,
+manager_hidden_ap_found (NMDevice *device,
                          NMAccessPoint *ap,
                          gpointer user_data)
 {
@@ -1128,7 +1384,7 @@ nm_manager_get_ipw_rfkill_state (NMManager *self)
 		NMDevice *candidate = NM_DEVICE (iter->data);
 		RfKillState candidate_state;
 
-		if (NM_IS_DEVICE_WIFI (candidate)) {
+		if (nm_device_get_device_type (candidate) == NM_DEVICE_TYPE_WIFI) {
 			candidate_state = nm_device_wifi_get_ipw_rfkill_state (NM_DEVICE_WIFI (candidate));
 
 			if (candidate_state > ipw_state)
@@ -1149,11 +1405,9 @@ nm_manager_get_modem_enabled_state (NMManager *self)
 	for (iter = priv->devices; iter; iter = g_slist_next (iter)) {
 		NMDevice *candidate = NM_DEVICE (iter->data);
 		RfKillState candidate_state = RFKILL_UNBLOCKED;
-		RfKillType devtype = RFKILL_TYPE_UNKNOWN;
 
-		g_object_get (G_OBJECT (candidate), NM_DEVICE_INTERFACE_RFKILL_TYPE, &devtype, NULL);
-		if (devtype == RFKILL_TYPE_WWAN) {
-			if (!nm_device_interface_get_enabled (NM_DEVICE_INTERFACE (candidate)))
+		if (nm_device_get_rfkill_type (candidate) == RFKILL_TYPE_WWAN) {
+			if (!nm_device_get_enabled (candidate))
 				candidate_state = RFKILL_SOFT_BLOCKED;
 
 			if (candidate_state > wwan_state)
@@ -1323,7 +1577,7 @@ disconnect_net_auth_done_cb (NMAuthChain *chain,
 	error = deactivate_disconnect_check_error (auth_error, result, "Disconnect");
 	if (!error) {
 		device = nm_auth_chain_get_data (chain, "device");
-		if (!nm_device_interface_disconnect (NM_DEVICE_INTERFACE (device), &error))
+		if (!nm_device_disconnect (device, &error))
 			g_assert (error);
 	}
 
@@ -1375,7 +1629,7 @@ manager_device_disconnect_request (NMDevice *device,
 
 	/* Yay for root */
 	if (0 == sender_uid) {
-		if (!nm_device_interface_disconnect (NM_DEVICE_INTERFACE (device), &error)) {
+		if (!nm_device_disconnect (device, &error)) {
 			dbus_g_method_return_error (context, error);
 			g_clear_error (&error);
 		} else
@@ -1403,12 +1657,23 @@ add_device (NMManager *self, NMDevice *device)
 	const GSList *unmanaged_specs;
 	NMConnection *existing = NULL;
 	gboolean managed = FALSE, enabled = FALSE;
-	RfKillType rtype = RFKILL_TYPE_UNKNOWN;
+	RfKillType rtype;
+	NMDeviceType devtype;
 
 	iface = nm_device_get_ip_iface (device);
 	g_assert (iface);
 
-	if (!NM_IS_DEVICE_MODEM (device) && find_device_by_ip_iface (self, iface)) {
+	devtype = nm_device_get_device_type (device);
+
+	/* Ignore the device if we already know about it.  But some modems will
+	 * provide pseudo-ethernet devices that NM has already claimed while
+	 * ModemManager is still detecting the modem's serial ports, so when the
+	 * MM modem object finally shows up it may have the same IP interface as the
+	 * ethernet interface we've already detected.  In this case we skip the
+	 * check for an existing device with the same IP interface name and kill
+	 * the ethernet device later in favor of the modem device.
+	 */
+	if ((devtype != NM_DEVICE_TYPE_MODEM) && find_device_by_ip_iface (self, iface)) {
 		g_object_unref (device);
 		return;
 	}
@@ -1419,11 +1684,11 @@ add_device (NMManager *self, NMDevice *device)
 					  G_CALLBACK (manager_device_state_changed),
 					  self);
 
-	g_signal_connect (device, NM_DEVICE_INTERFACE_DISCONNECT_REQUEST,
+	g_signal_connect (device, NM_DEVICE_DISCONNECT_REQUEST,
 					  G_CALLBACK (manager_device_disconnect_request),
 					  self);
 
-	if (NM_IS_DEVICE_WIFI (device)) {
+	if (devtype == NM_DEVICE_TYPE_WIFI) {
 		/* Attach to the access-point-added signal so that the manager can fill
 		 * non-SSID-broadcasting APs with an SSID.
 		 */
@@ -1437,25 +1702,21 @@ add_device (NMManager *self, NMDevice *device)
 		g_signal_connect (device, "notify::" NM_DEVICE_WIFI_IPW_RFKILL_STATE,
 		                  G_CALLBACK (manager_ipw_rfkill_state_changed),
 		                  self);
-		rtype = RFKILL_TYPE_WLAN;
-	} else if (NM_IS_DEVICE_MODEM (device)) {
+	} else if (devtype == NM_DEVICE_TYPE_MODEM) {
 		g_signal_connect (device, NM_DEVICE_MODEM_ENABLE_CHANGED,
 		                  G_CALLBACK (manager_modem_enabled_changed),
 		                  self);
-		rtype = RFKILL_TYPE_WWAN;
-#if WITH_WIMAX
-	} else if (NM_IS_DEVICE_WIMAX (device)) {
-		rtype = RFKILL_TYPE_WIMAX;
-#endif
 	}
 
+	/* Update global rfkill state for this device type with the device's
+	 * rfkill state, and then set this device's rfkill state based on the
+	 * global state.
+	 */
+	rtype = nm_device_get_rfkill_type (device);
 	if (rtype != RFKILL_TYPE_UNKNOWN) {
-		/* Update global rfkill state with this device's rfkill state, and
-		 * then set this device's rfkill state based on the global state.
-		 */
 		nm_manager_rfkill_update (self, rtype);
 		enabled = radio_enabled_for_type (self, rtype, TRUE);
-		nm_device_interface_set_enabled (NM_DEVICE_INTERFACE (device), enabled);
+		nm_device_set_enabled (device, enabled);
 	}
 
 	type_desc = nm_device_get_type_desc (device);
@@ -1477,12 +1738,11 @@ add_device (NMManager *self, NMDevice *device)
 	/* Check if we should assume the device's active connection by matching its
 	 * config with an existing system connection.
 	 */
-	if (nm_device_interface_can_assume_connections (NM_DEVICE_INTERFACE (device))) {
+	if (nm_device_can_assume_connections (device)) {
 		GSList *connections = NULL;
 
 		connections = nm_settings_get_connections (priv->settings);
-		existing = nm_device_interface_connection_match_config (NM_DEVICE_INTERFACE (device),
-		                                                        (const GSList *) connections);
+		existing = nm_device_connection_match_config (device, (const GSList *) connections);
 		g_slist_free (connections);
 
 		if (existing)
@@ -1494,7 +1754,7 @@ add_device (NMManager *self, NMDevice *device)
 	/* Start the device if it's supposed to be managed */
 	unmanaged_specs = nm_settings_get_unmanaged_specs (priv->settings);
 	if (   !manager_sleeping (self)
-	    && !nm_device_interface_spec_match_list (NM_DEVICE_INTERFACE (device), unmanaged_specs)) {
+	    && !nm_device_spec_match_list (device, unmanaged_specs)) {
 		nm_device_set_managed (device,
 		                       TRUE,
 		                       existing ? NM_DEVICE_STATE_REASON_CONNECTION_ASSUMED :
@@ -1505,16 +1765,21 @@ add_device (NMManager *self, NMDevice *device)
 	nm_settings_device_added (priv->settings, device);
 	g_signal_emit (self, signals[DEVICE_ADDED], 0, device);
 
+	/* New devices might be master interfaces for virtual interfaces; so we may
+	 * need to create new virtual interfaces now.
+	 */
+	system_create_virtual_devices (self);
+
 	/* If the device has a connection it can assume, do that now */
 	if (existing && managed && nm_device_is_available (device)) {
-		const char *ac_path;
+		NMActiveConnection *ac;
 		GError *error = NULL;
 
 		nm_log_dbg (LOGD_DEVICE, "(%s): will attempt to assume existing connection",
 		            nm_device_get_iface (device));
 
-		ac_path = internal_activate_device (self, device, existing, NULL, FALSE, 0, TRUE, &error);
-		if (ac_path)
+		ac = internal_activate_device (self, device, existing, NULL, FALSE, 0, TRUE, NULL, &error);
+		if (ac)
 			g_object_notify (G_OBJECT (self), NM_MANAGER_ACTIVE_CONNECTIONS);
 		else {
 			nm_log_warn (LOGD_DEVICE, "assumed connection %s failed to activate: (%d) %s",
@@ -1570,14 +1835,14 @@ bluez_manager_find_connection (NMManager *manager,
 		const char *con_type;
 		const char *bt_type;
 
-		s_con = NM_SETTING_CONNECTION (nm_connection_get_setting (candidate, NM_TYPE_SETTING_CONNECTION));
+		s_con = nm_connection_get_setting_connection (candidate);
 		g_assert (s_con);
 		con_type = nm_setting_connection_get_connection_type (s_con);
 		g_assert (con_type);
 		if (!g_str_equal (con_type, NM_SETTING_BLUETOOTH_SETTING_NAME))
 			continue;
 
-		s_bt = (NMSettingBluetooth *) nm_connection_get_setting (candidate, NM_TYPE_SETTING_BLUETOOTH);
+		s_bt = nm_connection_get_setting_bluetooth (candidate);
 		if (!s_bt)
 			continue;
 
@@ -1612,7 +1877,7 @@ bluez_manager_resync_devices (NMManager *self)
 		guint32 uuids;
 		const char *bdaddr;
 
-		if (NM_IS_DEVICE_BT (candidate)) {
+		if (nm_device_get_device_type (candidate) == NM_DEVICE_TYPE_BT) {
 			uuids = nm_device_bt_get_capabilities (NM_DEVICE_BT (candidate));
 			bdaddr = nm_device_bt_get_hw_address (NM_DEVICE_BT (candidate));
 
@@ -1734,23 +1999,246 @@ find_device_by_ifindex (NMManager *self, guint32 ifindex)
 	return NULL;
 }
 
+#define PLUGIN_PREFIX "libnm-device-plugin-"
+
+typedef struct {
+	NMDeviceType t;
+	guint priority;
+	NMDeviceFactoryCreateFunc create_func;
+} PluginInfo;
+
+static gint
+plugin_sort (PluginInfo *a, PluginInfo *b)
+{
+	/* Higher priority means sort earlier in the list (ie, return -1) */
+	if (a->priority > b->priority)
+		return -1;
+	else if (a->priority < b->priority)
+		return 1;
+	return 0;
+}
+
+static void
+load_device_factories (NMManager *self)
+{
+	NMManagerPrivate *priv = NM_MANAGER_GET_PRIVATE (self);
+	GDir *dir;
+	GError *error = NULL;
+	const char *item;
+	char *path;
+	GSList *list = NULL, *iter;
+
+	dir = g_dir_open (NMPLUGINDIR, 0, &error);
+	if (!dir) {
+		nm_log_warn (LOGD_HW, "Failed to open plugin directory %s: %s",
+		             NMPLUGINDIR,
+		             (error && error->message) ? error->message : "(unknown)");
+		g_clear_error (&error);
+		return;
+	}
+
+	while ((item = g_dir_read_name (dir))) {
+		GModule *plugin;
+		NMDeviceFactoryCreateFunc create_func;
+		NMDeviceFactoryPriorityFunc priority_func;
+		NMDeviceFactoryTypeFunc type_func;
+		PluginInfo *info = NULL;
+		NMDeviceType plugin_type;
+
+		if (!g_str_has_prefix (item, PLUGIN_PREFIX))
+			continue;
+
+		path = g_module_build_path (NMPLUGINDIR, item);
+		g_assert (path);
+		plugin = g_module_open (path, G_MODULE_BIND_LOCAL);
+		g_free (path);
+
+		if (!plugin) {
+			nm_log_warn (LOGD_HW, "(%s): failed to load plugin: %s", item, g_module_error ());
+			continue;
+		}
+
+		if (!g_module_symbol (plugin, "nm_device_factory_get_type", (gpointer) (&type_func))) {
+			nm_log_warn (LOGD_HW, "(%s): failed to find device factory: %s", item, g_module_error ());
+			g_module_close (plugin);
+			continue;
+		}
+
+		/* Make sure we don't double-load plugins */
+		plugin_type = type_func ();
+		for (iter = list; iter; iter = g_slist_next (iter)) {
+			PluginInfo *candidate = iter->data;
+
+			if (plugin_type == candidate->t) {
+				info = candidate;
+				break;
+			}
+		}
+		if (info) {
+			g_module_close (plugin);
+			continue;
+		}
+
+		if (!g_module_symbol (plugin, "nm_device_factory_create_device", (gpointer) (&create_func))) {
+			nm_log_warn (LOGD_HW, "(%s): failed to find device creator: %s", item, g_module_error ());
+			g_module_close (plugin);
+			continue;
+		}
+
+		info = g_malloc0 (sizeof (*info));
+		info->create_func = create_func;
+		info->t = plugin_type;
+
+		/* Grab priority; higher number equals higher priority */
+		if (g_module_symbol (plugin, "nm_device_factory_get_priority", (gpointer) (&priority_func)))
+			info->priority = priority_func ();
+		else {
+			nm_log_dbg (LOGD_HW, "(%s): failed to find device factory priority func: %s",
+			            item, g_module_error ());
+		}
+
+		g_module_make_resident (plugin);
+		list = g_slist_insert_sorted (list, info, (GCompareFunc) plugin_sort);
+
+		nm_log_info (LOGD_HW, "Loaded device factory: %s", g_module_name (plugin));
+	};
+	g_dir_close (dir);
+
+	/* Ditch the priority info and copy the factory functions to our private data */
+	for (iter = list; iter; iter = g_slist_next (iter)) {
+		PluginInfo *info = iter->data;
+
+		priv->factories = g_slist_append (priv->factories, info->create_func);
+		g_free (info);
+	}
+	g_slist_free (list);
+}
+
+static gboolean
+is_wireless (GUdevDevice *device)
+{
+	const char *tmp;
+
+	/* Check devtype, newer kernels (2.6.32+) have this */
+	tmp = g_udev_device_get_property (device, "DEVTYPE");
+	if (g_strcmp0 (tmp, "wlan") == 0)
+		return TRUE;
+
+	/* Otherwise hit up WEXT directly */
+	return wifi_utils_is_wifi (g_udev_device_get_name (device),
+	                           g_udev_device_get_sysfs_path (device));
+}
+
+static gboolean
+is_olpc_mesh (GUdevDevice *device)
+{
+	const gchar *prop = g_udev_device_get_property (device, "ID_NM_OLPC_MESH");
+	return (prop != NULL);
+}
+
+static gboolean
+is_infiniband (GUdevDevice *device)
+{
+	gint etype = g_udev_device_get_sysfs_attr_as_int (device, "type");
+	return etype == ARPHRD_INFINIBAND;
+}
+
+static gboolean
+is_bond (int ifindex)
+{
+	return (nm_system_get_iface_type (ifindex, NULL) == NM_IFACE_TYPE_BOND);
+}
+
+static gboolean
+is_vlan (int ifindex)
+{
+	return (nm_system_get_iface_type (ifindex, NULL) == NM_IFACE_TYPE_VLAN);
+}
+
 static void
 udev_device_added_cb (NMUdevManager *udev_mgr,
                       GUdevDevice *udev_device,
-                      NMDeviceCreatorFn creator_fn,
+                      const char *iface,
+                      const char *sysfs_path,
+                      const char *driver,
+                      int ifindex,
                       gpointer user_data)
 {
 	NMManager *self = NM_MANAGER (user_data);
-	GObject *device;
-	guint32 ifindex;
+	NMManagerPrivate *priv = NM_MANAGER_GET_PRIVATE (self);
+	NMDevice *device = NULL;
+	GSList *iter;
+	GError *error = NULL;
 
-	ifindex = g_udev_device_get_property_as_int (udev_device, "IFINDEX");
-	if (find_device_by_ifindex (self, ifindex))
+	g_return_if_fail (udev_device != NULL);
+	g_return_if_fail (iface != NULL);
+	g_return_if_fail (sysfs_path != NULL);
+	g_return_if_fail (driver != NULL);
+	g_return_if_fail (ifindex >= 0);
+
+	device = find_device_by_ifindex (self, ifindex);
+	if (device) {
+		/* If it's a virtual device we may need to update its UDI */
+		if (nm_system_get_iface_type (ifindex, iface) != NM_IFACE_TYPE_UNSPEC)
+			g_object_set (G_OBJECT (device), NM_DEVICE_UDI, sysfs_path, NULL);
 		return;
+	}
+
+	/* Try registered device factories */
+	for (iter = priv->factories; iter; iter = g_slist_next (iter)) {
+		NMDeviceFactoryCreateFunc create_func = iter->data;
+
+		g_clear_error (&error);
+		device = (NMDevice *) create_func (udev_device, sysfs_path, iface, driver, &error);
+		if (device && NM_IS_DEVICE (device)) {
+			g_assert_no_error (error);
+			break;  /* success! */
+		}
+
+		if (error) {
+			nm_log_warn (LOGD_HW, "%s: factory failed to create device: (%d) %s",
+			             sysfs_path,
+			             error ? error->code : -1,
+			             error ? error->message : "(unknown)");
+			g_clear_error (&error);
+			return;
+		}
+	}
+
+	if (device == NULL) {
+		if (is_olpc_mesh (udev_device)) /* must be before is_wireless */
+			device = nm_device_olpc_mesh_new (sysfs_path, iface, driver);
+		else if (is_wireless (udev_device))
+			device = nm_device_wifi_new (sysfs_path, iface, driver);
+		else if (is_infiniband (udev_device))
+			device = nm_device_infiniband_new (sysfs_path, iface, driver);
+		else if (is_bond (ifindex))
+			device = nm_device_bond_new (sysfs_path, iface);
+		else if (is_vlan (ifindex)) {
+			int parent_ifindex = -1;
+			NMDevice *parent;
+
+			/* Have to find the parent device */
+			if (nm_system_get_iface_vlan_info (ifindex, &parent_ifindex, NULL)) {
+				parent = find_device_by_ifindex (self, parent_ifindex);
+				if (parent)
+					device = nm_device_vlan_new (sysfs_path, iface, parent);
+				else {
+					/* If udev signaled the VLAN interface before it signaled
+					 * the VLAN's parent at startup we may not know about the
+					 * parent device yet.  But we'll find it on the second pass
+					 * from nm_manager_start().
+					 */
+					nm_log_dbg (LOGD_HW, "(%s): VLAN parent interface unknown", iface);
+				}
+			} else
+				nm_log_err (LOGD_HW, "(%s): failed to get VLAN parent ifindex", iface);
+		} else
+			device = nm_device_ethernet_new (sysfs_path, iface, driver);
+	}
 
-	device = creator_fn (udev_mgr, udev_device, manager_sleeping (self));
 	if (device)
-		add_device (self, NM_DEVICE (device));
+		add_device (self, device);
 }
 
 static void
@@ -1855,7 +2343,7 @@ nm_manager_get_act_request_by_path (NMManager *manager,
 		if (!req)
 			continue;
 
-		ac_path = nm_act_request_get_active_connection_path (req);
+		ac_path = nm_active_connection_get_path (NM_ACTIVE_CONNECTION (req));
 		if (!strcmp (path, ac_path)) {
 			*device = NM_DEVICE (iter->data);
 			return req;
@@ -1865,7 +2353,7 @@ nm_manager_get_act_request_by_path (NMManager *manager,
 	return NULL;
 }
 
-static const char *
+static NMActiveConnection *
 internal_activate_device (NMManager *manager,
                           NMDevice *device,
                           NMConnection *connection,
@@ -1873,20 +2361,18 @@ internal_activate_device (NMManager *manager,
                           gboolean user_requested,
                           gulong sender_uid,
                           gboolean assumed,
+                          NMActiveConnection *master,
                           GError **error)
 {
 	NMActRequest *req;
-	NMDeviceInterface *dev_iface;
 	gboolean success;
 
 	g_return_val_if_fail (NM_IS_MANAGER (manager), NULL);
 	g_return_val_if_fail (NM_IS_DEVICE (device), NULL);
 	g_return_val_if_fail (NM_IS_CONNECTION (connection), NULL);
 
-	dev_iface = NM_DEVICE_INTERFACE (device);
-
 	/* Ensure the requested connection is compatible with the device */
-	if (!nm_device_interface_check_connection_compatible (dev_iface, connection, error))
+	if (!nm_device_check_connection_compatible (device, connection, error))
 		return NULL;
 
 	/* Tear down any existing connection */
@@ -1903,14 +2389,322 @@ internal_activate_device (NMManager *manager,
 	                          user_requested,
 	                          sender_uid,
 	                          assumed,
-	                          (gpointer) device);
-	success = nm_device_interface_activate (dev_iface, req, error);
+	                          (gpointer) device,
+	                          master);
+	success = nm_device_activate (device, req, error);
 	g_object_unref (req);
 
-	return success ? nm_act_request_get_active_connection_path (req) : NULL;
+	return success ? NM_ACTIVE_CONNECTION (req) : NULL;
+}
+
+/**
+ * find_master:
+ * @self: #NMManager object
+ * @connection: the #NMConnection to find the master connection and device for
+ * @device: the #NMDevice, if any, which will activate @connection
+ * @out_master_connection: on success, the master connection of @connection if
+ *   that master connection was found
+ * @out_master_device: on success, the master device of @connection if that
+ *   master device was found
+ *
+ * Given an #NMConnection, attempts to find its master connection and/or its
+ * master device.  This function may return a master connection, a master device,
+ * or both.  If only a connection is returned, that master connection is not
+ * currently active on any device.  If only a device is returned, that device
+ * is not currently activated with any connection.  If both are returned, then
+ * the device is currently activated or activating with the returned master
+ * connection.
+ *
+ * Returns: %TRUE if the master device and/or connection could be found or if
+ *  the connection did not require a master, %FALSE otherwise
+ **/
+static gboolean
+find_master (NMManager *self,
+             NMConnection *connection,
+             NMDevice *device,
+             NMConnection **out_master_connection,
+             NMDevice **out_master_device)
+{
+	NMManagerPrivate *priv = NM_MANAGER_GET_PRIVATE (self);
+	NMSettingConnection *s_con;
+	const char *master;
+	NMDevice *master_device = NULL;
+	NMConnection *master_connection = NULL;
+	GSList *iter, *connections = NULL;
+
+	s_con = nm_connection_get_setting_connection (connection);
+	g_assert (s_con);
+	master = nm_setting_connection_get_master (s_con);
+
+	if (master == NULL)
+		return TRUE;  /* success, but no master */
+
+	/* Try as an interface name first */
+	master_device = find_device_by_ip_iface (self, master);
+	if (master_device) {
+		/* A device obviously can't be its own master */
+		if (master_device == device)
+			return FALSE;
+	} else {
+		/* Try master as a connection UUID */
+		master_connection = (NMConnection *) nm_settings_get_connection_by_uuid (priv->settings, master);
+		if (master_connection) {
+			/* Check if the master connection is activated on some device already */
+			for (iter = priv->devices; iter; iter = g_slist_next (iter)) {
+				NMDevice *candidate = NM_DEVICE (iter->data);
+
+				if (candidate == device)
+					continue;
+
+				if (nm_device_get_connection (candidate) == master_connection) {
+					master_device = candidate;
+					break;
+				}
+			}
+		} else {
+			/* Might be a virtual interface that hasn't been created yet, so
+			 * look through the interface names of connections that require
+			 * virtual interfaces and see if one of their virtual interface
+			 * names matches the master.
+			 */
+			connections = nm_settings_get_connections (priv->settings);
+			for (iter = connections; iter && !master_connection; iter = g_slist_next (iter)) {
+				NMConnection *candidate = iter->data;
+				char *vname;
+
+				if (connection_needs_virtual_device (candidate)) {
+					vname = get_virtual_iface_name (self, candidate, NULL);
+					if (g_strcmp0 (master, vname) == 0)
+						master_connection = candidate;
+					g_free (vname);
+				}
+			}
+			g_slist_free (connections);
+		}
+	}
+
+	if (out_master_connection)
+		*out_master_connection = master_connection;
+	if (out_master_device)
+		*out_master_device = master_device;
+
+    return master_device || master_connection;
+}
+
+static gboolean
+is_compatible_with_slave (NMConnection *master, NMConnection *slave)
+{
+	NMSettingConnection *s_con;
+
+	g_return_val_if_fail (master, FALSE);
+	g_return_val_if_fail (slave, FALSE);
+
+	s_con = nm_connection_get_setting_connection (slave);
+	g_assert (s_con);
+
+	return nm_connection_is_type (master, nm_setting_connection_get_slave_type (s_con));
+}
+
+/**
+ * ensure_master_active_connection:
+ *
+ * @self: the #NMManager
+ * @dbus_sender: if the request was initiated by a user via D-Bus, the
+ *   dbus sender name of the client that requested the activation; for auto
+ *   activated connections use %NULL
+ * @connection: the connection that should depend on @master_connection
+ * @device: the #NMDevice, if any, which will activate @connection
+ * @master_connection: the master connection
+ * @master_device: the master device
+ * @error: the error, if an error occurred
+ *
+ * Determines whether a given #NMConnection depends on another connection to
+ * be activated, and if so, finds that master connection or creates it.
+ *
+ * Returns: the master #NMActiveConnection that the caller should depend on, or
+ * %NULL if an error occurred
+ */
+static NMActiveConnection *
+ensure_master_active_connection (NMManager *self,
+                                 const char *dbus_sender,
+                                 NMConnection *connection,
+                                 NMDevice *device,
+                                 NMConnection *master_connection,
+                                 NMDevice *master_device,
+                                 GError **error)
+{
+	NMManagerPrivate *priv = NM_MANAGER_GET_PRIVATE (self);
+	NMActiveConnection *master_ac = NULL;
+	NMDeviceState master_state;
+	GSList *iter;
+
+	g_assert (connection);
+	g_assert (master_connection || master_device);
+
+	/* If the master device isn't activated then we need to activate it using
+	 * compatible connection.  If it's already activating we can just proceed.
+	 */
+	if (master_device) {
+		/* If we're passed a connection and a device, we require that connection
+		 * be already activated on the device, eg returned from find_master().
+		 */
+		if (master_connection)
+			g_assert (nm_device_get_connection (master_device) == master_connection);
+
+		master_state = nm_device_get_state (master_device);
+		if (   (master_state == NM_DEVICE_STATE_ACTIVATED)
+		    || nm_device_is_activating (master_device)) {
+			/* Device already using master_connection */
+			return NM_ACTIVE_CONNECTION (nm_device_get_act_request (master_device));
+		}
+
+		/* If the device is disconnected, find a compabile connection and
+		 * activate it on the device.
+		 */
+		if (master_state == NM_DEVICE_STATE_DISCONNECTED) {
+			GSList *connections;
+
+			g_assert (master_connection == NULL);
+
+			/* Find a compatible connection and activate this device using it */
+			connections = nm_settings_get_connections (priv->settings);
+			for (iter = connections; iter; iter = g_slist_next (iter)) {
+				NMConnection *candidate = NM_CONNECTION (iter->data);
+
+				/* Ensure eg bond slave and the candidate master is a bond master */
+				if (!is_compatible_with_slave (candidate, connection))
+					continue;
+
+				if (nm_device_check_connection_compatible (master_device, candidate, NULL)) {
+					master_ac = nm_manager_activate_connection (self,
+					                                            candidate,
+					                                            NULL,
+					                                            nm_device_get_path (master_device),
+					                                            dbus_sender,
+					                                            error);
+					g_slist_free (connections);
+					return master_ac;
+				}
+			}
+			g_slist_free (connections);
+
+			g_set_error (error,
+			             NM_MANAGER_ERROR,
+			             NM_MANAGER_ERROR_UNKNOWN_CONNECTION,
+			             "No compatible connection found for master device %s.",
+			             nm_device_get_iface (master_device));
+			return NULL;
+		}
+
+		/* Otherwise, the device is unmanaged, unavailable, or disconnecting */
+		g_set_error (error,
+		             NM_MANAGER_ERROR,
+		             NM_MANAGER_ERROR_UNMANAGED_DEVICE,
+		             "Master device %s unmanaged or not available for activation",
+		             nm_device_get_iface (master_device));
+	} else if (master_connection) {
+		gboolean found_device = FALSE;
+
+		/* Find a compatible device and activate it using this connection */
+		for (iter = priv->devices; iter; iter = g_slist_next (iter)) {
+			NMDevice *candidate = NM_DEVICE (iter->data);
+
+			if (candidate == device) {
+				/* A device obviously can't be its own master */
+				continue;
+			}
+
+			if (!nm_device_check_connection_compatible (candidate, master_connection, NULL))
+				continue;
+
+			found_device = TRUE;
+			master_state = nm_device_get_state (candidate);
+			if (master_state != NM_DEVICE_STATE_DISCONNECTED)
+				continue;
+
+			return nm_manager_activate_connection (self,
+			                                       master_connection,
+			                                       NULL,
+			                                       nm_device_get_path (candidate),
+			                                       dbus_sender,
+			                                       error);
+		}
+
+		/* Device described by master_connection may be a virtual one that's
+		 * not created yet.
+		 */
+		if (!found_device && connection_needs_virtual_device (master_connection)) {
+			return nm_manager_activate_connection (self,
+			                                       master_connection,
+			                                       NULL,
+			                                       NULL,
+			                                       dbus_sender,
+			                                       error);
+		}
+
+		g_set_error (error,
+		             NM_MANAGER_ERROR,
+		             NM_MANAGER_ERROR_UNKNOWN_DEVICE,
+		             "No compatible disconnected device found for master connection %s.",
+		             nm_connection_get_uuid (master_connection));
+	} else
+		g_assert_not_reached ();
+
+	return NULL;
+}
+
+static NMActiveConnection *
+activate_vpn_connection (NMManager *self,
+                         NMConnection *connection,
+                         const char *specific_object,
+                         const char *device_path,
+                         gulong sender_uid,
+                         GError **error)
+{
+	NMManagerPrivate *priv = NM_MANAGER_GET_PRIVATE (self);
+	NMActRequest *parent_req = NULL;
+	NMDevice *device = NULL;
+	GSList *iter;
+
+	if (specific_object) {
+		/* Find the specifc connection the client requested we use */
+		parent_req = nm_manager_get_act_request_by_path (self, specific_object, &device);
+		if (!parent_req) {
+			g_set_error_literal (error, NM_MANAGER_ERROR, NM_MANAGER_ERROR_CONNECTION_NOT_ACTIVE,
+			                     "Base connection for VPN connection not active.");
+			return NULL;
+		}
+	} else {
+		/* Just find the current default connection */
+		for (iter = priv->devices; iter; iter = g_slist_next (iter)) {
+			NMDevice *candidate = NM_DEVICE (iter->data);
+			NMActRequest *candidate_req;
+
+			candidate_req = nm_device_get_act_request (candidate);
+			if (candidate_req && nm_active_connection_get_default (NM_ACTIVE_CONNECTION (candidate_req))) {
+				device = candidate;
+				parent_req = candidate_req;
+				break;
+			}
+		}
+	}
+
+	if (!device || !parent_req) {
+		g_set_error_literal (error, NM_MANAGER_ERROR, NM_MANAGER_ERROR_UNKNOWN_DEVICE,
+		                     "Could not find source connection, or the source connection had no active device.");
+		return NULL;
+	}
+
+	return nm_vpn_manager_activate_connection (priv->vpn_manager,
+	                                           connection,
+	                                           device,
+	                                           nm_active_connection_get_path (NM_ACTIVE_CONNECTION (parent_req)),
+	                                           TRUE,
+	                                           sender_uid,
+	                                           error);
 }
 
-const char *
+NMActiveConnection *
 nm_manager_activate_connection (NMManager *manager,
                                 NMConnection *connection,
                                 const char *specific_object,
@@ -1920,11 +2714,13 @@ nm_manager_activate_connection (NMManager *manager,
 {
 	NMManagerPrivate *priv;
 	NMDevice *device = NULL;
-	NMSettingConnection *s_con;
-	NMVPNConnection *vpn_connection;
-	const char *path = NULL;
 	gulong sender_uid = 0;
 	DBusError dbus_error;
+	NMDeviceState state;
+	char *iface;
+	NMDevice *master_device = NULL;
+	NMConnection *master_connection = NULL;
+	NMActiveConnection *master_ac = NULL;
 
 	g_return_val_if_fail (manager != NULL, NULL);
 	g_return_val_if_fail (connection != NULL, NULL);
@@ -1948,87 +2744,141 @@ nm_manager_activate_connection (NMManager *manager,
 		}
 	}
 
-	s_con = NM_SETTING_CONNECTION (nm_connection_get_setting (connection, NM_TYPE_SETTING_CONNECTION));
-	g_assert (s_con);
+	/* VPN ? */
+	if (nm_connection_is_type (connection, NM_SETTING_VPN_SETTING_NAME))
+		return activate_vpn_connection (manager, connection, specific_object, device_path, sender_uid, error);
 
-	if (!strcmp (nm_setting_connection_get_connection_type (s_con), NM_SETTING_VPN_SETTING_NAME)) {
-		NMActRequest *parent_req = NULL;
-
-		/* VPN connection */
+	/* Device-based connection */
+	if (device_path) {
+		device = nm_manager_get_device_by_path (manager, device_path);
+		if (!device) {
+			g_set_error_literal (error, NM_MANAGER_ERROR, NM_MANAGER_ERROR_UNKNOWN_DEVICE,
+			                     "Device not found");
+			return NULL;
+		}
 
-		if (specific_object) {
-			/* Find the specifc connection the client requested we use */
-			parent_req = nm_manager_get_act_request_by_path (manager, specific_object, &device);
-			if (!parent_req) {
-				g_set_error (error,
-				             NM_MANAGER_ERROR, NM_MANAGER_ERROR_CONNECTION_NOT_ACTIVE,
-				             "%s", "Base connection for VPN connection not active.");
+		/* If it's a virtual interface make sure the device given by the
+		 * path matches the connection's interface details.
+		 */
+		if (connection_needs_virtual_device (connection)) {
+			iface = get_virtual_iface_name (manager, connection, NULL);
+			if (!iface) {
+				g_set_error_literal (error, NM_MANAGER_ERROR, NM_MANAGER_ERROR_UNKNOWN_DEVICE,
+					                 "Failed to determine connection's virtual interface name");
+				return NULL;
+			} else if (g_strcmp0 (iface, nm_device_get_ip_iface (device)) != 0) {
+				g_set_error_literal (error, NM_MANAGER_ERROR, NM_MANAGER_ERROR_UNKNOWN_DEVICE,
+					                 "Device given by path did not match connection's virtual interface name");
+				g_free (iface);
 				return NULL;
 			}
-		} else {
-			GSList *iter;
+			g_free (iface);
+		}
+	} else {
+		/* Virtual connections (VLAN, bond, etc) may not specify a device
+		 * path because the device may not be created yet, or it be given
+		 * by the connection's properties instead.  Find the device the
+		 * connection refers to, or create it if needed.
+		 */
+		if (!connection_needs_virtual_device (connection)) {
+			g_set_error_literal (error, NM_MANAGER_ERROR, NM_MANAGER_ERROR_UNKNOWN_DEVICE,
+				                 "This connection requires an existing device.");
+			return NULL;
+		}
 
-			/* Just find the current default connection */
-			for (iter = priv->devices; iter; iter = g_slist_next (iter)) {
-				NMDevice *candidate = NM_DEVICE (iter->data);
-				NMActRequest *candidate_req;
+		iface = get_virtual_iface_name (manager, connection, NULL);
+		if (!iface) {
+			g_set_error_literal (error, NM_MANAGER_ERROR, NM_MANAGER_ERROR_UNKNOWN_DEVICE,
+				                 "Failed to determine connection's virtual interface name");
+			return NULL;
+		}
 
-				candidate_req = nm_device_get_act_request (candidate);
-				if (candidate_req && nm_act_request_get_default (candidate_req)) {
-					device = candidate;
-					parent_req = candidate_req;
-					break;
-				}
+		device = find_device_by_ip_iface (manager, iface);
+		if (!device) {
+			/* Create it */
+			device = system_create_virtual_device (manager, connection);
+			if (!device) {
+				g_set_error_literal (error, NM_MANAGER_ERROR, NM_MANAGER_ERROR_UNKNOWN_DEVICE,
+						             "Failed to create virtual interface");
+				return NULL;
 			}
-		}
 
-		if (!device || !parent_req) {
-			g_set_error (error,
-			             NM_MANAGER_ERROR, NM_MANAGER_ERROR_UNKNOWN_DEVICE,
-			             "%s", "Could not find source connection, or the source connection had no active device.");
-			return NULL;
+			/* A newly created device, if allowed to be managed by NM, will be
+			 * in the UNAVAILABLE state here.  Since we want to use it right
+			 * away, we transition it immediately to DISCONNECTED.
+			 */
+			if (   nm_device_is_available (device)
+			    && (nm_device_get_state (device) == NM_DEVICE_STATE_UNAVAILABLE)) {
+				nm_device_state_changed (device,
+				                         NM_DEVICE_STATE_DISCONNECTED,
+				                         NM_DEVICE_STATE_REASON_NONE);
+			}
 		}
+	}
 
-		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);
-		if (vpn_connection)
-			path = nm_vpn_connection_get_active_connection_path (vpn_connection);
-	} else {
-		NMDeviceState state;
+	state = nm_device_get_state (device);
+	if (state < NM_DEVICE_STATE_DISCONNECTED) {
+		g_set_error_literal (error, NM_MANAGER_ERROR, NM_MANAGER_ERROR_UNMANAGED_DEVICE,
+			                 "Device not managed by NetworkManager or unavailable");
+		return NULL;
+	}
 
-		/* Device-based connection */
-		device = nm_manager_get_device_by_path (manager, device_path);
-		if (!device) {
-			g_set_error (error,
-			             NM_MANAGER_ERROR, NM_MANAGER_ERROR_UNKNOWN_DEVICE,
-			             "%s", "Device not found");
+	/* Try to find the master connection/device if the connection has a dependency */
+	if (!find_master (manager, connection, device, &master_connection, &master_device)) {
+		g_set_error_literal (error, NM_MANAGER_ERROR, NM_MANAGER_ERROR_UNKNOWN_DEVICE,
+			                 "Master connection not found or invalid");
+		return NULL;
+	}
+
+	/* Ensure there's a master active connection the new connection we're
+	 * activating can depend on.
+	 */
+	if (master_connection || master_device) {
+		if (master_connection) {
+			nm_log_dbg (LOGD_CORE, "Activation of '%s' requires master connection '%s'",
+			            nm_connection_get_id (connection),
+			            nm_connection_get_id (master_connection));
+		}
+		if (master_device) {
+			nm_log_dbg (LOGD_CORE, "Activation of '%s' requires master device '%s'",
+			            nm_connection_get_id (connection),
+			            nm_device_get_ip_iface (master_device));
+		}
+
+		/* Ensure eg bond slave and the candidate master is a bond master */
+		if (master_connection && !is_compatible_with_slave (master_connection, connection)) {
+			g_set_error_literal (error, NM_MANAGER_ERROR, NM_MANAGER_ERROR_DEPENDENCY_FAILED,
+					             "The master connection was not compatible");
 			return NULL;
 		}
 
-		state = nm_device_interface_get_state (NM_DEVICE_INTERFACE (device));
-		if (state < NM_DEVICE_STATE_DISCONNECTED) {
-			g_set_error (error,
-			             NM_MANAGER_ERROR, NM_MANAGER_ERROR_UNMANAGED_DEVICE,
-			             "%s", "Device not managed by NetworkManager or unavailable");
+		master_ac = ensure_master_active_connection (manager,
+		                                             dbus_sender,
+		                                             connection,
+		                                             device,
+		                                             master_connection,
+		                                             master_device,
+		                                             error);
+		if (!master_ac) {
+			if (error)
+				g_assert (*error);
 			return NULL;
 		}
 
-		path = internal_activate_device (manager,
-		                                 device,
-		                                 connection,
-		                                 specific_object,
-		                                 dbus_sender ? TRUE : FALSE,
-		                                 dbus_sender ? sender_uid : 0,
-		                                 FALSE,
-		                                 error);
+		nm_log_dbg (LOGD_CORE, "Activation of '%s' depends on active connection %s",
+		            nm_connection_get_id (connection),
+		            nm_active_connection_get_path (master_ac));
 	}
 
-	return path;
+	return internal_activate_device (manager,
+	                                 device,
+	                                 connection,
+	                                 specific_object,
+	                                 dbus_sender ? TRUE : FALSE,
+	                                 dbus_sender ? sender_uid : 0,
+	                                 FALSE,
+	                                 master_ac,
+	                                 error);
 }
 
 /* 
@@ -2042,7 +2892,7 @@ pending_activate (NMManager *self, PendingActivation *pending)
 {
 	NMManagerPrivate *priv = NM_MANAGER_GET_PRIVATE (self);
 	NMSettingsConnection *connection;
-	const char *path = NULL;
+	NMActiveConnection *ac = NULL;
 	GError *error = NULL;
 	char *sender;
 
@@ -2058,24 +2908,25 @@ pending_activate (NMManager *self, PendingActivation *pending)
 
 	sender = dbus_g_method_get_sender (pending->context);
 	g_assert (sender);
-	path = nm_manager_activate_connection (self,
-	                                       NM_CONNECTION (connection),
-	                                       pending->specific_object_path,
-	                                       pending->device_path,
-	                                       sender,
-	                                       &error);
+	ac = nm_manager_activate_connection (self,
+	                                     NM_CONNECTION (connection),
+	                                     pending->specific_object_path,
+	                                     pending->device_path,
+	                                     sender,
+	                                     &error);
 	g_free (sender);
 
-	if (!path) {
+	if (ac)
+		g_object_notify (G_OBJECT (pending->manager), NM_MANAGER_ACTIVE_CONNECTIONS);
+	else {
 		nm_log_warn (LOGD_CORE, "connection %s failed to activate: (%d) %s",
 		             pending->connection_path,
 		             error ? error->code : -1,
 		             error && error->message ? error->message : "(unknown)");
-	} else
-		g_object_notify (G_OBJECT (pending->manager), NM_MANAGER_ACTIVE_CONNECTIONS);
+	}
 
 out:
-	pending_activation_destroy (pending, error, path);
+	pending_activation_destroy (pending, error, ac);
 	g_clear_error (&error);
 }
 
@@ -2207,7 +3058,7 @@ nm_manager_deactivate_connection (NMManager *manager,
 		if (!req)
 			continue;
 
-		if (!strcmp (connection_path, nm_act_request_get_active_connection_path (req))) {
+		if (!strcmp (connection_path, nm_active_connection_get_path (NM_ACTIVE_CONNECTION (req)))) {
 			nm_device_state_changed (device,
 			                         NM_DEVICE_STATE_DISCONNECTED,
 			                         reason);
@@ -2286,7 +3137,7 @@ impl_manager_deactivate_connection (NMManager *self,
 
 		req = nm_device_get_act_request (NM_DEVICE (iter->data));
 		if (req)
-			req_path = nm_act_request_get_active_connection_path (req);
+			req_path = nm_active_connection_get_path (NM_ACTIVE_CONNECTION (req));
 
 		if (req_path && !strcmp (active_path, req_path)) {
 			connection = nm_act_request_get_connection (req);
@@ -2384,7 +3235,6 @@ do_sleep_wake (NMManager *self)
 			for (i = 0; i < RFKILL_TYPE_MAX; i++) {
 				RadioState *rstate = &priv->radio_states[i];
 				gboolean enabled = radio_enabled_for_rstate (rstate, TRUE);
-				RfKillType devtype = RFKILL_TYPE_UNKNOWN;
 
 				if (rstate->desc) {
 					nm_log_dbg (LOGD_RFKILL, "%s %s devices (hw_enabled %d, sw_enabled %d, user_enabled %d)",
@@ -2392,13 +3242,12 @@ do_sleep_wake (NMManager *self)
 					            rstate->desc, rstate->hw_enabled, rstate->sw_enabled, rstate->user_enabled);
 				}
 
-				g_object_get (G_OBJECT (device), NM_DEVICE_INTERFACE_RFKILL_TYPE, &devtype, NULL);
-				if (devtype == rstate->rtype)
-					nm_device_interface_set_enabled (NM_DEVICE_INTERFACE (device), enabled);
+				if (nm_device_get_rfkill_type (device) == rstate->rtype)
+					nm_device_set_enabled (device, enabled);
 			}
 
 			nm_device_clear_autoconnect_inhibit (device);
-			if (nm_device_interface_spec_match_list (NM_DEVICE_INTERFACE (device), unmanaged_specs))
+			if (nm_device_spec_match_list (device, unmanaged_specs))
 				nm_device_set_managed (device, FALSE, NM_DEVICE_STATE_REASON_NOW_UNMANAGED);
 			else
 				nm_device_set_managed (device, TRUE, NM_DEVICE_STATE_REASON_NOW_MANAGED);
@@ -2823,6 +3672,20 @@ nm_manager_start (NMManager *self)
 
 	nm_udev_manager_query_devices (priv->udev_mgr);
 	bluez_manager_resync_devices (self);
+
+	/* Query devices again to ensure that we catch all virtual interfaces (like
+	 * VLANs) that require a parent.  If during the first pass the VLAN
+	 * interface was detected first, the parent wouldn't exist yet and creating
+	 * the VLAN would fail.  The second query ensures that we'll have a valid
+	 * parent for the VLAN during the second pass.
+	 */
+	nm_udev_manager_query_devices (priv->udev_mgr);
+
+	/*
+	 * Connections added before the manager is started do not emit
+	 * connection-added signals thus devices have to be created manually.
+	 */
+	system_create_virtual_devices (self);
 }
 
 static gboolean
@@ -2857,6 +3720,23 @@ handle_firmware_changed (gpointer user_data)
 	return FALSE;
 }
 
+#if WITH_CONCHECK
+static void
+connectivity_changed (NMConnectivity *connectivity,
+                      GParamSpec *pspec,
+                      gpointer user_data)
+{
+	NMManager *self = NM_MANAGER (user_data);
+	gboolean connected;
+
+	connected = nm_connectivity_get_connected (connectivity);
+	nm_log_dbg (LOGD_CORE, "connectivity checking indicates %s",
+	            connected ? "CONNECTED" : "NOT CONNECTED");
+
+	nm_manager_update_state (self);
+}
+#endif  /* WITH_CONCHECK */
+
 static void
 firmware_dir_changed (GFileMonitor *monitor,
                       GFile *file,
@@ -3058,6 +3938,9 @@ nm_manager_new (NMSettings *settings,
                 gboolean initial_wifi_enabled,
                 gboolean initial_wwan_enabled,
                 gboolean initial_wimax_enabled,
+                const gchar *connectivity_uri,
+                gint connectivity_interval,
+                const gchar *connectivity_response,
                 GError **error)
 {
 	NMManagerPrivate *priv;
@@ -3073,6 +3956,13 @@ nm_manager_new (NMSettings *settings,
 
 	priv = NM_MANAGER_GET_PRIVATE (singleton);
 
+#if WITH_CONCHECK
+	priv->connectivity = nm_connectivity_new (connectivity_uri, connectivity_interval, connectivity_response);
+
+	g_signal_connect (priv->connectivity, "notify::" NM_CONNECTIVITY_CONNECTED,
+	                  G_CALLBACK (connectivity_changed), singleton);
+#endif
+
 	bus = nm_dbus_manager_get_connection (priv->dbus_mgr);
 	g_assert (bus);
 	dbus_connection = dbus_g_connection_get_connection (bus);
@@ -3099,13 +3989,13 @@ nm_manager_new (NMSettings *settings,
 	g_signal_connect (priv->settings, "notify::" NM_SETTINGS_HOSTNAME,
 	                  G_CALLBACK (system_hostname_changed_cb), singleton);
 	g_signal_connect (priv->settings, NM_SETTINGS_SIGNAL_CONNECTION_ADDED,
-	                  G_CALLBACK (connections_changed), singleton);
+	                  G_CALLBACK (connection_added), singleton);
 	g_signal_connect (priv->settings, NM_SETTINGS_SIGNAL_CONNECTION_UPDATED,
-	                  G_CALLBACK (connections_changed), singleton);
+	                  G_CALLBACK (connection_changed), singleton);
 	g_signal_connect (priv->settings, NM_SETTINGS_SIGNAL_CONNECTION_REMOVED,
-	                  G_CALLBACK (connections_changed), singleton);
+	                  G_CALLBACK (connection_removed), singleton);
 	g_signal_connect (priv->settings, NM_SETTINGS_SIGNAL_CONNECTION_VISIBILITY_CHANGED,
-	                  G_CALLBACK (connections_changed), singleton);
+	                  G_CALLBACK (connection_changed), singleton);
 
 	dbus_g_connection_register_g_object (bus, NM_DBUS_PATH, G_OBJECT (singleton));
 
@@ -3171,6 +4061,13 @@ dispose (GObject *object)
 		                                   TRUE);
 	}
 
+#if WITH_CONCHECK
+	if (priv->connectivity) {
+		g_object_unref (priv->connectivity);
+		priv->connectivity = NULL;
+	}
+#endif
+
 	g_free (priv->hostname);
 
 	g_object_unref (priv->settings);
@@ -3224,6 +4121,8 @@ dispose (GObject *object)
 		g_object_unref (priv->fw_monitor);
 	}
 
+	g_slist_free (priv->factories);
+
 	if (priv->timestamp_update_id) {
 		g_source_remove (priv->timestamp_update_id);
 		priv->timestamp_update_id = 0;
@@ -3436,7 +4335,7 @@ periodic_update_active_connection_timestamps (gpointer user_data)
 		req = nm_manager_get_act_request_by_path (manager, active_path, &device);
 		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));
+			                                         (guint64) time (NULL), FALSE);
 		else {
 			/* The connection is probably VPN */
 			NMVPNConnection *vpn_con;
@@ -3444,7 +4343,7 @@ periodic_update_active_connection_timestamps (gpointer user_data)
 			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));
+				                                         (guint64) time (NULL), FALSE);
 		}
 	}
 
@@ -3570,6 +4469,8 @@ nm_manager_init (NMManager *manager)
 		             KERNEL_FIRMWARE_DIR);
 	}
 
+	load_device_factories (manager);
+
 	/* Update timestamps in active connections */
 	priv->timestamp_update_id = g_timeout_add_seconds (300, (GSourceFunc) periodic_update_active_connection_timestamps, manager);
 }
diff --git a/src/nm-manager.h b/src/nm-manager.h
index b044971f..58ba4605 100644
--- a/src/nm-manager.h
+++ b/src/nm-manager.h
@@ -26,7 +26,6 @@
 #include <glib-object.h>
 #include <dbus/dbus-glib.h>
 #include "nm-device.h"
-#include "nm-device-interface.h"
 #include "nm-settings.h"
 
 #define NM_TYPE_MANAGER            (nm_manager_get_type ())
@@ -36,6 +35,19 @@
 #define NM_IS_MANAGER_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((obj), NM_TYPE_MANAGER))
 #define NM_MANAGER_GET_CLASS(obj)  (G_TYPE_INSTANCE_GET_CLASS ((obj), NM_TYPE_MANAGER, NMManagerClass))
 
+typedef enum {
+	NM_MANAGER_ERROR_UNKNOWN_CONNECTION = 0,      /*< nick=UnknownConnection >*/
+	NM_MANAGER_ERROR_UNKNOWN_DEVICE,              /*< nick=UnknownDevice >*/
+	NM_MANAGER_ERROR_UNMANAGED_DEVICE,            /*< nick=UnmanagedDevice >*/
+	NM_MANAGER_ERROR_SYSTEM_CONNECTION,           /*< nick=SystemConnection >*/
+	NM_MANAGER_ERROR_PERMISSION_DENIED,           /*< nick=PermissionDenied >*/
+	NM_MANAGER_ERROR_CONNECTION_NOT_ACTIVE,       /*< nick=ConnectionNotActive >*/
+	NM_MANAGER_ERROR_ALREADY_ASLEEP_OR_AWAKE,     /*< nick=AlreadyAsleepOrAwake >*/
+	NM_MANAGER_ERROR_ALREADY_ENABLED_OR_DISABLED, /*< nick=AlreadyEnabledOrDisabled >*/
+	NM_MANAGER_ERROR_UNSUPPORTED_CONNECTION_TYPE, /*< nick=UnsupportedConnectionType >*/
+	NM_MANAGER_ERROR_DEPENDENCY_FAILED,           /*< nick=DependencyFailed >*/
+} NMManagerError;
+
 #define NM_MANAGER_VERSION "version"
 #define NM_MANAGER_STATE "state"
 #define NM_MANAGER_NETWORKING_ENABLED "networking-enabled"
@@ -73,7 +85,10 @@ NMManager *nm_manager_new (NMSettings *settings,
                            gboolean initial_net_enabled,
                            gboolean initial_wifi_enabled,
                            gboolean initial_wwan_enabled,
-						   gboolean initial_wimax_enabled,
+                           gboolean initial_wimax_enabled,
+                           const gchar *connectivity_uri,
+                           gint connectivity_interval,
+                           const gchar *connectivity_response,
                            GError **error);
 
 NMManager *nm_manager_get (void);
@@ -84,12 +99,16 @@ void nm_manager_start (NMManager *manager);
 
 GSList *nm_manager_get_devices (NMManager *manager);
 
-const char * nm_manager_activate_connection (NMManager *manager,
-                                             NMConnection *connection,
-                                             const char *specific_object,
-                                             const char *device_path,
-                                             const char *dbus_sender, /* NULL if automatic */
-                                             GError **error);
+NMDevice *nm_manager_get_device_by_master (NMManager *manager,
+					   const char *master,
+					   const char *driver);
+
+NMActiveConnection *nm_manager_activate_connection (NMManager *manager,
+                                                    NMConnection *connection,
+                                                    const char *specific_object,
+                                                    const char *device_path,
+                                                    const char *dbus_sender, /* NULL if automatic */
+                                                    GError **error);
 
 gboolean nm_manager_deactivate_connection (NMManager *manager,
                                            const char *connection_path,
diff --git a/src/nm-netlink-compat.c b/src/nm-netlink-compat.c
index e91a1ff2..974121ad 100644
--- a/src/nm-netlink-compat.c
+++ b/src/nm-netlink-compat.c
@@ -20,7 +20,13 @@
 
 #include <config.h>
 #include <glib.h>
+#include <unistd.h>
+#include <sys/ioctl.h>
+#include <sys/socket.h>
+#include <linux/if_vlan.h>
+#include <linux/sockios.h>
 
+#include "nm-logging.h"
 #include "nm-netlink-compat.h"
 
 #ifndef HAVE_LIBNL1
@@ -102,4 +108,135 @@ nl_compat_error (int err)
 
 	return -err;
 }
+
+int
+rtnl_link_vlan_get_id (struct rtnl_link *l)
+{
+	int fd;
+	struct vlan_ioctl_args if_request;
+	char *if_name = NULL;
+
+	memset (&if_request, 0, sizeof (struct vlan_ioctl_args));
+
+	if ((if_name = rtnl_link_get_name (l)) == NULL)
+		return -1;
+
+	strcpy (if_request.device1, if_name);
+
+	if ((fd = socket (AF_INET, SOCK_STREAM, 0)) < 0) {
+		nm_log_err (LOGD_DEVICE, "couldn't open control socket.");
+		return -1;
+	}
+
+	if_request.cmd = GET_VLAN_VID_CMD;
+	if (ioctl (fd, SIOCSIFVLAN, &if_request) < 0) {
+		nm_log_err (LOGD_DEVICE, "couldn't get vlan id for %s.", if_name);
+		goto err_out;
+	}
+
+	close(fd);
+	return if_request.u.VID;
+err_out:
+	close(fd);
+	return -1;
+}
+
+int
+rtnl_link_vlan_set_flags (struct rtnl_link *l, unsigned int flags)
+{
+	int fd;
+	struct vlan_ioctl_args if_request;
+	char *if_name = NULL;
+
+
+	if ((if_name = rtnl_link_get_name (l)) == NULL)
+		return -1;
+
+	if ((fd = socket (AF_INET, SOCK_STREAM, 0)) < 0) {
+		nm_log_err (LOGD_DEVICE, "couldn't open control socket.");
+		return -1;
+	}
+
+	memset (&if_request, 0, sizeof (struct vlan_ioctl_args));
+	strcpy (if_request.device1, if_name);
+	if_request.cmd = SET_VLAN_FLAG_CMD;
+	if_request.u.flag = flags;
+
+	if (ioctl (fd, SIOCSIFVLAN, &if_request) < 0) {
+		nm_log_err (LOGD_DEVICE, "couldn't set flag in device %s.", if_name);
+		goto err_out;
+	}
+
+	close(fd);
+	return 0;
+err_out:
+	close(fd);
+	return -1;
+}
+
+int
+rtnl_link_vlan_set_ingress_map (struct rtnl_link *l, int from, uint32_t to)
+{
+	int fd;
+	struct vlan_ioctl_args if_request;
+	char *if_name = NULL;
+
+	if ((if_name = rtnl_link_get_name (l)) == NULL)
+		return -1;
+
+	if ((fd = socket (AF_INET, SOCK_STREAM, 0)) < 0) {
+		nm_log_err (LOGD_DEVICE, "couldn't open control socket.");
+		return -1;
+	}
+
+	memset (&if_request, 0, sizeof (struct vlan_ioctl_args));
+	strcpy (if_request.device1, if_name);
+	if_request.cmd = SET_VLAN_INGRESS_PRIORITY_CMD;
+	if_request.u.skb_priority = from;
+	if_request.vlan_qos = to;
+
+	if (ioctl (fd, SIOCSIFVLAN, &if_request) < 0) {
+		nm_log_err (LOGD_DEVICE, "couldn't set ingress map on device %s.", if_name);
+		goto err_out;
+	}
+
+	close(fd);
+	return 0;
+err_out:
+	close(fd);
+	return -1;
+}
+
+int
+rtnl_link_vlan_set_egress_map (struct rtnl_link *l, int from, uint32_t to)
+{
+	int fd;
+	struct vlan_ioctl_args if_request;
+	char *if_name = NULL;
+
+	if ((if_name = rtnl_link_get_name (l)) == NULL)
+		return -1;
+
+	if ((fd = socket (AF_INET, SOCK_STREAM, 0)) < 0) {
+		nm_log_err (LOGD_DEVICE, "couldn't open control socket.");
+		return -1;
+	}
+
+	memset (&if_request, 0, sizeof (struct vlan_ioctl_args));
+	strcpy (if_request.device1, if_name);
+	if_request.cmd = SET_VLAN_EGRESS_PRIORITY_CMD;
+	if_request.u.skb_priority = from;
+	if_request.vlan_qos = to;
+
+	if (ioctl (fd, SIOCSIFVLAN, &if_request) < 0) {
+		nm_log_err (LOGD_DEVICE, "couldn't set egress map on device %s.", if_name);
+		goto err_out;
+	}
+
+	close(fd);
+	return 0;
+err_out:
+	close(fd);
+	return -1;
+}
 #endif
diff --git a/src/nm-netlink-compat.h b/src/nm-netlink-compat.h
index af21fb9a..eb0926ad 100644
--- a/src/nm-netlink-compat.h
+++ b/src/nm-netlink-compat.h
@@ -16,6 +16,7 @@
  * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
  *
  * Copyright (C) 2011 Caixa Magica Software.
+ * Copyright (C) 2011 - 2012 Red Hat, Inc.
  */
 
 #ifndef NM_NETLINK_COMPAT_H
@@ -68,7 +69,7 @@ __rtnl_link_alloc_cache (struct nl_sock *h, struct nl_cache **cache)
 
 /* functions with similar prototypes */
 #define nlmsg_datalen nlmsg_len
-#endif
+#endif  /* HAVE_LIBNL2 */
 
 
 /* libnl-1.0 compat functions */
@@ -202,6 +203,79 @@ __nl_cache_include (struct nl_cache *cache, struct nl_object *obj, change_func_t
 #define NLE_NOACCESS            27
 #define NLE_PERM                28
 #define NLE_PKTLOC_FILE         29
-#endif
+
+#endif  /* HAVE_LIBNL1 */
+
+/* Stuff that only libnl3 has */
+#if defined(HAVE_LIBNL1) || defined(HAVE_LIBNL2)
+
+static inline int
+rtnl_link_bond_add (struct nl_sock *h, const char *name, void *data)
+{
+	/* Bonding only in libnl3 */
+	return -NLE_OPNOTSUPP;
+}
+
+static inline int
+rtnl_link_get_kernel (struct nl_sock *h, int f, const char *name, struct rtnl_link **out_link)
+{
+	/* Bonding only in libnl3 */
+	return -NLE_OPNOTSUPP;
+}
+
+static inline char *
+rtnl_link_get_type (struct rtnl_link *rtnl_link)
+{
+	/* Bonding only in libnl3 */
+	return NULL;
+}
+
+static inline int
+rtnl_link_bond_enslave_ifindex (struct nl_sock *h, int master_ifidx, int slave_ifidx)
+{
+	/* Bonding only in libnl3 */
+	return -NLE_OPNOTSUPP;
+}
+
+static inline int
+rtnl_link_bond_release_ifindex (struct nl_sock *h, int slave_ifidx)
+{
+	/* Bonding only in libnl3 */
+	return -NLE_OPNOTSUPP;
+}
+
+static inline int
+rtnl_link_vlan_set_id (struct rtnl_link *l, int id)
+{
+	/* VLAN only in libnl3 */
+	return -NLE_OPNOTSUPP;
+}
+
+int rtnl_link_vlan_get_id (struct rtnl_link *l);
+int rtnl_link_vlan_set_flags (struct rtnl_link *l, unsigned int flags);
+int rtnl_link_vlan_set_ingress_map (struct rtnl_link *l, int from, uint32_t to);
+int rtnl_link_vlan_set_egress_map (struct rtnl_link *l, int from, uint32_t to);
+
+static inline int
+rtnl_link_set_type (struct rtnl_link *l, const char *type)
+{
+	/* Operation only in libnl3 */
+	return -NLE_OPNOTSUPP;
+}
+
+static inline int
+rtnl_link_add (struct nl_sock *sk, struct rtnl_link *l, int flags)
+{
+	/* Operation only in libnl3 */
+	return -NLE_OPNOTSUPP;
+}
+
+static inline int
+rtnl_link_delete(struct nl_sock *sk, const struct rtnl_link *l)
+{
+	/* Operation only in libnl3 */
+	return -NLE_OPNOTSUPP;
+}
+#endif  /* HAVE_LIBNL1 || HAVE_LIBNL2 */
 
 #endif /* NM_NETLINK_COMPAT_H */
diff --git a/src/nm-netlink-monitor.c b/src/nm-netlink-monitor.c
index 9b8dac5c..29a21e3c 100644
--- a/src/nm-netlink-monitor.c
+++ b/src/nm-netlink-monitor.c
@@ -76,7 +76,6 @@ enum {
 	NOTIFICATION = 0,
 	CARRIER_ON,
 	CARRIER_OFF,
-	ERROR,
 	LAST_SIGNAL
 };
 static guint signals[LAST_SIGNAL] = { 0 };
@@ -84,11 +83,60 @@ static guint signals[LAST_SIGNAL] = { 0 };
 
 G_DEFINE_TYPE (NMNetlinkMonitor, nm_netlink_monitor, G_TYPE_OBJECT);
 
+/****************************************************************/
+
+static gboolean
+detach_monitor (gpointer data)
+{
+	nm_log_warn (LOGD_HW, "detaching netlink event monitor");
+	nm_netlink_monitor_detach (NM_NETLINK_MONITOR (data));
+	return FALSE;
+}
+
+static void
+log_error_limited (NMNetlinkMonitor *monitor, guint32 code, const char *fmt, ...)
+{
+	static time_t rl_time = 0;
+	static guint32 rl_code = 0;
+	static guint32 rl_count = 0;
+	va_list args;
+	char *msg;
+	time_t now;
+
+	g_return_if_fail (monitor != NULL);
+
+	now = time (NULL);
+
+	if ((code != rl_code) || (now > rl_time + 10)) {
+		va_start (args, fmt);
+		msg = g_strdup_vprintf (fmt, args);
+		va_end (args);
+
+		nm_log_warn (LOGD_HW, "error monitoring device for netlink events: %s\n", msg);
+		g_free (msg);
+
+		rl_time = now;
+		rl_code = code;
+		rl_count = 0;
+	}
+
+	rl_count++;
+	if (rl_count > 100) {
+		/* Broken drivers will sometimes cause a flood of netlink errors.
+		 * rh #459205, novell #443429, lp #284507
+		 */
+		nm_log_warn (LOGD_HW, "excessive netlink errors ocurred, disabling netlink monitor.");
+		nm_log_warn (LOGD_HW, "link change events will not be processed.");
+		g_idle_add_full (G_PRIORITY_HIGH, detach_monitor, monitor, NULL);
+	}
+}
+
+/****************************************************************/
+
 static void
 link_msg_handler (struct nl_object *obj, void *arg)
 {
 	NMNetlinkMonitor *self = NM_NETLINK_MONITOR (arg);
-	GError *error;
 	struct rtnl_link *filter;
 	struct rtnl_link *link_obj;
 	guint flags;
@@ -96,12 +144,9 @@ link_msg_handler (struct nl_object *obj, void *arg)
 
 	filter = rtnl_link_alloc ();
 	if (!filter) {
-		error = g_error_new (NM_NETLINK_MONITOR_ERROR,
-		                     NM_NETLINK_MONITOR_ERROR_BAD_ALLOC,
-		                     _("error processing netlink message: %s"),
-		                     nl_geterror (ENOMEM));
-		g_signal_emit (self, signals[ERROR], 0, error);
-		g_error_free (error);
+		log_error_limited (self, NM_NETLINK_MONITOR_ERROR_BAD_ALLOC,
+		                   _("error processing netlink message: %s"),
+		                   nl_geterror (ENOMEM));
 		return;
 	}
 
@@ -195,7 +240,6 @@ 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);
@@ -204,22 +248,17 @@ event_handler (GIOChannel *channel,
 	g_return_val_if_fail (priv->event_id > 0, TRUE);
 
 	if (io_condition & ERROR_CONDITIONS) {
-		const char *err_msg;
+		const char *err_msg = _("error occurred while waiting for data on socket");
 		int err_code = 0;
 		socklen_t err_len = sizeof (err_code);
 
 		/* Grab error information */	 
 		if (getsockopt (g_io_channel_unix_get_fd (channel), 
-						SOL_SOCKET, SO_ERROR, (void *) &err_code, &err_len))
+						SOL_SOCKET, SO_ERROR,
+						(void *) &err_code, &err_len) == 0)
 			err_msg = strerror (err_code);
-		else
-			err_msg = _("error occurred while waiting for data on socket");
 
-		error = g_error_new (NM_NETLINK_MONITOR_ERROR,
-		                     NM_NETLINK_MONITOR_ERROR_WAITING_FOR_SOCKET_DATA,
-		                     "%s", err_msg);
-		g_signal_emit (self, signals[ERROR], 0, error);
-		g_error_free (error);
+		log_error_limited (self, NM_NETLINK_MONITOR_ERROR_WAITING_FOR_SOCKET_DATA, "%s", err_msg);
 		return TRUE;
 	} else if (io_condition & DISCONNECT_CONDITIONS)
 		return FALSE;
@@ -229,12 +268,9 @@ event_handler (GIOChannel *channel,
 	/* Process the netlink messages */
 	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 (err));
-		g_signal_emit (self, signals[ERROR], 0, error);
-		g_error_free (error);
+		log_error_limited (self, NM_NETLINK_MONITOR_ERROR_PROCESSING_MESSAGE,
+		                   _("error processing netlink message: %s"),
+		                   nl_geterror (err));
 	}
 
 	return TRUE;
@@ -578,20 +614,18 @@ deferred_emit_carrier_state (gpointer user_data)
 	return FALSE;
 }
 
-gboolean
-nm_netlink_monitor_request_status (NMNetlinkMonitor *self, GError **error)
+void
+nm_netlink_monitor_request_status (NMNetlinkMonitor *self)
 {
 	NMNetlinkMonitorPrivate *priv;
 
-	g_return_val_if_fail (NM_IS_NETLINK_MONITOR (self), FALSE);
+	g_return_if_fail (NM_IS_NETLINK_MONITOR (self));
 
 	priv = NM_NETLINK_MONITOR_GET_PRIVATE (self);
 
 	/* Schedule the carrier state emission */
 	if (!priv->request_status_id)
 		priv->request_status_id = g_idle_add (deferred_emit_carrier_state, self);
-
-	return TRUE;
 }
 
 typedef struct {
@@ -778,10 +812,26 @@ NMNetlinkMonitor *
 nm_netlink_monitor_get (void)
 {
 	static NMNetlinkMonitor *singleton = NULL;
+	GError *error = NULL;
 
-	if (!singleton)
-		singleton = NM_NETLINK_MONITOR (g_object_new (NM_TYPE_NETLINK_MONITOR, NULL));
-	else
+	if (!singleton) {
+		singleton = (NMNetlinkMonitor *) g_object_new (NM_TYPE_NETLINK_MONITOR, NULL);
+		g_return_val_if_fail (singleton != NULL, NULL);
+
+		if (nm_netlink_monitor_open_connection (singleton, &error)) {
+			nm_netlink_monitor_attach (singleton);
+			/* Request initial status of cards */
+			nm_netlink_monitor_request_status (singleton);
+		} else {
+			nm_log_warn (LOGD_HW, "Failed to connect to netlink: (%d) %s",
+			             error ? error->code : 0,
+			             (error && error->message) ? error->message : "(unknown)");
+			g_clear_error (&error);
+
+			g_object_unref (singleton);
+			singleton = NULL;
+		}
+	} else
 		g_object_ref (singleton);
 
 	return singleton;
@@ -860,14 +910,6 @@ nm_netlink_monitor_class_init (NMNetlinkMonitorClass *monitor_class)
 		              G_STRUCT_OFFSET (NMNetlinkMonitorClass, carrier_off),
 		              NULL, NULL, g_cclosure_marshal_VOID__INT,
 		              G_TYPE_NONE, 1, G_TYPE_INT);
-
-	signals[ERROR] =
-		g_signal_new ("error",
-		              G_OBJECT_CLASS_TYPE (object_class),
-		              G_SIGNAL_RUN_LAST,
-		              G_STRUCT_OFFSET (NMNetlinkMonitorClass, error),
-		              NULL, NULL, g_cclosure_marshal_VOID__POINTER,
-		              G_TYPE_NONE, 1, G_TYPE_POINTER);
 }
 
 GQuark
diff --git a/src/nm-netlink-monitor.h b/src/nm-netlink-monitor.h
index 5c1fa339..4e0787bd 100644
--- a/src/nm-netlink-monitor.h
+++ b/src/nm-netlink-monitor.h
@@ -58,7 +58,6 @@ typedef struct {
 	void (*notification) (NMNetlinkMonitor *monitor, struct nl_msg *msg);
 	void (*carrier_on)   (NMNetlinkMonitor *monitor, int index);
 	void (*carrier_off)  (NMNetlinkMonitor *monitor, int index);
-	void (*error)        (NMNetlinkMonitor *monitor, GError *error);
 } NMNetlinkMonitorClass;
 
 
@@ -83,8 +82,8 @@ void              nm_netlink_monitor_unsubscribe      (NMNetlinkMonitor *monitor
 gboolean          nm_netlink_monitor_request_ip6_info (NMNetlinkMonitor *monitor,
                                                        GError **error);
 
-gboolean          nm_netlink_monitor_request_status   (NMNetlinkMonitor *monitor,
-                                                       GError **error);
+void              nm_netlink_monitor_request_status   (NMNetlinkMonitor *monitor);
+
 gboolean          nm_netlink_monitor_get_flags_sync   (NMNetlinkMonitor *monitor,
                                                        guint32 ifindex,
                                                        guint32 *ifflags,
diff --git a/src/nm-netlink-utils.c b/src/nm-netlink-utils.c
index 4a62aa55..99aebcb8 100644
--- a/src/nm-netlink-utils.c
+++ b/src/nm-netlink-utils.c
@@ -165,45 +165,50 @@ nm_netlink_route_new (int ifindex,
 }
 
 /**
- * nm_netlink_route_add:
+ * _route_add:
  * @route: the route to add
+ * @family: address family, either %AF_INET or %AF_INET6
+ * @dest: the route destination address, either a struct in_addr or a struct
+ *   in6_addr depending on @family
+ * @dest_prefix: the CIDR prefix of @dest
+ * @gateway: the gateway through which to reach @dest, if any; given as a
+ *   struct in_addr or struct in6_addr depending on @family
+ * @flags: flags to pass to rtnl_route_add(), eg %NLM_F_REPLACE
  *
  * 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)
+static int
+_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;
+	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);
+	if (family == AF_INET) {
+		addrlen = sizeof (struct in_addr);
 		log = LOGD_IP4;
-	}
-	else if (family == AF_INET6) {
-		addrlen = sizeof(struct in6_addr);
+	} else if (family == AF_INET6) {
+		addrlen = sizeof (struct in6_addr);
 		log = LOGD_IP6;
-	} else {
+	} else
 		g_assert_not_reached ();
-	}
 
-
-	sk = nm_netlink_get_default_handle();
+	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);
+		tmp_addr = g_malloc0 (addrlen);
+		memcpy (tmp_addr, dest, addrlen);
 
 		dest_addr = nl_addr_build (family, tmp_addr, addrlen);
-		g_free(tmp_addr);
+		g_free (tmp_addr);
 
 		g_return_val_if_fail (dest_addr != NULL, -NLE_INVAL);
 		nl_addr_set_prefixlen (dest_addr, dest_prefix);
@@ -214,20 +219,19 @@ int nm_netlink_route_add(struct rtnl_route * route,
 
 	/* Build up the gateway address */
 	if (gateway) {
-		tmp_addr = g_malloc0(addrlen);
-		memcpy(tmp_addr, gateway, addrlen);
+		tmp_addr = g_malloc0 (addrlen);
+		memcpy (tmp_addr, gateway, addrlen);
 
 		gw_addr = nl_addr_build (family, tmp_addr, addrlen);
-		g_free(tmp_addr);
+		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 {
+			nl_addr_put (gw_addr);
+		} else
 			nm_log_err (LOGD_DEVICE | log, "Invalid gateway");
-		}
 	}
 
 	err = rtnl_route_add (sk, route, flags);
@@ -236,15 +240,54 @@ int nm_netlink_route_add(struct rtnl_route * route,
 	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_route4_add:
+ * @route: the route to add
+ * @dest: the route destination address in network byte order
+ * @dest_prefix: the CIDR prefix of @dest
+ * @gateway: the gateway through which to reach @dest, if any, in network byte order
+ * @flags: flags to pass to rtnl_route_add(), eg %NLM_F_REPLACE
+ *
+ * Adds an IPv4 route with the given parameters.
+ *
+ * Returns: zero if succeeded or the netlink error otherwise.
+ **/
+int
+nm_netlink_route4_add (struct rtnl_route *route,
+                       guint32 *dst,
+                       int prefix,
+                       guint32 *gw,
+                       int flags)
+{
+	return _route_add (route, AF_INET, dst, prefix, gw, flags);
+}
+
+/**
+ * nm_netlink_route6_add:
+ * @route: the route to add
+ * @dest: the route destination address
+ * @dest_prefix: the CIDR prefix of @dest
+ * @gateway: the gateway through which to reach @dest, if any
+ * @flags: flags to pass to rtnl_route_add(), eg %NLM_F_REPLACE
+ *
+ * Adds an IPv6 route with the given parameters.
+ *
+ * Returns: zero if succeeded or the netlink error otherwise.
+ **/
+int
+nm_netlink_route6_add (struct rtnl_route *route,
+                       const struct in6_addr *dst,
+                       int prefix,
+                       const struct in6_addr *gw,
+                       int flags)
+{
+	return _route_add (route, AF_INET6, dst, prefix, gw, flags);
+}
+
+/**
  * nm_netlink_route_delete:
  * @route: the route to delete
  *
diff --git a/src/nm-netlink-utils.h b/src/nm-netlink-utils.h
index c6c452a0..697faaf0 100644
--- a/src/nm-netlink-utils.h
+++ b/src/nm-netlink-utils.h
@@ -24,6 +24,7 @@
 #include <glib.h>
 #include <netlink/route/rtnl.h>
 #include <netlink/route/route.h>
+#include <netinet/in.h>
 
 gboolean nm_netlink_find_address (int ifindex,
                                   int family,
@@ -43,11 +44,16 @@ struct rtnl_route * nm_netlink_route_new (int ifindex,
                                           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 nm_netlink_route4_add (struct rtnl_route *route,
+                           guint32 *dst,
+                           int prefix,
+                           guint32 *gw,
+                           int flags);
+
+int nm_netlink_route6_add (struct rtnl_route *route,
+                          const struct in6_addr *dst,
                           int prefix,
-                          const void * gw, /* struct in_addr or struct in6_addr */
+                          const struct in6_addr *gw,
                           int flags);
 
 gboolean nm_netlink_route_delete (struct rtnl_route *route);
@@ -76,5 +82,5 @@ struct rtnl_route * nm_netlink_foreach_route (int ifindex,
                                               NlRouteForeachFunc callback,
                                               gpointer user_data);
 
-#endif  /* NM_NETLINK_MONITOR_H */
+#endif  /* NM_NETLINK_UTILS_H */
 
diff --git a/src/nm-policy.c b/src/nm-policy.c
index 669db28b..babf1649 100644
--- a/src/nm-policy.c
+++ b/src/nm-policy.c
@@ -31,14 +31,7 @@
 #include "nm-wifi-ap.h"
 #include "nm-activation-request.h"
 #include "nm-logging.h"
-#include "nm-device-interface.h"
 #include "nm-device.h"
-#include "nm-device-wifi.h"
-#include "nm-device-ethernet.h"
-#include "nm-device-modem.h"
-#if WITH_WIMAX
-#include "nm-device-wimax.h"
-#endif
 #include "nm-dbus-manager.h"
 #include "nm-setting-ip4-config.h"
 #include "nm-setting-connection.h"
@@ -47,6 +40,7 @@
 #include "nm-vpn-manager.h"
 #include "nm-policy-hostname.h"
 #include "nm-manager-auth.h"
+#include "nm-firewall-manager.h"
 
 struct NMPolicy {
 	NMManager *manager;
@@ -60,6 +54,9 @@ struct NMPolicy {
 	gulong vpn_activated_id;
 	gulong vpn_deactivated_id;
 
+	NMFirewallManager *fw_manager;
+	gulong fw_started_id;
+
 	NMSettings *settings;
 
 	NMDevice *default_device4;
@@ -80,6 +77,9 @@ struct NMPolicy {
 #define RESET_RETRIES_TIMER 300
 #define FAILURE_REASON_TAG "failure-reason"
 
+static void schedule_activate_all (NMPolicy *policy);
+
+
 static NMDevice *
 get_best_ip4_device (NMManager *manager, NMActRequest **out_req)
 {
@@ -95,6 +95,7 @@ get_best_ip4_device (NMManager *manager, NMActRequest **out_req)
 	devices = nm_manager_get_devices (manager);
 	for (iter = devices; iter; iter = g_slist_next (iter)) {
 		NMDevice *dev = NM_DEVICE (iter->data);
+		NMDeviceType devtype = nm_device_get_device_type (dev);
 		NMActRequest *req;
 		NMConnection *connection;
 		NMIP4Config *ip4_config;
@@ -117,7 +118,7 @@ get_best_ip4_device (NMManager *manager, NMActRequest **out_req)
 		g_assert (connection);
 
 		/* Never set the default route through an IPv4LL-addressed device */
-		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)
 			method = nm_setting_ip4_config_get_method (s_ip4);
 
@@ -135,7 +136,7 @@ get_best_ip4_device (NMManager *manager, NMActRequest **out_req)
 			}
 		}
 
-		if (!can_default && !NM_IS_DEVICE_MODEM (dev))
+		if (!can_default && (devtype != NM_DEVICE_TYPE_MODEM))
 			continue;
 
 		/* 'never-default' devices can't ever be the default */
@@ -169,6 +170,7 @@ get_best_ip6_device (NMManager *manager, NMActRequest **out_req)
 	devices = nm_manager_get_devices (manager);
 	for (iter = devices; iter; iter = g_slist_next (iter)) {
 		NMDevice *dev = NM_DEVICE (iter->data);
+		NMDeviceType devtype = nm_device_get_device_type (dev);
 		NMActRequest *req;
 		NMConnection *connection;
 		NMIP6Config *ip6_config;
@@ -191,7 +193,7 @@ get_best_ip6_device (NMManager *manager, NMActRequest **out_req)
 		g_assert (connection);
 
 		/* Never set the default route through an IPv4LL-addressed device */
-		s_ip6 = (NMSettingIP6Config *) nm_connection_get_setting (connection, NM_TYPE_SETTING_IP6_CONFIG);
+		s_ip6 = nm_connection_get_setting_ip6_config (connection);
 		if (s_ip6)
 			method = nm_setting_ip6_config_get_method (s_ip6);
 
@@ -209,7 +211,7 @@ get_best_ip6_device (NMManager *manager, NMActRequest **out_req)
 			}
 		}
 
-		if (!can_default && !NM_IS_DEVICE_MODEM (dev))
+		if (!can_default && (devtype != NM_DEVICE_TYPE_MODEM))
 			continue;
 
 		/* 'never-default' devices can't ever be the default */
@@ -471,7 +473,7 @@ update_ip4_routing_and_dns (NMPolicy *policy, gboolean force_update)
 			can_default = FALSE;
 
 		/* Check the user's preference from the NMConnection */
-		s_ip4 = (NMSettingIP4Config *) nm_connection_get_setting (vpn_connection, NM_TYPE_SETTING_IP4_CONFIG);
+		s_ip4 = nm_connection_get_setting_ip4_config (vpn_connection);
 		if (s_ip4 && nm_setting_ip4_config_get_never_default (s_ip4))
 			can_default = FALSE;
 
@@ -533,7 +535,7 @@ update_ip4_routing_and_dns (NMPolicy *policy, gboolean force_update)
 
 		req = nm_device_get_act_request (dev);
 		if (req && (req != best_req))
-			nm_act_request_set_default (req, FALSE);
+			nm_active_connection_set_default (NM_ACTIVE_CONNECTION (req), FALSE);
 	}
 
 	dns_mgr = nm_dns_manager_get (NULL);
@@ -544,10 +546,10 @@ update_ip4_routing_and_dns (NMPolicy *policy, gboolean force_update)
 	 * if the connection is shared dnsmasq picks up the right stuff.
 	 */
 	if (best_req)
-		nm_act_request_set_default (best_req, TRUE);
+		nm_active_connection_set_default (NM_ACTIVE_CONNECTION (best_req), TRUE);
 
 	if (connection)
-		s_con = (NMSettingConnection *) nm_connection_get_setting (connection, NM_TYPE_SETTING_CONNECTION);
+		s_con = nm_connection_get_setting_connection (connection);
 
 	connection_id = s_con ? nm_setting_connection_get_id (s_con) : NULL;
 	if (connection_id) {
@@ -598,7 +600,7 @@ update_ip6_routing_and_dns (NMPolicy *policy, gboolean force_update)
 		/* If it's marked 'never-default', don't make it default */
 		vpn_connection = nm_vpn_connection_get_connection (candidate);
 		g_assert (vpn_connection);
-		s_ip6 = (NMSettingIP6Config *) nm_connection_get_setting (vpn_connection, NM_TYPE_SETTING_IP6_CONFIG);
+		s_ip6 = nm_connection_get_setting_ip6_config (vpn_connection);
 		if (s_ip6 && nm_setting_ip6_config_get_never_default (s_ip6))
 			can_default = FALSE;
 
@@ -660,7 +662,7 @@ update_ip6_routing_and_dns (NMPolicy *policy, gboolean force_update)
 
 		req = nm_device_get_act_request (dev);
 		if (req && (req != best_req))
-			nm_act_request_set_default6 (req, FALSE);
+			nm_active_connection_set_default6 (NM_ACTIVE_CONNECTION (req), FALSE);
 	}
 
 	dns_mgr = nm_dns_manager_get (NULL);
@@ -671,10 +673,10 @@ update_ip6_routing_and_dns (NMPolicy *policy, gboolean force_update)
 	 * if the connection is shared dnsmasq picks up the right stuff.
 	 */
 	if (best_req)
-		nm_act_request_set_default6 (best_req, TRUE);
+		nm_active_connection_set_default6 (NM_ACTIVE_CONNECTION (best_req), TRUE);
 
 	if (connection)
-		s_con = (NMSettingConnection *) nm_connection_get_setting (connection, NM_TYPE_SETTING_CONNECTION);
+		s_con = nm_connection_get_setting_connection (connection);
 
 	connection_id = s_con ? nm_setting_connection_get_id (s_con) : NULL;
 	if (connection_id) {
@@ -792,7 +794,9 @@ auto_activate_device (gpointer user_data)
 		                                     NULL,
 		                                     &error)) {
 			nm_log_info (LOGD_DEVICE, "Connection '%s' auto-activation failed: (%d) %s",
-			             nm_connection_get_id (best_connection), error->code, error->message);
+			             nm_connection_get_id (best_connection),
+			             error ? error->code : -1,
+			             error ? error->message : "(none)");
 			g_error_free (error);
 		}
 	}
@@ -870,7 +874,7 @@ reset_retries_all (NMSettings *settings, NMDevice *device)
 
 	connections = nm_settings_get_connections (settings);
 	for (iter = connections; iter; iter = g_slist_next (iter)) {
-		if (!device || nm_device_interface_check_connection_compatible (NM_DEVICE_INTERFACE (device), iter->data, &error))
+		if (!device || nm_device_check_connection_compatible (device, iter->data, &error))
 			set_connection_auto_retries (NM_CONNECTION (iter->data), RETRIES_DEFAULT);
 		g_clear_error (&error);
 	}
@@ -917,11 +921,11 @@ schedule_activate_check (NMPolicy *policy, NMDevice *device, guint delay_seconds
 	if (nm_manager_get_state (policy->manager) == NM_STATE_ASLEEP)
 		return;
 
-	state = nm_device_interface_get_state (NM_DEVICE_INTERFACE (device));
+	state = nm_device_get_state (device);
 	if (state < NM_DEVICE_STATE_DISCONNECTED)
 		return;
 
-	if (!nm_device_interface_get_enabled (NM_DEVICE_INTERFACE (device)))
+	if (!nm_device_get_enabled (device))
 		return;
 
 	if (!nm_device_autoconnect_allowed (device))
@@ -940,6 +944,7 @@ reset_connections_retries (gpointer user_data)
 	NMPolicy *policy = (NMPolicy *) user_data;
 	GSList *connections, *iter;
 	time_t con_stamp, min_stamp, now;
+	gboolean changed = FALSE;
 
 	policy->reset_retries_id = 0;
 
@@ -952,6 +957,7 @@ reset_connections_retries (gpointer user_data)
 		if (con_stamp + RESET_RETRIES_TIMER <= now) {
 			set_connection_auto_retries (NM_CONNECTION (iter->data), RETRIES_DEFAULT);
 			g_object_set_data (G_OBJECT (iter->data), RESET_RETRIES_TIMESTAMP_TAG, GSIZE_TO_POINTER (0));
+			changed = TRUE;
 			continue;
 		}
 		if (con_stamp < min_stamp)
@@ -962,19 +968,53 @@ reset_connections_retries (gpointer user_data)
 	/* Schedule the handler again if there are some stamps left */
 	if (min_stamp != now)
 		policy->reset_retries_id = g_timeout_add_seconds (RESET_RETRIES_TIMER - (now - min_stamp), reset_connections_retries, policy);
+
+	/* If anything changed, try to activate the newly re-enabled connections */
+	if (changed)
+		schedule_activate_all (policy);
+
 	return FALSE;
 }
 
 static NMConnection *
 get_device_connection (NMDevice *device)
 {
-	NMActRequest *req;
+	NMActRequest *req = NULL;
 
 	req = nm_device_get_act_request (device);
-	if (!req)
-		return NULL;
+	return req ? nm_act_request_get_connection (req) : NULL;
+}
+
+static void schedule_activate_all (NMPolicy *policy);
+
+static void
+activate_slave_connections (NMPolicy *policy, NMConnection *connection,
+                            NMDevice *device)
+{
+	const char *master_device;
+	GSList *connections, *iter;
+
+	master_device = nm_device_get_iface (device);
+	g_assert (master_device);
+
+	connections = nm_settings_get_connections (policy->settings);
+	for (iter = connections; iter; iter = g_slist_next (iter)) {
+		NMConnection *slave;
+		NMSettingConnection *s_slave_con;
+
+		slave = NM_CONNECTION (iter->data);
+		g_assert (slave);
 
-	return nm_act_request_get_connection (req);
+		s_slave_con = nm_connection_get_setting_connection (slave);
+		g_assert (s_slave_con);
+
+		if (!g_strcmp0 (nm_setting_connection_get_master (s_slave_con), master_device))
+			set_connection_auto_retries (slave, RETRIES_DEFAULT);
+	}
+
+	g_slist_free (connections);
+
+	schedule_activate_all (policy);
 }
 
 static void
@@ -995,7 +1035,9 @@ device_state_changed (NMDevice *device,
 		/* Mark the connection invalid if it failed during activation so that
 		 * it doesn't get automatically chosen over and over and over again.
 		 */
-		if (connection && IS_ACTIVATING_STATE (old_state)) {
+		if (   connection
+		    && old_state >= NM_DEVICE_STATE_PREPARE
+		    && old_state <= NM_DEVICE_STATE_ACTIVATED) {
 			guint32 tries = get_connection_auto_retries (connection);
 
 			if (reason == NM_DEVICE_STATE_REASON_NO_SECRETS) {
@@ -1064,6 +1106,13 @@ device_state_changed (NMDevice *device,
 		update_routing_and_dns (policy, FALSE);
 		schedule_activate_check (policy, device, 0);
 		break;
+
+	case NM_DEVICE_STATE_PREPARE:
+		/* Reset auto-connect retries of all slaves and schedule them for
+		 * activation. */
+		activate_slave_connections (policy, connection, device);
+		break;
+
 	default:
 		break;
 	}
@@ -1078,23 +1127,21 @@ device_ip_config_changed (NMDevice *device,
 }
 
 static void
-wireless_networks_changed (NMDeviceWifi *device, NMAccessPoint *ap, gpointer user_data)
+wireless_networks_changed (NMDevice *device, GObject *ap, gpointer user_data)
 {
-	schedule_activate_check ((NMPolicy *) user_data, NM_DEVICE (device), 0);
+	schedule_activate_check ((NMPolicy *) user_data, device, 0);
 }
 
-#if WITH_WIMAX
 static void
-nsps_changed (NMDeviceWimax *device, NMWimaxNsp *nsp, gpointer user_data)
+nsps_changed (NMDevice *device, GObject *nsp, gpointer user_data)
 {
-	schedule_activate_check ((NMPolicy *) user_data, NM_DEVICE (device), 0);
+	schedule_activate_check ((NMPolicy *) user_data, device, 0);
 }
-#endif
 
 static void
-modem_enabled_changed (NMDeviceModem *device, gpointer user_data)
+modem_enabled_changed (NMDevice *device, gpointer user_data)
 {
-	schedule_activate_check ((NMPolicy *) (user_data), NM_DEVICE (device), 0);
+	schedule_activate_check ((NMPolicy *) (user_data), device, 0);
 }
 
 typedef struct {
@@ -1120,19 +1167,23 @@ device_added (NMManager *manager, NMDevice *device, gpointer user_data)
 	NMPolicy *policy = (NMPolicy *) user_data;
 
 	_connect_device_signal (policy, device, "state-changed", device_state_changed);
-	_connect_device_signal (policy, device, "notify::" NM_DEVICE_INTERFACE_IP4_CONFIG, device_ip_config_changed);
-	_connect_device_signal (policy, device, "notify::" NM_DEVICE_INTERFACE_IP6_CONFIG, device_ip_config_changed);
+	_connect_device_signal (policy, device, "notify::" NM_DEVICE_IP4_CONFIG, device_ip_config_changed);
+	_connect_device_signal (policy, device, "notify::" NM_DEVICE_IP6_CONFIG, device_ip_config_changed);
 
-	if (NM_IS_DEVICE_WIFI (device)) {
+	switch (nm_device_get_device_type (device)) {
+	case NM_DEVICE_TYPE_WIFI:
 		_connect_device_signal (policy, device, "access-point-added", wireless_networks_changed);
 		_connect_device_signal (policy, device, "access-point-removed", wireless_networks_changed);
-#if WITH_WIMAX
-	} else if (NM_IS_DEVICE_WIMAX (device)) {
+		break;
+	case NM_DEVICE_TYPE_WIMAX:
 		_connect_device_signal (policy, device, "nsp-added", nsps_changed);
 		_connect_device_signal (policy, device, "nsp-removed", nsps_changed);
-#endif
-	} else if (NM_IS_DEVICE_MODEM (device)) {
-		_connect_device_signal (policy, device, NM_DEVICE_MODEM_ENABLE_CHANGED, modem_enabled_changed);
+		break;
+	case NM_DEVICE_TYPE_MODEM:
+		_connect_device_signal (policy, device, "enable-changed", modem_enabled_changed);
+		break;
+	default:
+		break;
 	}
 }
 
@@ -1200,14 +1251,80 @@ connections_loaded (NMSettings *settings, gpointer user_data)
 }
 
 static void
+add_or_change_zone_cb (GError *error, gpointer user_data)
+{
+	NMDevice *device = NM_DEVICE (user_data);
+
+	if (error) {
+		/* FIXME: what do we do here? */
+	}
+
+	g_object_unref (device);
+}
+
+static void
+firewall_update_zone (NMPolicy *policy, NMConnection *connection)
+{
+	NMSettingConnection *s_con = nm_connection_get_setting_connection (connection);
+	GSList *iter, *devices;
+
+	devices = nm_manager_get_devices (policy->manager);
+	/* find dev with passed connection and change zone its interface belongs to */
+	for (iter = devices; iter; iter = g_slist_next (iter)) {
+		NMDevice *dev = NM_DEVICE (iter->data);
+
+		if (   (get_device_connection (dev) == connection)
+		    && (nm_device_get_state (dev) == NM_DEVICE_STATE_ACTIVATED)) {
+			nm_firewall_manager_add_or_change_zone (policy->fw_manager,
+			                                        nm_device_get_ip_iface (dev),
+			                                        nm_setting_connection_get_zone (s_con),
+			                                        FALSE, /* change zone */
+			                                        add_or_change_zone_cb,
+			                                        g_object_ref (dev));
+		}
+	}
+}
+
+static void
+firewall_started (NMFirewallManager *manager,
+                  gpointer user_data)
+{
+	NMPolicy *policy = (NMPolicy *) user_data;
+	NMConnection *connection;
+	NMSettingConnection *s_con;
+	GSList *iter, *devices;
+
+	devices = nm_manager_get_devices (policy->manager);
+	/* add interface of each device to correct zone */
+	for (iter = devices; iter; iter = g_slist_next (iter)) {
+		NMDevice *dev = NM_DEVICE (iter->data);
+
+		connection = get_device_connection (dev);
+		s_con = nm_connection_get_setting_connection (connection);
+		if (nm_device_get_state (dev) == NM_DEVICE_STATE_ACTIVATED) {
+			nm_firewall_manager_add_or_change_zone (policy->fw_manager,
+			                                        nm_device_get_ip_iface (dev),
+			                                        nm_setting_connection_get_zone (s_con),
+			                                        TRUE, /* add zone */
+			                                        add_or_change_zone_cb,
+			                                        g_object_ref (dev));
+		}
+	}
+}
+
+static void
 connection_updated (NMSettings *settings,
                     NMConnection *connection,
                     gpointer user_data)
 {
+	NMPolicy *policy = (NMPolicy *) user_data;
+
+	firewall_update_zone (policy, connection);
+
 	/* Reset auto retries back to default since connection was updated */
 	set_connection_auto_retries (connection, RETRIES_DEFAULT);
 
-	schedule_activate_all ((NMPolicy *) user_data);
+	schedule_activate_all (policy);
 }
 
 static void
@@ -1325,6 +1442,11 @@ nm_policy_new (NMManager *manager,
 	                       G_CALLBACK (vpn_connection_deactivated), policy);
 	policy->vpn_deactivated_id = id;
 
+	policy->fw_manager = nm_firewall_manager_get();
+	id = g_signal_connect (policy->fw_manager, "started",
+	                       G_CALLBACK (firewall_started), policy);
+	policy->fw_started_id = id;
+
 	_connect_manager_signal (policy, "state-changed", global_state_changed);
 	_connect_manager_signal (policy, "notify::" NM_MANAGER_HOSTNAME, hostname_changed);
 	_connect_manager_signal (policy, "notify::" NM_MANAGER_SLEEPING, sleeping_changed);
@@ -1369,6 +1491,9 @@ nm_policy_destroy (NMPolicy *policy)
 	g_signal_handler_disconnect (policy->vpn_manager, policy->vpn_deactivated_id);
 	g_object_unref (policy->vpn_manager);
 
+	g_signal_handler_disconnect (policy->fw_manager, policy->fw_started_id);
+	g_object_unref (policy->fw_manager);
+
 	for (iter = policy->manager_ids; iter; iter = g_slist_next (iter))
 		g_signal_handler_disconnect (policy->manager, GPOINTER_TO_UINT (iter->data));
 	g_slist_free (policy->manager_ids);
diff --git a/src/nm-properties-changed-signal.c b/src/nm-properties-changed-signal.c
index 4a9db8af..871d1bb0 100644
--- a/src/nm-properties-changed-signal.c
+++ b/src/nm-properties-changed-signal.c
@@ -16,13 +16,16 @@
  * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
  *
  * Copyright (C) 2007 - 2008 Novell, Inc.
- * Copyright (C) 2008 Red Hat, Inc.
+ * Copyright (C) 2008 - 2012 Red Hat, Inc.
  */
 
 #include <string.h>
 #include <stdio.h>
 
 #include <dbus/dbus-glib.h>
+#ifdef DEBUG
+#include "nm-logging.h"
+#endif
 #include "nm-properties-changed-signal.h"
 #include "nm-dbus-glib-types.h"
 
diff --git a/src/nm-session-monitor.c b/src/nm-session-monitor-ck.c
index 7ee9013a..72ffc9ff 100644
--- a/src/nm-session-monitor.c
+++ b/src/nm-session-monitor-ck.c
@@ -20,13 +20,12 @@
 
 #include "config.h"
 #include <errno.h>
-#include <pwd.h>
 #include <string.h>
-#include <sys/types.h>
 #include <sys/stat.h>
 #include <gio/gio.h>
 #include "nm-logging.h"
 
+#include "nm-session-utils.h"
 #include "nm-session-monitor.h"
 
 #define CKDB_PATH "/var/run/ConsoleKit/database"
@@ -66,53 +65,6 @@ G_DEFINE_TYPE (NMSessionMonitor, nm_session_monitor, G_TYPE_OBJECT);
 
 /********************************************************************/
 
-#define NM_SESSION_MONITOR_ERROR         (nm_session_monitor_error_quark ())
-GQuark nm_session_monitor_error_quark    (void) G_GNUC_CONST;
-GType  nm_session_monitor_error_get_type (void) G_GNUC_CONST;
-
-typedef enum {
-	NM_SESSION_MONITOR_ERROR_IO_ERROR = 0,
-	NM_SESSION_MONITOR_ERROR_MALFORMED_DATABASE,
-	NM_SESSION_MONITOR_ERROR_UNKNOWN_USER,
-	NM_SESSION_MONITOR_ERROR_NO_DATABASE,
-} NMSessionMonitorError;
-
-GQuark
-nm_session_monitor_error_quark (void)
-{
-	static GQuark ret = 0;
-
-	if (G_UNLIKELY (ret == 0))
-		ret = g_quark_from_static_string ("nm-session-monitor-error");
-	return ret;
-}
-
-#define ENUM_ENTRY(NAME, DESC) { NAME, "" #NAME "", DESC }
-
-GType
-nm_session_monitor_error_get_type (void)
-{
-	static GType etype = 0;
-
-	if (etype == 0) {
-		static const GEnumValue values[] = {
-			/* Some I/O operation on the CK database failed */
-			ENUM_ENTRY (NM_SESSION_MONITOR_ERROR_IO_ERROR, "IOError"),
-			/* Error parsing the CK database */
-			ENUM_ENTRY (NM_SESSION_MONITOR_ERROR_MALFORMED_DATABASE, "MalformedDatabase"),
-			/* Username or UID could could not be found */
-			ENUM_ENTRY (NM_SESSION_MONITOR_ERROR_UNKNOWN_USER, "UnknownUser"),
-			/* No ConsoleKit database */
-			ENUM_ENTRY (NM_SESSION_MONITOR_ERROR_NO_DATABASE, "NoDatabase"),
-			{ 0, 0, 0 }
-		};
-
-		etype = g_enum_register_static ("NMSessionMonitorError", values);
-	}
-	return etype;
-}
-/********************************************************************/
-
 typedef struct {
 	char *user;
 	uid_t uid;
@@ -149,7 +101,7 @@ session_new (GKeyFile *keyfile, const char *group, GError **error)
 {
 	GError *local = NULL;
 	Session *s;
-	struct passwd *pw;
+	const char *uname = NULL;
 
 	s = g_new0 (Session, 1);
 	g_assert (s);
@@ -173,16 +125,9 @@ session_new (GKeyFile *keyfile, const char *group, GError **error)
 	if (local)
 		goto error;
 
-	pw = getpwuid (s->uid);
-	if (!pw) {
-		g_set_error (&local,
-			         NM_SESSION_MONITOR_ERROR,
-			         NM_SESSION_MONITOR_ERROR_UNKNOWN_USER,
-			         "Could not get username for UID %d",
-			         s->uid);
-		goto error;
-	}
-	s->user = g_strdup (pw->pw_name);
+	if (!nm_session_uid_to_user (s->uid, &uname, error))
+		return FALSE;
+	s->user = g_strdup (uname);
 
 	return s;
 
@@ -289,10 +234,6 @@ ensure_database (NMSessionMonitor *self, GError **error)
 {
 	gboolean ret = FALSE;
 
-#if NO_CONSOLEKIT
-	return TRUE;
-#endif
-
 	if (self->database != NULL) {
 		struct stat statbuf;
 
@@ -339,10 +280,6 @@ nm_session_monitor_init (NMSessionMonitor *self)
 	GError *error = NULL;
 	GFile *file;
 
-#if NO_CONSOLEKIT
-	return;
-#endif
-
 	/* Sessions-by-user is responsible for destroying the Session objects */
 	self->sessions_by_user = g_hash_table_new_full (g_str_hash, g_str_equal,
 	                                                NULL, (GDestroyNotify) session_free);
@@ -428,50 +365,6 @@ nm_session_monitor_get (void)
 
 /* ---------------------------------------------------------------------------------------------------- */
 
-#if NO_CONSOLEKIT
-static gboolean
-uid_to_user (uid_t uid, const char **out_user, GError **error)
-{
-	struct passwd *pw;
-
-	pw = getpwuid (uid);
-	if (!pw) {
-		g_set_error (error,
-			         NM_SESSION_MONITOR_ERROR,
-			         NM_SESSION_MONITOR_ERROR_UNKNOWN_USER,
-			         "Could not get username for UID %d",
-			         uid);
-		return FALSE;
-	}
-
-	/* Ugly, but hey, use ConsoleKit */
-	if (out_user)
-		*out_user = pw->pw_name;
-	return TRUE;
-}
-
-static gboolean
-user_to_uid (const char *user, uid_t *out_uid, GError **error)
-{
-	struct passwd *pw;
-
-	pw = getpwnam (user);
-	if (!pw) {
-		g_set_error (error,
-			         NM_SESSION_MONITOR_ERROR,
-			         NM_SESSION_MONITOR_ERROR_UNKNOWN_USER,
-			         "Could not get UID for username '%s'",
-			         user);
-		return FALSE;
-	}
-
-	/* Ugly, but hey, use ConsoleKit */
-	if (out_uid)
-		*out_uid = pw->pw_uid;
-	return TRUE;
-}
-#endif
-
 /**
  * nm_session_monitor_user_has_session:
  * @monitor: A #NMSessionMonitor.
@@ -491,12 +384,6 @@ nm_session_monitor_user_has_session (NMSessionMonitor *monitor,
 {
 	Session *s;
 
-#if NO_CONSOLEKIT
-	if (!user_to_uid (username, out_uid, error))
-		return FALSE;
-	return TRUE;
-#endif
-
 	if (!ensure_database (monitor, error))
 		return FALSE;
 
@@ -534,12 +421,6 @@ nm_session_monitor_uid_has_session (NMSessionMonitor *monitor,
 {
 	Session *s;
 
-#if NO_CONSOLEKIT
-	if (!uid_to_user (uid, out_user, error))
-		return FALSE;
-	return TRUE;
-#endif
-
 	if (!ensure_database (monitor, error))
 		return FALSE;
 
@@ -576,10 +457,6 @@ nm_session_monitor_user_active (NMSessionMonitor *monitor,
 {
 	Session *s;
 
-#if NO_CONSOLEKIT
-	return TRUE;
-#endif
-
 	if (!ensure_database (monitor, error))
 		return FALSE;
 
@@ -614,10 +491,6 @@ nm_session_monitor_uid_active (NMSessionMonitor *monitor,
 {
 	Session *s;
 
-#if NO_CONSOLEKIT
-	return TRUE;
-#endif
-
 	if (!ensure_database (monitor, error))
 		return FALSE;
 
diff --git a/src/nm-session-monitor-null.c b/src/nm-session-monitor-null.c
new file mode 100644
index 00000000..beabcf21
--- /dev/null
+++ b/src/nm-session-monitor-null.c
@@ -0,0 +1,171 @@
+/* -*- Mode: C; tab-width: 4; indent-tabs-mode: t; c-basic-offset: 4 -*- */
+/* This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * (C) Copyright 2008 - 2010 Red Hat, Inc.
+ * Author: David Zeuthen <davidz@redhat.com>
+ * Author: Dan Williams <dcbw@redhat.com>
+ */
+
+#include "config.h"
+#include <string.h>
+#include "nm-logging.h"
+
+#include "nm-session-utils.h"
+#include "nm-session-monitor.h"
+
+/* <internal>
+ * SECTION:nm-session-monitor
+ * @title: NMSessionMonitor
+ * @short_description: Monitor sessions
+ *
+ * The #NMSessionMonitor class is a utility class to track and monitor sessions.
+ */
+
+struct _NMSessionMonitor {
+	GObject parent_instance;
+};
+
+struct _NMSessionMonitorClass {
+	GObjectClass parent_class;
+
+	void (*changed) (NMSessionMonitor *monitor);
+};
+
+
+enum {
+	CHANGED,
+	LAST_SIGNAL,
+};
+static guint signals[LAST_SIGNAL] = {0};
+
+G_DEFINE_TYPE (NMSessionMonitor, nm_session_monitor, G_TYPE_OBJECT);
+
+/********************************************************************/
+
+static void
+nm_session_monitor_init (NMSessionMonitor *self)
+{
+}
+
+static void
+nm_session_monitor_class_init (NMSessionMonitorClass *klass)
+{
+	/**
+	 * NMSessionMonitor::changed:
+	 * @monitor: A #NMSessionMonitor
+	 *
+	 * Emitted when something changes.
+	 */
+	signals[CHANGED] = g_signal_new (NM_SESSION_MONITOR_CHANGED,
+	                                 NM_TYPE_SESSION_MONITOR,
+	                                 G_SIGNAL_RUN_LAST,
+	                                 0, NULL, NULL,
+	                                 g_cclosure_marshal_VOID__VOID,
+	                                 G_TYPE_NONE, 0);
+}
+
+NMSessionMonitor *
+nm_session_monitor_get (void)
+{
+	static NMSessionMonitor *singleton = NULL;
+
+	if (singleton)
+		return g_object_ref (singleton);
+
+	singleton = NM_SESSION_MONITOR (g_object_new (NM_TYPE_SESSION_MONITOR, NULL));
+	g_assert (singleton);
+	return singleton;
+}
+
+/* ---------------------------------------------------------------------------------------------------- */
+
+/**
+ * nm_session_monitor_user_has_session:
+ * @monitor: A #NMSessionMonitor.
+ * @username: A username.
+ * @error: Return location for error.
+ *
+ * Checks whether the given @username is logged into a session or not.
+ *
+ * Returns: %FALSE if @error is set otherwise %TRUE if the given @username is
+ * currently logged into a session.
+ */
+gboolean
+nm_session_monitor_user_has_session (NMSessionMonitor *monitor,
+                                     const char *username,
+                                     uid_t *out_uid,
+                                     GError **error)
+{
+	return nm_session_user_to_uid (username, out_uid, error);
+}
+
+/**
+ * nm_session_monitor_uid_has_session:
+ * @monitor: A #NMSessionMonitor.
+ * @uid: A user ID.
+ * @error: Return location for error.
+ *
+ * Checks whether the given @uid is logged into a session or not.
+ *
+ * Returns: %FALSE if @error is set otherwise %TRUE if the given @uid is
+ * currently logged into a session.
+ */
+gboolean
+nm_session_monitor_uid_has_session (NMSessionMonitor *monitor,
+                                    uid_t uid,
+                                    const char **out_user,
+                                    GError **error)
+{
+	return nm_session_uid_to_user (uid, out_user, error);
+}
+
+/**
+ * nm_session_monitor_user_active:
+ * @monitor: A #NMSessionMonitor.
+ * @username: A username.
+ * @error: Return location for error.
+ *
+ * Checks whether the given @username is logged into a active session or not.
+ *
+ * Returns: %FALSE if @error is set otherwise %TRUE if the given @username is
+ * logged into an active session.
+ */
+gboolean
+nm_session_monitor_user_active (NMSessionMonitor *monitor,
+                                const char *username,
+                                GError **error)
+{
+	return TRUE;
+}
+
+/**
+ * nm_session_monitor_uid_active:
+ * @monitor: A #NMSessionMonitor.
+ * @uid: A user ID.
+ * @error: Return location for error.
+ *
+ * Checks whether the given @uid is logged into a active session or not.
+ *
+ * Returns: %FALSE if @error is set otherwise %TRUE if the given @uid is
+ * logged into an active session.
+ */
+gboolean
+nm_session_monitor_uid_active (NMSessionMonitor *monitor,
+                               uid_t uid,
+                               GError **error)
+{
+	return TRUE;
+}
+
diff --git a/src/nm-session-monitor-systemd.c b/src/nm-session-monitor-systemd.c
new file mode 100644
index 00000000..29ba7c21
--- /dev/null
+++ b/src/nm-session-monitor-systemd.c
@@ -0,0 +1,251 @@
+/* -*- Mode: C; tab-width: 4; indent-tabs-mode: t; c-basic-offset: 4 -*- */
+/*
+ * Copyright (C) 2011 Red Hat, Inc.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General
+ * Public License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place, Suite 330,
+ * Boston, MA 02111-1307, USA.
+ *
+ * Author: Matthias Clasen
+ */
+
+#include "config.h"
+#include <errno.h>
+#include <pwd.h>
+#include <grp.h>
+#include <string.h>
+#include <glib/gstdio.h>
+#include <systemd/sd-login.h>
+#include <stdlib.h>
+
+#include "nm-session-utils.h"
+#include "nm-session-monitor.h"
+
+/********************************************************************/
+
+typedef struct {
+	GSource source;
+	GPollFD pollfd;
+	sd_login_monitor *monitor;
+} SdSource;
+
+static gboolean
+sd_source_prepare (GSource *source, gint *timeout)
+{
+	*timeout = -1;
+	return FALSE;
+}
+
+static gboolean
+sd_source_check (GSource *source)
+{
+	SdSource *sd_source = (SdSource *) source;
+
+	return sd_source->pollfd.revents != 0;
+}
+
+static gboolean
+sd_source_dispatch (GSource     *source,
+                    GSourceFunc  callback,
+                    gpointer     user_data)
+
+{
+	SdSource *sd_source = (SdSource *)source;
+	gboolean ret;
+
+	g_warn_if_fail (callback != NULL);
+	ret = (*callback) (user_data);
+	sd_login_monitor_flush (sd_source->monitor);
+	return ret;
+}
+
+static void
+sd_source_finalize (GSource *source)
+{
+	SdSource *sd_source = (SdSource*) source;
+
+	sd_login_monitor_unref (sd_source->monitor);
+}
+
+static GSourceFuncs sd_source_funcs = {
+	sd_source_prepare,
+	sd_source_check,
+	sd_source_dispatch,
+	sd_source_finalize
+};
+
+static GSource *
+sd_source_new (void)
+{
+	GSource *source;
+	SdSource *sd_source;
+	int ret;
+
+	source = g_source_new (&sd_source_funcs, sizeof (SdSource));
+	sd_source = (SdSource *)source;
+
+	ret = sd_login_monitor_new (NULL, &sd_source->monitor);
+	if (ret < 0)
+		g_printerr ("Error getting login monitor: %d", ret);
+	else {
+		sd_source->pollfd.fd = sd_login_monitor_get_fd (sd_source->monitor);
+		sd_source->pollfd.events = G_IO_IN;
+		g_source_add_poll (source, &sd_source->pollfd);
+	}
+
+	return source;
+}
+
+struct _NMSessionMonitor {
+	GObject parent_instance;
+
+	GSource *sd_source;
+};
+
+struct _NMSessionMonitorClass {
+	GObjectClass parent_class;
+
+	void (*changed) (NMSessionMonitor *monitor);
+};
+
+
+enum {
+	CHANGED_SIGNAL,
+	LAST_SIGNAL,
+};
+static guint signals[LAST_SIGNAL] = {0};
+
+G_DEFINE_TYPE (NMSessionMonitor, nm_session_monitor, G_TYPE_OBJECT);
+
+/* ---------------------------------------------------------------------------------------------------- */
+
+static gboolean
+sessions_changed (gpointer user_data)
+{
+	NMSessionMonitor *monitor = NM_SESSION_MONITOR (user_data);
+
+	g_signal_emit (monitor, signals[CHANGED_SIGNAL], 0);
+	return TRUE;
+}
+
+
+static void
+nm_session_monitor_init (NMSessionMonitor *monitor)
+{
+	monitor->sd_source = sd_source_new ();
+	g_source_set_callback (monitor->sd_source, sessions_changed, monitor, NULL);
+	g_source_attach (monitor->sd_source, NULL);
+}
+
+static void
+nm_session_monitor_finalize (GObject *object)
+{
+	NMSessionMonitor *monitor = NM_SESSION_MONITOR (object);
+
+	if (monitor->sd_source != NULL) {
+		g_source_destroy (monitor->sd_source);
+		g_source_unref (monitor->sd_source);
+	}
+
+	if (G_OBJECT_CLASS (nm_session_monitor_parent_class)->finalize != NULL)
+		G_OBJECT_CLASS (nm_session_monitor_parent_class)->finalize (object);
+}
+
+static void
+nm_session_monitor_class_init (NMSessionMonitorClass *klass)
+{
+	GObjectClass *gobject_class;
+
+	gobject_class = G_OBJECT_CLASS (klass);
+	gobject_class->finalize = nm_session_monitor_finalize;
+
+	/**
+	 * NMSessionMonitor::changed:
+	 * @monitor: A #NMSessionMonitor
+	 *
+	 * Emitted when something changes.
+	 */
+	signals[CHANGED_SIGNAL] = g_signal_new ("changed",
+	                                        NM_TYPE_SESSION_MONITOR,
+	                                        G_SIGNAL_RUN_LAST,
+	                                        G_STRUCT_OFFSET (NMSessionMonitorClass, changed),
+	                                        NULL,                   /* accumulator      */
+	                                        NULL,                   /* accumulator data */
+	                                        g_cclosure_marshal_VOID__VOID,
+	                                        G_TYPE_NONE,
+	                                        0);
+}
+
+NMSessionMonitor *
+nm_session_monitor_get (void)
+{
+	static NMSessionMonitor *singleton = NULL;
+
+	if (singleton)
+		return g_object_ref (singleton);
+
+	singleton = NM_SESSION_MONITOR (g_object_new (NM_TYPE_SESSION_MONITOR, NULL));
+	g_assert (singleton);
+	return singleton;
+}
+
+gboolean
+nm_session_monitor_user_has_session (NMSessionMonitor *monitor,
+                                     const char *username,
+                                     uid_t *out_uid,
+                                     GError **error)
+{
+	uid_t uid;
+
+	if (!nm_session_user_to_uid (username, &uid, error))
+		return FALSE;
+
+	if (out_uid)
+		*out_uid = uid;
+
+	return nm_session_monitor_uid_has_session (monitor, uid, NULL, error);
+}
+
+gboolean
+nm_session_monitor_user_active (NMSessionMonitor *monitor,
+                                const char *username,
+                                GError **error)
+{
+	uid_t uid;
+
+	if (!nm_session_user_to_uid (username, &uid, error))
+		return FALSE;
+
+	return nm_session_monitor_uid_active (monitor, uid, error);
+}
+
+gboolean
+nm_session_monitor_uid_has_session (NMSessionMonitor *monitor,
+                                    uid_t uid,
+                                    const char **out_user,
+                                    GError **error)
+{
+	if (!nm_session_uid_to_user (uid, out_user, error))
+		return FALSE;
+
+	return sd_uid_get_sessions (uid, FALSE, NULL) > 0;
+}
+
+gboolean
+nm_session_monitor_uid_active (NMSessionMonitor *monitor,
+                               uid_t uid,
+                               GError **error)
+{
+	return sd_uid_get_sessions (uid, TRUE, NULL) > 0;
+}
diff --git a/src/nm-session-utils.c b/src/nm-session-utils.c
new file mode 100644
index 00000000..269e2f81
--- /dev/null
+++ b/src/nm-session-utils.c
@@ -0,0 +1,79 @@
+/* -*- Mode: C; tab-width: 4; indent-tabs-mode: t; c-basic-offset: 4 -*- */
+/* This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Copyright (C) 2012 Red Hat, Inc.
+ * Author: Dan Williams <dcbw@redhat.com>
+ */
+
+#include <pwd.h>
+#include <sys/types.h>
+
+#include "nm-session-utils.h"
+
+/********************************************************************/
+
+GQuark
+nm_session_monitor_error_quark (void)
+{
+	static GQuark ret = 0;
+
+	if (G_UNLIKELY (ret == 0))
+		ret = g_quark_from_static_string ("nm-session-monitor-error");
+	return ret;
+}
+
+/********************************************************************/
+
+gboolean
+nm_session_uid_to_user (uid_t uid, const char **out_user, GError **error)
+{
+	struct passwd *pw;
+
+	pw = getpwuid (uid);
+	if (!pw) {
+		g_set_error (error,
+			         NM_SESSION_MONITOR_ERROR,
+			         NM_SESSION_MONITOR_ERROR_UNKNOWN_USER,
+			         "Could not get username for UID %d",
+			         uid);
+		return FALSE;
+	}
+
+	if (out_user)
+		*out_user = pw->pw_name;
+	return TRUE;
+}
+
+gboolean
+nm_session_user_to_uid (const char *user, uid_t *out_uid, GError **error)
+{
+	struct passwd *pw;
+
+	pw = getpwnam (user);
+	if (!pw) {
+		g_set_error (error,
+			         NM_SESSION_MONITOR_ERROR,
+			         NM_SESSION_MONITOR_ERROR_UNKNOWN_USER,
+			         "Could not get UID for username '%s'",
+			         user);
+		return FALSE;
+	}
+
+	/* Ugly, but hey, use ConsoleKit */
+	if (out_uid)
+		*out_uid = pw->pw_uid;
+	return TRUE;
+}
+
diff --git a/src/nm-session-utils.h b/src/nm-session-utils.h
new file mode 100644
index 00000000..54b6d4c4
--- /dev/null
+++ b/src/nm-session-utils.h
@@ -0,0 +1,41 @@
+/* -*- Mode: C; tab-width: 4; indent-tabs-mode: t; c-basic-offset: 4 -*- */
+/* This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Copyright (C) 2012 Red Hat, Inc.
+ * Author: Dan Williams <dcbw@redhat.com>
+ */
+
+#ifndef NM_SESSION_UTILS_H
+#define NM_SESSION_UTILS_H
+
+#include <glib.h>
+#include <glib-object.h>
+
+#define NM_SESSION_MONITOR_ERROR         (nm_session_monitor_error_quark ())
+GQuark nm_session_monitor_error_quark    (void) G_GNUC_CONST;
+GType  nm_session_monitor_error_get_type (void) G_GNUC_CONST;
+
+typedef enum {
+	NM_SESSION_MONITOR_ERROR_IO_ERROR = 0,       /*< nick=IOError >*/
+	NM_SESSION_MONITOR_ERROR_MALFORMED_DATABASE, /*< nick=MalformedDatabase >*/
+	NM_SESSION_MONITOR_ERROR_UNKNOWN_USER,       /*< nick=UnknownUser >*/
+	NM_SESSION_MONITOR_ERROR_NO_DATABASE,        /*< nick=NoDatabase >*/
+} NMSessionMonitorError;
+
+gboolean nm_session_uid_to_user (uid_t uid, const char **out_user, GError **error);
+
+gboolean nm_session_user_to_uid (const char *user, uid_t *out_uid, GError **error);
+
+#endif  /* NM_SESSION_UTILS_H */
diff --git a/src/nm-system.c b/src/nm-system.c
index 62ab8b93..91153ec2 100644
--- a/src/nm-system.c
+++ b/src/nm-system.c
@@ -21,6 +21,7 @@
  * Copyright (C) January, 1998 Sergei Viznyuk <sv@phystech.com>
  */
 
+#include <config.h>
 #include <sys/types.h>
 #include <sys/socket.h>
 #include <sys/ioctl.h>
@@ -41,6 +42,8 @@
 #include <glib.h>
 #include <ctype.h>
 #include <linux/if.h>
+#include <linux/sockios.h>
+#include <linux/if_bonding.h>
 
 #include "nm-system.h"
 #include "nm-device.h"
@@ -57,6 +60,16 @@
 #include <netlink/utils.h>
 #include <netlink/route/link.h>
 
+#ifdef HAVE_LIBNL3
+#include <netlink/route/link/bonding.h>
+#include <netlink/route/link/vlan.h>
+#endif
+
+#if !HAVE_VLAN_FLAG_LOOSE_BINDING
+/* Older kernels don't have this flag */
+#define VLAN_FLAG_LOOSE_BINDING 0x04
+#endif
+
 static void nm_system_device_set_priority (int ifindex,
                                            NMIP4Config *config,
                                            int priority);
@@ -108,7 +121,7 @@ nm_system_device_set_ip4_route (int ifindex,
 	g_return_val_if_fail (route != NULL, NULL);
 
 	/* Add the route */
-	err = nm_netlink_route_add(route, AF_INET, &ip4_dest, ip4_prefix, &ip4_gateway, 0);
+	err = nm_netlink_route4_add (route, &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;
@@ -116,9 +129,9 @@ nm_system_device_set_ip4_route (int ifindex,
 		route2 = nm_netlink_route_new (ifindex, AF_INET, mss, NULL);
 		if (route2) {
 			/* Add route to gateway over bridge */
-			err = nm_netlink_route_add(route2, AF_INET, &ip4_gateway, 32, NULL, 0);
+			err = nm_netlink_route4_add (route2, &ip4_gateway, 32, NULL, 0);
 			if (!err) {
-				err = nm_netlink_route_add(route, AF_INET, &ip4_dest, ip4_prefix, &ip4_gateway, 0);
+				err = nm_netlink_route4_add (route, &ip4_dest, ip4_prefix, &ip4_gateway, 0);
 				if (err)
 					nm_netlink_route_delete (route2);
 			}
@@ -233,7 +246,7 @@ sync_addresses (int ifindex,
 
 		if (buf_valid) {
 			nm_log_dbg (log_domain, "(%s): removing address '%s/%d'",
-			            iface, buf, nl_addr_get_prefixlen (nladdr));
+			            iface, buf, rtnl_addr_get_prefixlen (match_addr));
 		}
 
 		/* Otherwise, match_addr should be removed from the interface. */
@@ -479,18 +492,18 @@ nm_system_set_ip6_route (int ifindex,
 	g_return_val_if_fail (route != NULL, -1);
 
 	/* Add the route */
-	err = nm_netlink_route_add(route, AF_INET6, &ip6_dest, ip6_prefix, &ip6_gateway, 0);
+	err = nm_netlink_route6_add (route, 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 = nm_netlink_route_new (ifindex, AF_INET6, mss, NULL);
 		if (route2) {
-			err = nm_netlink_route_add(route, AF_INET6, &ip6_gateway, 128, NULL, 0);
+			err = nm_netlink_route6_add (route, ip6_gateway, 128, NULL, 0);
 			/* Add route to gateway over bridge */
 			if (!err) {
 				/* Try adding the route again */
-				err = nm_netlink_route_add(route, AF_INET6, &ip6_dest, ip6_prefix, &ip6_gateway, 0);
+				err = nm_netlink_route6_add (route, ip6_dest, ip6_prefix, ip6_gateway, 0);
 				if (err)
 					nm_netlink_route_delete (route2);
 			}
@@ -588,7 +601,7 @@ nm_system_apply_ip6_config (int ifindex,
 			                               RTPROT_UNSPEC,
 			                               RT_TABLE_UNSPEC,
 			                               NULL);
-			if (err) {
+			if (err && (err != -NLE_EXIST)) {
 				nm_log_err (LOGD_DEVICE | LOGD_IP6,
 				            "(%s): failed to set IPv6 route: %s",
 				            iface ? iface : "unknown",
@@ -657,15 +670,8 @@ nm_system_iface_set_up (int ifindex,
 	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_iface_is_up (int ifindex)
+guint32
+nm_system_iface_get_flags (int ifindex)
 {
 	struct rtnl_link *l;
 	guint32 flags;
@@ -686,7 +692,20 @@ nm_system_iface_is_up (int ifindex)
 	flags = rtnl_link_get_flags (l);
 	rtnl_link_put (l);
 
-	return flags & IFF_UP;
+	return flags;
+}
+
+/**
+ * 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_iface_is_up (int ifindex)
+{
+	return nm_system_iface_get_flags (ifindex) & IFF_UP;
 }
 
 /**
@@ -812,7 +831,7 @@ add_ip4_route_to_gateway (int ifindex, guint32 gw, guint32 mss)
 	g_return_val_if_fail (route != NULL, NULL);
 
 	/* Add direct route to the gateway */
-	err = nm_netlink_route_add(route, AF_INET, &gw, 32, NULL, 0);
+	err = nm_netlink_route4_add (route, &gw, 32, NULL, 0);
 	if (err) {
 		char *iface = nm_netlink_index_to_iface (ifindex);
 
@@ -836,7 +855,7 @@ replace_default_ip4_route (int ifindex, guint32 gw, guint32 mss)
 	struct rtnl_route *route = NULL;
 	struct nl_sock *nlh;
 	int err = -1;
-	int dst=0;
+	guint32 dst = 0;
 
 	g_return_val_if_fail (ifindex > 0, -ENODEV);
 
@@ -850,7 +869,9 @@ replace_default_ip4_route (int ifindex, guint32 gw, guint32 mss)
 	g_return_val_if_fail (route != NULL, -ENOMEM);
 
 	/* Add the new default route */
-	err = nm_netlink_route_add (route, AF_INET, &dst, 0, &gw, NLM_F_REPLACE);
+	err = nm_netlink_route4_add (route, &dst, 0, &gw, NLM_F_REPLACE);
+	if (err == -NLE_EXIST)
+		err = 0;
 
 	rtnl_route_put (route);
 	return err;
@@ -985,7 +1006,7 @@ add_ip6_route_to_gateway (int ifindex, const struct in6_addr *gw)
 	g_return_val_if_fail (route != NULL, NULL);
 
 	/* Add direct route to the gateway */
-	err = nm_netlink_route_add(route, AF_INET, gw, 128, NULL, 0);
+	err = nm_netlink_route6_add (route, gw, 128, NULL, 0);
 	if (err) {
 		char *iface = nm_netlink_index_to_iface (ifindex);
 
@@ -1020,11 +1041,10 @@ replace_default_ip6_route (int ifindex, const struct in6_addr *gw)
 	g_return_val_if_fail (route != NULL, -ENOMEM);
 
 	/* Add the new default route */
-	nm_netlink_route_add(route, AF_INET6, NULL, 0, gw, NLM_F_REPLACE);
+	err = nm_netlink_route6_add (route, &in6addr_any, 0, gw, NLM_F_REPLACE);
 	if (err == -NLE_EXIST) {
 		/* FIXME: even though we use NLM_F_REPLACE the kernel won't replace
-		 * the route if it's the same.  Should try to remove it first, then
-		 * add the new one again here.
+		 * the route if it's the same.  Suppress the pointless error.
 		 */
 		err = 0;
 	}
@@ -1051,6 +1071,9 @@ nm_system_replace_default_ip6_route (int ifindex, const struct in6_addr *gw)
 	if (err == 0)
 		return TRUE;
 
+	if (err == -NLE_EXIST)
+		return TRUE;
+
 	iface = nm_netlink_index_to_iface (ifindex);
 	if (!iface)
 		goto out;
@@ -1202,3 +1225,762 @@ nm_system_device_set_priority (int ifindex,
 		rtnl_route_put (found);
 	}
 }
+
+static const struct {
+	const char *option;
+	const char *default_value;
+} bonding_defaults[] = {
+	{ "mode", "balance-rr" },
+	{ "arp_interval", "0" },
+	{ "miimon", "0" },
+
+	{ "ad_select", "stable" },
+	{ "arp_validate", "none" },
+	{ "downdelay", "0" },
+	{ "fail_over_mac", "none" },
+	{ "lacp_rate", "slow" },
+	{ "min_links", "0" },
+	{ "num_grat_arp", "1" },
+	{ "num_unsol_na", "1" },
+	{ "primary", "" },
+	{ "primary_reselect", "always" },
+	{ "resend_igmp", "1" },
+	{ "updelay", "0" },
+	{ "use_carrier", "1" },
+	{ "xmit_hash_policy", "layer2" },
+	{ NULL, NULL }
+};
+
+static void
+remove_bonding_entries (const char *iface, const char *path)
+{
+	char cmd[20];
+	char *value, **entries;
+	gboolean ret;
+	int i;
+
+	if (!g_file_get_contents (path, &value, NULL, NULL))
+		return;
+
+	entries = g_strsplit (value, " ", -1);
+	for (i = 0; entries[i]; i++) {
+		snprintf (cmd, sizeof (cmd), "-%s", g_strstrip (entries[i]));
+		ret = nm_utils_do_sysctl (path, cmd);
+		if (!ret) {
+			nm_log_warn (LOGD_HW, "(%s): failed to remove entry '%s' from '%s'",
+			             iface, entries[i], path);
+		}
+	}
+	g_strfreev (entries);
+}
+
+static gboolean
+option_valid_for_nm_setting (const char *option, const char **valid_opts)
+{
+	while (*valid_opts) {
+		if (strcmp (option, *valid_opts) == 0)
+			return TRUE;
+		valid_opts++;
+	}
+	return FALSE;
+}
+
+gboolean
+nm_system_apply_bonding_config (const char *iface, NMSettingBond *s_bond)
+{
+	const char **valid_opts;
+	const char *option, *value;
+	char path[FILENAME_MAX];
+	char *current, *space;
+	gboolean ret;
+	int i;
+
+	g_return_val_if_fail (iface != NULL, FALSE);
+
+	/* Remove old slaves and arp_ip_targets */
+	snprintf (path, sizeof (path), "/sys/class/net/%s/bonding/arp_ip_target", iface);
+	remove_bonding_entries (iface, path);
+	snprintf (path, sizeof (path), "/sys/class/net/%s/bonding/slaves", iface);
+	remove_bonding_entries (iface, path);
+
+	/* Apply config/defaults */
+	valid_opts = nm_setting_bond_get_valid_options (s_bond);
+	for (i = 0; bonding_defaults[i].option; i++) {
+		option = bonding_defaults[i].option;
+		if (option_valid_for_nm_setting (option, valid_opts))
+			value = nm_setting_bond_get_option_by_name (s_bond, option);
+		else
+			value = NULL;
+		if (!value)
+			value = bonding_defaults[i].default_value;
+
+		snprintf (path, sizeof (path), "/sys/class/net/%s/bonding/%s", iface, option);
+		if (g_file_get_contents (path, &current, NULL, NULL)) {
+			g_strstrip (current);
+			space = strchr (current, ' ');
+			if (space)
+				*space = '\0';
+			if (strcmp (current, value) != 0) {
+				ret = nm_utils_do_sysctl (path, value);
+				if (!ret) {
+					nm_log_warn (LOGD_HW, "(%s): failed to set bonding attribute "
+					             "'%s' to '%s'", iface, option, value);
+				}
+			}
+		}
+	}
+
+	/* Handle arp_ip_target */
+	value = nm_setting_bond_get_option_by_name (s_bond, "arp_ip_target");
+	if (value) {
+		char **addresses, cmd[20];
+
+		snprintf (path, sizeof (path), "/sys/class/net/%s/bonding/arp_ip_target", iface);
+		addresses = g_strsplit (value, ",", -1);
+		for (i = 0; addresses[i]; i++) {
+			snprintf (cmd, sizeof (cmd), "+%s", g_strstrip (addresses[i]));
+			ret = nm_utils_do_sysctl (path, cmd);
+			if (!ret) {
+				nm_log_warn (LOGD_HW, "(%s): failed to add arp_ip_target '%s'",
+				             iface, addresses[i]);
+			}
+		}
+		g_strfreev (addresses);
+	}
+
+	return TRUE;
+}
+
+/**
+ * nm_system_add_bonding_master:
+ * @iface: the interface name for the new bond master
+ *
+ * Adds a virtual bonding device if it does not exist yet.
+ *
+ * Returns: %TRUE on success, %FALSE on failure
+ */
+gboolean
+nm_system_add_bonding_master (const char *iface)
+{
+	struct nl_sock *sock;
+	int err;
+
+	g_return_val_if_fail (iface != NULL, FALSE);
+
+	sock = nm_netlink_get_default_handle ();
+
+	/* Existing bonding devices with matching name will be reused */
+	err = rtnl_link_bond_add (sock, iface, NULL);
+	if (err < 0) {
+		nm_log_err (LOGD_DEVICE, "(%s): error %d returned from "
+		            "rtnl_link_bond_add(): %s",
+		            iface, err, nl_geterror (err));
+		return FALSE;
+	}
+	return TRUE;
+}
+
+static gboolean
+nm_system_iface_compat_enslave (const char *master_iface, const char *slave_iface)
+{
+	struct ifreq ifr;
+	int fd;
+	gboolean ret = FALSE;
+
+	memset (&ifr, 0, sizeof (ifr));
+
+	fd = socket (PF_INET, SOCK_DGRAM, 0);
+	if (fd < 0) {
+		nm_log_err (LOGD_DEVICE, "couldn't open control socket.");
+		return FALSE;
+	}
+
+	strncpy (ifr.ifr_name, master_iface, IFNAMSIZ);
+	strncpy (ifr.ifr_slave, slave_iface, IFNAMSIZ);
+
+	if (ioctl (fd, SIOCBONDENSLAVE, &ifr) < 0 &&
+	    ioctl (fd, BOND_ENSLAVE_OLD, &ifr) < 0) {
+		nm_log_err (LOGD_DEVICE, "(%s): error enslaving %s: %d (%s)",
+		            master_iface, slave_iface, errno, strerror (errno));
+	} else
+		ret = TRUE;
+
+	close (fd);
+
+	return ret;
+}
+
+/**
+ * nm_system_iface_enslave:
+ * @master_ifindex: master device interface index
+ * @master_iface: master device interface name
+ * @slave_ifindex: slave device interface index
+ * @slave_iface: slave device interface name
+ *
+ * Enslaves the 'slave' to 'master. This function targets implementing a
+ * generic interface to attaching all kinds of slaves to masters. Currently
+ * only bonding is properly supported due to the backwards compatibility
+ * function being bonding specific.
+ *
+ * The slave device needs to be down as a prerequisite.
+ *
+ * Returns: %TRUE on success, or %FALSE
+ */
+gboolean
+nm_system_iface_enslave (gint master_ifindex,
+                         const char *master_iface,
+                         gint slave_ifindex,
+                         const char *slave_iface)
+{
+	struct nl_sock *sock;
+	int err;
+
+	g_return_val_if_fail (master_ifindex >= 0, FALSE);
+	g_return_val_if_fail (master_iface != NULL, FALSE);
+	g_return_val_if_fail (slave_ifindex >= 0, FALSE);
+	g_return_val_if_fail (slave_iface != NULL, FALSE);
+
+	sock = nm_netlink_get_default_handle ();
+
+	if (!(nm_system_iface_get_flags (master_ifindex) & IFF_MASTER)) {
+		nm_log_err (LOGD_DEVICE, "(%s): interface is not a master", master_iface);
+		return FALSE;
+	}
+
+	g_assert (!nm_system_iface_is_up (slave_ifindex));
+
+	if (nm_system_iface_get_flags (slave_ifindex) & IFF_SLAVE) {
+		nm_log_err (LOGD_DEVICE, "(%s): %s is already a slave",
+		            master_iface, slave_iface);
+		return FALSE;
+	}
+
+	err = rtnl_link_bond_enslave_ifindex (sock, master_ifindex, slave_ifindex);
+	if (err == -NLE_OPNOTSUPP)
+		return nm_system_iface_compat_enslave (master_iface, slave_iface);
+
+	if (err < 0) {
+		nm_log_err (LOGD_DEVICE, "(%s): error enslaving %s: %d (%s)",
+		            master_iface, slave_iface, err, nl_geterror (err));
+		return FALSE;
+	}
+
+	return TRUE;
+}
+
+static gboolean
+nm_system_iface_compat_release (const char *master_iface, const char *slave_iface)
+{
+	struct ifreq ifr;
+	int fd;
+	gboolean ret = FALSE;
+
+	memset (&ifr, 0, sizeof (ifr));
+
+	fd = socket (PF_INET, SOCK_DGRAM, 0);
+	if (fd < 0) {
+		nm_log_err (LOGD_DEVICE, "couldn't open control socket.");
+		return FALSE;
+	}
+
+	strncpy (ifr.ifr_name, master_iface, IFNAMSIZ);
+	strncpy (ifr.ifr_slave, slave_iface, IFNAMSIZ);
+
+	if (ioctl (fd, SIOCBONDRELEASE, &ifr) < 0 &&
+	    ioctl (fd, BOND_RELEASE_OLD, &ifr) < 0) {
+		nm_log_err (LOGD_DEVICE, "(%s): error releasing slave %s: %d (%s)",
+		            master_iface, slave_iface, errno, strerror (errno));
+	} else
+		ret = TRUE;
+
+	close (fd);
+	return ret;
+}
+
+/**
+ * nm_system_iface_release:
+ * @master_ifindex: master device interface index
+ * @master_iface: master device interface name
+ * @slave_ifindex: slave device interface index
+ * @slave_iface: slave device interface name
+ *
+ * Releases the 'slave' which is attached to 'master. This function targets
+ * implementing a generic interface to releasing all kinds of slaves. Currently
+ * only bonding is properly supported due to the backwards compatibility
+ * function being bonding specific.
+ *
+ * Returns: %TRUE on success, or %FALSE
+ */
+gboolean
+nm_system_iface_release (gint master_ifindex,
+                         const char *master_iface,
+                         gint slave_ifindex,
+                         const char *slave_iface)
+{
+	struct nl_sock *sock;
+	int err;
+
+	g_return_val_if_fail (master_ifindex >= 0, FALSE);
+	g_return_val_if_fail (master_iface != NULL, FALSE);
+	g_return_val_if_fail (slave_ifindex >= 0, FALSE);
+	g_return_val_if_fail (slave_iface != NULL, FALSE);
+
+	sock = nm_netlink_get_default_handle ();
+
+	/* Only release if this is actually a slave */
+	if (!(nm_system_iface_get_flags (slave_ifindex) & IFF_SLAVE))
+		return TRUE;
+
+	err = rtnl_link_bond_release_ifindex (sock, slave_ifindex);
+	if (err == -NLE_OPNOTSUPP)
+		return nm_system_iface_compat_release (master_iface, slave_iface);
+	else if (err < 0) {
+		nm_log_err (LOGD_DEVICE, "(%s): error releasing slave %s: %d (%s)",
+		            master_iface, slave_iface, err, nl_geterror (err));
+		return FALSE;
+	}
+
+	return TRUE;
+}
+
+/**
+ * nm_system_get_iface_type:
+ * @ifindex: interface index
+ * @name: name of interface
+ *
+ * Lookup the type of an interface.  At least one of @ifindex or @name must
+ * be provided.
+ *
+ * Returns: Interface type (NM_IFACE_TYPE_*) or NM_IFACE_TYPE_UNSPEC.
+ **/
+int
+nm_system_get_iface_type (int ifindex, const char *name)
+{
+	struct rtnl_link *result;
+	struct nl_sock *nlh;
+	char *type;
+	int res = NM_IFACE_TYPE_UNSPEC;
+
+	g_return_val_if_fail (ifindex >= 0 || name, NM_IFACE_TYPE_UNSPEC);
+
+	nlh = nm_netlink_get_default_handle ();
+	if (!nlh)
+		goto out;
+
+	/* Prefer interface indexes to names */
+	if (rtnl_link_get_kernel (nlh, ifindex, ifindex < 0 ? name : NULL, &result) < 0)
+		goto out;
+
+	type = rtnl_link_get_type (result);
+
+	if (!g_strcmp0 (type, "bond"))
+		res = NM_IFACE_TYPE_BOND;
+	else if (!g_strcmp0 (type, "vlan"))
+		res = NM_IFACE_TYPE_VLAN;
+	else if (!g_strcmp0 (type, "dummy"))
+		res = NM_IFACE_TYPE_DUMMY;
+
+	rtnl_link_put (result);
+out:
+	return res;
+}
+
+/**
+ * nm_system_get_iface_vlan_info:
+ * @ifindex: the VLAN interface index
+ * @out_parent_ifindex: on success, the interface index of the parent interface of
+ *   @iface
+ * @out_vlan_id: on success, the VLAN ID of @iface
+ *
+ * Gets the VLAN parent interface name and VLAN ID.
+ *
+ * Returns: %TRUE if the interface is a VLAN device and no error occurred;
+ *   %FALSE if the interface was not a VLAN interface or an error occurred
+ **/
+gboolean
+nm_system_get_iface_vlan_info (int ifindex,
+                               int *out_parent_ifindex,
+                               int *out_vlan_id)
+{
+	struct nl_sock *nlh;
+	struct rtnl_link *lk;
+	struct nl_cache *cache = NULL;
+	gboolean success = FALSE;
+	int ret;
+
+	if (nm_system_get_iface_type (ifindex, NULL) != NM_IFACE_TYPE_VLAN)
+		return FALSE;
+
+	nlh = nm_netlink_get_default_handle ();
+	if (!nlh)
+		return FALSE;
+
+	ret = rtnl_link_alloc_cache (nlh, &cache);
+	g_return_val_if_fail (ret == 0, FALSE);
+	g_return_val_if_fail (cache != NULL, FALSE);
+
+	lk = rtnl_link_get (cache, ifindex);
+	if (lk) {
+		if (out_parent_ifindex)
+			*out_parent_ifindex = rtnl_link_get_link (lk);
+		if (out_vlan_id)
+			*out_vlan_id = rtnl_link_vlan_get_id (lk);
+
+		rtnl_link_put (lk);
+		success = TRUE;
+	}
+
+	nl_cache_free (cache);
+	return success;
+}
+
+static gboolean
+nm_system_iface_compat_set_name (const char *old_name, const char *new_name)
+{
+	int fd;
+	struct ifreq ifr;
+
+	if ((fd = socket (AF_INET, SOCK_STREAM, 0)) < 0) {
+		nm_log_err (LOGD_DEVICE, "couldn't open control socket.");
+		return -1;
+	}
+
+	memset (&ifr, 0, sizeof (struct ifreq));
+	strncpy (ifr.ifr_name, old_name, sizeof (ifr.ifr_name));
+	strncpy (ifr.ifr_newname, new_name, sizeof (ifr.ifr_newname));
+
+	if (ioctl (fd, SIOCSIFNAME, &ifr) < 0) {
+		nm_log_err (LOGD_DEVICE, "cann't change %s with %s.", old_name, new_name);
+		close (fd);
+		return FALSE;
+	}
+
+	close (fd);
+	return TRUE;
+}
+
+static gboolean
+nm_system_iface_compat_set_vlan_name_type (int name_type)
+{
+	int fd;
+	struct vlan_ioctl_args if_request;
+
+	if ((fd = socket (AF_INET, SOCK_STREAM, 0)) < 0) {
+		nm_log_err (LOGD_DEVICE, "couldn't open control socket.");
+		return -1;
+	}
+
+	memset (&if_request, 0, sizeof (struct vlan_ioctl_args));
+	if_request.cmd = SET_VLAN_NAME_TYPE_CMD;
+	if_request.u.name_type = name_type;
+
+	if (ioctl (fd, SIOCSIFVLAN, &if_request) < 0) {
+		nm_log_err (LOGD_DEVICE, "couldn't set name type.");
+		close (fd);
+		return FALSE;
+	}
+
+	close (fd);
+	return TRUE;
+}
+
+static gboolean
+nm_system_iface_compat_add_vlan_device (const char *master, int vid)
+{
+	int fd;
+	struct vlan_ioctl_args if_request;
+
+	g_return_val_if_fail (master, FALSE);
+	g_return_val_if_fail (vid < 4096, FALSE);
+
+	/*
+	 * use VLAN_NAME_TYPE_RAW_PLUS_VID_NO_PAD as default,
+	 * we will overwrite it with rtnl_link_set_name() later.
+	 */
+	if (!nm_system_iface_compat_set_vlan_name_type (VLAN_NAME_TYPE_RAW_PLUS_VID_NO_PAD))
+		return FALSE;
+
+	if ((fd = socket (AF_INET, SOCK_STREAM, 0)) < 0) {
+		nm_log_err (LOGD_DEVICE, "couldn't open control socket.");
+		return -1;
+	}
+
+	memset (&if_request, 0, sizeof (struct vlan_ioctl_args));
+	strcpy (if_request.device1, master);
+	if_request.cmd = ADD_VLAN_CMD;
+	if_request.u.VID = vid;
+
+	if (ioctl (fd, SIOCSIFVLAN, &if_request) < 0) {
+		nm_log_err (LOGD_DEVICE, "couldn't add vlan device %s vid %d.", master, vid);
+		close (fd);
+		return FALSE;
+	}
+
+	close (fd);
+	return TRUE;
+}
+
+static gboolean
+nm_system_iface_compat_rem_vlan_device (const char *iface)
+{
+	int fd;
+	struct vlan_ioctl_args if_request;
+
+	if ((fd = socket (AF_INET, SOCK_STREAM, 0)) < 0) {
+		nm_log_err (LOGD_DEVICE, "couldn't open control socket.");
+		return -1;
+	}
+
+	memset (&if_request, 0, sizeof (struct vlan_ioctl_args));
+        strcpy (if_request.device1, iface);
+	if_request.cmd = DEL_VLAN_CMD;
+
+	if (ioctl (fd, SIOCSIFVLAN, &if_request) < 0) {
+		nm_log_err (LOGD_DEVICE, "couldn't rem vlan device %s.", iface);
+		close (fd);
+		return FALSE;
+	}
+
+	close (fd);
+	return TRUE;
+}
+
+static gboolean
+nm_system_iface_compat_add_vlan (NMConnection *connection,
+				const char *iface,
+				int master_ifindex)
+{
+	NMSettingVlan *s_vlan;
+	int vlan_id;
+	guint32 vlan_flags = 0;
+	guint32 num, i, from, to;
+	int ifindex;
+	struct rtnl_link *new_link = NULL;
+	char *master = nm_netlink_index_to_iface (master_ifindex);
+	char *name = NULL;
+
+	s_vlan = nm_connection_get_setting_vlan (connection);
+	g_return_val_if_fail (s_vlan, FALSE);
+
+	vlan_id = nm_setting_vlan_get_id (s_vlan);
+
+	if (!iface) {
+		iface = nm_connection_get_virtual_iface_name (connection);
+		g_return_val_if_fail (iface != NULL, FALSE);
+	}
+
+	/*
+	 * Use VLAN_NAME_TYPE_RAW_PLUS_VID_NO_PAD as default,
+	 * we will overwrite it with rtnl_link_set_name() later.
+	 */
+	name = nm_utils_new_vlan_name(master, vlan_id);
+
+	/*
+	 * vconfig add
+	 */
+
+	if (!nm_system_iface_compat_add_vlan_device (master, vlan_id))
+		goto err_out;
+
+	/*
+	 * get corresponding rtnl_link
+	 */
+
+	if (!nm_system_iface_compat_set_name (name, iface))
+		goto err_out_delete_vlan_with_default_name;
+
+	ifindex = nm_netlink_iface_to_index (iface);
+	if (ifindex <= 0)
+		goto err_out;
+
+	new_link = nm_netlink_index_to_rtnl_link (ifindex);
+	if (!new_link)
+		goto err_out_delete_vlan_with_default_name;
+
+	/*
+	 * vconfig set_flag
+	 */
+	vlan_flags = nm_setting_vlan_get_flags (s_vlan);
+	if (vlan_flags)
+		if (rtnl_link_vlan_set_flags (new_link, vlan_flags))
+			goto err_out_delete_vlan_with_new_name;
+
+	/*
+	 * vconfig set_ingress_map
+	 */
+	num = nm_setting_vlan_get_num_priorities (s_vlan, NM_VLAN_INGRESS_MAP);
+	for (i = 0; i < num; i++) {
+		if (nm_setting_vlan_get_priority (s_vlan, NM_VLAN_INGRESS_MAP, i, &from, &to))
+			if (rtnl_link_vlan_set_ingress_map (new_link, from, to))
+				goto err_out_delete_vlan_with_new_name;
+	}
+
+	/*
+	 * vconfig set_egress_map
+	 */
+	num = nm_setting_vlan_get_num_priorities (s_vlan, NM_VLAN_EGRESS_MAP);
+	for (i = 0; i < num; i++) {
+		if (nm_setting_vlan_get_priority (s_vlan, NM_VLAN_EGRESS_MAP, i, &from, &to))
+			if (rtnl_link_vlan_set_egress_map (new_link, from, to))
+				goto err_out_delete_vlan_with_new_name;
+	}
+
+	rtnl_link_put (new_link);
+	return TRUE;
+
+err_out:
+	g_free (name);
+	return FALSE;
+
+err_out_delete_vlan_with_default_name:
+	nm_system_iface_compat_rem_vlan_device (name);
+	g_free (name);
+	return FALSE;
+
+err_out_delete_vlan_with_new_name:
+	rtnl_link_put (new_link);
+	nm_system_iface_compat_rem_vlan_device (iface);
+	g_free (name);
+	return FALSE;
+}
+
+/**
+ * nm_system_add_vlan_iface:
+ * @connection: the #NMConnection that describes the VLAN interface
+ * @iface: the interface name of the new VLAN interface
+ * @parent_ifindex: the interface index of the new VLAN interface's master
+ *  interface
+ *
+ * Add a VLAN device named @iface and specified in @connection.
+ *
+ * Returns: %TRUE on success, %FALSE on failure
+ */
+gboolean
+nm_system_add_vlan_iface (NMConnection *connection,
+                          const char *iface,
+                          int parent_ifindex)
+{
+	NMSettingVlan *s_vlan;
+	int ret = -1;
+	struct rtnl_link *new_link = NULL;
+	struct nl_sock *nlh = NULL;
+	guint32 vlan_id = 0;
+	guint32 vlan_flags = 0;
+	guint32 num, i, from, to;
+
+	g_return_val_if_fail (parent_ifindex >= 0, FALSE);
+
+	nlh = nm_netlink_get_default_handle ();
+	g_return_val_if_fail (nlh != NULL, FALSE);
+
+	s_vlan = nm_connection_get_setting_vlan (connection);
+	g_return_val_if_fail (s_vlan, FALSE);
+
+	vlan_id = nm_setting_vlan_get_id (s_vlan);
+
+	if (!iface) {
+		iface = nm_connection_get_virtual_iface_name (connection);
+		g_return_val_if_fail (iface != NULL, FALSE);
+	}
+
+	new_link = rtnl_link_alloc ();
+	if (!new_link) {
+		g_warn_if_fail (new_link != NULL);
+		goto out;
+	}
+
+	ret = rtnl_link_set_type (new_link, "vlan");
+	if (ret == -NLE_OPNOTSUPP) {
+		/*
+		 * There is no linbl3, try ioctl.
+		 */
+		ret = -1;
+		if (nm_system_iface_compat_add_vlan (connection, iface, parent_ifindex))
+			ret = 0;
+		goto out;
+	}
+
+	rtnl_link_set_link (new_link, parent_ifindex);
+	rtnl_link_set_name (new_link, iface);
+	rtnl_link_vlan_set_id (new_link, vlan_id);
+
+	vlan_flags = nm_setting_vlan_get_flags (s_vlan);
+	if (vlan_flags) {
+		guint kernel_flags = 0;
+
+		if (vlan_flags & NM_VLAN_FLAG_REORDER_HEADERS)
+			kernel_flags |= VLAN_FLAG_REORDER_HDR;
+		if (vlan_flags & NM_VLAN_FLAG_GVRP)
+			kernel_flags |= VLAN_FLAG_GVRP;
+		if (vlan_flags & NM_VLAN_FLAG_LOOSE_BINDING)
+			kernel_flags |= VLAN_FLAG_LOOSE_BINDING;
+
+		rtnl_link_vlan_set_flags (new_link, kernel_flags);
+	}
+
+	num = nm_setting_vlan_get_num_priorities (s_vlan, NM_VLAN_INGRESS_MAP);
+	for (i = 0; i < num; i++) {
+		if (nm_setting_vlan_get_priority (s_vlan, NM_VLAN_INGRESS_MAP, i, &from, &to))
+			rtnl_link_vlan_set_ingress_map (new_link, (int) from, (int) to);
+	}
+
+	num = nm_setting_vlan_get_num_priorities (s_vlan, NM_VLAN_EGRESS_MAP);
+	for (i = 0; i < num; i++) {
+		if (nm_setting_vlan_get_priority (s_vlan, NM_VLAN_EGRESS_MAP, i, &from, &to))
+			rtnl_link_vlan_set_egress_map (new_link, (int) from, (int) to);
+	}
+
+	ret = rtnl_link_add (nlh, new_link, NLM_F_CREATE);
+
+out:
+	if (new_link)
+		rtnl_link_put (new_link);
+	return (ret == 0);
+}
+
+/**
+ * nm_system_del_vlan_iface:
+ * @iface: the interface name
+ *
+ * Delete a VLAN interface specified by @iface.
+ *
+ * Returns: %TRUE on success, or %FALSE
+ */
+gboolean
+nm_system_del_vlan_iface (const char *iface)
+{
+	int ret = 0;
+	struct nl_sock *nlh = NULL;
+	struct nl_cache *cache = NULL;
+	struct rtnl_link *new_link = NULL;
+	int itype;
+
+	g_return_val_if_fail (iface != NULL, FALSE);
+
+	itype = nm_system_get_iface_type (-1, iface);
+	g_return_val_if_fail (itype == NM_IFACE_TYPE_VLAN, FALSE);
+
+	nlh = nm_netlink_get_default_handle ();
+	g_return_val_if_fail (nlh != NULL, FALSE);
+
+	ret = rtnl_link_alloc_cache (nlh, &cache);
+	g_return_val_if_fail (ret == 0, FALSE);
+	g_return_val_if_fail (cache != NULL, FALSE);
+
+	new_link = rtnl_link_get_by_name (cache, iface);
+	if (new_link) {
+		ret = rtnl_link_delete (nlh, new_link);
+		if (ret == -NLE_OPNOTSUPP) {
+			/*
+			 * There is no linbl3, try ioctl.
+			 */
+			ret = -1;
+			if (nm_system_iface_compat_rem_vlan_device (iface))
+				ret = 0;
+		}
+	}
+
+	rtnl_link_put (new_link);
+	nl_cache_free (cache);
+	return (ret == 0) ? TRUE : FALSE;
+}
diff --git a/src/nm-system.h b/src/nm-system.h
index ae4e7d91..84ae6c27 100644
--- a/src/nm-system.h
+++ b/src/nm-system.h
@@ -30,6 +30,8 @@
 #include <glib.h>
 #include "nm-device.h"
 #include "nm-ip4-config.h"
+#include "nm-setting-bond.h"
+#include "nm-setting-vlan.h"
 
 /* Prototypes for system/distribution dependent functions,
  * implemented in the backend files in backends/ directory
@@ -56,9 +58,6 @@ struct rtnl_route *nm_system_add_ip4_vpn_gateway_route (NMDevice *parent_device,
 
 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              (int ifindex,
                                                          NMIP4Config *config,
                                                          int priority,
@@ -83,10 +82,42 @@ gboolean        nm_system_iface_set_up                  (int ifindex,
                                                          gboolean up,
                                                          gboolean *no_firmware);
 
+guint32		nm_system_iface_get_flags		(int ifindex);
 gboolean        nm_system_iface_is_up                   (int ifindex);
 
 gboolean		nm_system_iface_set_mtu                 (int ifindex, guint32 mtu);
 
 gboolean		nm_system_iface_set_mac                 (int ifindex, const struct ether_addr *mac);
 
+gboolean        nm_system_apply_bonding_config          (const char *iface,
+                                                         NMSettingBond *s_bond);
+gboolean        nm_system_add_bonding_master            (const char *iface);
+
+gboolean        nm_system_iface_enslave                 (gint master_ifindex,
+                                                         const char *master_iface,
+                                                         gint slave_ifindex,
+                                                         const char *slave_iface);
+gboolean        nm_system_iface_release                 (gint master_ifindex,
+                                                         const char *master_iface,
+                                                         gint slave_ifindex,
+                                                         const char *slave_iface);
+
+enum {
+		NM_IFACE_TYPE_UNSPEC = 0,
+		NM_IFACE_TYPE_BOND,
+		NM_IFACE_TYPE_VLAN,
+		NM_IFACE_TYPE_DUMMY,
+};
+
+int             nm_system_get_iface_type      (int ifindex, const char *name);
+
+gboolean        nm_system_get_iface_vlan_info (int ifindex,
+                                               int *out_parent_ifindex,
+                                               int *out_vlan_id);
+
+gboolean        nm_system_add_vlan_iface (NMConnection *connection,
+                                          const char *iface,
+                                          int parent_ifindex);
+gboolean        nm_system_del_vlan_iface (const char *iface);
+
 #endif
diff --git a/src/nm-udev-manager.c b/src/nm-udev-manager.c
index e8c6b822..45262f87 100644
--- a/src/nm-udev-manager.c
+++ b/src/nm-udev-manager.c
@@ -15,32 +15,19 @@
  * with this program; if not, write to the Free Software Foundation, Inc.,
  * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
  *
- * Copyright (C) 2009 - 2011 Red Hat, Inc.
+ * Copyright (C) 2009 - 2012 Red Hat, Inc.
  */
 
 #include <config.h>
-#include <signal.h>
-#include <string.h>
-#include <stdlib.h>
-#include <sys/stat.h>
-#include <stdio.h>
-#include <sys/ioctl.h>
-#include <unistd.h>
-
-#include "wireless-helper.h"
+#include <net/if_arp.h>
 
+#include <gmodule.h>
 #include <gudev/gudev.h>
 
 #include "nm-udev-manager.h"
 #include "nm-marshal.h"
 #include "nm-logging.h"
-#include "NetworkManagerUtils.h"
-#include "nm-device-wifi.h"
-#include "nm-device-olpc-mesh.h"
-#include "nm-device-ethernet.h"
-#if WITH_WIMAX
-#include "nm-device-wimax.h"
-#endif
+#include "nm-system.h"
 
 typedef struct {
 	GUdevClient *client;
@@ -342,69 +329,52 @@ rfkill_remove (NMUdevManager *self,
 	}
 }
 
-static gboolean
-is_wireless (GUdevDevice *device)
+static void
+net_add (NMUdevManager *self, GUdevDevice *udev_device)
 {
-	char phy80211_path[255];
-	struct stat s;
-	int fd;
-	struct iwreq iwr;
-	const char *ifname, *path;
-	gboolean is_wifi = FALSE;
-
-	ifname = g_udev_device_get_name (device);
-	g_assert (ifname);
-
-	fd = socket (PF_INET, SOCK_DGRAM, 0);
-	if (fd == -1)
-		return FALSE;
-
-	strncpy (iwr.ifr_ifrn.ifrn_name, ifname, IFNAMSIZ);
-
-	path = g_udev_device_get_sysfs_path (device);
-	snprintf (phy80211_path, sizeof (phy80211_path), "%s/phy80211", path);
+	GUdevDevice *parent = NULL, *grandparent = NULL;
+	gint ifindex;
+	gint etype;
+	const char *ifname, *driver, *path, *subsys, *tmp;
+	gboolean is_ctc;
 
-	if (   (ioctl (fd, SIOCGIWNAME, &iwr) == 0)
-	    || (stat (phy80211_path, &s) == 0 && (s.st_mode & S_IFDIR)))
-		is_wifi = TRUE;
+	g_return_if_fail (udev_device != NULL);
 
-	close (fd);
-	return is_wifi;
-}
+	ifname = g_udev_device_get_name (udev_device);
+	if (!ifname) {
+		nm_log_dbg (LOGD_HW, "failed to get device's interface");
+		return;
+	}
 
-static gboolean
-is_olpc_mesh (GUdevDevice *device)
-{
-	const gchar *prop = g_udev_device_get_property (device, "ID_NM_OLPC_MESH");
-	return (prop != NULL);
-}
+	etype = g_udev_device_get_sysfs_attr_as_int (udev_device, "type");
+	is_ctc = (strncmp (ifname, "ctc", 3) == 0) && (etype == 256);
 
-static gboolean
-is_wimax (const char *driver)
-{
-	/* FIXME: check 'DEVTYPE' instead; but since we only support Intel
-	 * WiMAX devices for now this is appropriate.
+	/* Ignore devices that don't report Ethernet encapsulation, except for
+	 * s390 CTC-type devices that report 256 for some reason.
+	 * FIXME: use something other than interface name to detect CTC here.
 	 */
-	return g_strcmp0 (driver, "i2400m_usb") == 0;
-}
-
-static GObject *
-device_creator (NMUdevManager *manager,
-                GUdevDevice *udev_device,
-                gboolean sleeping)
-{
-	GObject *device = NULL;
-	const char *ifname, *driver, *path, *subsys;
-	GUdevDevice *parent = NULL, *grandparent = NULL;
-	gint ifindex;
+	if ((etype != ARPHRD_ETHER) && (etype != ARPHRD_INFINIBAND) && (is_ctc == FALSE)) {
+		nm_log_dbg (LOGD_HW, "(%s): ignoring interface with type %d", ifname, etype);
+		return;
+	}
 
-	ifname = g_udev_device_get_name (udev_device);
-	g_assert (ifname);
+	/* Not all ethernet devices are immediately usable; newer mobile broadband
+	 * devices (Ericsson, Option, Sierra) require setup on the tty before the
+	 * ethernet device is usable.  2.6.33 and later kernels set the 'DEVTYPE'
+	 * uevent variable which we can use to ignore the interface as a NMDevice
+	 * subclass.  ModemManager will pick it up though and so we'll handle it
+	 * through the mobile broadband stuff.
+	 */
+	tmp = g_udev_device_get_property (udev_device, "DEVTYPE");
+	if (g_strcmp0 (tmp, "wwan") == 0) {
+		nm_log_dbg (LOGD_HW, "(%s): ignoring interface with devtype '%s'", ifname, tmp);
+		return;
+	}
 
 	path = g_udev_device_get_sysfs_path (udev_device);
 	if (!path) {
 		nm_log_warn (LOGD_HW, "couldn't determine device path; ignoring...");
-		return NULL;
+		return;
 	}
 
 	driver = g_udev_device_get_driver (udev_device);
@@ -429,94 +399,39 @@ device_creator (NMUdevManager *manager,
 		}
 	}
 
-	if (!driver) {
-		if (g_str_has_prefix (ifname, "easytether")) {
-			driver = "easytether";
-		} else {
-			nm_log_warn (LOGD_HW, "%s: couldn't determine device driver; ignoring...", path);
-			goto out;
-		}
-	}
-
 	ifindex = g_udev_device_get_sysfs_attr_as_int (udev_device, "ifindex");
 	if (ifindex <= 0) {
 		nm_log_warn (LOGD_HW, "%s: device had invalid ifindex %d; ignoring...", path, (guint32) ifindex);
 		goto out;
 	}
 
-	if (is_olpc_mesh (udev_device)) /* must be before is_wireless */
-		device = (GObject *) nm_device_olpc_mesh_new (path, ifname, driver);
-	else if (is_wireless (udev_device))
-		device = (GObject *) nm_device_wifi_new (path, ifname, driver);
-	else if (is_wimax (driver)) {
-#if WITH_WIMAX
-		device = (GObject *) nm_device_wimax_new (path, ifname, driver);
-#endif
-	} else
-		device = (GObject *) nm_device_ethernet_new (path, ifname, driver);
+	if (!driver) {
+		switch (nm_system_get_iface_type (ifindex, ifname)) {
+		case NM_IFACE_TYPE_BOND:
+			driver = "bonding";
+			break;
+		case NM_IFACE_TYPE_VLAN:
+			driver = "8021q";
+			break;
+		default:
+			if (g_str_has_prefix (ifname, "easytether"))
+				driver = "easytether";
+			break;
+		}
+		
+		if (!driver) {
+			nm_log_warn (LOGD_HW, "%s: couldn't determine device driver; ignoring...", path);
+			goto out;
+		}
+	}
+
+	g_signal_emit (self, signals[DEVICE_ADDED], 0, udev_device, ifname, path, driver, ifindex);
 
 out:
 	if (grandparent)
 		g_object_unref (grandparent);
 	if (parent)
 		g_object_unref (parent);
-	return device;
-}
-
-static void
-net_add (NMUdevManager *self, GUdevDevice *device)
-{
-	gint etype;
-	const char *iface;
-	const char *tmp;
-	gboolean is_ctc;
-
-	g_return_if_fail (device != NULL);
-
-	iface = g_udev_device_get_name (device);
-	if (!iface) {
-		nm_log_dbg (LOGD_HW, "failed to get device's interface");
-		return;
-	}
-
-	etype = g_udev_device_get_sysfs_attr_as_int (device, "type");
-	is_ctc = (strncmp (iface, "ctc", 3) == 0) && (etype == 256);
-
-	/* Ignore devices that don't report Ethernet encapsulation, except for
-	 * s390 CTC-type devices that report 256 for some reason.
-	 * FIXME: use something other than interface name to detect CTC here.
-	 */
-	if ((etype != 1) && (is_ctc == FALSE)) {
-		nm_log_dbg (LOGD_HW, "(%s): ignoring interface with type %d", iface, etype);
-		return;
-	}
-
-	/* Not all ethernet devices are immediately usable; newer mobile broadband
-	 * devices (Ericsson, Option, Sierra) require setup on the tty before the
-	 * ethernet device is usable.  2.6.33 and later kernels set the 'DEVTYPE'
-	 * uevent variable which we can use to ignore the interface as a NMDevice
-	 * subclass.  ModemManager will pick it up though and so we'll handle it
-	 * through the mobile broadband stuff.
-	 */
-	tmp = g_udev_device_get_property (device, "DEVTYPE");
-	if (g_strcmp0 (tmp, "wwan") == 0) {
-		nm_log_dbg (LOGD_HW, "(%s): ignoring interface with devtype '%s'", iface, tmp);
-		return;
-	}
-
-	/* Ignore Nokia cdc-ether interfaces in PC-Suite mode since we need to
-	 * talk phonet to use them, which ModemManager doesn't do yet.
-	 */
-	tmp = g_udev_device_get_property (device, "ID_VENDOR_ID");
-	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, "(%s): ignoring Nokia PC-Suite ethernet interface", iface);
-			return;
-		}
-	}
-
-	g_signal_emit (self, signals[DEVICE_ADDED], 0, device, device_creator);
 }
 
 static void
@@ -638,8 +553,8 @@ nm_udev_manager_class_init (NMUdevManagerClass *klass)
 					  G_SIGNAL_RUN_FIRST,
 					  G_STRUCT_OFFSET (NMUdevManagerClass, device_added),
 					  NULL, NULL,
-					  _nm_marshal_VOID__POINTER_POINTER,
-					  G_TYPE_NONE, 2, G_TYPE_POINTER, G_TYPE_POINTER);
+					  _nm_marshal_VOID__POINTER_POINTER_POINTER_POINTER_INT,
+					  G_TYPE_NONE, 5, G_TYPE_POINTER, G_TYPE_POINTER, G_TYPE_POINTER, G_TYPE_POINTER, G_TYPE_INT);
 
 	signals[DEVICE_REMOVED] =
 		g_signal_new ("device-removed",
diff --git a/src/nm-udev-manager.h b/src/nm-udev-manager.h
index e7866f96..61d3b7cf 100644
--- a/src/nm-udev-manager.h
+++ b/src/nm-udev-manager.h
@@ -16,7 +16,7 @@
  * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
  *
  * Copyright (C) 2007 - 2008 Novell, Inc.
- * Copyright (C) 2007 - 2008 Red Hat, Inc.
+ * Copyright (C) 2007 - 2012 Red Hat, Inc.
  */
 
 #ifndef NM_UDEV_MANAGER_H
@@ -52,7 +52,10 @@ typedef struct {
 	/* Virtual functions */
 	void (*device_added) (NMUdevManager *manager,
 	                      GUdevDevice *device,
-	                      NMDeviceCreatorFn creator_fn);
+	                      const char *iface,
+	                      const char *sysfs_path,
+	                      const char *driver,
+	                      int ifindex);
 
 	void (*device_removed) (NMUdevManager *manager, GUdevDevice *device);
 
diff --git a/src/nm-wifi-ap.c b/src/nm-wifi-ap.c
index be836df0..92a99b69 100644
--- a/src/nm-wifi-ap.c
+++ b/src/nm-wifi-ap.c
@@ -19,10 +19,9 @@
  * Copyright (C) 2006 - 2008 Novell, Inc.
  */
 
-#include "wireless-helper.h"
-
 #include <string.h>
 #include <stdlib.h>
+#include <netinet/ether.h>
 
 #include "nm-wifi-ap.h"
 #include "nm-wifi-ap-utils.h"
@@ -30,7 +29,7 @@
 #include "nm-utils.h"
 #include "nm-logging.h"
 #include "nm-dbus-manager.h"
-#include "wpa.h"
+
 #include "nm-properties-changed-signal.h"
 #include "nm-setting-wireless.h"
 #include "nm-glib-compat.h"
@@ -43,6 +42,7 @@
 typedef struct
 {
 	char *dbus_path;
+	char *supplicant_path;   /* D-Bus object path of this AP from wpa_supplicant */
 
 	/* Scanned or cached values */
 	GByteArray *	ssid;
@@ -107,6 +107,7 @@ finalize (GObject *object)
 	NMAccessPointPrivate *priv = NM_AP_GET_PRIVATE (object);
 
 	g_free (priv->dbus_path);
+	g_free (priv->supplicant_path);
 	if (priv->ssid)
 		g_byte_array_free (priv->ssid, TRUE);
 
@@ -183,7 +184,7 @@ get_property (GObject *object, guint prop_id,
 		g_value_set_uint (value, priv->freq);
 		break;
 	case PROP_HW_ADDRESS:
-		g_value_take_string (value, nm_ether_ntop (&priv->address));
+		g_value_take_string (value, nm_utils_hwaddr_ntoa (&priv->address, ARPHRD_ETHER));
 		break;
 	case PROP_MODE:
 		g_value_set_uint (value, priv->mode);
@@ -346,15 +347,10 @@ nm_ap_export_to_dbus (NMAccessPoint *ap)
  * Create a new, blank user access point info structure
  *
  */
-NMAccessPoint *nm_ap_new (void)
+static NMAccessPoint *
+nm_ap_new (void)
 {
-	GObject *object;
-
-	object = g_object_new (NM_TYPE_AP, NULL);
-	if (!object)
-		return NULL;
-
-	return (NMAccessPoint *) object;
+	return (NMAccessPoint *) g_object_new (NM_TYPE_AP, NULL);
 }
 
 static NM80211ApSecurityFlags
@@ -431,7 +427,7 @@ foreach_property_cb (gpointer key, gpointer value, gpointer user_data)
 		GArray *array = g_value_get_boxed (variant);
 
 		if (!strcmp (key, "SSID")) {
-			guint32 len = MIN (IW_ESSID_MAX_SIZE, array->len);
+			guint32 len = MIN (32, array->len);
 			GByteArray *ssid;
 
 			/* Stupid ieee80211 layer uses <hidden> */
@@ -510,7 +506,7 @@ foreach_property_cb (gpointer key, gpointer value, gpointer user_data)
 }
 
 NMAccessPoint *
-nm_ap_new_from_properties (GHashTable *properties)
+nm_ap_new_from_properties (const char *supplicant_path, GHashTable *properties)
 {
 	NMAccessPoint *ap;
 	GTimeVal cur_time;
@@ -525,6 +521,8 @@ nm_ap_new_from_properties (GHashTable *properties)
 	g_object_freeze_notify (G_OBJECT (ap));
 	g_hash_table_foreach (properties, foreach_property_cb, ap);
 
+	nm_ap_set_supplicant_path (ap, supplicant_path);
+
 	/* ignore APs with invalid BSSIDs */
 	addr = nm_ap_get_address (ap);
 	if (   !(memcmp (addr->ether_addr_octet, bad_bssid1, ETH_ALEN))
@@ -635,7 +633,7 @@ nm_ap_new_fake_from_connection (NMConnection *connection)
 
 	g_return_val_if_fail (connection != NULL, NULL);
 
-	s_wireless = NM_SETTING_WIRELESS (nm_connection_get_setting (connection, NM_TYPE_SETTING_WIRELESS));
+	s_wireless = nm_connection_get_setting_wireless (connection);
 	g_return_val_if_fail (s_wireless != NULL, NULL);
 
 	ssid = nm_setting_wireless_get_ssid (s_wireless);
@@ -672,7 +670,7 @@ nm_ap_new_fake_from_connection (NMConnection *connection)
 		nm_ap_set_freq (ap, freq);
 	}
 
-	s_wireless_sec = (NMSettingWirelessSecurity *) nm_connection_get_setting (connection, NM_TYPE_SETTING_WIRELESS_SECURITY);
+	s_wireless_sec = nm_connection_get_setting_wireless_security (connection);
 	/* Assume presence of a security setting means the AP is encrypted */
 	if (!s_wireless_sec)
 		goto done;
@@ -784,6 +782,24 @@ nm_ap_get_dbus_path (NMAccessPoint *ap)
 	return NM_AP_GET_PRIVATE (ap)->dbus_path;
 }
 
+const char *
+nm_ap_get_supplicant_path (NMAccessPoint *ap)
+{
+	g_return_val_if_fail (NM_IS_AP (ap), NULL);
+
+	return NM_AP_GET_PRIVATE (ap)->supplicant_path;
+}
+
+void
+nm_ap_set_supplicant_path (NMAccessPoint *ap, const char *path)
+{
+	g_return_if_fail (NM_IS_AP (ap));
+	g_return_if_fail (path != NULL);
+
+	g_free (NM_AP_GET_PRIVATE (ap)->supplicant_path);
+	NM_AP_GET_PRIVATE (ap)->supplicant_path = g_strdup (path);
+}
+
 /*
  * Get/set functions for ssid
  *
@@ -1130,7 +1146,7 @@ nm_ap_check_compatible (NMAccessPoint *self,
 
 	priv = NM_AP_GET_PRIVATE (self);
 
-	s_wireless = NM_SETTING_WIRELESS (nm_connection_get_setting (connection, NM_TYPE_SETTING_WIRELESS));
+	s_wireless = nm_connection_get_setting_wireless (connection);
 	if (s_wireless == NULL)
 		return FALSE;
 	
@@ -1168,8 +1184,7 @@ nm_ap_check_compatible (NMAccessPoint *self,
 			return FALSE;
 	}
 
-	s_wireless_sec = (NMSettingWirelessSecurity *) nm_connection_get_setting (connection,
-	                                                                          NM_TYPE_SETTING_WIRELESS_SECURITY);
+	s_wireless_sec = nm_connection_get_setting_wireless_security (connection);
 
 	return nm_setting_wireless_ap_security_compatible (s_wireless,
 	                                                   s_wireless_sec,
diff --git a/src/nm-wifi-ap.h b/src/nm-wifi-ap.h
index 31100d34..a0087323 100644
--- a/src/nm-wifi-ap.h
+++ b/src/nm-wifi-ap.h
@@ -57,13 +57,17 @@ typedef struct {
 
 GType nm_ap_get_type (void);
 
-NMAccessPoint *	nm_ap_new				(void);
-NMAccessPoint * nm_ap_new_from_properties (GHashTable *properties);
+NMAccessPoint * nm_ap_new_from_properties (const char *supplicant_path,
+                                           GHashTable *properties);
 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 char *        nm_ap_get_supplicant_path (NMAccessPoint *ap);
+void                nm_ap_set_supplicant_path (NMAccessPoint *ap,
+                                               const char *path);
+
 const GByteArray *	nm_ap_get_ssid (const NMAccessPoint * ap);
 void				nm_ap_set_ssid (NMAccessPoint * ap, const GByteArray * ssid);
 
diff --git a/src/NetworkManager.conf b/src/org.freedesktop.NetworkManager.conf
index 15b11b7e..15b11b7e 100644
--- a/src/NetworkManager.conf
+++ b/src/org.freedesktop.NetworkManager.conf
diff --git a/src/ppp-manager/Makefile.am b/src/ppp-manager/Makefile.am
index 540e5855..8df2f584 100644
--- a/src/ppp-manager/Makefile.am
+++ b/src/ppp-manager/Makefile.am
@@ -1,10 +1,13 @@
 INCLUDES = \
 	-I${top_srcdir} \
 	-I${top_srcdir}/include \
+	-I${top_builddir}/include \
 	-I${top_srcdir}/libnm-util \
+	-I${top_builddir}/libnm-util \
 	-I${top_srcdir}/src \
-	-I${top_srcdir}/src/logging \
-	-I${top_builddir}/marshallers
+	-I${top_srcdir}/src/generated \
+	-I${top_builddir}/src/generated \
+	-I${top_srcdir}/src/logging
 
 noinst_LTLIBRARIES = libppp-manager.la
 
@@ -28,7 +31,7 @@ libppp_manager_la_CPPFLAGS = \
 	-DPLUGINDIR=\"$(PPPD_PLUGIN_DIR)\"
 
 libppp_manager_la_LIBADD = \
-	$(top_builddir)/marshallers/libmarshallers.la \
+	$(top_builddir)/src/generated/libnm-generated.la \
 	$(top_builddir)/src/logging/libnm-logging.la \
 	$(DBUS_LIBS) \
 	$(GLIB_LIBS)
diff --git a/src/ppp-manager/Makefile.in b/src/ppp-manager/Makefile.in
index 90f855b3..55355a7d 100644
--- a/src/ppp-manager/Makefile.in
+++ b/src/ppp-manager/Makefile.in
@@ -79,7 +79,7 @@ am__installdirs = "$(DESTDIR)$(pppd_plugindir)"
 LTLIBRARIES = $(noinst_LTLIBRARIES) $(pppd_plugin_LTLIBRARIES)
 am__DEPENDENCIES_1 =
 libppp_manager_la_DEPENDENCIES =  \
-	$(top_builddir)/marshallers/libmarshallers.la \
+	$(top_builddir)/src/generated/libnm-generated.la \
 	$(top_builddir)/src/logging/libnm-logging.la \
 	$(am__DEPENDENCIES_1) $(am__DEPENDENCIES_1)
 am_libppp_manager_la_OBJECTS = libppp_manager_la-nm-ppp-manager.lo
@@ -177,6 +177,8 @@ GIO_LIBS = @GIO_LIBS@
 GLIB_CFLAGS = @GLIB_CFLAGS@
 GLIB_GENMARSHAL = @GLIB_GENMARSHAL@
 GLIB_LIBS = @GLIB_LIBS@
+GLIB_MAKEFILE = @GLIB_MAKEFILE@
+GLIB_MKENUMS = @GLIB_MKENUMS@
 GMODULE_CFLAGS = @GMODULE_CFLAGS@
 GMODULE_LIBS = @GMODULE_LIBS@
 GMSGFMT = @GMSGFMT@
@@ -231,11 +233,15 @@ LIBNL2_LIBS = @LIBNL2_LIBS@
 LIBNL3_CFLAGS = @LIBNL3_CFLAGS@
 LIBNL3_LIBS = @LIBNL3_LIBS@
 LIBNL_CFLAGS = @LIBNL_CFLAGS@
+LIBNL_GENL3_CFLAGS = @LIBNL_GENL3_CFLAGS@
+LIBNL_GENL3_LIBS = @LIBNL_GENL3_LIBS@
 LIBNL_LIBS = @LIBNL_LIBS@
 LIBNL_ROUTE3_CFLAGS = @LIBNL_ROUTE3_CFLAGS@
 LIBNL_ROUTE3_LIBS = @LIBNL_ROUTE3_LIBS@
 LIBOBJS = @LIBOBJS@
 LIBS = @LIBS@
+LIBSOUP_CFLAGS = @LIBSOUP_CFLAGS@
+LIBSOUP_LIBS = @LIBSOUP_LIBS@
 LIBTOOL = @LIBTOOL@
 LIPO = @LIPO@
 LN_S = @LN_S@
@@ -246,6 +252,7 @@ MAINT = @MAINT@
 MAKEINFO = @MAKEINFO@
 MANIFEST_TOOL = @MANIFEST_TOOL@
 MKDIR_P = @MKDIR_P@
+MOC = @MOC@
 MSGFMT = @MSGFMT@
 MSGFMT_015 = @MSGFMT_015@
 MSGMERGE = @MSGMERGE@
@@ -285,6 +292,8 @@ SED = @SED@
 SET_MAKE = @SET_MAKE@
 SHELL = @SHELL@
 STRIP = @STRIP@
+SYSTEMD_CFLAGS = @SYSTEMD_CFLAGS@
+SYSTEMD_LIBS = @SYSTEMD_LIBS@
 SYSTEM_CA_PATH = @SYSTEM_CA_PATH@
 UDEV_BASE_DIR = @UDEV_BASE_DIR@
 USE_NLS = @USE_NLS@
@@ -351,10 +360,13 @@ top_srcdir = @top_srcdir@
 INCLUDES = \
 	-I${top_srcdir} \
 	-I${top_srcdir}/include \
+	-I${top_builddir}/include \
 	-I${top_srcdir}/libnm-util \
+	-I${top_builddir}/libnm-util \
 	-I${top_srcdir}/src \
-	-I${top_srcdir}/src/logging \
-	-I${top_builddir}/marshallers
+	-I${top_srcdir}/src/generated \
+	-I${top_builddir}/src/generated \
+	-I${top_srcdir}/src/logging
 
 noinst_LTLIBRARIES = libppp-manager.la
 libppp_manager_la_SOURCES = \
@@ -371,7 +383,7 @@ libppp_manager_la_CPPFLAGS = \
 	-DPLUGINDIR=\"$(PPPD_PLUGIN_DIR)\"
 
 libppp_manager_la_LIBADD = \
-	$(top_builddir)/marshallers/libmarshallers.la \
+	$(top_builddir)/src/generated/libnm-generated.la \
 	$(top_builddir)/src/logging/libnm-logging.la \
 	$(DBUS_LIBS) \
 	$(GLIB_LIBS)
diff --git a/src/ppp-manager/nm-ppp-manager.c b/src/ppp-manager/nm-ppp-manager.c
index 3546f8d7..59698c34 100644
--- a/src/ppp-manager/nm-ppp-manager.c
+++ b/src/ppp-manager/nm-ppp-manager.c
@@ -16,7 +16,7 @@
  * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
  *
  * Copyright (C) 2008 Novell, Inc.
- * Copyright (C) 2008 - 2010 Red Hat, Inc.
+ * Copyright (C) 2008 - 2011 Red Hat, Inc.
  */
 
 #include <config.h>
@@ -374,7 +374,7 @@ extract_details_from_connection (NMConnection *connection,
 	g_return_val_if_fail (username != NULL, FALSE);
 	g_return_val_if_fail (password != NULL, FALSE);
 
-	s_con = NM_SETTING_CONNECTION (nm_connection_get_setting (connection, NM_TYPE_SETTING_CONNECTION));
+	s_con = nm_connection_get_setting_connection (connection);
 	g_assert (s_con);
 
 	connection_type = nm_setting_connection_get_connection_type (s_con);
@@ -579,7 +579,7 @@ impl_ppp_manager_set_ip4_config (NMPPPManager *manager,
 	g_object_set_data (G_OBJECT (connection), PPP_MANAGER_SECRET_TRIES, NULL);
 
 	/* Merge in custom MTU */
-	s_ppp = (NMSettingPPP *) nm_connection_get_setting (connection, NM_TYPE_SETTING_PPP);
+	s_ppp = nm_connection_get_setting_ppp (connection);
 	if (s_ppp) {
 		guint32 mtu = nm_setting_ppp_get_mtu (s_ppp);
 
@@ -935,12 +935,6 @@ pppoe_fill_defaults (NMSettingPPP *setting)
 	if (!nm_setting_ppp_get_mru (setting))
 		g_object_set (setting, NM_SETTING_PPP_MRU, (guint32) 1492, NULL);
 
-	if (!nm_setting_ppp_get_lcp_echo_interval (setting))
-		g_object_set (setting, NM_SETTING_PPP_LCP_ECHO_INTERVAL, (guint32) 20, NULL);
-
-	if (!nm_setting_ppp_get_lcp_echo_failure (setting))
-		g_object_set (setting, NM_SETTING_PPP_LCP_ECHO_FAILURE, (guint32) 3, NULL);
-
 	g_object_set (setting,
 			    NM_SETTING_PPP_NOAUTH, TRUE,
 			    NM_SETTING_PPP_NODEFLATE, TRUE,
@@ -999,7 +993,7 @@ nm_ppp_manager_start (NMPPPManager *manager,
 	connection = nm_act_request_get_connection (req);
 	g_assert (connection);
 
-	s_ppp = (NMSettingPPP *) nm_connection_get_setting (connection, NM_TYPE_SETTING_PPP);
+	s_ppp = nm_connection_get_setting_ppp (connection);
 	if (!s_ppp) {
 		/* If the PPP settings are all default we may not have a PPP setting yet,
 		 * so just make a default one here.
@@ -1008,7 +1002,7 @@ nm_ppp_manager_start (NMPPPManager *manager,
 		s_ppp_created = TRUE;
 	}
 	
-	pppoe_setting = (NMSettingPPPOE *) nm_connection_get_setting (connection, NM_TYPE_SETTING_PPPOE);
+	pppoe_setting = nm_connection_get_setting_pppoe (connection);
 	if (pppoe_setting)
 		pppoe_fill_defaults (s_ppp);
 
diff --git a/src/settings/Makefile.am b/src/settings/Makefile.am
index 21dc5bb0..8024d541 100644
--- a/src/settings/Makefile.am
+++ b/src/settings/Makefile.am
@@ -2,10 +2,13 @@ SUBDIRS=plugins . tests
 
 INCLUDES = -I${top_srcdir} \
            -I${top_srcdir}/include \
+           -I${top_builddir}/include \
            -I${top_srcdir}/libnm-util \
+           -I${top_builddir}/libnm-util \
+           -I${top_srcdir}/src/generated \
+           -I${top_builddir}/src/generated \
            -I${top_srcdir}/src/logging \
-           -I${top_srcdir}/src \
-           -I${top_builddir}/marshallers
+           -I${top_srcdir}/src
 
 noinst_LTLIBRARIES = libsettings.la libtest-settings-utils.la
 
@@ -64,7 +67,7 @@ libsettings_la_CPPFLAGS = \
 
 libsettings_la_LIBADD = \
 	$(top_builddir)/libnm-util/libnm-util.la \
-	$(top_builddir)/marshallers/libmarshallers.la \
+	$(top_builddir)/src/generated/libnm-generated.la \
 	$(top_builddir)/src/logging/libnm-logging.la \
 	$(builddir)/plugins/keyfile/libnm-settings-plugin-keyfile.la \
 	$(DBUS_LIBS) \
diff --git a/src/settings/Makefile.in b/src/settings/Makefile.in
index b4f4508f..d1278206 100644
--- a/src/settings/Makefile.in
+++ b/src/settings/Makefile.in
@@ -58,7 +58,7 @@ LTLIBRARIES = $(noinst_LTLIBRARIES)
 am__DEPENDENCIES_1 =
 libsettings_la_DEPENDENCIES =  \
 	$(top_builddir)/libnm-util/libnm-util.la \
-	$(top_builddir)/marshallers/libmarshallers.la \
+	$(top_builddir)/src/generated/libnm-generated.la \
 	$(top_builddir)/src/logging/libnm-logging.la \
 	$(builddir)/plugins/keyfile/libnm-settings-plugin-keyfile.la \
 	$(am__DEPENDENCIES_1) $(am__DEPENDENCIES_1) \
@@ -203,6 +203,8 @@ GIO_LIBS = @GIO_LIBS@
 GLIB_CFLAGS = @GLIB_CFLAGS@
 GLIB_GENMARSHAL = @GLIB_GENMARSHAL@
 GLIB_LIBS = @GLIB_LIBS@
+GLIB_MAKEFILE = @GLIB_MAKEFILE@
+GLIB_MKENUMS = @GLIB_MKENUMS@
 GMODULE_CFLAGS = @GMODULE_CFLAGS@
 GMODULE_LIBS = @GMODULE_LIBS@
 GMSGFMT = @GMSGFMT@
@@ -257,11 +259,15 @@ LIBNL2_LIBS = @LIBNL2_LIBS@
 LIBNL3_CFLAGS = @LIBNL3_CFLAGS@
 LIBNL3_LIBS = @LIBNL3_LIBS@
 LIBNL_CFLAGS = @LIBNL_CFLAGS@
+LIBNL_GENL3_CFLAGS = @LIBNL_GENL3_CFLAGS@
+LIBNL_GENL3_LIBS = @LIBNL_GENL3_LIBS@
 LIBNL_LIBS = @LIBNL_LIBS@
 LIBNL_ROUTE3_CFLAGS = @LIBNL_ROUTE3_CFLAGS@
 LIBNL_ROUTE3_LIBS = @LIBNL_ROUTE3_LIBS@
 LIBOBJS = @LIBOBJS@
 LIBS = @LIBS@
+LIBSOUP_CFLAGS = @LIBSOUP_CFLAGS@
+LIBSOUP_LIBS = @LIBSOUP_LIBS@
 LIBTOOL = @LIBTOOL@
 LIPO = @LIPO@
 LN_S = @LN_S@
@@ -272,6 +278,7 @@ MAINT = @MAINT@
 MAKEINFO = @MAKEINFO@
 MANIFEST_TOOL = @MANIFEST_TOOL@
 MKDIR_P = @MKDIR_P@
+MOC = @MOC@
 MSGFMT = @MSGFMT@
 MSGFMT_015 = @MSGFMT_015@
 MSGMERGE = @MSGMERGE@
@@ -311,6 +318,8 @@ SED = @SED@
 SET_MAKE = @SET_MAKE@
 SHELL = @SHELL@
 STRIP = @STRIP@
+SYSTEMD_CFLAGS = @SYSTEMD_CFLAGS@
+SYSTEMD_LIBS = @SYSTEMD_LIBS@
 SYSTEM_CA_PATH = @SYSTEM_CA_PATH@
 UDEV_BASE_DIR = @UDEV_BASE_DIR@
 USE_NLS = @USE_NLS@
@@ -377,10 +386,13 @@ top_srcdir = @top_srcdir@
 SUBDIRS = plugins . tests
 INCLUDES = -I${top_srcdir} \
            -I${top_srcdir}/include \
+           -I${top_builddir}/include \
            -I${top_srcdir}/libnm-util \
+           -I${top_builddir}/libnm-util \
+           -I${top_srcdir}/src/generated \
+           -I${top_builddir}/src/generated \
            -I${top_srcdir}/src/logging \
-           -I${top_srcdir}/src \
-           -I${top_builddir}/marshallers
+           -I${top_srcdir}/src
 
 noinst_LTLIBRARIES = libsettings.la libtest-settings-utils.la
 libtest_settings_utils_la_SOURCES = \
@@ -438,7 +450,7 @@ libsettings_la_CPPFLAGS = \
 
 libsettings_la_LIBADD = \
 	$(top_builddir)/libnm-util/libnm-util.la \
-	$(top_builddir)/marshallers/libmarshallers.la \
+	$(top_builddir)/src/generated/libnm-generated.la \
 	$(top_builddir)/src/logging/libnm-logging.la \
 	$(builddir)/plugins/keyfile/libnm-settings-plugin-keyfile.la \
 	$(DBUS_LIBS) \
diff --git a/src/settings/nm-agent-manager.c b/src/settings/nm-agent-manager.c
index 5ccbdc67..b7057400 100644
--- a/src/settings/nm-agent-manager.c
+++ b/src/settings/nm-agent-manager.c
@@ -36,6 +36,7 @@
 #include "nm-manager-auth.h"
 #include "nm-setting-vpn.h"
 #include "nm-setting-connection.h"
+#include "nm-enum-types.h"
 
 G_DEFINE_TYPE (NMAgentManager, nm_agent_manager, G_TYPE_OBJECT)
 
@@ -88,17 +89,6 @@ static void impl_agent_manager_unregister (NMAgentManager *self,
 /********************************************************************/
 
 #define NM_AGENT_MANAGER_ERROR         (nm_agent_manager_error_quark ())
-#define NM_TYPE_AGENT_MANAGER_ERROR    (nm_agent_manager_error_get_type ())
-
-typedef enum {
-	NM_AGENT_MANAGER_ERROR_SENDER_UNKNOWN = 0,
-	NM_AGENT_MANAGER_ERROR_PERMISSION_DENIED,
-	NM_AGENT_MANAGER_ERROR_SESSION_NOT_FOUND,
-	NM_AGENT_MANAGER_ERROR_INVALID_IDENTIFIER,
-	NM_AGENT_MANAGER_ERROR_NOT_REGISTERED,
-	NM_AGENT_MANAGER_ERROR_INTERNAL_ERROR,
-	NM_AGENT_MANAGER_ERROR_NO_SECRETS
-} NMAgentManagerError;
 
 static GQuark
 nm_agent_manager_error_quark (void)
@@ -110,37 +100,6 @@ nm_agent_manager_error_quark (void)
 	return ret;
 }
 
-#define ENUM_ENTRY(NAME, DESC) { NAME, "" #NAME "", DESC }
-
-static GType
-nm_agent_manager_error_get_type (void)
-{
-	static GType etype = 0;
-
-	if (etype == 0) {
-		static const GEnumValue values[] = {
-			/* Unable to determine caller's sender or UID */
-			ENUM_ENTRY (NM_AGENT_MANAGER_ERROR_SENDER_UNKNOWN, "SenderUnknown"),
-			/* Permission for some operation was denied */
-			ENUM_ENTRY (NM_AGENT_MANAGER_ERROR_PERMISSION_DENIED, "PermissionDenied"),
-			/* The caller's session could not be determined */
-			ENUM_ENTRY (NM_AGENT_MANAGER_ERROR_SESSION_NOT_FOUND, "SessionNotFound"),
-			/* The identifier was invalid */
-			ENUM_ENTRY (NM_AGENT_MANAGER_ERROR_INVALID_IDENTIFIER, "InvalidIdentifier"),
-			/* Request was not from a registered agent */
-			ENUM_ENTRY (NM_AGENT_MANAGER_ERROR_NOT_REGISTERED, "NotRegistered"),
-			/* Some internal error occurred */
-			ENUM_ENTRY (NM_AGENT_MANAGER_ERROR_INTERNAL_ERROR, "InternalError"),
-			/* No secrets were available */
-			ENUM_ENTRY (NM_AGENT_MANAGER_ERROR_NO_SECRETS, "NoSecrets"),
-			{ 0, 0, 0 }
-		};
-
-		etype = g_enum_register_static ("NMAgentManagerError", values);
-	}
-	return etype;
-}
-
 /*************************************************************/
 
 static gboolean
@@ -962,7 +921,7 @@ get_next_cb (Request *req)
 		 * we use the 'modify.own' permission instead of 'modify.system'.  If the
 		 * request affects more than just the caller, require 'modify.system'.
 		 */
-		s_con = (NMSettingConnection *) nm_connection_get_setting (req->connection, NM_TYPE_SETTING_CONNECTION);
+		s_con = nm_connection_get_setting_connection (req->connection);
 		g_assert (s_con);
 		if (nm_setting_connection_get_num_permissions (s_con) == 1)
 			perm = NM_AUTH_PERMISSION_SETTINGS_MODIFY_OWN;
diff --git a/src/settings/nm-agent-manager.h b/src/settings/nm-agent-manager.h
index e49f579d..9e8de44b 100644
--- a/src/settings/nm-agent-manager.h
+++ b/src/settings/nm-agent-manager.h
@@ -34,6 +34,16 @@
 #define NM_IS_AGENT_MANAGER_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((obj), NM_TYPE_AGENT_MANAGER))
 #define NM_AGENT_MANAGER_GET_CLASS(obj)  (G_TYPE_INSTANCE_GET_CLASS ((obj), NM_TYPE_AGENT_MANAGER, NMAgentManagerClass))
 
+typedef enum {
+	NM_AGENT_MANAGER_ERROR_SENDER_UNKNOWN = 0, /*< nick=SenderUnknown >*/
+	NM_AGENT_MANAGER_ERROR_PERMISSION_DENIED,  /*< nick=PermissionDenied >*/
+	NM_AGENT_MANAGER_ERROR_SESSION_NOT_FOUND,  /*< nick=SessionNotFound >*/
+	NM_AGENT_MANAGER_ERROR_INVALID_IDENTIFIER, /*< nick=InvalidIdentifier >*/
+	NM_AGENT_MANAGER_ERROR_NOT_REGISTERED,     /*< nick=NotRegistered >*/
+	NM_AGENT_MANAGER_ERROR_INTERNAL_ERROR,     /*< nick=InternalError >*/
+	NM_AGENT_MANAGER_ERROR_NO_SECRETS          /*< nick=NoSecrets >*/
+} NMAgentManagerError;
+
 typedef struct {
 	GObject parent;
 } NMAgentManager;
diff --git a/src/settings/nm-settings-connection.c b/src/settings/nm-settings-connection.c
index cdad8325..5d240c77 100644
--- a/src/settings/nm-settings-connection.c
+++ b/src/settings/nm-settings-connection.c
@@ -221,7 +221,7 @@ nm_settings_connection_recheck_visibility (NMSettingsConnection *self)
 
 	priv = NM_SETTINGS_CONNECTION_GET_PRIVATE (self);
 
-	s_con = (NMSettingConnection *) nm_connection_get_setting (NM_CONNECTION (self), NM_TYPE_SETTING_CONNECTION);
+	s_con = nm_connection_get_setting_connection (NM_CONNECTION (self));
 	g_assert (s_con);
 
 	/* Check every user in the ACL for a session */
@@ -1024,7 +1024,7 @@ check_writable (NMConnection *connection, GError **error)
 	g_return_val_if_fail (connection != NULL, FALSE);
 	g_return_val_if_fail (NM_IS_CONNECTION (connection), FALSE);
 
-	s_con = (NMSettingConnection *) nm_connection_get_setting (connection, NM_TYPE_SETTING_CONNECTION);
+	s_con = nm_connection_get_setting_connection (connection);
 	if (!s_con) {
 		g_set_error_literal (error,
 		                     NM_SETTINGS_ERROR,
@@ -1175,11 +1175,11 @@ get_modify_permission_update (NMConnection *old, NMConnection *new)
 	NMSettingConnection *s_con;
 	guint32 orig_num = 0, new_num = 0;
 
-	s_con = (NMSettingConnection *) nm_connection_get_setting (old, NM_TYPE_SETTING_CONNECTION);
+	s_con = nm_connection_get_setting_connection (old);
 	g_assert (s_con);
 	orig_num = nm_setting_connection_get_num_permissions (s_con);
 
-	s_con = (NMSettingConnection *) nm_connection_get_setting (new, NM_TYPE_SETTING_CONNECTION);
+	s_con = nm_connection_get_setting_connection (new);
 	g_assert (s_con);
 	new_num = nm_setting_connection_get_num_permissions (s_con);
 
@@ -1283,7 +1283,7 @@ get_modify_permission_basic (NMSettingsConnection *connection)
 	 * we use the 'modify.own' permission instead of 'modify.system'.  If the
 	 * request affects more than just the caller, require 'modify.system'.
 	 */
-	s_con = (NMSettingConnection *) nm_connection_get_setting (NM_CONNECTION (connection), NM_TYPE_SETTING_CONNECTION);
+	s_con = nm_connection_get_setting_connection (NM_CONNECTION (connection));
 	g_assert (s_con);
 	if (nm_setting_connection_get_num_permissions (s_con) == 1)
 		return NM_AUTH_PERMISSION_SETTINGS_MODIFY_OWN;
@@ -1422,11 +1422,14 @@ nm_settings_connection_get_timestamp (NMSettingsConnection *connection)
  * @connection: the #NMSettingsConnection
  * @timestamp: timestamp to set into the connection and to store into
  * the timestamps database
+ * @flush_to_disk: if %TRUE, commit timestamp update to persistent storage
  *
  * Updates the connection and timestamps database with the provided timestamp.
  **/
 void
-nm_settings_connection_update_timestamp (NMSettingsConnection *connection, guint64 timestamp)
+nm_settings_connection_update_timestamp (NMSettingsConnection *connection,
+                                         guint64 timestamp,
+                                         gboolean flush_to_disk)
 {
 	NMSettingsConnectionPrivate *priv = NM_SETTINGS_CONNECTION_GET_PRIVATE (connection);
 	const char *connection_uuid;
@@ -1438,6 +1441,9 @@ nm_settings_connection_update_timestamp (NMSettingsConnection *connection, guint
 	/* Update timestamp in private storage */
 	priv->timestamp = timestamp;
 
+	if (flush_to_disk == FALSE)
+		return;
+
 	/* Save timestamp to timestamps database file */
 	timestamps_file = g_key_file_new ();
 	if (!g_key_file_load_from_file (timestamps_file, SETTINGS_TIMESTAMPS_FILE, G_KEY_FILE_KEEP_COMMENTS, &error)) {
@@ -1576,7 +1582,7 @@ nm_settings_connection_add_seen_bssid (NMSettingsConnection *connection,
 		return;  /* Already in the list */
 
 	/* Add the new BSSID; let the hash take ownership of the allocated BSSID string */
-	bssid_str = nm_ether_ntop (seen_bssid);
+	bssid_str = nm_utils_hwaddr_ntoa (seen_bssid, ARPHRD_ETHER);
 	g_return_if_fail (bssid_str != NULL);
 	g_hash_table_insert (priv->seen_bssids, mac_dup (seen_bssid), bssid_str);
 
diff --git a/src/settings/nm-settings-connection.h b/src/settings/nm-settings-connection.h
index bc9e3c47..077a145d 100644
--- a/src/settings/nm-settings-connection.h
+++ b/src/settings/nm-settings-connection.h
@@ -124,7 +124,9 @@ void nm_settings_connection_signal_remove (NMSettingsConnection *self);
 
 guint64 nm_settings_connection_get_timestamp (NMSettingsConnection *connection);
 
-void nm_settings_connection_update_timestamp (NMSettingsConnection *connection, guint64 timestamp);
+void nm_settings_connection_update_timestamp (NMSettingsConnection *connection,
+                                              guint64 timestamp,
+                                              gboolean flush_to_disk);
 
 void nm_settings_connection_read_and_fill_timestamp (NMSettingsConnection *connection);
 
diff --git a/src/settings/nm-settings-error.c b/src/settings/nm-settings-error.c
index 7e24fb71..fd4eca36 100644
--- a/src/settings/nm-settings-error.c
+++ b/src/settings/nm-settings-error.c
@@ -31,53 +31,3 @@ nm_settings_error_quark (void)
 
 	return ret;
 }
-
-#define ENUM_ENTRY(NAME, DESC) { NAME, "" #NAME "", DESC }
-
-GType
-nm_settings_error_get_type (void)
-{
-	static GType etype = 0;
-
-	if (etype == 0) {
-		static const GEnumValue values[] = {
-			ENUM_ENTRY (NM_SETTINGS_ERROR_GENERAL, "GeneralError"),
-
-			/* The connection was invalid. */
-			ENUM_ENTRY (NM_SETTINGS_ERROR_INVALID_CONNECTION, "InvalidConnection"),
-			/* The connection is read-only; modifications are not allowed. */
-			ENUM_ENTRY (NM_SETTINGS_ERROR_READ_ONLY_CONNECTION, "ReadOnlyConnection"),
-			/* A bug in the settings service caused the error. */
-			ENUM_ENTRY (NM_SETTINGS_ERROR_INTERNAL_ERROR, "InternalError"),
-			/* Retrieval or request of secrets failed. */
-			ENUM_ENTRY (NM_SETTINGS_ERROR_SECRETS_UNAVAILABLE, "SecretsUnavailable"),
-			/* The request for secrets was canceled. */
-			ENUM_ENTRY (NM_SETTINGS_ERROR_SECRETS_REQUEST_CANCELED, "SecretsRequestCanceled"),
-			/* The request could not be completed because permission was denied. */
-			ENUM_ENTRY (NM_SETTINGS_ERROR_PERMISSION_DENIED, "PermissionDenied"),
-			/* The requested setting does not existing in this connection. */
-			ENUM_ENTRY (NM_SETTINGS_ERROR_INVALID_SETTING, "InvalidSetting"),
-			/* The caller does not have permission to perform this operation */
-			ENUM_ENTRY (NM_SETTINGS_ERROR_NOT_PRIVILEGED, "NotPrivileged"),
-			/* No plugin supports adding new connections */
-			ENUM_ENTRY (NM_SETTINGS_ERROR_ADD_NOT_SUPPORTED, "AddNotSupported"),
-			/* The plugin providing this connection does not support updating it */
-			ENUM_ENTRY (NM_SETTINGS_ERROR_UPDATE_NOT_SUPPORTED, "UpdateNotSupported"),
-			/* The plugin providing this connection does not support deleting it */
-			ENUM_ENTRY (NM_SETTINGS_ERROR_DELETE_NOT_SUPPORTED, "DeleteNotSupported"),
-			/* Failed to add the connection */
-			ENUM_ENTRY (NM_SETTINGS_ERROR_ADD_FAILED, "AddFailed"),
-			/* No plugin supports modifying the system hostname */
-			ENUM_ENTRY (NM_SETTINGS_ERROR_SAVE_HOSTNAME_NOT_SUPPORTED, "SaveHostnameNotSupported"),
-			/* Saving the system hostname failed */
-			ENUM_ENTRY (NM_SETTINGS_ERROR_SAVE_HOSTNAME_FAILED, "SaveHostnameFailed"),
-			/* A connection with this UUID already exists */
-			ENUM_ENTRY (NM_SETTINGS_ERROR_UUID_EXISTS, "UuidExists"),
-			{ 0, 0, 0 }
-		};
-
-		etype = g_enum_register_static ("NMSettingsError", values);
-	}
-
-	return etype;
-}
diff --git a/src/settings/nm-settings-error.h b/src/settings/nm-settings-error.h
index b782a779..82132c6f 100644
--- a/src/settings/nm-settings-error.h
+++ b/src/settings/nm-settings-error.h
@@ -25,24 +25,24 @@
 #include <glib.h>
 #include <glib-object.h>
 
-enum {
-	NM_SETTINGS_ERROR_GENERAL = 0,
-	NM_SETTINGS_ERROR_INVALID_CONNECTION,
-	NM_SETTINGS_ERROR_READ_ONLY_CONNECTION,
-	NM_SETTINGS_ERROR_INTERNAL_ERROR,
-	NM_SETTINGS_ERROR_SECRETS_UNAVAILABLE,
-	NM_SETTINGS_ERROR_SECRETS_REQUEST_CANCELED,
-	NM_SETTINGS_ERROR_PERMISSION_DENIED,
-	NM_SETTINGS_ERROR_INVALID_SETTING,
-	NM_SETTINGS_ERROR_NOT_PRIVILEGED,
-	NM_SETTINGS_ERROR_ADD_NOT_SUPPORTED,
-	NM_SETTINGS_ERROR_UPDATE_NOT_SUPPORTED,
-	NM_SETTINGS_ERROR_DELETE_NOT_SUPPORTED,
-	NM_SETTINGS_ERROR_ADD_FAILED,
-	NM_SETTINGS_ERROR_SAVE_HOSTNAME_NOT_SUPPORTED,
-	NM_SETTINGS_ERROR_SAVE_HOSTNAME_FAILED,
-	NM_SETTINGS_ERROR_UUID_EXISTS,
-};
+typedef enum {
+	NM_SETTINGS_ERROR_GENERAL = 0,                 /*< nick=GeneralError >*/
+	NM_SETTINGS_ERROR_INVALID_CONNECTION,          /*< nick=InvalidConnection >*/
+	NM_SETTINGS_ERROR_READ_ONLY_CONNECTION,        /*< nick=ReadOnlyConnection >*/
+	NM_SETTINGS_ERROR_INTERNAL_ERROR,              /*< nick=InternalError >*/
+	NM_SETTINGS_ERROR_SECRETS_UNAVAILABLE,         /*< nick=SecretsUnavailable >*/
+	NM_SETTINGS_ERROR_SECRETS_REQUEST_CANCELED,    /*< nick=SecretsRequestCanceled >*/
+	NM_SETTINGS_ERROR_PERMISSION_DENIED,           /*< nick=PermissionDenied >*/
+	NM_SETTINGS_ERROR_INVALID_SETTING,             /*< nick=InvalidSetting >*/
+	NM_SETTINGS_ERROR_NOT_PRIVILEGED,              /*< nick=NotPrivileged >*/
+	NM_SETTINGS_ERROR_ADD_NOT_SUPPORTED,           /*< nick=AddNotSupported >*/
+	NM_SETTINGS_ERROR_UPDATE_NOT_SUPPORTED,        /*< nick=UpdateNotSupported >*/
+	NM_SETTINGS_ERROR_DELETE_NOT_SUPPORTED,        /*< nick=DeleteNotSupported >*/
+	NM_SETTINGS_ERROR_ADD_FAILED,                  /*< nick=AddFailed >*/
+	NM_SETTINGS_ERROR_SAVE_HOSTNAME_NOT_SUPPORTED, /*< nick=SaveHostnameNotSupported >*/
+	NM_SETTINGS_ERROR_SAVE_HOSTNAME_FAILED,        /*< nick=SaveHostnameFailed >*/
+	NM_SETTINGS_ERROR_UUID_EXISTS,                 /*< nick=UuidExists >*/
+} NMSettingsError;
 
 #define NM_SETTINGS_ERROR (nm_settings_error_quark ())
 GQuark nm_settings_error_quark (void);
diff --git a/src/settings/nm-settings.c b/src/settings/nm-settings.c
index f0bfc162..1ead4f8b 100644
--- a/src/settings/nm-settings.c
+++ b/src/settings/nm-settings.c
@@ -29,8 +29,7 @@
 #include <string.h>
 #include <ctype.h>
 #include <gmodule.h>
-#include <net/ethernet.h>
-#include <netinet/ether.h>
+#include <net/if_arp.h>
 #include <pwd.h>
 #include <dbus/dbus.h>
 #include <dbus/dbus-glib-lowlevel.h>
@@ -52,8 +51,11 @@
 #include <nm-setting-wired.h>
 #include <nm-setting-wireless.h>
 #include <nm-setting-wireless-security.h>
+#include <nm-setting-bond.h>
+#include <nm-utils.h>
 
 #include "../nm-device-ethernet.h"
+#include "../nm-device-wired.h"
 #include "nm-dbus-glib-types.h"
 #include "nm-settings.h"
 #include "nm-settings-connection.h"
@@ -226,36 +228,49 @@ impl_settings_list_connections (NMSettings *self,
 	return TRUE;
 }
 
-static gboolean
-impl_settings_get_connection_by_uuid (NMSettings *self,
-                                      const char *uuid,
-                                      char **out_object_path,
-                                      GError **error)
+NMSettingsConnection *
+nm_settings_get_connection_by_uuid (NMSettings *self, const char *uuid)
 {
-	NMSettingsPrivate *priv = NM_SETTINGS_GET_PRIVATE (self);
+	NMSettingsPrivate *priv;
+	NMSettingsConnection *candidate;
 	GHashTableIter iter;
-	NMConnection *candidate = NULL;
-	gboolean found = FALSE;
+
+	g_return_val_if_fail (self != NULL, NULL);
+	g_return_val_if_fail (NM_IS_SETTINGS (self), NULL);
+	g_return_val_if_fail (uuid != NULL, NULL);
+
+	priv = NM_SETTINGS_GET_PRIVATE (self);
 
 	load_connections (self);
 
 	g_hash_table_iter_init (&iter, priv->connections);
 	while (g_hash_table_iter_next (&iter, NULL, (gpointer) &candidate)) {
-		if (g_strcmp0 (uuid, nm_connection_get_uuid (candidate)) == 0) {
-			*out_object_path = g_strdup (nm_connection_get_path (candidate));
-			found = TRUE;
-			break;
-		}
+		if (g_strcmp0 (uuid, nm_connection_get_uuid (NM_CONNECTION (candidate))) == 0)
+			return candidate;
 	}
 
-	if (!found) {
+	return NULL;
+}
+
+static gboolean
+impl_settings_get_connection_by_uuid (NMSettings *self,
+                                      const char *uuid,
+                                      char **out_object_path,
+                                      GError **error)
+{
+	NMSettingsConnection *connection = NULL;
+
+	connection = nm_settings_get_connection_by_uuid (self, uuid);
+	if (connection)
+		*out_object_path = g_strdup (nm_connection_get_path (NM_CONNECTION (connection)));
+	else {
 		g_set_error_literal (error,
 		                     NM_SETTINGS_ERROR,
 		                     NM_SETTINGS_ERROR_INVALID_CONNECTION,
 		                     "No connection with the UUID was found.");
 	}
 
-	return found;
+	return !!connection;
 }
 
 static int
@@ -267,9 +282,9 @@ connection_sort (gconstpointer pa, gconstpointer pb)
 	NMSettingConnection *con_b;
 	guint64 ts_a, ts_b;
 
-	con_a = (NMSettingConnection *) nm_connection_get_setting (a, NM_TYPE_SETTING_CONNECTION);
+	con_a = nm_connection_get_setting_connection (a);
 	g_assert (con_a);
-	con_b = (NMSettingConnection *) nm_connection_get_setting (b, NM_TYPE_SETTING_CONNECTION);
+	con_b = nm_connection_get_setting_connection (b);
 	g_assert (con_b);
 
 	if (nm_setting_connection_get_autoconnect (con_a) != nm_setting_connection_get_autoconnect (con_b)) {
@@ -549,6 +564,7 @@ find_plugin (GSList *list, const char *pname)
 static gboolean
 load_plugins (NMSettings *self, const char **plugins, GError **error)
 {
+	NMSettingsPrivate *priv = NM_SETTINGS_GET_PRIVATE (self);
 	GSList *list = NULL;
 	const char **iter;
 	gboolean success = TRUE;
@@ -558,7 +574,7 @@ load_plugins (NMSettings *self, const char **plugins, GError **error)
 		char *full_name, *path;
 		const char *pname = *iter;
 		GObject *obj;
-		GObject * (*factory_func) (void);
+		GObject * (*factory_func) (const char *);
 
 		/* strip leading spaces */
 		while (isblank (*pname))
@@ -601,7 +617,7 @@ load_plugins (NMSettings *self, const char **plugins, GError **error)
 			break;
 		}
 
-		obj = (*factory_func) ();
+		obj = (*factory_func) (priv->config_file);
 		if (!obj || !NM_IS_SYSTEM_CONFIG_INTERFACE (obj)) {
 			g_set_error (error, 0, 0,
 			             "Plugin '%s' returned invalid system config object.",
@@ -901,6 +917,45 @@ add_new_connection (NMSettings *self,
 	return NULL;
 }
 
+static gboolean
+secrets_filter_cb (NMSetting *setting,
+                   const char *secret,
+                   NMSettingSecretFlags flags,
+                   gpointer user_data)
+{
+	NMSettingSecretFlags filter_flags = GPOINTER_TO_UINT (user_data);
+
+	/* Returns TRUE to remove the secret */
+
+	/* 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
+send_agent_owned_secrets (NMSettings *self,
+                          NMSettingsConnection *connection,
+                          gulong caller_uid)
+{
+	NMSettingsPrivate *priv = NM_SETTINGS_GET_PRIVATE (self);
+	NMConnection *for_agent;
+
+	/* Dupe the connection so we can clear out non-agent-owned secrets,
+	 * as agent-owned secrets are the only ones we send back to be saved.
+	 * Only send secrets to agents of the same UID that called update too.
+	 */
+	for_agent = nm_connection_duplicate (NM_CONNECTION (connection));
+	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 (priv->agent_mgr, for_agent, TRUE, caller_uid);
+	g_object_unref (for_agent);
+}
+
 static void
 pk_add_cb (NMAuthChain *chain,
            GError *chain_error,
@@ -915,6 +970,7 @@ pk_add_cb (NMAuthChain *chain,
 	NMSettingsConnection *added = NULL;
 	NMSettingsAddCallback callback;
 	gpointer callback_data;
+	gulong caller_uid;
 	const char *perm;
 
 	priv->auths = g_slist_remove (priv->auths, chain);
@@ -954,9 +1010,14 @@ pk_add_cb (NMAuthChain *chain,
 done:
 	callback = nm_auth_chain_get_data (chain, "callback");
 	callback_data = nm_auth_chain_get_data (chain, "callback-data");
+	caller_uid = nm_auth_chain_get_data_ulong (chain, "caller-uid");
 
 	callback (self, added, error, context, callback_data);
 
+	/* Send agent-owned secrets to the agents */
+	if (!error && added)
+		send_agent_owned_secrets (self, added, caller_uid);
+
 	g_clear_error (&error);
 	nm_auth_chain_unref (chain);
 }
@@ -974,6 +1035,38 @@ add_cb (NMSettings *self,
 		dbus_g_method_return (context, nm_connection_get_path (NM_CONNECTION (connection)));
 }
 
+/* FIXME: remove if/when kernel supports adhoc wpa */
+static gboolean
+is_adhoc_wpa (NMConnection *connection)
+{
+	NMSettingWireless *s_wifi;
+	NMSettingWirelessSecurity *s_wsec;
+	const char *mode, *key_mgmt;
+
+	/* The kernel doesn't support Ad-Hoc WPA connections well at this time,
+	 * and turns them into open networks.  It's been this way since at least
+	 * 2.6.30 or so; until that's fixed, disable WPA-protected Ad-Hoc networks.
+	 */
+
+	s_wifi = nm_connection_get_setting_wireless (connection);
+	if (!s_wifi)
+		return FALSE;
+
+	mode = nm_setting_wireless_get_mode (s_wifi);
+	if (g_strcmp0 (mode, NM_SETTING_WIRELESS_MODE_ADHOC) != 0)
+		return FALSE;
+
+	s_wsec = nm_connection_get_setting_wireless_security (connection);
+	if (!s_wsec)
+		return FALSE;
+
+	key_mgmt = nm_setting_wireless_security_get_key_mgmt (s_wsec);
+	if (g_strcmp0 (key_mgmt, "wpa-none") != 0)
+		return FALSE;
+
+	return TRUE;
+}
+
 void
 nm_settings_add_connection (NMSettings *self,
                             NMConnection *connection,
@@ -1001,6 +1094,19 @@ nm_settings_add_connection (NMSettings *self,
 		return;
 	}
 
+	/* The kernel doesn't support Ad-Hoc WPA connections well at this time,
+	 * and turns them into open networks.  It's been this way since at least
+	 * 2.6.30 or so; until that's fixed, disable WPA-protected Ad-Hoc networks.
+	 */
+	if (is_adhoc_wpa (connection)) {
+		error = g_error_new_literal (NM_SETTINGS_ERROR,
+		                             NM_SETTINGS_ERROR_INVALID_CONNECTION,
+		                             "WPA Ad-Hoc disabled due to kernel bugs");
+		callback (self, NULL, error, context, user_data);
+		g_error_free (error);
+		return;
+	}
+
 	/* Do any of the plugins support adding? */
 	if (!get_plugin (self, NM_SYSTEM_CONFIG_INTERFACE_CAP_MODIFY_CONNECTIONS)) {
 		error = g_error_new_literal (NM_SETTINGS_ERROR,
@@ -1044,7 +1150,7 @@ nm_settings_add_connection (NMSettings *self,
 	 * we use the 'modify.own' permission instead of 'modify.system'.  If the
 	 * request affects more than just the caller, require 'modify.system'.
 	 */
-	s_con = (NMSettingConnection *) nm_connection_get_setting (connection, NM_TYPE_SETTING_CONNECTION);
+	s_con = nm_connection_get_setting_connection (connection);
 	g_assert (s_con);
 	if (nm_setting_connection_get_num_permissions (s_con) == 1)
 		perm = NM_AUTH_PERMISSION_SETTINGS_MODIFY_OWN;
@@ -1060,6 +1166,7 @@ nm_settings_add_connection (NMSettings *self,
 	nm_auth_chain_set_data (chain, "connection", g_object_ref (connection), g_object_unref);
 	nm_auth_chain_set_data (chain, "callback", callback, NULL);
 	nm_auth_chain_set_data (chain, "callback-data", user_data, NULL);
+	nm_auth_chain_set_data_ulong (chain, "caller-uid", caller_uid);
 }
 
 static void
@@ -1172,13 +1279,14 @@ impl_settings_save_hostname (NMSettings *self,
 }
 
 static gboolean
-have_connection_for_device (NMSettings *self, GByteArray *mac)
+have_connection_for_device (NMSettings *self, GByteArray *mac, NMDevice *device)
 {
 	NMSettingsPrivate *priv = NM_SETTINGS_GET_PRIVATE (self);
 	GHashTableIter iter;
 	gpointer data;
 	NMSettingConnection *s_con;
 	NMSettingWired *s_wired;
+	NMSettingInfiniband *s_infiniband;
 	const GByteArray *setting_mac;
 	gboolean ret = FALSE;
 
@@ -1189,16 +1297,27 @@ have_connection_for_device (NMSettings *self, GByteArray *mac)
 	g_hash_table_iter_init (&iter, priv->connections);
 	while (g_hash_table_iter_next (&iter, NULL, &data)) {
 		NMConnection *connection = NM_CONNECTION (data);
-		const char *ctype;
+		const char *ctype, *iface;
 
 		s_con = nm_connection_get_setting_connection (connection);
 		ctype = nm_setting_connection_get_connection_type (s_con);
 
+		iface = nm_connection_get_virtual_iface_name (connection);
+		if (iface) {
+			if (!strcmp (iface, nm_device_get_iface (device))) {
+				ret = TRUE;
+				break;
+			} else
+				continue;
+		}
+
 		if (   strcmp (ctype, NM_SETTING_WIRED_SETTING_NAME)
+		    && strcmp (ctype, NM_SETTING_INFINIBAND_SETTING_NAME)
 		    && strcmp (ctype, NM_SETTING_PPPOE_SETTING_NAME))
 			continue;
 
 		s_wired = nm_connection_get_setting_wired (connection);
+		s_infiniband = nm_connection_get_setting_infiniband (connection);
 
 		/* No wired setting; therefore the PPPoE connection applies to any device */
 		if (!s_wired && !strcmp (ctype, NM_SETTING_PPPOE_SETTING_NAME)) {
@@ -1206,10 +1325,15 @@ have_connection_for_device (NMSettings *self, GByteArray *mac)
 			break;
 		}
 
-		setting_mac = nm_setting_wired_get_mac_address (s_wired);
+		g_assert (s_wired != NULL || s_infiniband != NULL);
+
+		setting_mac = s_wired ?
+			nm_setting_wired_get_mac_address (s_wired) :
+			nm_setting_infiniband_get_mac_address (s_infiniband);
 		if (setting_mac) {
 			/* A connection mac-locked to this device */
-			if (!memcmp (setting_mac->data, mac->data, ETH_ALEN)) {
+			if (mac->len == setting_mac->len &&
+				!memcmp (setting_mac->data, mac->data, mac->len)) {
 				ret = TRUE;
 				break;
 			}
@@ -1225,7 +1349,7 @@ have_connection_for_device (NMSettings *self, GByteArray *mac)
 
 /* Search through the list of blacklisted MAC addresses in the config file. */
 static gboolean
-is_mac_auto_wired_blacklisted (NMSettings *self, const GByteArray *mac)
+is_mac_auto_wired_blacklisted (NMSettings *self, const GByteArray *mac, int hwaddr_type)
 {
 	NMSettingsPrivate *priv = NM_SETTINGS_GET_PRIVATE (self);
 	GKeyFile *config;
@@ -1249,15 +1373,15 @@ is_mac_auto_wired_blacklisted (NMSettings *self, const GByteArray *mac)
 
 	list = g_key_file_get_string_list (config, "main", CONFIG_KEY_NO_AUTO_DEFAULT, NULL, NULL);
 	for (iter = list; iter && *iter; iter++) {
-		struct ether_addr *candidate;
+		guint8 *candidate, buffer[NM_UTILS_HWADDR_LEN_MAX];
 
-		if (strcmp(g_strstrip(*iter), "*") == 0) {
+		if (strcmp (g_strstrip (*iter), "*") == 0) {
 			found = TRUE;
 			break;
 		}
 
-		candidate = ether_aton (*iter);
-		if (candidate && !memcmp (mac->data, candidate->ether_addr_octet, ETH_ALEN)) {
+		candidate = nm_utils_hwaddr_aton (*iter, hwaddr_type, buffer);
+		if (candidate && !memcmp (mac->data, candidate, mac->len)) {
 			found = TRUE;
 			break;
 		}
@@ -1280,6 +1404,7 @@ default_wired_deleted (NMDefaultWiredConnection *wired,
 {
 	NMSettingsPrivate *priv = NM_SETTINGS_GET_PRIVATE (self);
 	NMSettingConnection *s_con;
+	int hwaddr_type;
 	char *tmp;
 	GKeyFile *config;
 	char **list, **iter, **updated;
@@ -1297,8 +1422,7 @@ default_wired_deleted (NMDefaultWiredConnection *wired,
 	 * connection for that device again.
 	 */
 
-	s_con = (NMSettingConnection *) nm_connection_get_setting (NM_CONNECTION (wired),
-	                                                           NM_TYPE_SETTING_CONNECTION);
+	s_con = nm_connection_get_setting_connection (NM_CONNECTION (wired));
 	g_assert (s_con);
 
 	/* Ignore removals of read-only connections, since they couldn't have
@@ -1311,20 +1435,27 @@ default_wired_deleted (NMDefaultWiredConnection *wired,
 	if (!config)
 		goto cleanup;
 
+	if (nm_connection_get_setting_wired (NM_CONNECTION (wired)))
+		hwaddr_type = ARPHRD_ETHER;
+	else if (nm_connection_get_setting_infiniband (NM_CONNECTION (wired)))
+		hwaddr_type = ARPHRD_INFINIBAND;
+	else
+		goto cleanup;
+
 	g_key_file_set_list_separator (config, ',');
 	g_key_file_load_from_file (config, priv->config_file, G_KEY_FILE_KEEP_COMMENTS, NULL);
 
 	list = g_key_file_get_string_list (config, "main", CONFIG_KEY_NO_AUTO_DEFAULT, &len, NULL);
 	for (iter = list; iter && *iter; iter++) {
-		struct ether_addr *candidate;
+		guint8 *candidate, buffer[NM_UTILS_HWADDR_LEN_MAX];
 
-		if (strcmp(g_strstrip(*iter), "*") == 0) {
+		if (strcmp (g_strstrip (*iter), "*") == 0) {
 			found = TRUE;
 			break;
 		}
 
-		candidate = ether_aton (*iter);
-		if (candidate && !memcmp (mac->data, candidate->ether_addr_octet, ETH_ALEN)) {
+		candidate = nm_utils_hwaddr_aton (*iter, hwaddr_type, buffer);
+		if (candidate && !memcmp (mac->data, candidate, mac->len)) {
 			found = TRUE;
 			break;
 		}
@@ -1332,9 +1463,7 @@ default_wired_deleted (NMDefaultWiredConnection *wired,
 
 	/* Add this device's MAC to the list */
 	if (!found) {
-		tmp = g_strdup_printf ("%02x:%02x:%02x:%02x:%02x:%02x",
-		                       mac->data[0], mac->data[1], mac->data[2],
-		                       mac->data[3], mac->data[4], mac->data[5]);
+		tmp = nm_utils_hwaddr_ntoa (mac->data, hwaddr_type);
 
 		/* New list; size + 1 for the new element, + 1 again for ending NULL */
 		updated = g_malloc0 (sizeof (char*) * (len + 2));
@@ -1424,13 +1553,14 @@ nm_settings_device_added (NMSettings *self, NMDevice *device)
 {
 	NMSettingsPrivate *priv = NM_SETTINGS_GET_PRIVATE (self);
 	GByteArray *mac = NULL;
-	struct ether_addr tmp;
+	const guint8 *hwaddr;
+	int hwaddr_type;
 	NMDefaultWiredConnection *wired;
 	gboolean read_only = TRUE;
 	const char *id;
 	char *defname;
 
-	if (nm_device_get_device_type (device) != NM_DEVICE_TYPE_ETHERNET)
+	if (!NM_IS_DEVICE_WIRED (device))
 		return;
 
 	/* If the device isn't managed or it already has a default wired connection,
@@ -1440,13 +1570,14 @@ nm_settings_device_added (NMSettings *self, NMDevice *device)
 	    || g_object_get_data (G_OBJECT (device), DEFAULT_WIRED_TAG))
 		return;
 
-	nm_device_ethernet_get_address (NM_DEVICE_ETHERNET (device), &tmp);
+	hwaddr = nm_device_wired_get_hwaddr (NM_DEVICE_WIRED (device));
+	hwaddr_type = nm_device_wired_get_hwaddr_type (NM_DEVICE_WIRED (device));
 
-	mac = g_byte_array_sized_new (ETH_ALEN);
-	g_byte_array_append (mac, tmp.ether_addr_octet, ETH_ALEN);
+	mac = g_byte_array_new ();
+	g_byte_array_append (mac, hwaddr, nm_utils_hwaddr_len (hwaddr_type));
 
-	if (   have_connection_for_device (self, mac)
-	    || is_mac_auto_wired_blacklisted (self, mac))
+	if (   have_connection_for_device (self, mac, device)
+		|| is_mac_auto_wired_blacklisted (self, mac, hwaddr_type))
 		goto ignore;
 
 	if (get_plugin (self, NM_SYSTEM_CONFIG_INTERFACE_CAP_MODIFY_CONNECTIONS))
@@ -1480,7 +1611,7 @@ nm_settings_device_removed (NMSettings *self, NMDevice *device)
 {
 	NMDefaultWiredConnection *connection;
 
-	if (nm_device_get_device_type (device) != NM_DEVICE_TYPE_ETHERNET)
+	if (!NM_IS_DEVICE_WIRED (device))
 		return;
 
 	connection = (NMDefaultWiredConnection *) g_object_get_data (G_OBJECT (device), DEFAULT_WIRED_TAG);
@@ -1518,7 +1649,7 @@ nm_settings_new (const char *config_file,
 	}
 
 	/* Add the keyfile plugin last */
-	keyfile_plugin = nm_settings_keyfile_plugin_new ();
+	keyfile_plugin = nm_settings_keyfile_plugin_new (config_file);
 	g_assert (keyfile_plugin);
 	add_plugin (self, NM_SYSTEM_CONFIG_INTERFACE (keyfile_plugin));
 
diff --git a/src/settings/nm-settings.h b/src/settings/nm-settings.h
index 77485e19..9a02f8fe 100644
--- a/src/settings/nm-settings.h
+++ b/src/settings/nm-settings.h
@@ -108,6 +108,9 @@ GSList *nm_settings_get_connections (NMSettings *settings);
 NMSettingsConnection *nm_settings_get_connection_by_path (NMSettings *settings,
                                                           const char *path);
 
+NMSettingsConnection *nm_settings_get_connection_by_uuid (NMSettings *settings,
+                                                          const char *uuid);
+
 const GSList *nm_settings_get_unmanaged_specs (NMSettings *self);
 
 char *nm_settings_get_hostname (NMSettings *self);
diff --git a/src/settings/nm-system-config-interface.h b/src/settings/nm-system-config-interface.h
index 96a64061..bbe74d49 100644
--- a/src/settings/nm-system-config-interface.h
+++ b/src/settings/nm-system-config-interface.h
@@ -39,7 +39,7 @@ G_BEGIN_DECLS
 /* Plugin's factory function that returns a GObject that implements
  * NMSystemConfigInterface.
  */
-GObject * nm_system_config_factory (void);
+GObject * nm_system_config_factory (const char *config_file);
 
 #define NM_TYPE_SYSTEM_CONFIG_INTERFACE      (nm_system_config_interface_get_type ())
 #define NM_SYSTEM_CONFIG_INTERFACE(obj)      (G_TYPE_CHECK_INSTANCE_CAST ((obj), NM_TYPE_SYSTEM_CONFIG_INTERFACE, NMSystemConfigInterface))
diff --git a/src/settings/plugins/Makefile.in b/src/settings/plugins/Makefile.in
index 7c9c8784..0997f445 100644
--- a/src/settings/plugins/Makefile.in
+++ b/src/settings/plugins/Makefile.in
@@ -152,6 +152,8 @@ GIO_LIBS = @GIO_LIBS@
 GLIB_CFLAGS = @GLIB_CFLAGS@
 GLIB_GENMARSHAL = @GLIB_GENMARSHAL@
 GLIB_LIBS = @GLIB_LIBS@
+GLIB_MAKEFILE = @GLIB_MAKEFILE@
+GLIB_MKENUMS = @GLIB_MKENUMS@
 GMODULE_CFLAGS = @GMODULE_CFLAGS@
 GMODULE_LIBS = @GMODULE_LIBS@
 GMSGFMT = @GMSGFMT@
@@ -206,11 +208,15 @@ LIBNL2_LIBS = @LIBNL2_LIBS@
 LIBNL3_CFLAGS = @LIBNL3_CFLAGS@
 LIBNL3_LIBS = @LIBNL3_LIBS@
 LIBNL_CFLAGS = @LIBNL_CFLAGS@
+LIBNL_GENL3_CFLAGS = @LIBNL_GENL3_CFLAGS@
+LIBNL_GENL3_LIBS = @LIBNL_GENL3_LIBS@
 LIBNL_LIBS = @LIBNL_LIBS@
 LIBNL_ROUTE3_CFLAGS = @LIBNL_ROUTE3_CFLAGS@
 LIBNL_ROUTE3_LIBS = @LIBNL_ROUTE3_LIBS@
 LIBOBJS = @LIBOBJS@
 LIBS = @LIBS@
+LIBSOUP_CFLAGS = @LIBSOUP_CFLAGS@
+LIBSOUP_LIBS = @LIBSOUP_LIBS@
 LIBTOOL = @LIBTOOL@
 LIPO = @LIPO@
 LN_S = @LN_S@
@@ -221,6 +227,7 @@ MAINT = @MAINT@
 MAKEINFO = @MAKEINFO@
 MANIFEST_TOOL = @MANIFEST_TOOL@
 MKDIR_P = @MKDIR_P@
+MOC = @MOC@
 MSGFMT = @MSGFMT@
 MSGFMT_015 = @MSGFMT_015@
 MSGMERGE = @MSGMERGE@
@@ -260,6 +267,8 @@ SED = @SED@
 SET_MAKE = @SET_MAKE@
 SHELL = @SHELL@
 STRIP = @STRIP@
+SYSTEMD_CFLAGS = @SYSTEMD_CFLAGS@
+SYSTEMD_LIBS = @SYSTEMD_LIBS@
 SYSTEM_CA_PATH = @SYSTEM_CA_PATH@
 UDEV_BASE_DIR = @UDEV_BASE_DIR@
 USE_NLS = @USE_NLS@
diff --git a/src/settings/plugins/ifcfg-rh/Makefile.am b/src/settings/plugins/ifcfg-rh/Makefile.am
index 9874d352..8b5b0f24 100644
--- a/src/settings/plugins/ifcfg-rh/Makefile.am
+++ b/src/settings/plugins/ifcfg-rh/Makefile.am
@@ -23,11 +23,12 @@ libifcfg_rh_io_la_SOURCES = \
 	utils.h
 
 INCLUDES = \
+	-I$(top_srcdir)/src/wifi \
 	-I$(top_srcdir)/src/settings \
 	-I$(top_srcdir)/include \
+	-I$(top_builddir)/include \
 	-I$(top_srcdir)/libnm-glib \
-	-I$(top_srcdir)/libnm-util \
-	-I$(top_builddir)/marshallers
+	-I$(top_srcdir)/libnm-util
 
 libifcfg_rh_io_la_CPPFLAGS = \
 	$(GLIB_CFLAGS) \
@@ -38,6 +39,7 @@ libifcfg_rh_io_la_CPPFLAGS = \
 	-DSBINDIR=\"$(sbindir)\"
 
 libifcfg_rh_io_la_LIBADD = \
+	$(top_builddir)/src/wifi/libwifi-utils.la \
 	$(top_builddir)/libnm-util/libnm-util.la \
 	$(GLIB_LIBS) \
 	$(NSS_LIBS)
@@ -59,7 +61,6 @@ libnm_settings_plugin_ifcfg_rh_la_LDFLAGS = -module -avoid-version
 libnm_settings_plugin_ifcfg_rh_la_LIBADD = \
 	$(top_builddir)/libnm-util/libnm-util.la \
 	$(top_builddir)/libnm-glib/libnm-glib.la \
-	$(top_builddir)/marshallers/libmarshallers.la \
 	libifcfg-rh-io.la \
 	$(GLIB_LIBS) \
 	$(GMODULE_LIBS) \
diff --git a/src/settings/plugins/ifcfg-rh/Makefile.in b/src/settings/plugins/ifcfg-rh/Makefile.in
index 79b66b2d..3325c7e8 100644
--- a/src/settings/plugins/ifcfg-rh/Makefile.in
+++ b/src/settings/plugins/ifcfg-rh/Makefile.in
@@ -81,6 +81,7 @@ am__installdirs = "$(DESTDIR)$(pkglibdir)" \
 LTLIBRARIES = $(noinst_LTLIBRARIES) $(pkglib_LTLIBRARIES)
 am__DEPENDENCIES_1 =
 libifcfg_rh_io_la_DEPENDENCIES =  \
+	$(top_builddir)/src/wifi/libwifi-utils.la \
 	$(top_builddir)/libnm-util/libnm-util.la $(am__DEPENDENCIES_1) \
 	$(am__DEPENDENCIES_1)
 am_libifcfg_rh_io_la_OBJECTS = libifcfg_rh_io_la-shvar.lo \
@@ -92,9 +93,8 @@ am__v_lt_ = $(am__v_lt_$(AM_DEFAULT_VERBOSITY))
 am__v_lt_0 = --silent
 libnm_settings_plugin_ifcfg_rh_la_DEPENDENCIES =  \
 	$(top_builddir)/libnm-util/libnm-util.la \
-	$(top_builddir)/libnm-glib/libnm-glib.la \
-	$(top_builddir)/marshallers/libmarshallers.la \
-	libifcfg-rh-io.la $(am__DEPENDENCIES_1) $(am__DEPENDENCIES_1) \
+	$(top_builddir)/libnm-glib/libnm-glib.la libifcfg-rh-io.la \
+	$(am__DEPENDENCIES_1) $(am__DEPENDENCIES_1) \
 	$(am__DEPENDENCIES_1)
 am_libnm_settings_plugin_ifcfg_rh_la_OBJECTS =  \
 	libnm_settings_plugin_ifcfg_rh_la-plugin.lo \
@@ -222,6 +222,8 @@ GIO_LIBS = @GIO_LIBS@
 GLIB_CFLAGS = @GLIB_CFLAGS@
 GLIB_GENMARSHAL = @GLIB_GENMARSHAL@
 GLIB_LIBS = @GLIB_LIBS@
+GLIB_MAKEFILE = @GLIB_MAKEFILE@
+GLIB_MKENUMS = @GLIB_MKENUMS@
 GMODULE_CFLAGS = @GMODULE_CFLAGS@
 GMODULE_LIBS = @GMODULE_LIBS@
 GMSGFMT = @GMSGFMT@
@@ -276,11 +278,15 @@ LIBNL2_LIBS = @LIBNL2_LIBS@
 LIBNL3_CFLAGS = @LIBNL3_CFLAGS@
 LIBNL3_LIBS = @LIBNL3_LIBS@
 LIBNL_CFLAGS = @LIBNL_CFLAGS@
+LIBNL_GENL3_CFLAGS = @LIBNL_GENL3_CFLAGS@
+LIBNL_GENL3_LIBS = @LIBNL_GENL3_LIBS@
 LIBNL_LIBS = @LIBNL_LIBS@
 LIBNL_ROUTE3_CFLAGS = @LIBNL_ROUTE3_CFLAGS@
 LIBNL_ROUTE3_LIBS = @LIBNL_ROUTE3_LIBS@
 LIBOBJS = @LIBOBJS@
 LIBS = @LIBS@
+LIBSOUP_CFLAGS = @LIBSOUP_CFLAGS@
+LIBSOUP_LIBS = @LIBSOUP_LIBS@
 LIBTOOL = @LIBTOOL@
 LIPO = @LIPO@
 LN_S = @LN_S@
@@ -291,6 +297,7 @@ MAINT = @MAINT@
 MAKEINFO = @MAKEINFO@
 MANIFEST_TOOL = @MANIFEST_TOOL@
 MKDIR_P = @MKDIR_P@
+MOC = @MOC@
 MSGFMT = @MSGFMT@
 MSGFMT_015 = @MSGFMT_015@
 MSGMERGE = @MSGMERGE@
@@ -330,6 +337,8 @@ SED = @SED@
 SET_MAKE = @SET_MAKE@
 SHELL = @SHELL@
 STRIP = @STRIP@
+SYSTEMD_CFLAGS = @SYSTEMD_CFLAGS@
+SYSTEMD_LIBS = @SYSTEMD_LIBS@
 SYSTEM_CA_PATH = @SYSTEM_CA_PATH@
 UDEV_BASE_DIR = @UDEV_BASE_DIR@
 USE_NLS = @USE_NLS@
@@ -412,11 +421,12 @@ libifcfg_rh_io_la_SOURCES = \
 	utils.h
 
 INCLUDES = \
+	-I$(top_srcdir)/src/wifi \
 	-I$(top_srcdir)/src/settings \
 	-I$(top_srcdir)/include \
+	-I$(top_builddir)/include \
 	-I$(top_srcdir)/libnm-glib \
-	-I$(top_srcdir)/libnm-util \
-	-I$(top_builddir)/marshallers
+	-I$(top_srcdir)/libnm-util
 
 libifcfg_rh_io_la_CPPFLAGS = \
 	$(GLIB_CFLAGS) \
@@ -427,6 +437,7 @@ libifcfg_rh_io_la_CPPFLAGS = \
 	-DSBINDIR=\"$(sbindir)\"
 
 libifcfg_rh_io_la_LIBADD = \
+	$(top_builddir)/src/wifi/libwifi-utils.la \
 	$(top_builddir)/libnm-util/libnm-util.la \
 	$(GLIB_LIBS) \
 	$(NSS_LIBS)
@@ -448,7 +459,6 @@ libnm_settings_plugin_ifcfg_rh_la_LDFLAGS = -module -avoid-version
 libnm_settings_plugin_ifcfg_rh_la_LIBADD = \
 	$(top_builddir)/libnm-util/libnm-util.la \
 	$(top_builddir)/libnm-glib/libnm-glib.la \
-	$(top_builddir)/marshallers/libmarshallers.la \
 	libifcfg-rh-io.la \
 	$(GLIB_LIBS) \
 	$(GMODULE_LIBS) \
diff --git a/src/settings/plugins/ifcfg-rh/common.h b/src/settings/plugins/ifcfg-rh/common.h
index 74a77c4c..fc8ce22a 100644
--- a/src/settings/plugins/ifcfg-rh/common.h
+++ b/src/settings/plugins/ifcfg-rh/common.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.
  *
- * (C) Copyright 2008 - 2010 Red Hat, Inc.
+ * (C) Copyright 2008 - 2011 Red Hat, Inc.
  */
 
 #ifndef __COMMON_H__
@@ -41,9 +41,12 @@
 #define IFCFG_PLUGIN_NAME "ifcfg-rh"
 #define IFCFG_PLUGIN_INFO "(c) 2007 - 2010 Red Hat, Inc.  To report bugs please use the NetworkManager mailing list."
 
-#define TYPE_ETHERNET "Ethernet"
-#define TYPE_WIRELESS "Wireless"
-#define TYPE_BRIDGE   "Bridge"
+#define TYPE_ETHERNET   "Ethernet"
+#define TYPE_WIRELESS   "Wireless"
+#define TYPE_INFINIBAND "InfiniBand"
+#define TYPE_BRIDGE     "Bridge"
+#define TYPE_BOND       "Bond"
+#define TYPE_VLAN       "Vlan"
 
 #define SECRET_FLAG_AGENT "user"
 #define SECRET_FLAG_NOT_SAVED "ask"
diff --git a/src/settings/plugins/ifcfg-rh/plugin.c b/src/settings/plugins/ifcfg-rh/plugin.c
index b4be4cba..04d5463c 100644
--- a/src/settings/plugins/ifcfg-rh/plugin.c
+++ b/src/settings/plugins/ifcfg-rh/plugin.c
@@ -569,7 +569,7 @@ impl_ifcfgrh_get_ifcfg_details (SCPluginIfcfg *plugin,
 		return FALSE;
 	}
 
-	s_con = (NMSettingConnection *) nm_connection_get_setting (NM_CONNECTION (connection), NM_TYPE_SETTING_CONNECTION);
+	s_con = nm_connection_get_setting_connection (NM_CONNECTION (connection));
 	if (!s_con) {
 		g_set_error (error,
 		             NM_SETTINGS_ERROR,
@@ -790,7 +790,7 @@ system_config_interface_init (NMSystemConfigInterface *system_config_interface_c
 }
 
 G_MODULE_EXPORT GObject *
-nm_system_config_factory (void)
+nm_system_config_factory (const char *config_file)
 {
 	static SCPluginIfcfg *singleton = NULL;
 	SCPluginIfcfgPrivate *priv;
diff --git a/src/settings/plugins/ifcfg-rh/reader.c b/src/settings/plugins/ifcfg-rh/reader.c
index 910cca35..01d83c1b 100644
--- a/src/settings/plugins/ifcfg-rh/reader.c
+++ b/src/settings/plugins/ifcfg-rh/reader.c
@@ -15,7 +15,7 @@
  * with this program; if not, write to the Free Software Foundation, Inc.,
  * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
  *
- * Copyright (C) 2008 - 2011 Red Hat, Inc.
+ * Copyright (C) 2008 - 2012 Red Hat, Inc.
  */
 
 #include <config.h>
@@ -33,25 +33,22 @@
 #include <netinet/ether.h>
 #include <linux/if.h>
 
-#ifndef __user
-#define __user
-#endif
-#include <linux/types.h>
-#include <wireless.h>
-#undef __user
-
 #include <glib.h>
 #include <glib/gi18n.h>
 #include <nm-connection.h>
 #include <NetworkManager.h>
 #include <nm-setting-connection.h>
 #include <nm-setting-ip4-config.h>
+#include <nm-setting-vlan.h>
 #include <nm-setting-ip6-config.h>
 #include <nm-setting-wired.h>
 #include <nm-setting-wireless.h>
 #include <nm-setting-8021x.h>
+#include <nm-setting-bond.h>
 #include <nm-utils.h>
 
+#include "wifi-utils.h"
+
 #include "common.h"
 #include "shvar.h"
 #include "utils.h"
@@ -77,16 +74,46 @@ get_int (const char *str, int *value)
 	return TRUE;
 }
 
+static char *
+make_connection_name (shvarFile *ifcfg,
+                      const char *ifcfg_name,
+                      const char *suggested,
+                      const char *prefix)
+{
+	char *full_name = NULL, *name;
+
+	/* If the ifcfg file already has a NAME, always use that */
+	name = svGetValue (ifcfg, "NAME", FALSE);
+	if (name && strlen (name))
+		return name;
+
+	/* Otherwise construct a new NAME */
+	g_free (name);
+	if (!prefix)
+		prefix = _("System");
+
+	/* For cosmetic reasons, if the suggested name is the same as
+	 * the ifcfg files name, don't use it.  Mainly for wifi so that
+	 * the SSID is shown in the connection ID instead of just "wlan0".
+	 */
+	if (suggested && strcmp (ifcfg_name, suggested))
+		full_name = g_strdup_printf ("%s %s (%s)", prefix, suggested, ifcfg_name);
+	else
+		full_name = g_strdup_printf ("%s %s", prefix, ifcfg_name);
+
+	return full_name;
+}
+
 static NMSetting *
 make_connection_setting (const char *file,
                          shvarFile *ifcfg,
                          const char *type,
-                         const char *suggested)
+                         const char *suggested,
+                         const char *prefix)
 {
 	NMSettingConnection *s_con;
 	const char *ifcfg_name = NULL;
-	char *new_id = NULL, *uuid = NULL, *value;
-	char *ifcfg_id;
+	char *new_id, *uuid = NULL, *zone = NULL, *value;
 
 	ifcfg_name = utils_get_ifcfg_name (file, TRUE);
 	if (!ifcfg_name)
@@ -94,32 +121,9 @@ make_connection_setting (const char *file,
 
 	s_con = NM_SETTING_CONNECTION (nm_setting_connection_new ());
 
-	/* Try the ifcfg file's internally defined name if available */
-	ifcfg_id = svGetValue (ifcfg, "NAME", FALSE);
-	if (ifcfg_id && strlen (ifcfg_id))
-		g_object_set (s_con, NM_SETTING_CONNECTION_ID, ifcfg_id, NULL);
-
-	if (!nm_setting_connection_get_id (s_con)) {
-		if (suggested) {
-			/* For cosmetic reasons, if the suggested name is the same as
-			 * the ifcfg files name, don't use it.  Mainly for wifi so that
-			 * the SSID is shown in the connection ID instead of just "wlan0".
-			 */
-			if (strcmp (ifcfg_name, suggested)) {
-				new_id = g_strdup_printf ("%s %s (%s)", reader_get_prefix (), suggested, ifcfg_name);
-				g_object_set (s_con, NM_SETTING_CONNECTION_ID, new_id, NULL);
-			}
-		}
-
-		/* Use the ifcfg file's name as a last resort */
-		if (!nm_setting_connection_get_id (s_con)) {
-			new_id = g_strdup_printf ("%s %s", reader_get_prefix (), ifcfg_name);
-			g_object_set (s_con, NM_SETTING_CONNECTION_ID, new_id, NULL);
-		}
-	}
-
+	new_id = make_connection_name (ifcfg, ifcfg_name, suggested, prefix);
+	g_object_set (s_con, NM_SETTING_CONNECTION_ID, new_id, NULL);
 	g_free (new_id);
-	g_free (ifcfg_id);
 
 	/* Try for a UUID key before falling back to hashing the file name */
 	uuid = svGetValue (ifcfg, "UUID", FALSE);
@@ -127,6 +131,7 @@ make_connection_setting (const char *file,
 		g_free (uuid);
 		uuid = nm_utils_uuid_generate_from_string (ifcfg->fileName);
 	}
+
 	g_object_set (s_con,
 	              NM_SETTING_CONNECTION_TYPE, type,
 	              NM_SETTING_CONNECTION_UUID, uuid,
@@ -153,14 +158,23 @@ make_connection_setting (const char *file,
 		g_strfreev (items);
 	}
 
+
+	zone = svGetValue(ifcfg, "ZONE", FALSE);
+	if (!zone || !strlen (zone)) {
+		g_free (zone);
+		zone = NULL;
+	}
+	g_object_set (s_con, NM_SETTING_CONNECTION_ZONE, zone, NULL);
+	g_free (zone);
+
 	return NM_SETTING (s_con);
 }
 
 static gboolean
-read_mac_address (shvarFile *ifcfg, const char *key, GByteArray **array, GError **error)
+read_mac_address (shvarFile *ifcfg, const char *key, int type,
+                  GByteArray **array, GError **error)
 {
 	char *value = NULL;
-	struct ether_addr *mac;
 
 	g_return_val_if_fail (ifcfg != NULL, FALSE);
 	g_return_val_if_fail (array != NULL, FALSE);
@@ -174,8 +188,8 @@ read_mac_address (shvarFile *ifcfg, const char *key, GByteArray **array, GError
 		return TRUE;
 	}
 
-	mac = ether_aton (value);
-	if (!mac) {
+	*array = nm_utils_hwaddr_atoba (value, type);
+	if (!*array) {
 		g_set_error (error, IFCFG_PLUGIN_ERROR, 0,
 		             "%s: the MAC address '%s' was invalid.", key, value);
 		g_free (value);
@@ -183,8 +197,6 @@ read_mac_address (shvarFile *ifcfg, const char *key, GByteArray **array, GError
 	}
 
 	g_free (value);
-	*array = g_byte_array_sized_new (ETH_ALEN);
-	g_byte_array_append (*array, (guint8 *) mac->ether_addr_octet, ETH_ALEN);
 	return TRUE;
 }
 
@@ -266,7 +278,7 @@ fill_ip4_setting_from_ibft (shvarFile *ifcfg,
 		goto done;
 	}
 
-	if (!read_mac_address (ifcfg, "HWADDR", &ifcfg_mac, error))
+	if (!read_mac_address (ifcfg, "HWADDR", ARPHRD_ETHER, &ifcfg_mac, error))
 		goto done;
 	/* Ensure we got a MAC */
 	if (!ifcfg_mac) {
@@ -627,7 +639,6 @@ read_one_ip4_route (shvarFile *ifcfg,
 
 	g_return_val_if_fail (ifcfg != NULL, NULL);
 	g_return_val_if_fail (network_file != NULL, NULL);
-	g_return_val_if_fail (which >= 0, NULL);
 
 	route = nm_ip4_route_new ();
 
@@ -1115,7 +1126,7 @@ static NMSetting *
 make_ip4_setting (shvarFile *ifcfg,
                   const char *network_file,
                   const char *iscsiadm_path,
-                  gboolean valid_ip6_config,
+                  gboolean can_disable_ip4,
                   GError **error)
 {
 	NMSettingIP4Config *s_ip4 = NULL;
@@ -1230,7 +1241,7 @@ make_ip4_setting (shvarFile *ifcfg,
 		    && !tmp_ip4_0 && !tmp_prefix_0 && !tmp_netmask_0
 		    && !tmp_ip4_1 && !tmp_prefix_1 && !tmp_netmask_1
 		    && !tmp_ip4_2 && !tmp_prefix_2 && !tmp_netmask_2) {
-			if (valid_ip6_config)
+			if (can_disable_ip4)
 				/* Nope, no IPv4 */
 				method = NM_SETTING_IP4_CONFIG_METHOD_DISABLED;
 			else
@@ -1255,7 +1266,7 @@ make_ip4_setting (shvarFile *ifcfg,
 	              NM_SETTING_IP4_CONFIG_IGNORE_AUTO_DNS, !svTrueValue (ifcfg, "PEERDNS", TRUE),
 	              NM_SETTING_IP4_CONFIG_IGNORE_AUTO_ROUTES, !svTrueValue (ifcfg, "PEERROUTES", TRUE),
 	              NM_SETTING_IP4_CONFIG_NEVER_DEFAULT, never_default,
-	              NM_SETTING_IP4_CONFIG_MAY_FAIL, !svTrueValue (ifcfg, "IPV4_FAILURE_FATAL", TRUE),
+	              NM_SETTING_IP4_CONFIG_MAY_FAIL, !svTrueValue (ifcfg, "IPV4_FAILURE_FATAL", FALSE),
 	              NULL);
 
 	if (strcmp (method, NM_SETTING_IP4_CONFIG_METHOD_DISABLED) == 0)
@@ -1424,6 +1435,9 @@ make_ip6_setting (shvarFile *ifcfg,
 	guint32 i;
 	shvarFile *network_ifcfg;
 	gboolean never_default = FALSE, tmp_success;
+	gboolean ip6_privacy, ip6_privacy_prefer_public_ip;
+	char *ip6_privacy_str;
+	NMSettingIP6ConfigPrivacy ip6_privacy_val;
 
 	s_ip6 = (NMSettingIP6Config *) nm_setting_ip6_config_new ();
 	if (!s_ip6) {
@@ -1510,12 +1524,29 @@ make_ip6_setting (shvarFile *ifcfg,
 	}
 	/* TODO - handle other methods */
 
+	/* Read IPv6 Privacy Extensions configuration */
+	ip6_privacy_str = svGetValue (ifcfg, "IPV6_PRIVACY", FALSE);
+	if (ip6_privacy_str) {
+		ip6_privacy = svTrueValue (ifcfg, "IPV6_PRIVACY", FALSE);
+		if (!ip6_privacy)
+			ip6_privacy = g_strcmp0 (ip6_privacy_str, "rfc4941") == 0 ||
+			              g_strcmp0 (ip6_privacy_str, "rfc3041") == 0;
+	}
+	ip6_privacy_prefer_public_ip = svTrueValue (ifcfg, "IPV6_PRIVACY_PREFER_PUBLIC_IP", FALSE);
+	ip6_privacy_val = ip6_privacy_str ?
+	                      (ip6_privacy ?
+	                          (ip6_privacy_prefer_public_ip ? NM_SETTING_IP6_CONFIG_PRIVACY_PREFER_PUBLIC_ADDR : NM_SETTING_IP6_CONFIG_PRIVACY_PREFER_TEMP_ADDR) :
+	                          NM_SETTING_IP6_CONFIG_PRIVACY_DISABLED) :
+	                      NM_SETTING_IP6_CONFIG_PRIVACY_UNKNOWN;
+	g_free (ip6_privacy_str);
+
 	g_object_set (s_ip6,
 	              NM_SETTING_IP6_CONFIG_METHOD, method,
 	              NM_SETTING_IP6_CONFIG_IGNORE_AUTO_DNS, !svTrueValue (ifcfg, "IPV6_PEERDNS", TRUE),
 	              NM_SETTING_IP6_CONFIG_IGNORE_AUTO_ROUTES, !svTrueValue (ifcfg, "IPV6_PEERROUTES", TRUE),
 	              NM_SETTING_IP6_CONFIG_NEVER_DEFAULT, never_default,
 	              NM_SETTING_IP6_CONFIG_MAY_FAIL, !svTrueValue (ifcfg, "IPV6_FAILURE_FATAL", FALSE),
+	              NM_SETTING_IP6_CONFIG_IP6_PRIVACY, ip6_privacy_val,
 	              NULL);
 
 	/* Don't bother to read IP, DNS and routes when IPv6 is disabled */
@@ -1926,6 +1957,7 @@ parse_wpa_psk (shvarFile *ifcfg,
 {
 	shvarFile *keys_ifcfg;
 	char *psk = NULL, *p, *hashed = NULL;
+	size_t plen;
 	gboolean quoted = FALSE;
 
 	/* Passphrase must be between 10 and 66 characters in length because WPA
@@ -1949,8 +1981,10 @@ parse_wpa_psk (shvarFile *ifcfg,
 		return NULL;
 
 	p = psk;
+	plen = strlen (p);
 
-	if (p[0] == '"' && psk[strlen (psk) - 1] == '"')
+	if (   (plen >= 2 && (p[0] == '"' || p[0] == '\'') && p[0] == p[plen - 1])
+	    || (plen >= 3 && p[0] == '$' && p[1] == '\'' && p[1] == p[plen - 1]))
 		quoted = TRUE;
 
 	if (!quoted && (strlen (psk) == 64)) {
@@ -1970,21 +2004,18 @@ parse_wpa_psk (shvarFile *ifcfg,
 		 * and between 8 and 63 characters as a passphrase.
 		 */
 
-		if (quoted) {
-			/* Get rid of the quotes */
-			p++;
-			p[strlen (p) - 1] = '\0';
-		}
+		/* Get rid of the quotes */
+		hashed = utils_single_unquote_string (p);
 
 		/* Length check */
-		if (strlen (p) < 8 || strlen (p) > 63) {
+		if (strlen (hashed) < 8 || strlen (hashed) > 63) {
 			g_set_error (error, IFCFG_PLUGIN_ERROR, 0,
 			             "Invalid WPA_PSK (passphrases must be between "
 			             "8 and 63 characters long (inclusive))");
+			g_free (hashed);
+			hashed = NULL;
 			goto out;
 		}
-
-		hashed = g_strdup (p);
 	}
 
 	if (!hashed) {
@@ -2045,18 +2076,18 @@ eap_simple_reader (const char *eap_method,
 }
 
 static char *
-get_cert_file (const char *ifcfg_path, const char *cert_path)
+get_full_file_path (const char *ifcfg_path, const char *file_path)
 {
-	const char *base = cert_path;
+	const char *base = file_path;
 	char *p, *ret, *dirname;
 
 	g_return_val_if_fail (ifcfg_path != NULL, NULL);
-	g_return_val_if_fail (cert_path != NULL, NULL);
+	g_return_val_if_fail (file_path != NULL, NULL);
 
-	if (cert_path[0] == '/')
-		return g_strdup (cert_path);
+	if (file_path[0] == '/')
+		return g_strdup (file_path);
 
-	p = strrchr (cert_path, '/');
+	p = strrchr (file_path, '/');
 	if (p)
 		base = p + 1;
 
@@ -2102,7 +2133,7 @@ eap_tls_reader (const char *eap_method,
 
 	ca_cert = svGetValue (ifcfg, ca_cert_key, FALSE);
 	if (ca_cert) {
-		real_path = get_cert_file (ifcfg->fileName, ca_cert);
+		real_path = get_full_file_path (ifcfg->fileName, ca_cert);
 		if (phase2) {
 			if (!nm_setting_802_1x_set_phase2_ca_cert (s_8021x,
 			                                           real_path,
@@ -2159,7 +2190,7 @@ eap_tls_reader (const char *eap_method,
 		goto done;
 	}
 
-	real_path = get_cert_file (ifcfg->fileName, privkey);
+	real_path = get_full_file_path (ifcfg->fileName, privkey);
 	if (phase2) {
 		if (!nm_setting_802_1x_set_phase2_private_key (s_8021x,
 		                                               real_path,
@@ -2196,7 +2227,7 @@ eap_tls_reader (const char *eap_method,
 			goto done;
 		}
 
-		real_path = get_cert_file (ifcfg->fileName, client_cert);
+		real_path = get_full_file_path (ifcfg->fileName, client_cert);
 		if (phase2) {
 			if (!nm_setting_802_1x_set_phase2_client_cert (s_8021x,
 			                                               real_path,
@@ -2246,7 +2277,7 @@ eap_peap_reader (const char *eap_method,
 
 	ca_cert = svGetValue (ifcfg, "IEEE_8021X_CA_CERT", FALSE);
 	if (ca_cert) {
-		real_cert_path = get_cert_file (ifcfg->fileName, ca_cert);
+		real_cert_path = get_full_file_path (ifcfg->fileName, ca_cert);
 		if (!nm_setting_802_1x_set_ca_cert (s_8021x,
 		                                    real_cert_path,
 		                                    NM_SETTING_802_1X_CK_SCHEME_PATH,
@@ -2352,7 +2383,7 @@ eap_ttls_reader (const char *eap_method,
 
 	ca_cert = svGetValue (ifcfg, "IEEE_8021X_CA_CERT", FALSE);
 	if (ca_cert) {
-		real_cert_path = get_cert_file (ifcfg->fileName, ca_cert);
+		real_cert_path = get_full_file_path (ifcfg->fileName, ca_cert);
 		if (!nm_setting_802_1x_set_ca_cert (s_8021x,
 		                                    real_cert_path,
 		                                    NM_SETTING_802_1X_CK_SCHEME_PATH,
@@ -2422,6 +2453,111 @@ done:
 	return success;
 }
 
+static gboolean
+eap_fast_reader (const char *eap_method,
+                 shvarFile *ifcfg,
+                 shvarFile *keys,
+                 NMSetting8021x *s_8021x,
+                 gboolean phase2,
+                 GError **error)
+{
+	char *anon_ident = NULL;
+	char *pac_file = NULL;
+	char *real_pac_path = NULL;
+	char *inner_auth = NULL;
+	char *fast_provisioning = NULL;
+	char *lower;
+	char **list = NULL, **iter;
+	const char* pac_prov_str;
+	gboolean allow_unauth = FALSE, allow_auth = FALSE;
+	gboolean success = FALSE;
+
+	pac_file = svGetValue (ifcfg, "IEEE_8021X_PAC_FILE", FALSE);
+	if (pac_file) {
+		real_pac_path = get_full_file_path (ifcfg->fileName, pac_file);
+		g_object_set (s_8021x, NM_SETTING_802_1X_PAC_FILE, real_pac_path, NULL);
+	}
+
+	fast_provisioning = svGetValue (ifcfg, "IEEE_8021X_FAST_PROVISIONING", FALSE);
+	if (fast_provisioning) {
+		list = g_strsplit_set (fast_provisioning, " \t", 0);
+		for (iter = list; iter && *iter; iter++) {
+			if (**iter == '\0')
+				continue;
+			if (strcmp (*iter, "allow-unauth") == 0)
+				allow_unauth = TRUE;
+			else if (strcmp (*iter, "allow-auth") == 0)
+				allow_auth = TRUE;
+			else {
+				PLUGIN_WARN (IFCFG_PLUGIN_NAME, "    warning: invalid IEEE_8021X_FAST_PROVISIONING '%s' "
+				             "(space-separated list of these values [allow-auth, allow-unauth] expected)",
+				             *iter);
+			}
+		}
+		g_strfreev (list);
+		list = NULL;
+	}
+	pac_prov_str = allow_unauth ? (allow_auth ? "3" : "1") : (allow_auth ? "2" : "0");
+	g_object_set (s_8021x, NM_SETTING_802_1X_PHASE1_FAST_PROVISIONING, pac_prov_str, NULL);
+
+	if (!pac_file && !(allow_unauth || allow_auth)) {
+		g_set_error (error, IFCFG_PLUGIN_ERROR, 0,
+		             "IEEE_8021X_PAC_FILE not provided and EAP-FAST automatic PAC provisioning disabled.");
+		goto done;
+	}
+
+	anon_ident = svGetValue (ifcfg, "IEEE_8021X_ANON_IDENTITY", FALSE);
+	if (anon_ident && strlen (anon_ident))
+		g_object_set (s_8021x, NM_SETTING_802_1X_ANONYMOUS_IDENTITY, anon_ident, NULL);
+
+	inner_auth = svGetValue (ifcfg, "IEEE_8021X_INNER_AUTH_METHODS", FALSE);
+	if (!inner_auth) {
+		g_set_error (error, IFCFG_PLUGIN_ERROR, 0,
+		             "Missing IEEE_8021X_INNER_AUTH_METHODS.");
+		goto done;
+	}
+
+	/* Handle options for the inner auth method */
+	list = g_strsplit (inner_auth, " ", 0);
+	for (iter = list; iter && *iter; iter++) {
+		if (!strlen (*iter))
+			continue;
+
+		if (   !strcmp (*iter, "MSCHAPV2")
+		    || !strcmp (*iter, "GTC")) {
+			if (!eap_simple_reader (*iter, ifcfg, keys, s_8021x, TRUE, error))
+				goto done;
+		} else {
+			g_set_error (error, IFCFG_PLUGIN_ERROR, 0,
+			             "Unknown IEEE_8021X_INNER_AUTH_METHOD '%s'.",
+			             *iter);
+			goto done;
+		}
+
+		lower = g_ascii_strdown (*iter, -1);
+		g_object_set (s_8021x, NM_SETTING_802_1X_PHASE2_AUTH, lower, NULL);
+		g_free (lower);
+		break;
+	}
+
+	if (!nm_setting_802_1x_get_phase2_auth (s_8021x)) {
+		g_set_error (error, IFCFG_PLUGIN_ERROR, 0,
+		             "No valid IEEE_8021X_INNER_AUTH_METHODS found.");
+		goto done;
+	}
+
+	success = TRUE;
+
+done:
+	g_strfreev (list);
+	g_free (inner_auth);
+	g_free (fast_provisioning);
+	g_free (real_pac_path);
+	g_free (pac_file);
+	g_free (anon_ident);
+	return success;
+}
+
 typedef struct {
 	const char *method;
 	gboolean (*reader)(const char *eap_method,
@@ -2443,6 +2579,7 @@ static EAPReader eap_readers[] = {
 	{ "tls", eap_tls_reader, FALSE },
 	{ "peap", eap_peap_reader, FALSE },
 	{ "ttls", eap_ttls_reader, FALSE },
+	{ "fast", eap_fast_reader, FALSE },
 	{ NULL, NULL }
 };
 
@@ -2749,7 +2886,7 @@ make_wireless_setting (shvarFile *ifcfg,
 
 	s_wireless = NM_SETTING_WIRELESS (nm_setting_wireless_new ());
 
-	if (read_mac_address (ifcfg, "HWADDR", &array, error)) {
+	if (read_mac_address (ifcfg, "HWADDR", ARPHRD_ETHER, &array, error)) {
 		if (array) {
 			g_object_set (s_wireless, NM_SETTING_WIRELESS_MAC_ADDRESS, array, NULL);
 
@@ -2773,7 +2910,7 @@ make_wireless_setting (shvarFile *ifcfg,
 	}
 
 	array = NULL;
-	if (read_mac_address (ifcfg, "MACADDR", &array, error)) {
+	if (read_mac_address (ifcfg, "MACADDR", ARPHRD_ETHER, &array, error)) {
 		if (array) {
 			g_object_set (s_wireless, NM_SETTING_WIRELESS_CLONED_MAC_ADDRESS, array, NULL);
 			g_byte_array_free (array, TRUE);
@@ -2901,19 +3038,16 @@ make_wireless_setting (shvarFile *ifcfg,
 
 	value = svGetValue (ifcfg, "BSSID", FALSE);
 	if (value) {
-		struct ether_addr *eth;
 		GByteArray *bssid;
 
-		eth = ether_aton (value);
-		if (!eth) {
+		bssid = nm_utils_hwaddr_atoba (value, ARPHRD_ETHER);
+		if (!bssid) {
 			g_set_error (error, IFCFG_PLUGIN_ERROR, 0,
 			             "Invalid BSSID '%s'", value);
 			g_free (value);
 			goto error;
 		}
 
-		bssid = g_byte_array_sized_new (ETH_ALEN);
-		g_byte_array_append (bssid, eth->ether_addr_octet, ETH_ALEN);
 		g_object_set (s_wireless, NM_SETTING_WIRELESS_BSSID, bssid, NULL);
 		g_byte_array_free (bssid, TRUE);
 		g_free (value);
@@ -3032,7 +3166,7 @@ wireless_connection_from_ifcfg (const char *file,
 	/* Connection */
 	con_setting = make_connection_setting (file, ifcfg,
 	                                       NM_SETTING_WIRELESS_SETTING_NAME,
-	                                       printable_ssid);
+	                                       printable_ssid, NULL);
 	g_free (printable_ssid);
 	if (!con_setting) {
 		g_set_error (error, IFCFG_PLUGIN_ERROR, 0,
@@ -3082,7 +3216,7 @@ make_wired_setting (shvarFile *ifcfg,
 		g_free (value);
 	}
 
-	if (read_mac_address (ifcfg, "HWADDR", &mac, error)) {
+	if (read_mac_address (ifcfg, "HWADDR", ARPHRD_ETHER, &mac, error)) {
 		if (mac) {
 			g_object_set (s_wired, NM_SETTING_WIRED_MAC_ADDRESS, mac, NULL);
 
@@ -3193,7 +3327,7 @@ make_wired_setting (shvarFile *ifcfg,
 	}
 
 	mac = NULL;
-	if (read_mac_address (ifcfg, "MACADDR", &mac, error)) {
+	if (read_mac_address (ifcfg, "MACADDR", ARPHRD_ETHER, &mac, error)) {
 		if (mac) {
 			g_object_set (s_wired, NM_SETTING_WIRED_CLONED_MAC_ADDRESS, mac, NULL);
 			g_byte_array_free (mac, TRUE);
@@ -3260,6 +3394,7 @@ wired_connection_from_ifcfg (const char *file,
 	NMSetting *con_setting = NULL;
 	NMSetting *wired_setting = NULL;
 	NMSetting8021x *s_8021x = NULL;
+	char *value;
 
 	g_return_val_if_fail (file != NULL, NULL);
 	g_return_val_if_fail (ifcfg != NULL, NULL);
@@ -3271,7 +3406,7 @@ wired_connection_from_ifcfg (const char *file,
 		return NULL;
 	}
 
-	con_setting = make_connection_setting (file, ifcfg, NM_SETTING_WIRED_SETTING_NAME, NULL);
+	con_setting = make_connection_setting (file, ifcfg, NM_SETTING_WIRED_SETTING_NAME, NULL, NULL);
 	if (!con_setting) {
 		g_set_error (error, IFCFG_PLUGIN_ERROR, 0,
 		             "Failed to create connection setting.");
@@ -3280,6 +3415,238 @@ wired_connection_from_ifcfg (const char *file,
 	}
 	nm_connection_add_setting (connection, con_setting);
 
+	/* Might be a bond slave; handle master device or connection */
+	value = svGetValue (ifcfg, "MASTER", FALSE);
+	if (value) {
+		g_object_set (con_setting, NM_SETTING_CONNECTION_MASTER, value, NULL);
+		g_object_set (con_setting,
+		              NM_SETTING_CONNECTION_SLAVE_TYPE, NM_SETTING_BOND_SETTING_NAME,
+		              NULL);
+		g_free (value);
+	}
+
+	wired_setting = make_wired_setting (ifcfg, file, nm_controlled, unmanaged, &s_8021x, error);
+	if (!wired_setting) {
+		g_object_unref (connection);
+		return NULL;
+	}
+	nm_connection_add_setting (connection, wired_setting);
+
+	if (s_8021x)
+		nm_connection_add_setting (connection, NM_SETTING (s_8021x));
+
+	if (!nm_connection_verify (connection, error)) {
+		g_object_unref (connection);
+		return NULL;
+	}
+
+	return connection;
+}
+
+static NMSetting *
+make_infiniband_setting (shvarFile *ifcfg,
+                         const char *file,
+                         gboolean nm_controlled,
+                         char **unmanaged,
+                         GError **error)
+{
+	NMSettingInfiniband *s_infiniband;
+	char *value = NULL;
+	GByteArray *mac = NULL;
+	int mtu;
+
+	s_infiniband = NM_SETTING_INFINIBAND (nm_setting_infiniband_new ());
+
+	value = svGetValue (ifcfg, "MTU", FALSE);
+	if (value) {
+		if (get_int (value, &mtu)) {
+			if (mtu >= 0 && mtu < 65536)
+				g_object_set (s_infiniband, NM_SETTING_INFINIBAND_MTU, mtu, NULL);
+		} else {
+			/* Shouldn't be fatal... */
+			PLUGIN_WARN (IFCFG_PLUGIN_NAME, "    warning: invalid MTU '%s'", value);
+		}
+		g_free (value);
+	}
+
+	if (read_mac_address (ifcfg, "HWADDR", ARPHRD_INFINIBAND, &mac, error)) {
+		if (mac) {
+			g_object_set (s_infiniband, NM_SETTING_INFINIBAND_MAC_ADDRESS, mac, NULL);
+
+			/* A connection can only be unmanaged if we know the MAC address */
+			if (!nm_controlled) {
+				char *mac_str = nm_utils_hwaddr_ntoa (mac->data, ARPHRD_INFINIBAND);
+				*unmanaged = g_strdup_printf ("mac:%s", mac_str);
+				g_free (mac_str);
+			}
+
+			g_byte_array_free (mac, TRUE);
+		}
+	} else {
+		g_object_unref (s_infiniband);
+		return NULL;
+	}
+
+	if (svTrueValue (ifcfg, "CONNECTED_MODE", FALSE))
+		g_object_set (s_infiniband, NM_SETTING_INFINIBAND_TRANSPORT_MODE, "connected", NULL);
+	else
+		g_object_set (s_infiniband, NM_SETTING_INFINIBAND_TRANSPORT_MODE, "datagram", NULL);
+
+	if (!nm_controlled && !*unmanaged) {
+		/* If NM_CONTROLLED=no but there wasn't a MAC address, notify
+		   the user that the device cannot be unmanaged.
+		 */
+		PLUGIN_WARN (IFCFG_PLUGIN_NAME, "    warning: NM_CONTROLLED was false but HWADDR was missing; device will be managed");
+	}
+
+	return (NMSetting *) s_infiniband;
+}
+
+static NMConnection *
+infiniband_connection_from_ifcfg (const char *file,
+                                  shvarFile *ifcfg,
+                                  gboolean nm_controlled,
+                                  char **unmanaged,
+                                  GError **error)
+{
+	NMConnection *connection = NULL;
+	NMSetting *con_setting = NULL;
+	NMSetting *infiniband_setting = NULL;
+
+	g_return_val_if_fail (file != NULL, NULL);
+	g_return_val_if_fail (ifcfg != NULL, NULL);
+
+	connection = nm_connection_new ();
+	if (!connection) {
+		g_set_error (error, IFCFG_PLUGIN_ERROR, 0,
+		             "Failed to allocate new connection for %s.", file);
+		return NULL;
+	}
+
+	con_setting = make_connection_setting (file, ifcfg, NM_SETTING_INFINIBAND_SETTING_NAME, NULL, NULL);
+	if (!con_setting) {
+		g_set_error (error, IFCFG_PLUGIN_ERROR, 0,
+		             "Failed to create connection setting.");
+		g_object_unref (connection);
+		return NULL;
+	}
+	nm_connection_add_setting (connection, con_setting);
+
+	infiniband_setting = make_infiniband_setting (ifcfg, file, nm_controlled, unmanaged, error);
+	if (!infiniband_setting) {
+		g_object_unref (connection);
+		return NULL;
+	}
+	nm_connection_add_setting (connection, infiniband_setting);
+
+	if (!nm_connection_verify (connection, error)) {
+		g_object_unref (connection);
+		return NULL;
+	}
+
+	return connection;
+}
+
+static void
+handle_bond_option (NMSettingBond *s_bond,
+                    const char *key,
+                    const char *value)
+{
+	if (!nm_setting_bond_add_option (s_bond, key, value))
+		PLUGIN_WARN (IFCFG_PLUGIN_NAME, "    warning: invalid bonding option '%s'", key);
+}
+
+static NMSetting *
+make_bond_setting (shvarFile *ifcfg,
+                   const char *file,
+                   gboolean nm_controlled,
+                   char **unmanaged,
+                   GError **error)
+{
+	NMSettingBond *s_bond;
+	char *value;
+
+	s_bond = NM_SETTING_BOND (nm_setting_bond_new ());
+
+	value = svGetValue (ifcfg, "DEVICE", FALSE);
+	if (!value || !strlen (value)) {
+		g_set_error (error, IFCFG_PLUGIN_ERROR, 0, "mandatory DEVICE keyword missing");
+		goto error;
+	}
+
+	g_object_set (s_bond, NM_SETTING_BOND_INTERFACE_NAME, value, NULL);
+	g_free (value);
+
+	value = svGetValue (ifcfg, "BONDING_OPTS", FALSE);
+	if (value) {
+		char **items, **iter;
+
+		items = g_strsplit_set (value, " ", -1);
+		for (iter = items; iter && *iter; iter++) {
+			if (strlen (*iter)) {
+				char **keys, *key, *val;
+
+				keys = g_strsplit_set (*iter, "=", 2);
+				if (keys && *keys) {
+					key = *keys;
+					val = *(keys + 1);
+					if (val && strlen(key) && strlen(val))
+						handle_bond_option (s_bond, key, val);
+				}
+
+				g_strfreev (keys);
+			}
+		}
+		g_free (value);
+		g_strfreev (items);
+	}
+
+	return (NMSetting *) s_bond;
+
+error:
+	g_object_unref (s_bond);
+	return NULL;
+}
+
+static NMConnection *
+bond_connection_from_ifcfg (const char *file,
+                            shvarFile *ifcfg,
+                            gboolean nm_controlled,
+                            char **unmanaged,
+                            GError **error)
+{
+	NMConnection *connection = NULL;
+	NMSetting *con_setting = NULL;
+	NMSetting *bond_setting = NULL;
+	NMSetting *wired_setting = NULL;
+	NMSetting8021x *s_8021x = NULL;
+
+	g_return_val_if_fail (file != NULL, NULL);
+	g_return_val_if_fail (ifcfg != NULL, NULL);
+
+	connection = nm_connection_new ();
+	if (!connection) {
+		g_set_error (error, IFCFG_PLUGIN_ERROR, 0,
+		             "Failed to allocate new connection for %s.", file);
+		return NULL;
+	}
+
+	con_setting = make_connection_setting (file, ifcfg, NM_SETTING_BOND_SETTING_NAME, NULL, _("Bond"));
+	if (!con_setting) {
+		g_set_error (error, IFCFG_PLUGIN_ERROR, 0,
+		             "Failed to create connection setting.");
+		g_object_unref (connection);
+		return NULL;
+	}
+	nm_connection_add_setting (connection, con_setting);
+
+	bond_setting = make_bond_setting (ifcfg, file, nm_controlled, unmanaged, error);
+	if (!bond_setting) {
+		g_object_unref (connection);
+		return NULL;
+	}
+	nm_connection_add_setting (connection, bond_setting);
+
 	wired_setting = make_wired_setting (ifcfg, file, nm_controlled, unmanaged, &s_8021x, error);
 	if (!wired_setting) {
 		g_object_unref (connection);
@@ -3299,50 +3666,245 @@ wired_connection_from_ifcfg (const char *file,
 }
 
 static gboolean
-is_wireless_device (const char *iface)
+is_bond_device (const char *name, shvarFile *parsed)
 {
-	int fd;
-	struct iw_range range;
-	struct iwreq wrq;
-	gboolean is_wireless = FALSE;
+	g_return_val_if_fail (name != NULL, FALSE);
+	g_return_val_if_fail (parsed != NULL, FALSE);
+
+	if (svTrueValue (parsed, "BONDING_MASTER", FALSE))
+		return TRUE;
+	
+	/* XXX: Check for "bond[\d]+"? */
 
-	g_return_val_if_fail (iface != NULL, FALSE);
+	return FALSE;
+}
 
-	fd = socket(AF_INET, SOCK_DGRAM, 0);
-	if (fd == -1)
-		return FALSE;
+static gboolean
+is_vlan_device (const char *name, shvarFile *parsed)
+{
+	g_return_val_if_fail (name != NULL, FALSE);
+	g_return_val_if_fail (parsed != NULL, FALSE);
 
-	memset (&wrq, 0, sizeof (struct iwreq));
-	memset (&range, 0, sizeof (struct iw_range));
-	strncpy (wrq.ifr_name, iface, IFNAMSIZ);
-	wrq.u.data.pointer = (caddr_t) &range;
-	wrq.u.data.length = sizeof (struct iw_range);
+	if (svTrueValue (parsed, "VLAN", FALSE))
+		return TRUE;
 
-	if (ioctl (fd, SIOCGIWRANGE, &wrq) == 0)
-		is_wireless = TRUE;
-	else {
-		if (errno == EOPNOTSUPP)
-			is_wireless = FALSE;
-		else {
-			/* Sigh... some wired devices (kvm/qemu) return EINVAL when the
-			 * device is down even though it's not a wireless device.  So try
-			 * IWNAME as a fallback.
-			 */
-			memset (&wrq, 0, sizeof (struct iwreq));
-			strncpy (wrq.ifr_name, iface, IFNAMSIZ);
-			if (ioctl (fd, SIOCGIWNAME, &wrq) == 0)
-				is_wireless = TRUE;
+	return FALSE;
+}
+
+static void
+parse_prio_map_list (NMSettingVlan *s_vlan,
+                     shvarFile *ifcfg,
+                     const char *key,
+                     NMVlanPriorityMap map)
+{
+	char *value;
+	gchar **list = NULL, **iter;
+
+	value = svGetValue (ifcfg, key, FALSE);
+	if (!value)
+		return;
+
+	list = g_strsplit_set (value, ",", -1);
+	g_free (value);
+
+	for (iter = list; iter && *iter; iter++) {
+		if (!*iter || !strchr (*iter, ':'))
+			continue;
+
+		if (!nm_setting_vlan_add_priority_str (s_vlan, map, *iter)) {
+			PLUGIN_WARN (IFCFG_PLUGIN_NAME, "    warning: invalid %s priority map item '%s'",
+			             key, *iter);
+		}
+	}
+	g_strfreev (list);
+}
+
+static NMSetting *
+make_vlan_setting (shvarFile *ifcfg,
+                   const char *file,
+                   gboolean nm_controlled,
+                   char **out_master,
+                   char **unmanaged,
+                   NMSetting8021x **s_8021x,
+                   GError **error)
+{
+	NMSettingVlan *s_vlan = NULL;
+	char *value = NULL;
+	char *iface_name = NULL;
+	char *parent = NULL;
+	const char *p = NULL, *w;
+	gboolean has_numbers = FALSE;
+	gint vlan_id = -1;
+	guint32 vlan_flags = 0;
+
+	value = svGetValue (ifcfg, "VLAN_ID", FALSE);
+	if (value) {
+		errno = 0;
+		vlan_id = (gint) g_ascii_strtoll (value, NULL, 10);
+		if (vlan_id < 0 || vlan_id > 4096 || errno) {
+			g_set_error (error, IFCFG_PLUGIN_ERROR, 0, "Invalid VLAN_ID '%s'", value);
+			g_free (value);
+			return NULL;
+		}
+		g_free (value);
+	}
+
+	/* Need DEVICE if we don't have a separate VLAN_ID property */
+	iface_name = svGetValue (ifcfg, "DEVICE", FALSE);
+	if (!iface_name && vlan_id < 0) {
+		g_set_error_literal (error, IFCFG_PLUGIN_ERROR, 0,
+		                     "Missing DEVICE property; cannot determine VLAN ID.");
+		return NULL;
+	}
+
+	s_vlan = NM_SETTING_VLAN (nm_setting_vlan_new ());
+
+	if (iface_name) {
+		g_object_set (s_vlan, NM_SETTING_VLAN_INTERFACE_NAME, iface_name, NULL);
+
+		p = strchr (iface_name, '.');
+		if (p) {
+			/* eth0.43; PHYSDEV is assumed from it */
+			parent = g_strndup (iface_name, p - iface_name);
+			p++;
+		} else {
+			/* format like vlan43; PHYSDEV or MASTER must be set */
+			if (g_str_has_prefix (iface_name, "vlan"))
+				p = iface_name + 4;
 		}
+
+		w = p;
+		while (*w && !has_numbers)
+			has_numbers = g_ascii_isdigit (*w);
+
+		/* Grab VLAN ID from interface name; this takes precedence over the
+		 * separate VLAN_ID property for backwards compat.
+		 */
+		if (has_numbers) {
+			errno = 0;
+			vlan_id = (gint) g_ascii_strtoll (p, NULL, 10);
+			if (vlan_id < 0 || vlan_id > 4095 || errno) {
+				g_set_error (error, IFCFG_PLUGIN_ERROR, 0,
+				             "Failed to determine VLAN ID from DEVICE '%s'",
+				             iface_name);
+				goto error;
+			}
+		}
+	}
+
+	if (vlan_id < 0) {
+		g_set_error_literal (error, IFCFG_PLUGIN_ERROR, 0,
+		                     "Failed to determine VLAN ID from DEVICE or VLAN_ID.");
+		goto error;
 	}
+	g_object_set (s_vlan, NM_SETTING_VLAN_ID, vlan_id, NULL);
 
-	close (fd);
-	return is_wireless;
+	if (!parent)
+		parent = svGetValue (ifcfg, "PHYSDEV", FALSE);
+	if (parent == NULL) {
+		g_set_error_literal (error, IFCFG_PLUGIN_ERROR, 0,
+		                     "Failed to determine VLAN parent from DEVICE or PHYSDEV");
+		goto error;
+	}
+	g_object_set (s_vlan, NM_SETTING_VLAN_PARENT, parent, NULL);
+
+	if (svTrueValue (ifcfg, "REORDER_HDR", FALSE))
+		vlan_flags |= NM_VLAN_FLAG_REORDER_HEADERS;
+
+	value = svGetValue (ifcfg, "VLAN_FLAGS", FALSE);
+	if (value) {
+		if (g_strstr_len (value, -1, "GVRP"))
+			vlan_flags |= NM_VLAN_FLAG_GVRP;
+		if (g_strstr_len (value, -1, "LOOSE_BINDING"))
+			vlan_flags |= NM_VLAN_FLAG_LOOSE_BINDING;
+	}
+
+	g_object_set (s_vlan, NM_SETTING_VLAN_FLAGS, vlan_flags, NULL);
+	g_free (value);
+
+	parse_prio_map_list (s_vlan, ifcfg, "VLAN_INGRESS_PRIORITY_MAP", NM_VLAN_INGRESS_MAP);
+	parse_prio_map_list (s_vlan, ifcfg, "VLAN_EGRESS_PRIORITY_MAP", NM_VLAN_EGRESS_MAP);
+
+	if (out_master)
+		*out_master = svGetValue (ifcfg, "MASTER", FALSE);
+	return (NMSetting *) s_vlan;
+
+error:
+	g_free (parent);
+	g_free (iface_name);
+	g_object_unref (s_vlan);
+	return NULL;
+}
+
+static NMConnection *
+vlan_connection_from_ifcfg (const char *file,
+                            shvarFile *ifcfg,
+                            gboolean nm_controlled,
+                            char **unmanaged,
+                            GError **error)
+{
+	NMConnection *connection = NULL;
+	NMSetting *con_setting = NULL;
+	NMSetting *wired_setting = NULL;
+	NMSetting *vlan_setting = NULL;
+	NMSetting8021x *s_8021x = NULL;
+	char *master = NULL;
+
+	g_return_val_if_fail (file != NULL, NULL);
+	g_return_val_if_fail (ifcfg != NULL, NULL);
+
+	connection = nm_connection_new ();
+	if (!connection) {
+		g_set_error (error, IFCFG_PLUGIN_ERROR, 0,
+			     "Failed to allocate new connection for %s.", file);
+		return NULL;
+	}
+
+	con_setting = make_connection_setting (file, ifcfg, NM_SETTING_VLAN_SETTING_NAME, NULL, "Vlan");
+	if (!con_setting) {
+		g_set_error (error, IFCFG_PLUGIN_ERROR, 0,
+			     "Failed to create connection setting.");
+		g_object_unref (connection);
+		return NULL;
+	}
+	nm_connection_add_setting (connection, con_setting);
+
+	vlan_setting = make_vlan_setting (ifcfg, file, nm_controlled, &master, unmanaged, &s_8021x, error);
+	if (!vlan_setting) {
+		g_object_unref (connection);
+		return NULL;
+	}
+	nm_connection_add_setting (connection, vlan_setting);
+
+	/* Handle master interface or connection */
+	if (master) {
+		g_object_set (con_setting, NM_SETTING_CONNECTION_MASTER, master, NULL);
+		g_object_set (con_setting,
+		              NM_SETTING_CONNECTION_SLAVE_TYPE, NM_SETTING_VLAN_SETTING_NAME,
+		              NULL);
+		g_free (master);
+	}
+
+	wired_setting = make_wired_setting (ifcfg, file, nm_controlled, unmanaged, &s_8021x, error);
+	if (!wired_setting) {
+		g_object_unref (connection);
+		return NULL;
+	}
+	nm_connection_add_setting (connection, wired_setting);
+
+	if (s_8021x)
+		nm_connection_add_setting (connection, NM_SETTING (s_8021x));
+	if (!nm_connection_verify (connection, error)) {
+		g_object_unref (connection);
+		return NULL;
+	}
+
+	return connection;
 }
 
 enum {
 	IGNORE_REASON_NONE = 0x00,
 	IGNORE_REASON_BRIDGE = 0x01,
-	IGNORE_REASON_VLAN = 0x02,
 };
 
 NMConnection *
@@ -3363,7 +3925,7 @@ connection_from_file (const char *filename,
 	NMSetting *s_ip4, *s_ip6;
 	const char *ifcfg_name = NULL;
 	gboolean nm_controlled = TRUE;
-	gboolean ip6_used = FALSE;
+	gboolean can_disable_ip4 = FALSE;
 	GError *error = NULL;
 	guint32 ignore_reason = IGNORE_REASON_NONE;
 
@@ -3402,9 +3964,6 @@ connection_from_file (const char *filename,
 	if (!type) {
 		char *device;
 
-		/* If no type, if the device has wireless extensions, it's wifi,
-		 * otherwise it's ethernet.
-		 */
 		device = svGetValue (parsed, "DEVICE", FALSE);
 		if (!device) {
 			g_set_error (&error, IFCFG_PLUGIN_ERROR, 0,
@@ -3422,8 +3981,12 @@ connection_from_file (const char *filename,
 		}
 
 		if (!test_type) {
+			if (is_bond_device (device, parsed))
+				type = g_strdup (TYPE_BOND);
+			else if (is_vlan_device (device, parsed))
+				type = g_strdup (TYPE_VLAN);
 			/* Test wireless extensions */
-			if (is_wireless_device (device))
+			else if (wifi_utils_is_wifi (device, NULL))
 				type = g_strdup (TYPE_WIRELESS);
 			else
 				type = g_strdup (TYPE_ETHERNET);
@@ -3456,7 +4019,14 @@ connection_from_file (const char *filename,
 		g_free (lower);
 	}
 
-	/* Ignore BRIDGE= and VLAN= connections for now too (rh #619863) */
+	if (svTrueValue (parsed, "BONDING_MASTER", FALSE) &&
+	    strcasecmp (type, TYPE_BOND)) {
+		g_set_error (&error, IFCFG_PLUGIN_ERROR, 0,
+		             "BONDING_MASTER=yes key only allowed in TYPE=bond connections");
+		goto done;
+	}
+
+	/* Ignore BRIDGE= connections for now too (rh #619863) */
 	tmp = svGetValue (parsed, "BRIDGE", FALSE);
 	if (tmp) {
 		g_free (tmp);
@@ -3464,24 +4034,21 @@ connection_from_file (const char *filename,
 		ignore_reason = IGNORE_REASON_BRIDGE;
 	}
 
-	if (nm_controlled) {
-		tmp = svGetValue (parsed, "VLAN", FALSE);
-		if (tmp) {
-			g_free (tmp);
-			nm_controlled = FALSE;
-			ignore_reason = IGNORE_REASON_VLAN;
-		}
-	}
-
 	/* Construct the connection */
 	if (!strcasecmp (type, TYPE_ETHERNET))
 		connection = wired_connection_from_ifcfg (filename, parsed, nm_controlled, unmanaged, &error);
 	else if (!strcasecmp (type, TYPE_WIRELESS))
 		connection = wireless_connection_from_ifcfg (filename, parsed, nm_controlled, unmanaged, &error);
-	else if (!strcasecmp (type, TYPE_BRIDGE)) {
+	else if (!strcasecmp (type, TYPE_INFINIBAND))
+		connection = infiniband_connection_from_ifcfg (filename, parsed, nm_controlled, unmanaged, &error);
+	else if (!strcasecmp (type, TYPE_BOND))
+		connection = bond_connection_from_ifcfg (filename, parsed, nm_controlled, unmanaged, &error);
+	else if (!strcasecmp (type, TYPE_VLAN))
+		connection = vlan_connection_from_ifcfg (filename, parsed, nm_controlled, unmanaged, &error);
+	else if (!strcasecmp (type, TYPE_BRIDGE))
 		g_set_error (&error, IFCFG_PLUGIN_ERROR, 0,
 		             "Bridge connections are not yet supported");
-	} else {
+	else {
 		g_set_error (&error, IFCFG_PLUGIN_ERROR, 0,
 		             "Unknown connection type '%s'", type);
 	}
@@ -3524,10 +4091,13 @@ connection_from_file (const char *filename,
 		nm_connection_add_setting (connection, s_ip6);
 		method = nm_setting_ip6_config_get_method (NM_SETTING_IP6_CONFIG (s_ip6));
 		if (method && strcmp (method, NM_SETTING_IP6_CONFIG_METHOD_IGNORE))
-			ip6_used = TRUE;
+			can_disable_ip4 = TRUE;
 	}
 
-	s_ip4 = make_ip4_setting (parsed, network_file, iscsiadm_path, ip6_used, &error);
+	if (utils_disabling_ip4_config_allowed (connection))
+		can_disable_ip4 = TRUE;
+
+	s_ip4 = make_ip4_setting (parsed, network_file, iscsiadm_path, can_disable_ip4, &error);
 	if (error) {
 		g_object_unref (connection);
 		connection = NULL;
@@ -3544,7 +4114,7 @@ connection_from_file (const char *filename,
 	    && !g_ascii_strcasecmp (bootproto, "ibft")) {
 		NMSettingConnection *s_con;
 
-		s_con = (NMSettingConnection *) nm_connection_get_setting (connection, NM_TYPE_SETTING_CONNECTION);
+		s_con = nm_connection_get_setting_connection (connection);
 		g_assert (s_con);
 
 		g_object_set (G_OBJECT (s_con), NM_SETTING_CONNECTION_READ_ONLY, TRUE, NULL);
@@ -3569,9 +4139,3 @@ done:
 	return connection;
 }
 
-const char *
-reader_get_prefix (void)
-{
-	return _("System");
-}
-
diff --git a/src/settings/plugins/ifcfg-rh/reader.h b/src/settings/plugins/ifcfg-rh/reader.h
index 2a031977..97c727cc 100644
--- a/src/settings/plugins/ifcfg-rh/reader.h
+++ b/src/settings/plugins/ifcfg-rh/reader.h
@@ -37,6 +37,4 @@ NMConnection *connection_from_file (const char *filename,
                                     GError **error,
                                     gboolean *ignore_error);
 
-const char *reader_get_prefix (void);
-
 #endif  /* __READER_H__ */
diff --git a/src/settings/plugins/ifcfg-rh/tests/Makefile.am b/src/settings/plugins/ifcfg-rh/tests/Makefile.am
index 1b76a474..5b34ffe3 100644
--- a/src/settings/plugins/ifcfg-rh/tests/Makefile.am
+++ b/src/settings/plugins/ifcfg-rh/tests/Makefile.am
@@ -2,6 +2,7 @@ SUBDIRS=network-scripts
 
 INCLUDES = \
 	-I$(top_srcdir)/include \
+	-I$(top_builddir)/include \
 	-I$(top_srcdir)/libnm-util \
 	-I$(top_srcdir)/libnm-glib \
 	-I$(srcdir)/../
@@ -20,7 +21,9 @@ test_ifcfg_rh_CPPFLAGS = \
 test_ifcfg_rh_LDADD = \
 	$(top_builddir)/libnm-glib/libnm-glib.la \
 	$(top_builddir)/libnm-util/libnm-util.la \
+	$(top_builddir)/src/wifi/libwifi-utils.la \
 	$(builddir)/../libifcfg-rh-io.la \
+	$(LIBM)
 	$(DBUS_LIBS)
 
 test_ifcfg_rh_utils_SOURCES = \
diff --git a/src/settings/plugins/ifcfg-rh/tests/Makefile.in b/src/settings/plugins/ifcfg-rh/tests/Makefile.in
index 71c5d60b..5e8abf83 100644
--- a/src/settings/plugins/ifcfg-rh/tests/Makefile.in
+++ b/src/settings/plugins/ifcfg-rh/tests/Makefile.in
@@ -61,6 +61,7 @@ test_ifcfg_rh_OBJECTS = $(am_test_ifcfg_rh_OBJECTS)
 am__DEPENDENCIES_1 =
 test_ifcfg_rh_DEPENDENCIES = $(top_builddir)/libnm-glib/libnm-glib.la \
 	$(top_builddir)/libnm-util/libnm-util.la \
+	$(top_builddir)/src/wifi/libwifi-utils.la \
 	$(builddir)/../libifcfg-rh-io.la $(am__DEPENDENCIES_1)
 AM_V_lt = $(am__v_lt_$(V))
 am__v_lt_ = $(am__v_lt_$(AM_DEFAULT_VERBOSITY))
@@ -183,6 +184,8 @@ GIO_LIBS = @GIO_LIBS@
 GLIB_CFLAGS = @GLIB_CFLAGS@
 GLIB_GENMARSHAL = @GLIB_GENMARSHAL@
 GLIB_LIBS = @GLIB_LIBS@
+GLIB_MAKEFILE = @GLIB_MAKEFILE@
+GLIB_MKENUMS = @GLIB_MKENUMS@
 GMODULE_CFLAGS = @GMODULE_CFLAGS@
 GMODULE_LIBS = @GMODULE_LIBS@
 GMSGFMT = @GMSGFMT@
@@ -237,11 +240,15 @@ LIBNL2_LIBS = @LIBNL2_LIBS@
 LIBNL3_CFLAGS = @LIBNL3_CFLAGS@
 LIBNL3_LIBS = @LIBNL3_LIBS@
 LIBNL_CFLAGS = @LIBNL_CFLAGS@
+LIBNL_GENL3_CFLAGS = @LIBNL_GENL3_CFLAGS@
+LIBNL_GENL3_LIBS = @LIBNL_GENL3_LIBS@
 LIBNL_LIBS = @LIBNL_LIBS@
 LIBNL_ROUTE3_CFLAGS = @LIBNL_ROUTE3_CFLAGS@
 LIBNL_ROUTE3_LIBS = @LIBNL_ROUTE3_LIBS@
 LIBOBJS = @LIBOBJS@
 LIBS = @LIBS@
+LIBSOUP_CFLAGS = @LIBSOUP_CFLAGS@
+LIBSOUP_LIBS = @LIBSOUP_LIBS@
 LIBTOOL = @LIBTOOL@
 LIPO = @LIPO@
 LN_S = @LN_S@
@@ -252,6 +259,7 @@ MAINT = @MAINT@
 MAKEINFO = @MAKEINFO@
 MANIFEST_TOOL = @MANIFEST_TOOL@
 MKDIR_P = @MKDIR_P@
+MOC = @MOC@
 MSGFMT = @MSGFMT@
 MSGFMT_015 = @MSGFMT_015@
 MSGMERGE = @MSGMERGE@
@@ -291,6 +299,8 @@ SED = @SED@
 SET_MAKE = @SET_MAKE@
 SHELL = @SHELL@
 STRIP = @STRIP@
+SYSTEMD_CFLAGS = @SYSTEMD_CFLAGS@
+SYSTEMD_LIBS = @SYSTEMD_LIBS@
 SYSTEM_CA_PATH = @SYSTEM_CA_PATH@
 UDEV_BASE_DIR = @UDEV_BASE_DIR@
 USE_NLS = @USE_NLS@
@@ -357,6 +367,7 @@ top_srcdir = @top_srcdir@
 SUBDIRS = network-scripts
 INCLUDES = \
 	-I$(top_srcdir)/include \
+	-I$(top_builddir)/include \
 	-I$(top_srcdir)/libnm-util \
 	-I$(top_srcdir)/libnm-glib \
 	-I$(srcdir)/../
@@ -373,8 +384,9 @@ test_ifcfg_rh_CPPFLAGS = \
 test_ifcfg_rh_LDADD = \
 	$(top_builddir)/libnm-glib/libnm-glib.la \
 	$(top_builddir)/libnm-util/libnm-util.la \
+	$(top_builddir)/src/wifi/libwifi-utils.la \
 	$(builddir)/../libifcfg-rh-io.la \
-	$(DBUS_LIBS)
+	$(LIBM)
 
 test_ifcfg_rh_utils_SOURCES = \
 	test-ifcfg-rh-utils.c
@@ -833,6 +845,7 @@ uninstall-am:
 	mostlyclean-generic mostlyclean-libtool pdf pdf-am ps ps-am \
 	tags tags-recursive uninstall uninstall-am
 
+	$(DBUS_LIBS)
 
 @WITH_TESTS_TRUE@check-local: test-ifcfg-rh
 @WITH_TESTS_TRUE@	$(abs_builddir)/test-ifcfg-rh-utils
diff --git a/src/settings/plugins/ifcfg-rh/tests/network-scripts/Makefile.am b/src/settings/plugins/ifcfg-rh/tests/network-scripts/Makefile.am
index 935d0ec4..776962f0 100644
--- a/src/settings/plugins/ifcfg-rh/tests/network-scripts/Makefile.am
+++ b/src/settings/plugins/ifcfg-rh/tests/network-scripts/Makefile.am
@@ -36,6 +36,8 @@ EXTRA_DIST = \
 	ifcfg-test-wifi-leap-always-ask \
 	ifcfg-test-wifi-wpa-psk \
 	keys-test-wifi-wpa-psk \
+	ifcfg-test-wifi-wpa-psk-2 \
+	keys-test-wifi-wpa-psk-2 \
 	ifcfg-test-wifi-wpa-psk-unquoted \
 	keys-test-wifi-wpa-psk-unquoted \
 	ifcfg-test-wifi-wpa-psk-unquoted2 \
@@ -79,11 +81,16 @@ EXTRA_DIST = \
 	ifcfg-test-bridge-main \
 	ifcfg-test-bridge-component \
 	ifcfg-test-vlan-interface \
+	ifcfg-test-vlan-only-vlanid \
+	ifcfg-test-vlan-only-device \
 	ifcfg-test-wifi-wep-no-keys \
 	ifcfg-test-permissions \
 	ifcfg-test-wifi-wep-agent-keys \
 	ifcfg-test-wifi-dynamic-wep-leap \
-	keys-test-wifi-dynamic-wep-leap
+	keys-test-wifi-dynamic-wep-leap \
+	ifcfg-test-infiniband \
+	ifcfg-test-bond-main \
+	ifcfg-test-bond-slave
 
 check-local:
 	@for f in $(EXTRA_DIST); do \
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 6292f12c..4f34cfc3 100644
--- a/src/settings/plugins/ifcfg-rh/tests/network-scripts/Makefile.in
+++ b/src/settings/plugins/ifcfg-rh/tests/network-scripts/Makefile.in
@@ -107,6 +107,8 @@ GIO_LIBS = @GIO_LIBS@
 GLIB_CFLAGS = @GLIB_CFLAGS@
 GLIB_GENMARSHAL = @GLIB_GENMARSHAL@
 GLIB_LIBS = @GLIB_LIBS@
+GLIB_MAKEFILE = @GLIB_MAKEFILE@
+GLIB_MKENUMS = @GLIB_MKENUMS@
 GMODULE_CFLAGS = @GMODULE_CFLAGS@
 GMODULE_LIBS = @GMODULE_LIBS@
 GMSGFMT = @GMSGFMT@
@@ -161,11 +163,15 @@ LIBNL2_LIBS = @LIBNL2_LIBS@
 LIBNL3_CFLAGS = @LIBNL3_CFLAGS@
 LIBNL3_LIBS = @LIBNL3_LIBS@
 LIBNL_CFLAGS = @LIBNL_CFLAGS@
+LIBNL_GENL3_CFLAGS = @LIBNL_GENL3_CFLAGS@
+LIBNL_GENL3_LIBS = @LIBNL_GENL3_LIBS@
 LIBNL_LIBS = @LIBNL_LIBS@
 LIBNL_ROUTE3_CFLAGS = @LIBNL_ROUTE3_CFLAGS@
 LIBNL_ROUTE3_LIBS = @LIBNL_ROUTE3_LIBS@
 LIBOBJS = @LIBOBJS@
 LIBS = @LIBS@
+LIBSOUP_CFLAGS = @LIBSOUP_CFLAGS@
+LIBSOUP_LIBS = @LIBSOUP_LIBS@
 LIBTOOL = @LIBTOOL@
 LIPO = @LIPO@
 LN_S = @LN_S@
@@ -176,6 +182,7 @@ MAINT = @MAINT@
 MAKEINFO = @MAKEINFO@
 MANIFEST_TOOL = @MANIFEST_TOOL@
 MKDIR_P = @MKDIR_P@
+MOC = @MOC@
 MSGFMT = @MSGFMT@
 MSGFMT_015 = @MSGFMT_015@
 MSGMERGE = @MSGMERGE@
@@ -215,6 +222,8 @@ SED = @SED@
 SET_MAKE = @SET_MAKE@
 SHELL = @SHELL@
 STRIP = @STRIP@
+SYSTEMD_CFLAGS = @SYSTEMD_CFLAGS@
+SYSTEMD_LIBS = @SYSTEMD_LIBS@
 SYSTEM_CA_PATH = @SYSTEM_CA_PATH@
 UDEV_BASE_DIR = @UDEV_BASE_DIR@
 USE_NLS = @USE_NLS@
@@ -316,6 +325,8 @@ EXTRA_DIST = \
 	ifcfg-test-wifi-leap-always-ask \
 	ifcfg-test-wifi-wpa-psk \
 	keys-test-wifi-wpa-psk \
+	ifcfg-test-wifi-wpa-psk-2 \
+	keys-test-wifi-wpa-psk-2 \
 	ifcfg-test-wifi-wpa-psk-unquoted \
 	keys-test-wifi-wpa-psk-unquoted \
 	ifcfg-test-wifi-wpa-psk-unquoted2 \
@@ -359,11 +370,16 @@ EXTRA_DIST = \
 	ifcfg-test-bridge-main \
 	ifcfg-test-bridge-component \
 	ifcfg-test-vlan-interface \
+	ifcfg-test-vlan-only-vlanid \
+	ifcfg-test-vlan-only-device \
 	ifcfg-test-wifi-wep-no-keys \
 	ifcfg-test-permissions \
 	ifcfg-test-wifi-wep-agent-keys \
 	ifcfg-test-wifi-dynamic-wep-leap \
-	keys-test-wifi-dynamic-wep-leap
+	keys-test-wifi-dynamic-wep-leap \
+	ifcfg-test-infiniband \
+	ifcfg-test-bond-main \
+	ifcfg-test-bond-slave
 
 all: all-am
 
diff --git a/src/settings/plugins/ifcfg-rh/tests/network-scripts/ifcfg-test-bond-main b/src/settings/plugins/ifcfg-rh/tests/network-scripts/ifcfg-test-bond-main
new file mode 100644
index 00000000..4c4834d5
--- /dev/null
+++ b/src/settings/plugins/ifcfg-rh/tests/network-scripts/ifcfg-test-bond-main
@@ -0,0 +1,5 @@
+DEVICE=bond0
+ONBOOT=no
+TYPE=Bond
+BOOTPROTO=dhcp
+BONDING_OPTS="miimon=100"
diff --git a/src/settings/plugins/ifcfg-rh/tests/network-scripts/ifcfg-test-bond-slave b/src/settings/plugins/ifcfg-rh/tests/network-scripts/ifcfg-test-bond-slave
new file mode 100644
index 00000000..cfef2b16
--- /dev/null
+++ b/src/settings/plugins/ifcfg-rh/tests/network-scripts/ifcfg-test-bond-slave
@@ -0,0 +1,4 @@
+DEVICE=eth0
+HWADDR=00:22:15:59:62:97
+ONBOOT=no
+MASTER=bond0
diff --git a/src/settings/plugins/ifcfg-rh/tests/network-scripts/ifcfg-test-infiniband b/src/settings/plugins/ifcfg-rh/tests/network-scripts/ifcfg-test-infiniband
new file mode 100644
index 00000000..6c36f1de
--- /dev/null
+++ b/src/settings/plugins/ifcfg-rh/tests/network-scripts/ifcfg-test-infiniband
@@ -0,0 +1,8 @@
+TYPE=InfiniBand
+DEVICE=ib0
+HWADDR=80:00:11:22:33:44:55:66:77:88:99:aa:bb:cc:dd:ee:ff:00:11:22
+CONNECTED_MODE=yes
+MTU=65520
+IPADDR=192.168.2.2
+NETMASK=255.255.255.0
+GATEWAY=192.168.2.1
diff --git a/src/settings/plugins/ifcfg-rh/tests/network-scripts/ifcfg-test-vlan-interface b/src/settings/plugins/ifcfg-rh/tests/network-scripts/ifcfg-test-vlan-interface
index 6c841855..ccd75d7f 100644
--- a/src/settings/plugins/ifcfg-rh/tests/network-scripts/ifcfg-test-vlan-interface
+++ b/src/settings/plugins/ifcfg-rh/tests/network-scripts/ifcfg-test-vlan-interface
@@ -1,7 +1,12 @@
-DEVICE=eth1.43
 VLAN=yes
+TYPE=Vlan
+DEVICE=vlan43
+PHYSDEV=eth9
+REORDER_HDR=0
+VLAN_FLAGS=GVRP,LOOSE_BINDING
+VLAN_INGRESS_PRIORITY_MAP=0:1,2:5
+VLAN_EGRESS_PRIORITY_MAP=12:3,14:7,3:1
 ONBOOT=yes
-BOOTPROTO=none
+BOOTPROTO=static
 IPADDR=192.168.43.149
 NETMASK=255.255.255.0
-
diff --git a/src/settings/plugins/ifcfg-rh/tests/network-scripts/ifcfg-test-vlan-only-device b/src/settings/plugins/ifcfg-rh/tests/network-scripts/ifcfg-test-vlan-only-device
new file mode 100644
index 00000000..4ba06f28
--- /dev/null
+++ b/src/settings/plugins/ifcfg-rh/tests/network-scripts/ifcfg-test-vlan-only-device
@@ -0,0 +1,4 @@
+VLAN=yes
+TYPE=Vlan
+DEVICE=eth0.9
+
diff --git a/src/settings/plugins/ifcfg-rh/tests/network-scripts/ifcfg-test-vlan-only-vlanid b/src/settings/plugins/ifcfg-rh/tests/network-scripts/ifcfg-test-vlan-only-vlanid
new file mode 100644
index 00000000..622d41ec
--- /dev/null
+++ b/src/settings/plugins/ifcfg-rh/tests/network-scripts/ifcfg-test-vlan-only-vlanid
@@ -0,0 +1,6 @@
+VLAN=yes
+TYPE=Vlan
+PHYSDEV=eth9
+VLAN_ID=43
+ONBOOT=yes
+
diff --git a/src/settings/plugins/ifcfg-rh/tests/network-scripts/ifcfg-test-wifi-wpa-psk-2 b/src/settings/plugins/ifcfg-rh/tests/network-scripts/ifcfg-test-wifi-wpa-psk-2
new file mode 100644
index 00000000..038b656d
--- /dev/null
+++ b/src/settings/plugins/ifcfg-rh/tests/network-scripts/ifcfg-test-wifi-wpa-psk-2
@@ -0,0 +1,19 @@
+TYPE=Wireless
+DEVICE=eth2
+HWADDR=00:16:41:11:22:33
+NM_CONTROLLED=yes
+BOOTPROTO=dhcp
+ESSID=ipsum
+CHANNEL=6
+MODE=Managed
+RATE=auto
+ONBOOT=yes
+USERCTL=yes
+PEERDNS=yes
+IPV6INIT=no
+CIPHER_PAIRWISE="TKIP CCMP"
+CIPHER_GROUP="TKIP CCMP WEP40 WEP104"
+KEY_MGMT=WPA-PSK
+WPA_ALLOW_WPA=yes
+WPA_ALLOW_WPA2=yes
+
diff --git a/src/settings/plugins/ifcfg-rh/tests/network-scripts/keys-test-wifi-wpa-psk-2 b/src/settings/plugins/ifcfg-rh/tests/network-scripts/keys-test-wifi-wpa-psk-2
new file mode 100644
index 00000000..bf98da5a
--- /dev/null
+++ b/src/settings/plugins/ifcfg-rh/tests/network-scripts/keys-test-wifi-wpa-psk-2
@@ -0,0 +1,2 @@
+WPA_PSK=$'They\'re really saying I love you. >>`<<'
+
diff --git a/src/settings/plugins/ifcfg-rh/tests/test-ifcfg-rh.c b/src/settings/plugins/ifcfg-rh/tests/test-ifcfg-rh.c
index e32266cb..62882a76 100644
--- a/src/settings/plugins/ifcfg-rh/tests/test-ifcfg-rh.c
+++ b/src/settings/plugins/ifcfg-rh/tests/test-ifcfg-rh.c
@@ -23,6 +23,7 @@
 #include <unistd.h>
 #include <string.h>
 #include <netinet/ether.h>
+#include <linux/if_infiniband.h>
 #include <netinet/in.h>
 #include <arpa/inet.h>
 #include <sys/socket.h>
@@ -43,6 +44,7 @@
 #include <nm-setting-gsm.h>
 #include <nm-setting-cdma.h>
 #include <nm-setting-serial.h>
+#include <nm-setting-vlan.h>
 
 #include "nm-test-helpers.h"
 
@@ -235,7 +237,7 @@ test_read_minimal (void)
 
 	/* ===== CONNECTION SETTING ===== */
 
-	s_con = NM_SETTING_CONNECTION (nm_connection_get_setting (connection, NM_TYPE_SETTING_CONNECTION));
+	s_con = nm_connection_get_setting_connection (connection);
 	ASSERT (s_con != NULL,
 	        "minimal-wired-verify-connection", "failed to verify %s: missing %s setting",
 	        TEST_IFCFG_MINIMAL,
@@ -275,7 +277,7 @@ test_read_minimal (void)
 
 	/* ===== WIRED SETTING ===== */
 
-	s_wired = NM_SETTING_WIRED (nm_connection_get_setting (connection, NM_TYPE_SETTING_WIRED));
+	s_wired = nm_connection_get_setting_wired (connection);
 	ASSERT (s_wired != NULL,
 	        "minimal-wired-verify-wired", "failed to verify %s: missing %s setting",
 	        TEST_IFCFG_MINIMAL,
@@ -307,7 +309,7 @@ test_read_minimal (void)
 
 	/* ===== IPv4 SETTING ===== */
 
-	s_ip4 = NM_SETTING_IP4_CONFIG (nm_connection_get_setting (connection, NM_TYPE_SETTING_IP4_CONFIG));
+	s_ip4 = nm_connection_get_setting_ip4_config (connection);
 	ASSERT (s_ip4 != NULL,
 	        "minimal-wired-verify-ip4", "failed to verify %s: missing %s setting",
 	        TEST_IFCFG_MINIMAL,
@@ -379,7 +381,7 @@ test_read_unmanaged (void)
 
 	/* ===== CONNECTION SETTING ===== */
 
-	s_con = NM_SETTING_CONNECTION (nm_connection_get_setting (connection, NM_TYPE_SETTING_CONNECTION));
+	s_con = nm_connection_get_setting_connection (connection);
 	ASSERT (s_con != NULL,
 	        "unmanaged-verify-connection", "failed to verify %s: missing %s setting",
 	        TEST_IFCFG_UNMANAGED,
@@ -417,7 +419,7 @@ test_read_unmanaged (void)
 
 	/* ===== WIRED SETTING ===== */
 
-	s_wired = NM_SETTING_WIRED (nm_connection_get_setting (connection, NM_TYPE_SETTING_WIRED));
+	s_wired = nm_connection_get_setting_wired (connection);
 	ASSERT (s_wired != NULL,
 	        "unmanaged-verify-wired", "failed to verify %s: missing %s setting",
 	        TEST_IFCFG_UNMANAGED,
@@ -443,7 +445,7 @@ test_read_unmanaged (void)
 
 	/* ===== IPv4 SETTING ===== */
 
-	s_ip4 = NM_SETTING_IP4_CONFIG (nm_connection_get_setting (connection, NM_TYPE_SETTING_IP4_CONFIG));
+	s_ip4 = nm_connection_get_setting_ip4_config (connection);
 	ASSERT (s_ip4 == NULL,
 	        "unmanaged-verify-ip4", "failed to verify %s: unexpected %s setting",
 	        TEST_IFCFG_UNMANAGED,
@@ -504,7 +506,7 @@ test_read_wired_static (const char *file, const char *expected_id)
 
 	/* ===== CONNECTION SETTING ===== */
 
-	s_con = NM_SETTING_CONNECTION (nm_connection_get_setting (connection, NM_TYPE_SETTING_CONNECTION));
+	s_con = nm_connection_get_setting_connection (connection);
 	ASSERT (s_con != NULL,
 	        "wired-static-verify-connection", "failed to verify %s: missing %s setting",
 	        file,
@@ -539,7 +541,7 @@ test_read_wired_static (const char *file, const char *expected_id)
 
 	/* ===== WIRED SETTING ===== */
 
-	s_wired = NM_SETTING_WIRED (nm_connection_get_setting (connection, NM_TYPE_SETTING_WIRED));
+	s_wired = nm_connection_get_setting_wired (connection);
 	ASSERT (s_wired != NULL,
 	        "wired-static-verify-wired", "failed to verify %s: missing %s setting",
 	        file,
@@ -571,7 +573,7 @@ test_read_wired_static (const char *file, const char *expected_id)
 
 	/* ===== IPv4 SETTING ===== */
 
-	s_ip4 = NM_SETTING_IP4_CONFIG (nm_connection_get_setting (connection, NM_TYPE_SETTING_IP4_CONFIG));
+	s_ip4 = nm_connection_get_setting_ip4_config (connection);
 	ASSERT (s_ip4 != NULL,
 	        "wired-static-verify-ip4", "failed to verify %s: missing %s setting",
 	        file,
@@ -586,7 +588,7 @@ test_read_wired_static (const char *file, const char *expected_id)
 	        NM_SETTING_IP4_CONFIG_METHOD);
 
 	/* Implicit may-fail */
-	ASSERT (nm_setting_ip4_config_get_may_fail (s_ip4) == FALSE,
+	ASSERT (nm_setting_ip4_config_get_may_fail (s_ip4) == TRUE,
 	        "wired-static-verify-ip6", "failed to verify %s: unexpected %s / %s key value",
 	        file,
 	        NM_SETTING_IP4_CONFIG_SETTING_NAME,
@@ -666,7 +668,7 @@ test_read_wired_static (const char *file, const char *expected_id)
 	if (!strcmp (expected_id, "System test-wired-static")) {
 		/* ===== IPv6 SETTING ===== */
 
-		s_ip6 = NM_SETTING_IP6_CONFIG (nm_connection_get_setting (connection, NM_TYPE_SETTING_IP6_CONFIG));
+		s_ip6 = nm_connection_get_setting_ip6_config (connection);
 		ASSERT (s_ip6 != NULL,
 			"wired-static-verify-ip6", "failed to verify %s: missing %s setting",
 			file,
@@ -807,7 +809,7 @@ test_read_wired_static_no_prefix (guint32 expected_prefix)
 
 	/* ===== CONNECTION SETTING ===== */
 
-	s_con = NM_SETTING_CONNECTION (nm_connection_get_setting (connection, NM_TYPE_SETTING_CONNECTION));
+	s_con = nm_connection_get_setting_connection (connection);
 	ASSERT (s_con != NULL,
 	        "wired-static-no-prefix-verify-connection", "failed to verify %s: missing %s setting",
 	        file,
@@ -829,7 +831,7 @@ test_read_wired_static_no_prefix (guint32 expected_prefix)
 
 	/* ===== IPv4 SETTING ===== */
 
-	s_ip4 = NM_SETTING_IP4_CONFIG (nm_connection_get_setting (connection, NM_TYPE_SETTING_IP4_CONFIG));
+	s_ip4 = nm_connection_get_setting_ip4_config (connection);
 	ASSERT (s_ip4 != NULL,
 	        "wired-static-no-prefix-verify-ip4", "failed to verify %s: missing %s setting",
 	        file,
@@ -916,7 +918,7 @@ test_read_wired_dhcp (void)
 
 	/* ===== CONNECTION SETTING ===== */
 
-	s_con = NM_SETTING_CONNECTION (nm_connection_get_setting (connection, NM_TYPE_SETTING_CONNECTION));
+	s_con = nm_connection_get_setting_connection (connection);
 	ASSERT (s_con != NULL,
 	        "wired-dhcp-verify-connection", "failed to verify %s: missing %s setting",
 	        TEST_IFCFG_WIRED_DHCP,
@@ -951,7 +953,7 @@ test_read_wired_dhcp (void)
 
 	/* ===== WIRED SETTING ===== */
 
-	s_wired = NM_SETTING_WIRED (nm_connection_get_setting (connection, NM_TYPE_SETTING_WIRED));
+	s_wired = nm_connection_get_setting_wired (connection);
 	ASSERT (s_wired != NULL,
 	        "wired-dhcp-verify-wired", "failed to verify %s: missing %s setting",
 	        TEST_IFCFG_WIRED_DHCP,
@@ -977,7 +979,7 @@ test_read_wired_dhcp (void)
 
 	/* ===== IPv4 SETTING ===== */
 
-	s_ip4 = NM_SETTING_IP4_CONFIG (nm_connection_get_setting (connection, NM_TYPE_SETTING_IP4_CONFIG));
+	s_ip4 = nm_connection_get_setting_ip4_config (connection);
 	ASSERT (s_ip4 != NULL,
 	        "wired-dhcp-verify-ip4", "failed to verify %s: missing %s setting",
 	        TEST_IFCFG_WIRED_DHCP,
@@ -1089,7 +1091,7 @@ test_read_wired_global_gateway (void)
 
 	/* ===== CONNECTION SETTING ===== */
 
-	s_con = NM_SETTING_CONNECTION (nm_connection_get_setting (connection, NM_TYPE_SETTING_CONNECTION));
+	s_con = nm_connection_get_setting_connection (connection);
 	ASSERT (s_con != NULL,
 	        "wired-global-gateway-verify-connection", "failed to verify %s: missing %s setting",
 	        TEST_IFCFG_WIRED_GLOBAL_GATEWAY,
@@ -1110,7 +1112,7 @@ test_read_wired_global_gateway (void)
 
 	/* ===== WIRED SETTING ===== */
 
-	s_wired = NM_SETTING_WIRED (nm_connection_get_setting (connection, NM_TYPE_SETTING_WIRED));
+	s_wired = nm_connection_get_setting_wired (connection);
 	ASSERT (s_wired != NULL,
 	        "wired-global-gateway-verify-wired", "failed to verify %s: missing %s setting",
 	        TEST_IFCFG_WIRED_GLOBAL_GATEWAY,
@@ -1118,7 +1120,7 @@ test_read_wired_global_gateway (void)
 
 	/* ===== IPv4 SETTING ===== */
 
-	s_ip4 = NM_SETTING_IP4_CONFIG (nm_connection_get_setting (connection, NM_TYPE_SETTING_IP4_CONFIG));
+	s_ip4 = nm_connection_get_setting_ip4_config (connection);
 	ASSERT (s_ip4 != NULL,
 	        "wired-global-gateway-verify-ip4", "failed to verify %s: missing %s setting",
 	        TEST_IFCFG_WIRED_GLOBAL_GATEWAY,
@@ -1216,7 +1218,7 @@ test_read_wired_never_default (void)
 
 	/* ===== CONNECTION SETTING ===== */
 
-	s_con = NM_SETTING_CONNECTION (nm_connection_get_setting (connection, NM_TYPE_SETTING_CONNECTION));
+	s_con = nm_connection_get_setting_connection (connection);
 	ASSERT (s_con != NULL,
 	        "wired-never-default-verify-connection", "failed to verify %s: missing %s setting",
 	        TEST_IFCFG_WIRED_NEVER_DEFAULT,
@@ -1237,7 +1239,7 @@ test_read_wired_never_default (void)
 
 	/* ===== WIRED SETTING ===== */
 
-	s_wired = NM_SETTING_WIRED (nm_connection_get_setting (connection, NM_TYPE_SETTING_WIRED));
+	s_wired = nm_connection_get_setting_wired (connection);
 	ASSERT (s_wired != NULL,
 	        "wired-never-default-verify-wired", "failed to verify %s: missing %s setting",
 	        TEST_IFCFG_WIRED_NEVER_DEFAULT,
@@ -1245,7 +1247,7 @@ test_read_wired_never_default (void)
 
 	/* ===== IPv4 SETTING ===== */
 
-	s_ip4 = NM_SETTING_IP4_CONFIG (nm_connection_get_setting (connection, NM_TYPE_SETTING_IP4_CONFIG));
+	s_ip4 = nm_connection_get_setting_ip4_config (connection);
 	ASSERT (s_ip4 != NULL,
 	        "wired-never-default-verify-ip4", "failed to verify %s: missing %s setting",
 	        TEST_IFCFG_WIRED_NEVER_DEFAULT,
@@ -1274,7 +1276,7 @@ test_read_wired_never_default (void)
 
 	/* ===== IPv6 SETTING ===== */
 
-	s_ip6 = NM_SETTING_IP6_CONFIG (nm_connection_get_setting (connection, NM_TYPE_SETTING_IP6_CONFIG));
+	s_ip6 = nm_connection_get_setting_ip6_config (connection);
 	ASSERT (s_ip6 != NULL,
 	        "wired-never-default-verify-ip6", "failed to verify %s: missing %s setting",
 	        TEST_IFCFG_WIRED_NEVER_DEFAULT,
@@ -1341,7 +1343,7 @@ test_read_wired_defroute_no (void)
 
 	/* ===== CONNECTION SETTING ===== */
 
-	s_con = NM_SETTING_CONNECTION (nm_connection_get_setting (connection, NM_TYPE_SETTING_CONNECTION));
+	s_con = nm_connection_get_setting_connection (connection);
 	ASSERT (s_con != NULL,
 	        "wired-defroute-no-verify-connection", "failed to verify %s: missing %s setting",
 	        TEST_IFCFG_WIRED_DEFROUTE_NO,
@@ -1362,7 +1364,7 @@ test_read_wired_defroute_no (void)
 
 	/* ===== WIRED SETTING ===== */
 
-	s_wired = NM_SETTING_WIRED (nm_connection_get_setting (connection, NM_TYPE_SETTING_WIRED));
+	s_wired = nm_connection_get_setting_wired (connection);
 	ASSERT (s_wired != NULL,
 	        "wired-defroute-no-verify-wired", "failed to verify %s: missing %s setting",
 	        TEST_IFCFG_WIRED_DEFROUTE_NO,
@@ -1370,7 +1372,7 @@ test_read_wired_defroute_no (void)
 
 	/* ===== IPv4 SETTING ===== */
 
-	s_ip4 = NM_SETTING_IP4_CONFIG (nm_connection_get_setting (connection, NM_TYPE_SETTING_IP4_CONFIG));
+	s_ip4 = nm_connection_get_setting_ip4_config (connection);
 	ASSERT (s_ip4 != NULL,
 	        "wired-defroute-no-verify-ip4", "failed to verify %s: missing %s setting",
 	        TEST_IFCFG_WIRED_DEFROUTE_NO,
@@ -1392,7 +1394,7 @@ test_read_wired_defroute_no (void)
 
 	/* ===== IPv6 SETTING ===== */
 
-	s_ip6 = NM_SETTING_IP6_CONFIG (nm_connection_get_setting (connection, NM_TYPE_SETTING_IP6_CONFIG));
+	s_ip6 = nm_connection_get_setting_ip6_config (connection);
 	ASSERT (s_ip6 != NULL,
 	        "wired-defroute-no-verify-ip6", "failed to verify %s: missing %s setting",
 	        TEST_IFCFG_WIRED_DEFROUTE_NO,
@@ -1468,7 +1470,7 @@ test_read_wired_defroute_no_gatewaydev_yes (void)
 
 	/* ===== CONNECTION SETTING ===== */
 
-	s_con = NM_SETTING_CONNECTION (nm_connection_get_setting (connection, NM_TYPE_SETTING_CONNECTION));
+	s_con = nm_connection_get_setting_connection (connection);
 	ASSERT (s_con != NULL,
 	        "wired-defroute-no-gatewaydev-yes-verify-connection", "failed to verify %s: missing %s setting",
 	        TEST_IFCFG_WIRED_DEFROUTE_NO_GATEWAYDEV_YES,
@@ -1489,7 +1491,7 @@ test_read_wired_defroute_no_gatewaydev_yes (void)
 
 	/* ===== WIRED SETTING ===== */
 
-	s_wired = NM_SETTING_WIRED (nm_connection_get_setting (connection, NM_TYPE_SETTING_WIRED));
+	s_wired = nm_connection_get_setting_wired (connection);
 	ASSERT (s_wired != NULL,
 	        "wired-defroute-no-gatewaydev-yes-verify-wired", "failed to verify %s: missing %s setting",
 	        TEST_IFCFG_WIRED_DEFROUTE_NO_GATEWAYDEV_YES,
@@ -1497,7 +1499,7 @@ test_read_wired_defroute_no_gatewaydev_yes (void)
 
 	/* ===== IPv4 SETTING ===== */
 
-	s_ip4 = NM_SETTING_IP4_CONFIG (nm_connection_get_setting (connection, NM_TYPE_SETTING_IP4_CONFIG));
+	s_ip4 = nm_connection_get_setting_ip4_config (connection);
 	ASSERT (s_ip4 != NULL,
 	        "wired-defroute-no-gatewaydev-yes-verify-ip4", "failed to verify %s: missing %s setting",
 	        TEST_IFCFG_WIRED_DEFROUTE_NO_GATEWAYDEV_YES,
@@ -1519,7 +1521,7 @@ test_read_wired_defroute_no_gatewaydev_yes (void)
 
 	/* ===== IPv6 SETTING ===== */
 
-	s_ip6 = NM_SETTING_IP6_CONFIG (nm_connection_get_setting (connection, NM_TYPE_SETTING_IP6_CONFIG));
+	s_ip6 = nm_connection_get_setting_ip6_config (connection);
 	ASSERT (s_ip6 != NULL,
 	        "wired-defroute-no-gatewaydev-yes-verify-ip6", "failed to verify %s: missing %s setting",
 	        TEST_IFCFG_WIRED_DEFROUTE_NO_GATEWAYDEV_YES,
@@ -1597,7 +1599,7 @@ test_read_wired_static_routes (void)
 
 	/* ===== CONNECTION SETTING ===== */
 
-	s_con = NM_SETTING_CONNECTION (nm_connection_get_setting (connection, NM_TYPE_SETTING_CONNECTION));
+	s_con = nm_connection_get_setting_connection (connection);
 	ASSERT (s_con != NULL,
 	        "wired-static-routes-verify-connection", "failed to verify %s: missing %s setting",
 	        TEST_IFCFG_WIRED_STATIC_ROUTES,
@@ -1618,7 +1620,7 @@ test_read_wired_static_routes (void)
 
 	/* ===== WIRED SETTING ===== */
 
-	s_wired = NM_SETTING_WIRED (nm_connection_get_setting (connection, NM_TYPE_SETTING_WIRED));
+	s_wired = nm_connection_get_setting_wired (connection);
 	ASSERT (s_wired != NULL,
 	        "wired-static-routes-verify-wired", "failed to verify %s: missing %s setting",
 	        TEST_IFCFG_WIRED_STATIC_ROUTES,
@@ -1626,7 +1628,7 @@ test_read_wired_static_routes (void)
 
 	/* ===== IPv4 SETTING ===== */
 
-	s_ip4 = NM_SETTING_IP4_CONFIG (nm_connection_get_setting (connection, NM_TYPE_SETTING_IP4_CONFIG));
+	s_ip4 = nm_connection_get_setting_ip4_config (connection);
 	ASSERT (s_ip4 != NULL,
 	        "wired-static-routes-verify-ip4", "failed to verify %s: missing %s setting",
 	        TEST_IFCFG_WIRED_STATIC_ROUTES,
@@ -1764,7 +1766,7 @@ test_read_wired_static_routes_legacy (void)
 
 	/* ===== CONNECTION SETTING ===== */
 
-	s_con = NM_SETTING_CONNECTION (nm_connection_get_setting (connection, NM_TYPE_SETTING_CONNECTION));
+	s_con = nm_connection_get_setting_connection (connection);
 	ASSERT (s_con != NULL,
 	        "wired-static-routes-legacy-verify-connection", "failed to verify %s: missing %s setting",
 	        TEST_IFCFG_WIRED_STATIC_ROUTES_LEGACY,
@@ -1785,7 +1787,7 @@ test_read_wired_static_routes_legacy (void)
 
 	/* ===== WIRED SETTING ===== */
 
-	s_wired = NM_SETTING_WIRED (nm_connection_get_setting (connection, NM_TYPE_SETTING_WIRED));
+	s_wired = nm_connection_get_setting_wired (connection);
 	ASSERT (s_wired != NULL,
 	        "wired-static-routes-legacy-verify-wired", "failed to verify %s: missing %s setting",
 	        TEST_IFCFG_WIRED_STATIC_ROUTES_LEGACY,
@@ -1793,7 +1795,7 @@ test_read_wired_static_routes_legacy (void)
 
 	/* ===== IPv4 SETTING ===== */
 
-	s_ip4 = NM_SETTING_IP4_CONFIG (nm_connection_get_setting (connection, NM_TYPE_SETTING_IP4_CONFIG));
+	s_ip4 = nm_connection_get_setting_ip4_config (connection);
 	ASSERT (s_ip4 != NULL,
 	        "wired-static-routes-legacy-verify-ip4", "failed to verify %s: missing %s setting",
 	        TEST_IFCFG_WIRED_STATIC_ROUTES_LEGACY,
@@ -1961,7 +1963,7 @@ test_read_wired_ipv4_manual (const char *file, const char *expected_id)
 
 	/* ===== CONNECTION SETTING ===== */
 
-	s_con = NM_SETTING_CONNECTION (nm_connection_get_setting (connection, NM_TYPE_SETTING_CONNECTION));
+	s_con = nm_connection_get_setting_connection (connection);
 	ASSERT (s_con != NULL,
 	        "wired-ipv4-manual-verify-connection", "failed to verify %s: missing %s setting",
 	        file,
@@ -1982,7 +1984,7 @@ test_read_wired_ipv4_manual (const char *file, const char *expected_id)
 
 	/* ===== WIRED SETTING ===== */
 
-	s_wired = NM_SETTING_WIRED (nm_connection_get_setting (connection, NM_TYPE_SETTING_WIRED));
+	s_wired = nm_connection_get_setting_wired (connection);
 	ASSERT (s_wired != NULL,
 	        "wired-ipv4-manual-verify-wired", "failed to verify %s: missing %s setting",
 	        file,
@@ -1990,7 +1992,7 @@ test_read_wired_ipv4_manual (const char *file, const char *expected_id)
 
 	/* ===== IPv4 SETTING ===== */
 
-	s_ip4 = NM_SETTING_IP4_CONFIG (nm_connection_get_setting (connection, NM_TYPE_SETTING_IP4_CONFIG));
+	s_ip4 = nm_connection_get_setting_ip4_config (connection);
 	ASSERT (s_ip4 != NULL,
 	        "wired-ipv4-manual-verify-ip4", "failed to verify %s: missing %s setting",
 	        file,
@@ -2124,7 +2126,7 @@ test_read_wired_ipv6_manual (void)
 
 	/* ===== CONNECTION SETTING ===== */
 
-	s_con = NM_SETTING_CONNECTION (nm_connection_get_setting (connection, NM_TYPE_SETTING_CONNECTION));
+	s_con = nm_connection_get_setting_connection (connection);
 	ASSERT (s_con != NULL,
 	        "wired-ipv6-manual-verify-connection", "failed to verify %s: missing %s setting",
 	        TEST_IFCFG_WIRED_IPV6_MANUAL,
@@ -2145,7 +2147,7 @@ test_read_wired_ipv6_manual (void)
 
 	/* ===== WIRED SETTING ===== */
 
-	s_wired = NM_SETTING_WIRED (nm_connection_get_setting (connection, NM_TYPE_SETTING_WIRED));
+	s_wired = nm_connection_get_setting_wired (connection);
 	ASSERT (s_wired != NULL,
 	        "wired-ipv6-manual-verify-wired", "failed to verify %s: missing %s setting",
 	        TEST_IFCFG_WIRED_IPV6_MANUAL,
@@ -2153,7 +2155,7 @@ test_read_wired_ipv6_manual (void)
 
 	/* ===== IPv4 SETTING ===== */
 
-	s_ip4 = NM_SETTING_IP4_CONFIG (nm_connection_get_setting (connection, NM_TYPE_SETTING_IP4_CONFIG));
+	s_ip4 = nm_connection_get_setting_ip4_config (connection);
 	ASSERT (s_ip4 != NULL,
 	        "wired-ipv6-manual-verify-ip4", "failed to verify %s: missing %s setting",
 	        TEST_IFCFG_WIRED_IPV6_MANUAL,
@@ -2211,7 +2213,7 @@ test_read_wired_ipv6_manual (void)
 
 	/* ===== IPv6 SETTING ===== */
 
-	s_ip6 = NM_SETTING_IP6_CONFIG (nm_connection_get_setting (connection, NM_TYPE_SETTING_IP6_CONFIG));
+	s_ip6 = nm_connection_get_setting_ip6_config (connection);
 	ASSERT (s_ip6 != NULL,
 	        "wired-ipv6-manual-verify-ip6", "failed to verify %s: missing %s setting",
 	        TEST_IFCFG_WIRED_IPV6_MANUAL,
@@ -2415,7 +2417,7 @@ test_read_wired_ipv6_only (void)
 
 	/* ===== CONNECTION SETTING ===== */
 
-	s_con = NM_SETTING_CONNECTION (nm_connection_get_setting (connection, NM_TYPE_SETTING_CONNECTION));
+	s_con = nm_connection_get_setting_connection (connection);
 	ASSERT (s_con != NULL,
 	        "wired-ipv6-only-verify-connection", "failed to verify %s: missing %s setting",
 	        TEST_IFCFG_WIRED_IPV6_MANUAL,
@@ -2436,7 +2438,7 @@ test_read_wired_ipv6_only (void)
 
 	/* ===== WIRED SETTING ===== */
 
-	s_wired = NM_SETTING_WIRED (nm_connection_get_setting (connection, NM_TYPE_SETTING_WIRED));
+	s_wired = nm_connection_get_setting_wired (connection);
 	ASSERT (s_wired != NULL,
 	        "wired-ipv6-only-verify-wired", "failed to verify %s: missing %s setting",
 	        TEST_IFCFG_WIRED_IPV6_MANUAL,
@@ -2444,7 +2446,7 @@ test_read_wired_ipv6_only (void)
 
 	/* ===== IPv4 SETTING ===== */
 
-	s_ip4 = NM_SETTING_IP4_CONFIG (nm_connection_get_setting (connection, NM_TYPE_SETTING_IP4_CONFIG));
+	s_ip4 = nm_connection_get_setting_ip4_config (connection);
 	ASSERT (s_ip4 != NULL,
 	        "wired-ipv6-only-verify-ip4", "failed to verify %s: missing %s setting",
 	        TEST_IFCFG_WIRED_IPV6_MANUAL,
@@ -2459,7 +2461,7 @@ test_read_wired_ipv6_only (void)
 
 	/* ===== IPv6 SETTING ===== */
 
-	s_ip6 = NM_SETTING_IP6_CONFIG (nm_connection_get_setting (connection, NM_TYPE_SETTING_IP6_CONFIG));
+	s_ip6 = nm_connection_get_setting_ip6_config (connection);
 	ASSERT (s_ip6 != NULL,
 	        "wired-ipv6-only-verify-ip6", "failed to verify %s: missing %s setting",
 	        TEST_IFCFG_WIRED_IPV6_MANUAL,
@@ -2568,7 +2570,7 @@ test_read_wired_dhcp6_only (void)
 
 	/* ===== CONNECTION SETTING ===== */
 
-	s_con = NM_SETTING_CONNECTION (nm_connection_get_setting (connection, NM_TYPE_SETTING_CONNECTION));
+	s_con = nm_connection_get_setting_connection (connection);
 	ASSERT (s_con != NULL,
 	        "wired-dhcp6-only-verify-connection", "failed to verify %s: missing %s setting",
 	        TEST_IFCFG_WIRED_DHCP6_ONLY,
@@ -2589,7 +2591,7 @@ test_read_wired_dhcp6_only (void)
 
 	/* ===== WIRED SETTING ===== */
 
-	s_wired = NM_SETTING_WIRED (nm_connection_get_setting (connection, NM_TYPE_SETTING_WIRED));
+	s_wired = nm_connection_get_setting_wired (connection);
 	ASSERT (s_wired != NULL,
 	        "wired-dhcp6-only-verify-wired", "failed to verify %s: missing %s setting",
 	        TEST_IFCFG_WIRED_DHCP6_ONLY,
@@ -2597,7 +2599,7 @@ test_read_wired_dhcp6_only (void)
 
 	/* ===== IPv4 SETTING ===== */
 
-	s_ip4 = NM_SETTING_IP4_CONFIG (nm_connection_get_setting (connection, NM_TYPE_SETTING_IP4_CONFIG));
+	s_ip4 = nm_connection_get_setting_ip4_config (connection);
 	ASSERT (s_ip4 != NULL,
 	        "wired-dhcp6-only-verify-ip4", "failed to verify %s: missing %s setting",
 	        TEST_IFCFG_WIRED_DHCP6_ONLY,
@@ -2612,7 +2614,7 @@ test_read_wired_dhcp6_only (void)
 
 	/* ===== IPv6 SETTING ===== */
 
-	s_ip6 = NM_SETTING_IP6_CONFIG (nm_connection_get_setting (connection, NM_TYPE_SETTING_IP6_CONFIG));
+	s_ip6 = nm_connection_get_setting_ip6_config (connection);
 	ASSERT (s_ip6 != NULL,
 	        "wired-dhcp6-only-verify-ip6", "failed to verify %s: missing %s setting",
 	        TEST_IFCFG_WIRED_DHCP6_ONLY,
@@ -2668,7 +2670,7 @@ test_read_onboot_no (void)
 
 	/* ===== CONNECTION SETTING ===== */
 
-	s_con = NM_SETTING_CONNECTION (nm_connection_get_setting (connection, NM_TYPE_SETTING_CONNECTION));
+	s_con = nm_connection_get_setting_connection (connection);
 	ASSERT (s_con != NULL,
 	        "onboot-no-verify-connection", "failed to verify %s: missing %s setting",
 	        TEST_IFCFG_ONBOOT_NO,
@@ -2734,7 +2736,7 @@ test_read_wired_8021x_peap_mschapv2 (void)
 
 	/* ===== WIRED SETTING ===== */
 
-	s_wired = NM_SETTING_WIRED (nm_connection_get_setting (connection, NM_TYPE_SETTING_WIRED));
+	s_wired = nm_connection_get_setting_wired (connection);
 	ASSERT (s_wired != NULL,
 	        "wired-8021x-peap-mschapv2-verify-wired", "failed to verify %s: missing %s setting",
 	        TEST_IFCFG_WIRED_8021x_PEAP_MSCHAPV2,
@@ -2742,7 +2744,7 @@ test_read_wired_8021x_peap_mschapv2 (void)
 
 	/* ===== IPv4 SETTING ===== */
 
-	s_ip4 = NM_SETTING_IP4_CONFIG (nm_connection_get_setting (connection, NM_TYPE_SETTING_IP4_CONFIG));
+	s_ip4 = nm_connection_get_setting_ip4_config (connection);
 	ASSERT (s_ip4 != NULL,
 	        "wired-8021x-peap-mschapv2-verify-ip4", "failed to verify %s: missing %s setting",
 	        TEST_IFCFG_WIRED_8021x_PEAP_MSCHAPV2,
@@ -2757,7 +2759,7 @@ test_read_wired_8021x_peap_mschapv2 (void)
 	        NM_SETTING_IP4_CONFIG_METHOD);
 
 	/* ===== 802.1x SETTING ===== */
-	s_8021x = NM_SETTING_802_1X (nm_connection_get_setting (connection, NM_TYPE_SETTING_802_1X));
+	s_8021x = nm_connection_get_setting_802_1x (connection);
 	ASSERT (s_8021x != NULL,
 	        "wired-8021x-peap-mschapv2-verify-8021x", "failed to verify %s: missing %s setting",
 	        TEST_IFCFG_WIRED_8021x_PEAP_MSCHAPV2,
@@ -2929,11 +2931,11 @@ test_read_wired_8021x_tls_secret_flags (const char *ifcfg, NMSettingSecretFlags
 	g_assert (success);
 
 	/* ===== WIRED SETTING ===== */
-	s_wired = (NMSettingWired *) nm_connection_get_setting (connection, NM_TYPE_SETTING_WIRED);
+	s_wired = nm_connection_get_setting_wired (connection);
 	g_assert (s_wired);
 
 	/* ===== 802.1x SETTING ===== */
-	s_8021x = (NMSetting8021x *) nm_connection_get_setting (connection, NM_TYPE_SETTING_802_1X);
+	s_8021x = nm_connection_get_setting_802_1x (connection);
 	g_assert (s_8021x);
 	g_assert_cmpint (nm_setting_802_1x_get_num_eap_methods (s_8021x), ==, 1);
 	g_assert_cmpstr (nm_setting_802_1x_get_eap_method (s_8021x, 0), ==, "tls");
@@ -3001,7 +3003,7 @@ test_read_wifi_open (void)
 
 	/* ===== CONNECTION SETTING ===== */
 
-	s_con = NM_SETTING_CONNECTION (nm_connection_get_setting (connection, NM_TYPE_SETTING_CONNECTION));
+	s_con = nm_connection_get_setting_connection (connection);
 	ASSERT (s_con != NULL,
 	        "wifi-open-verify-connection", "failed to verify %s: missing %s setting",
 	        TEST_IFCFG_WIFI_OPEN,
@@ -3041,7 +3043,7 @@ test_read_wifi_open (void)
 
 	/* ===== WIRELESS SETTING ===== */
 
-	s_wireless = NM_SETTING_WIRELESS (nm_connection_get_setting (connection, NM_TYPE_SETTING_WIRELESS));
+	s_wireless = nm_connection_get_setting_wireless (connection);
 	ASSERT (s_wireless != NULL,
 	        "wifi-open-verify-wireless", "failed to verify %s: missing %s setting",
 	        TEST_IFCFG_WIFI_OPEN,
@@ -3120,7 +3122,7 @@ test_read_wifi_open (void)
 
 	/* ===== IPv4 SETTING ===== */
 
-	s_ip4 = NM_SETTING_IP4_CONFIG (nm_connection_get_setting (connection, NM_TYPE_SETTING_IP4_CONFIG));
+	s_ip4 = nm_connection_get_setting_ip4_config (connection);
 	ASSERT (s_ip4 != NULL,
 	        "wifi-open-verify-ip4", "failed to verify %s: missing %s setting",
 	        TEST_IFCFG_WIFI_OPEN,
@@ -3177,7 +3179,7 @@ test_read_wifi_open_auto (void)
 
 	/* ===== CONNECTION SETTING ===== */
 
-	s_con = NM_SETTING_CONNECTION (nm_connection_get_setting (connection, NM_TYPE_SETTING_CONNECTION));
+	s_con = nm_connection_get_setting_connection (connection);
 	ASSERT (s_con != NULL,
 	        "wifi-open-auto-verify-connection", "failed to verify %s: missing %s setting",
 	        TEST_IFCFG_WIFI_OPEN_AUTO,
@@ -3198,7 +3200,7 @@ test_read_wifi_open_auto (void)
 
 	/* ===== WIRELESS SETTING ===== */
 
-	s_wireless = NM_SETTING_WIRELESS (nm_connection_get_setting (connection, NM_TYPE_SETTING_WIRELESS));
+	s_wireless = nm_connection_get_setting_wireless (connection);
 	ASSERT (s_wireless != NULL,
 	        "wifi-open-auto-verify-wireless", "failed to verify %s: missing %s setting",
 	        TEST_IFCFG_WIFI_OPEN_AUTO,
@@ -3260,7 +3262,7 @@ test_read_wifi_open_ssid_hex (void)
 
 	/* ===== CONNECTION SETTING ===== */
 
-	s_con = NM_SETTING_CONNECTION (nm_connection_get_setting (connection, NM_TYPE_SETTING_CONNECTION));
+	s_con = nm_connection_get_setting_connection (connection);
 	ASSERT (s_con != NULL,
 	        "wifi-open-ssid-hex-verify-connection", "failed to verify %s: missing %s setting",
 	        TEST_IFCFG_WIFI_OPEN_SSID_HEX,
@@ -3281,7 +3283,7 @@ test_read_wifi_open_ssid_hex (void)
 
 	/* ===== WIRELESS SETTING ===== */
 
-	s_wireless = NM_SETTING_WIRELESS (nm_connection_get_setting (connection, NM_TYPE_SETTING_WIRELESS));
+	s_wireless = nm_connection_get_setting_wireless (connection);
 	ASSERT (s_wireless != NULL,
 	        "wifi-open-ssid-hex-verify-wireless", "failed to verify %s: missing %s setting",
 	        TEST_IFCFG_WIFI_OPEN_SSID_HEX,
@@ -3379,7 +3381,7 @@ test_read_wifi_open_ssid_quoted (void)
 
 	/* ===== CONNECTION SETTING ===== */
 
-	s_con = NM_SETTING_CONNECTION (nm_connection_get_setting (connection, NM_TYPE_SETTING_CONNECTION));
+	s_con = nm_connection_get_setting_connection (connection);
 	ASSERT (s_con != NULL,
 	        "wifi-open-ssid-quoted-verify-connection", "failed to verify %s: missing %s setting",
 	        TEST_IFCFG_WIFI_OPEN_SSID_QUOTED,
@@ -3400,7 +3402,7 @@ test_read_wifi_open_ssid_quoted (void)
 
 	/* ===== WIRELESS SETTING ===== */
 
-	s_wireless = NM_SETTING_WIRELESS (nm_connection_get_setting (connection, NM_TYPE_SETTING_WIRELESS));
+	s_wireless = nm_connection_get_setting_wireless (connection);
 	ASSERT (s_wireless != NULL,
 	        "wifi-open-ssid-quoted-verify-wireless", "failed to verify %s: missing %s setting",
 	        TEST_IFCFG_WIFI_OPEN_SSID_QUOTED,
@@ -3476,7 +3478,7 @@ test_read_wifi_wep (void)
 
 	/* ===== CONNECTION SETTING ===== */
 
-	s_con = NM_SETTING_CONNECTION (nm_connection_get_setting (connection, NM_TYPE_SETTING_CONNECTION));
+	s_con = nm_connection_get_setting_connection (connection);
 	ASSERT (s_con != NULL,
 	        "wifi-wep-verify-connection", "failed to verify %s: missing %s setting",
 	        TEST_IFCFG_WIFI_WEP,
@@ -3516,7 +3518,7 @@ test_read_wifi_wep (void)
 
 	/* ===== WIRELESS SETTING ===== */
 
-	s_wireless = NM_SETTING_WIRELESS (nm_connection_get_setting (connection, NM_TYPE_SETTING_WIRELESS));
+	s_wireless = nm_connection_get_setting_wireless (connection);
 	ASSERT (s_wireless != NULL,
 	        "wifi-wep-verify-wireless", "failed to verify %s: missing %s setting",
 	        TEST_IFCFG_WIFI_WEP,
@@ -3608,7 +3610,7 @@ test_read_wifi_wep (void)
 
 	/* ===== WIRELESS SECURITY SETTING ===== */
 
-	s_wsec = NM_SETTING_WIRELESS_SECURITY (nm_connection_get_setting (connection, NM_TYPE_SETTING_WIRELESS_SECURITY));
+	s_wsec = nm_connection_get_setting_wireless_security (connection);
 	ASSERT (s_wsec != NULL,
 	        "wifi-wep-verify-wireless", "failed to verify %s: missing %s setting",
 	        TEST_IFCFG_WIFI_WEP,
@@ -3687,7 +3689,7 @@ test_read_wifi_wep (void)
 
 	/* ===== IPv4 SETTING ===== */
 
-	s_ip4 = NM_SETTING_IP4_CONFIG (nm_connection_get_setting (connection, NM_TYPE_SETTING_IP4_CONFIG));
+	s_ip4 = nm_connection_get_setting_ip4_config (connection);
 	ASSERT (s_ip4 != NULL,
 	        "wifi-wep-verify-ip4", "failed to verify %s: missing %s setting",
 	        TEST_IFCFG_WIFI_WEP,
@@ -3752,7 +3754,7 @@ test_read_wifi_wep_adhoc (void)
 
 	/* ===== CONNECTION SETTING ===== */
 
-	s_con = NM_SETTING_CONNECTION (nm_connection_get_setting (connection, NM_TYPE_SETTING_CONNECTION));
+	s_con = nm_connection_get_setting_connection (connection);
 	ASSERT (s_con != NULL,
 	        "wifi-wep-adhoc-verify-connection", "failed to verify %s: missing %s setting",
 	        TEST_IFCFG_WIFI_WEP_ADHOC,
@@ -3785,7 +3787,7 @@ test_read_wifi_wep_adhoc (void)
 
 	/* ===== WIRELESS SETTING ===== */
 
-	s_wireless = NM_SETTING_WIRELESS (nm_connection_get_setting (connection, NM_TYPE_SETTING_WIRELESS));
+	s_wireless = nm_connection_get_setting_wireless (connection);
 	ASSERT (s_wireless != NULL,
 	        "wifi-wep-adhoc-verify-wireless", "failed to verify %s: missing %s setting",
 	        TEST_IFCFG_WIFI_WEP_ADHOC,
@@ -3852,7 +3854,7 @@ test_read_wifi_wep_adhoc (void)
 
 	/* ===== WIRELESS SECURITY SETTING ===== */
 
-	s_wsec = NM_SETTING_WIRELESS_SECURITY (nm_connection_get_setting (connection, NM_TYPE_SETTING_WIRELESS_SECURITY));
+	s_wsec = nm_connection_get_setting_wireless_security (connection);
 	ASSERT (s_wsec != NULL,
 	        "wifi-wep-adhoc-verify-wireless", "failed to verify %s: missing %s setting",
 	        TEST_IFCFG_WIFI_WEP_ADHOC,
@@ -3919,7 +3921,7 @@ test_read_wifi_wep_adhoc (void)
 
 	/* ===== IPv4 SETTING ===== */
 
-	s_ip4 = NM_SETTING_IP4_CONFIG (nm_connection_get_setting (connection, NM_TYPE_SETTING_IP4_CONFIG));
+	s_ip4 = nm_connection_get_setting_ip4_config (connection);
 	ASSERT (s_ip4 != NULL,
 	        "wifi-wep-adhoc-verify-ip4", "failed to verify %s: missing %s setting",
 	        TEST_IFCFG_WIFI_WEP_ADHOC,
@@ -4015,7 +4017,7 @@ test_read_wifi_wep_passphrase (void)
 
 	/* ===== CONNECTION SETTING ===== */
 
-	s_con = NM_SETTING_CONNECTION (nm_connection_get_setting (connection, NM_TYPE_SETTING_CONNECTION));
+	s_con = nm_connection_get_setting_connection (connection);
 	ASSERT (s_con != NULL,
 	        "wifi-wep-passphrase-verify-connection", "failed to verify %s: missing %s setting",
 	        TEST_IFCFG_WIFI_WEP_PASSPHRASE,
@@ -4023,7 +4025,7 @@ test_read_wifi_wep_passphrase (void)
 
 	/* ===== WIRELESS SETTING ===== */
 
-	s_wireless = NM_SETTING_WIRELESS (nm_connection_get_setting (connection, NM_TYPE_SETTING_WIRELESS));
+	s_wireless = nm_connection_get_setting_wireless (connection);
 	ASSERT (s_wireless != NULL,
 	        "wifi-wep-passphrase-verify-wireless", "failed to verify %s: missing %s setting",
 	        TEST_IFCFG_WIFI_WEP_PASSPHRASE,
@@ -4045,7 +4047,7 @@ test_read_wifi_wep_passphrase (void)
 
 	/* ===== WIRELESS SECURITY SETTING ===== */
 
-	s_wsec = NM_SETTING_WIRELESS_SECURITY (nm_connection_get_setting (connection, NM_TYPE_SETTING_WIRELESS_SECURITY));
+	s_wsec = nm_connection_get_setting_wireless_security (connection);
 	ASSERT (s_wsec != NULL,
 	        "wifi-wep-passphrase-verify-wireless", "failed to verify %s: missing %s setting",
 	        TEST_IFCFG_WIFI_WEP_PASSPHRASE,
@@ -4153,7 +4155,7 @@ test_read_wifi_wep_40_ascii (void)
 
 	/* ===== CONNECTION SETTING ===== */
 
-	s_con = NM_SETTING_CONNECTION (nm_connection_get_setting (connection, NM_TYPE_SETTING_CONNECTION));
+	s_con = nm_connection_get_setting_connection (connection);
 	ASSERT (s_con != NULL,
 	        "wifi-wep-40-ascii-verify-connection", "failed to verify %s: missing %s setting",
 	        TEST_IFCFG_WIFI_WEP_40_ASCII,
@@ -4161,7 +4163,7 @@ test_read_wifi_wep_40_ascii (void)
 
 	/* ===== WIRELESS SETTING ===== */
 
-	s_wireless = NM_SETTING_WIRELESS (nm_connection_get_setting (connection, NM_TYPE_SETTING_WIRELESS));
+	s_wireless = nm_connection_get_setting_wireless (connection);
 	ASSERT (s_wireless != NULL,
 	        "wifi-wep-40-ascii-verify-wireless", "failed to verify %s: missing %s setting",
 	        TEST_IFCFG_WIFI_WEP_40_ASCII,
@@ -4182,7 +4184,7 @@ test_read_wifi_wep_40_ascii (void)
 
 	/* ===== WIRELESS SECURITY SETTING ===== */
 
-	s_wsec = NM_SETTING_WIRELESS_SECURITY (nm_connection_get_setting (connection, NM_TYPE_SETTING_WIRELESS_SECURITY));
+	s_wsec = nm_connection_get_setting_wireless_security (connection);
 	ASSERT (s_wsec != NULL,
 	        "wifi-wep-40-ascii-verify-wireless", "failed to verify %s: missing %s setting",
 	        TEST_IFCFG_WIFI_WEP_40_ASCII,
@@ -4290,7 +4292,7 @@ test_read_wifi_wep_104_ascii (void)
 
 	/* ===== CONNECTION SETTING ===== */
 
-	s_con = NM_SETTING_CONNECTION (nm_connection_get_setting (connection, NM_TYPE_SETTING_CONNECTION));
+	s_con = nm_connection_get_setting_connection (connection);
 	ASSERT (s_con != NULL,
 	        "wifi-wep-104-ascii-verify-connection", "failed to verify %s: missing %s setting",
 	        TEST_IFCFG_WIFI_WEP_104_ASCII,
@@ -4298,7 +4300,7 @@ test_read_wifi_wep_104_ascii (void)
 
 	/* ===== WIRELESS SETTING ===== */
 
-	s_wireless = NM_SETTING_WIRELESS (nm_connection_get_setting (connection, NM_TYPE_SETTING_WIRELESS));
+	s_wireless = nm_connection_get_setting_wireless (connection);
 	ASSERT (s_wireless != NULL,
 	        "wifi-wep-104-ascii-verify-wireless", "failed to verify %s: missing %s setting",
 	        TEST_IFCFG_WIFI_WEP_104_ASCII,
@@ -4319,7 +4321,7 @@ test_read_wifi_wep_104_ascii (void)
 
 	/* ===== WIRELESS SECURITY SETTING ===== */
 
-	s_wsec = NM_SETTING_WIRELESS_SECURITY (nm_connection_get_setting (connection, NM_TYPE_SETTING_WIRELESS_SECURITY));
+	s_wsec = nm_connection_get_setting_wireless_security (connection);
 	ASSERT (s_wsec != NULL,
 	        "wifi-wep-104-ascii-verify-wireless", "failed to verify %s: missing %s setting",
 	        TEST_IFCFG_WIFI_WEP_104_ASCII,
@@ -4428,7 +4430,7 @@ test_read_wifi_leap (void)
 
 	/* ===== CONNECTION SETTING ===== */
 
-	s_con = NM_SETTING_CONNECTION (nm_connection_get_setting (connection, NM_TYPE_SETTING_CONNECTION));
+	s_con = nm_connection_get_setting_connection (connection);
 	ASSERT (s_con != NULL,
 	        "wifi-leap-verify-connection", "failed to verify %s: missing %s setting",
 	        TEST_IFCFG_WIFI_LEAP,
@@ -4449,7 +4451,7 @@ test_read_wifi_leap (void)
 
 	/* ===== WIRELESS SETTING ===== */
 
-	s_wireless = NM_SETTING_WIRELESS (nm_connection_get_setting (connection, NM_TYPE_SETTING_WIRELESS));
+	s_wireless = nm_connection_get_setting_wireless (connection);
 	ASSERT (s_wireless != NULL,
 	        "wifi-leap-verify-wireless", "failed to verify %s: missing %s setting",
 	        TEST_IFCFG_WIFI_LEAP,
@@ -4471,7 +4473,7 @@ test_read_wifi_leap (void)
 
 	/* ===== WIRELESS SECURITY SETTING ===== */
 
-	s_wsec = NM_SETTING_WIRELESS_SECURITY (nm_connection_get_setting (connection, NM_TYPE_SETTING_WIRELESS_SECURITY));
+	s_wsec = nm_connection_get_setting_wireless_security (connection);
 	ASSERT (s_wsec != NULL,
 	        "wifi-leap-verify-wireless", "failed to verify %s: missing %s setting",
 	        TEST_IFCFG_WIFI_LEAP,
@@ -4566,13 +4568,13 @@ test_read_wifi_leap_secret_flags (const char *file, NMSettingSecretFlags expecte
 	g_assert (success);
 
 	/* ===== WIRELESS SETTING ===== */
-	s_wifi = (NMSettingWireless *) nm_connection_get_setting (connection, NM_TYPE_SETTING_WIRELESS);
+	s_wifi = nm_connection_get_setting_wireless (connection);
 	g_assert (s_wifi);
 
 	g_assert (g_strcmp0 (nm_setting_wireless_get_security (s_wifi), NM_SETTING_WIRELESS_SECURITY_SETTING_NAME) == 0);
 
 	/* ===== WIRELESS SECURITY SETTING ===== */
-	s_wsec = (NMSettingWirelessSecurity *) nm_connection_get_setting (connection, NM_TYPE_SETTING_WIRELESS_SECURITY);
+	s_wsec = nm_connection_get_setting_wireless_security (connection);
 	g_assert (s_wsec);
 
 	g_assert (g_strcmp0 (nm_setting_wireless_security_get_key_mgmt (s_wsec), "ieee8021x") == 0);
@@ -4643,7 +4645,7 @@ test_read_wifi_wpa_psk (void)
 
 	/* ===== CONNECTION SETTING ===== */
 
-	s_con = NM_SETTING_CONNECTION (nm_connection_get_setting (connection, NM_TYPE_SETTING_CONNECTION));
+	s_con = nm_connection_get_setting_connection (connection);
 	ASSERT (s_con != NULL,
 	        "wifi-wpa-psk-verify-connection", "failed to verify %s: missing %s setting",
 	        TEST_IFCFG_WIFI_WPA_PSK,
@@ -4683,7 +4685,7 @@ test_read_wifi_wpa_psk (void)
 
 	/* ===== WIRELESS SETTING ===== */
 
-	s_wireless = NM_SETTING_WIRELESS (nm_connection_get_setting (connection, NM_TYPE_SETTING_WIRELESS));
+	s_wireless = nm_connection_get_setting_wireless (connection);
 	ASSERT (s_wireless != NULL,
 	        "wifi-wpa-psk-verify-wireless", "failed to verify %s: missing %s setting",
 	        TEST_IFCFG_WIFI_WPA_PSK,
@@ -4774,7 +4776,7 @@ test_read_wifi_wpa_psk (void)
 
 	/* ===== WIRELESS SECURITY SETTING ===== */
 
-	s_wsec = NM_SETTING_WIRELESS_SECURITY (nm_connection_get_setting (connection, NM_TYPE_SETTING_WIRELESS_SECURITY));
+	s_wsec = nm_connection_get_setting_wireless_security (connection);
 	ASSERT (s_wsec != NULL,
 	        "wifi-wpa-psk-verify-wireless", "failed to verify %s: missing %s setting",
 	        TEST_IFCFG_WIFI_WPA_PSK,
@@ -4887,7 +4889,7 @@ test_read_wifi_wpa_psk (void)
 
 	/* ===== IPv4 SETTING ===== */
 
-	s_ip4 = NM_SETTING_IP4_CONFIG (nm_connection_get_setting (connection, NM_TYPE_SETTING_IP4_CONFIG));
+	s_ip4 = nm_connection_get_setting_ip4_config (connection);
 	ASSERT (s_ip4 != NULL,
 	        "wifi-wpa-psk-verify-ip4", "failed to verify %s: missing %s setting",
 	        TEST_IFCFG_WIFI_WPA_PSK,
@@ -4908,6 +4910,111 @@ test_read_wifi_wpa_psk (void)
 	g_object_unref (connection);
 }
 
+#define TEST_IFCFG_WIFI_WPA_PSK_2 TEST_IFCFG_DIR"/network-scripts/ifcfg-test-wifi-wpa-psk-2"
+
+static void
+test_read_wifi_wpa_psk_2 (void)
+{
+	NMConnection *connection;
+	NMSettingConnection *s_con;
+	NMSettingWireless *s_wireless;
+	NMSettingWirelessSecurity *s_wsec;
+	char *unmanaged = NULL;
+	char *keyfile = NULL;
+	char *routefile = NULL;
+	char *route6file = NULL;
+	gboolean ignore_error = FALSE;
+	GError *error = NULL;
+	const char *tmp;
+	const char *expected_id = "System ipsum (test-wifi-wpa-psk-2)";
+	const char *expected_psk = "They're really saying I love you. >>`<<";
+
+	connection = connection_from_file (TEST_IFCFG_WIFI_WPA_PSK_2,
+                                     NULL,
+                                     TYPE_WIRELESS,
+                                     NULL,
+                                     &unmanaged,
+                                     &keyfile,
+                                     &routefile,
+                                     &route6file,
+                                     &error,
+                                     &ignore_error);
+	ASSERT (connection != NULL,
+	        "wifi-wpa-psk-2-read", "failed to read %s: %s", TEST_IFCFG_WIFI_WPA_PSK_2, error->message);
+
+	ASSERT (nm_connection_verify (connection, &error),
+	        "wifi-wpa-psk-2-verify", "failed to verify %s: %s", TEST_IFCFG_WIFI_WPA_PSK_2, error->message);
+
+	/* ===== CONNECTION SETTING ===== */
+
+	s_con = nm_connection_get_setting_connection (connection);
+	ASSERT (s_con != NULL,
+	        "wifi-wpa-psk-2-verify-connection", "failed to verify %s: missing %s setting",
+	        TEST_IFCFG_WIFI_WPA_PSK_2,
+	        NM_SETTING_CONNECTION_SETTING_NAME);
+
+	/* ID */
+	tmp = nm_setting_connection_get_id (s_con);
+	ASSERT (tmp != NULL,
+	        "wifi-wpa-psk-2-verify-connection", "failed to verify %s: missing %s / %s key",
+	        TEST_IFCFG_WIFI_WPA_PSK_2,
+	        NM_SETTING_CONNECTION_SETTING_NAME,
+	        NM_SETTING_CONNECTION_ID);
+	ASSERT (strcmp (tmp, expected_id) == 0,
+	        "wifi-wpa-psk-2-verify-connection", "failed to verify %s: unexpected %s / %s key value",
+	        TEST_IFCFG_WIFI_WPA_PSK_2,
+	        NM_SETTING_CONNECTION_SETTING_NAME,
+	        NM_SETTING_CONNECTION_ID);
+
+	/* ===== WIRELESS SETTING ===== */
+
+	s_wireless = nm_connection_get_setting_wireless (connection);
+	ASSERT (s_wireless != NULL,
+	        "wifi-wpa-psk-2-verify-wireless", "failed to verify %s: missing %s setting",
+	        TEST_IFCFG_WIFI_WPA_PSK_2,
+	        NM_SETTING_WIRELESS_SETTING_NAME);
+
+	/* Security */
+	tmp = nm_setting_wireless_get_security (s_wireless);
+	ASSERT (tmp != NULL,
+	        "wifi-wpa-psk-2-verify-wireless", "failed to verify %s: missing %s / %s key",
+	        TEST_IFCFG_WIFI_WPA_PSK_2,
+	        NM_SETTING_WIRELESS_SETTING_NAME,
+	        NM_SETTING_WIRELESS_SEC);
+	ASSERT (strcmp (tmp, NM_SETTING_WIRELESS_SECURITY_SETTING_NAME) == 0,
+	        "wifi-wpa-psk-2-verify-wireless", "failed to verify %s: unexpected %s / %s key value",
+	        TEST_IFCFG_WIFI_WPA_PSK_2,
+	        NM_SETTING_WIRELESS_SETTING_NAME,
+	        NM_SETTING_WIRELESS_SEC);
+
+	/* ===== WIRELESS SECURITY SETTING ===== */
+
+	s_wsec = nm_connection_get_setting_wireless_security (connection);
+	ASSERT (s_wsec != NULL,
+	        "wifi-wpa-psk-2-verify-wireless", "failed to verify %s: missing %s setting",
+	        TEST_IFCFG_WIFI_WPA_PSK_2,
+	        NM_SETTING_WIRELESS_SECURITY_SETTING_NAME);
+
+	/* PSK */
+	tmp = nm_setting_wireless_security_get_psk (s_wsec);
+	ASSERT (tmp != NULL,
+	        "wifi-wpa-psk-2-verify-wireless", "failed to verify %s: missing %s / %s key",
+	        TEST_IFCFG_WIFI_WPA_PSK_2,
+	        NM_SETTING_WIRELESS_SECURITY_SETTING_NAME,
+	        NM_SETTING_WIRELESS_SECURITY_PSK);
+	ASSERT (strcmp (tmp, expected_psk) == 0,
+	        "wifi-wpa-psk-2-verify-wireless", "failed to verify %s: unexpected %s / %s key value",
+	        TEST_IFCFG_WIFI_WPA_PSK_2,
+	        NM_SETTING_WIRELESS_SECURITY_SETTING_NAME,
+	        NM_SETTING_WIRELESS_SECURITY_PSK);
+
+	g_free (unmanaged);
+	g_free (keyfile);
+	g_free (routefile);
+	g_free (route6file);
+	g_object_unref (connection);
+}
+
 #define TEST_IFCFG_WIFI_WPA_PSK_UNQUOTED TEST_IFCFG_DIR"/network-scripts/ifcfg-test-wifi-wpa-psk-unquoted"
 
 static void
@@ -4945,7 +5052,7 @@ test_read_wifi_wpa_psk_unquoted (void)
 
 	/* ===== CONNECTION SETTING ===== */
 
-	s_con = NM_SETTING_CONNECTION (nm_connection_get_setting (connection, NM_TYPE_SETTING_CONNECTION));
+	s_con = nm_connection_get_setting_connection (connection);
 	ASSERT (s_con != NULL,
 	        "wifi-wpa-psk-unquoted-verify-connection", "failed to verify %s: missing %s setting",
 	        TEST_IFCFG_WIFI_WPA_PSK_UNQUOTED,
@@ -4966,7 +5073,7 @@ test_read_wifi_wpa_psk_unquoted (void)
 
 	/* ===== WIRELESS SETTING ===== */
 
-	s_wireless = NM_SETTING_WIRELESS (nm_connection_get_setting (connection, NM_TYPE_SETTING_WIRELESS));
+	s_wireless = nm_connection_get_setting_wireless (connection);
 	ASSERT (s_wireless != NULL,
 	        "wifi-wpa-psk-unquoted-verify-wireless", "failed to verify %s: missing %s setting",
 	        TEST_IFCFG_WIFI_WPA_PSK_UNQUOTED,
@@ -4987,7 +5094,7 @@ test_read_wifi_wpa_psk_unquoted (void)
 
 	/* ===== WIRELESS SECURITY SETTING ===== */
 
-	s_wsec = NM_SETTING_WIRELESS_SECURITY (nm_connection_get_setting (connection, NM_TYPE_SETTING_WIRELESS_SECURITY));
+	s_wsec = nm_connection_get_setting_wireless_security (connection);
 	ASSERT (s_wsec != NULL,
 	        "wifi-wpa-psk-unquoted-verify-wireless", "failed to verify %s: missing %s setting",
 	        TEST_IFCFG_WIFI_WPA_PSK_UNQUOTED,
@@ -5092,7 +5199,7 @@ test_read_wifi_wpa_psk_adhoc (void)
 
 	/* ===== CONNECTION SETTING ===== */
 
-	s_con = NM_SETTING_CONNECTION (nm_connection_get_setting (connection, NM_TYPE_SETTING_CONNECTION));
+	s_con = nm_connection_get_setting_connection (connection);
 	ASSERT (s_con != NULL,
 	        "wifi-wpa-psk-adhoc-verify-connection", "failed to verify %s: missing %s setting",
 	        TEST_IFCFG_WIFI_WPA_PSK_ADHOC,
@@ -5113,7 +5220,7 @@ test_read_wifi_wpa_psk_adhoc (void)
 
 	/* ===== WIRELESS SETTING ===== */
 
-	s_wireless = NM_SETTING_WIRELESS (nm_connection_get_setting (connection, NM_TYPE_SETTING_WIRELESS));
+	s_wireless = nm_connection_get_setting_wireless (connection);
 	ASSERT (s_wireless != NULL,
 	        "wifi-wpa-psk-adhoc-verify-wireless", "failed to verify %s: missing %s setting",
 	        TEST_IFCFG_WIFI_WPA_PSK_ADHOC,
@@ -5147,7 +5254,7 @@ test_read_wifi_wpa_psk_adhoc (void)
 
 	/* ===== WIRELESS SECURITY SETTING ===== */
 
-	s_wsec = NM_SETTING_WIRELESS_SECURITY (nm_connection_get_setting (connection, NM_TYPE_SETTING_WIRELESS_SECURITY));
+	s_wsec = nm_connection_get_setting_wireless_security (connection);
 	ASSERT (s_wsec != NULL,
 	        "wifi-wpa-psk-adhoc-verify-wireless", "failed to verify %s: missing %s setting",
 	        TEST_IFCFG_WIFI_WPA_PSK_ADHOC,
@@ -5221,7 +5328,7 @@ test_read_wifi_wpa_psk_adhoc (void)
 
 	/* ===== IPv4 SETTING ===== */
 
-	s_ip4 = NM_SETTING_IP4_CONFIG (nm_connection_get_setting (connection, NM_TYPE_SETTING_IP4_CONFIG));
+	s_ip4 = nm_connection_get_setting_ip4_config (connection);
 	ASSERT (s_ip4 != NULL,
 	        "wifi-wpa-psk-adhoc-verify-ip4", "failed to verify %s: missing %s setting",
 	        TEST_IFCFG_WIFI_WPA_PSK_ADHOC,
@@ -5283,7 +5390,7 @@ test_read_wifi_wpa_psk_hex (void)
 
 	/* ===== CONNECTION SETTING ===== */
 
-	s_con = NM_SETTING_CONNECTION (nm_connection_get_setting (connection, NM_TYPE_SETTING_CONNECTION));
+	s_con = nm_connection_get_setting_connection (connection);
 	ASSERT (s_con != NULL,
 	        "wifi-wpa-psk-hex-verify-connection", "failed to verify %s: missing %s setting",
 	        TEST_IFCFG_WIFI_WPA_PSK_HEX,
@@ -5304,7 +5411,7 @@ test_read_wifi_wpa_psk_hex (void)
 
 	/* ===== WIRELESS SETTING ===== */
 
-	s_wireless = NM_SETTING_WIRELESS (nm_connection_get_setting (connection, NM_TYPE_SETTING_WIRELESS));
+	s_wireless = nm_connection_get_setting_wireless (connection);
 	ASSERT (s_wireless != NULL,
 	        "wifi-wpa-psk-hex-verify-wireless", "failed to verify %s: missing %s setting",
 	        TEST_IFCFG_WIFI_WPA_PSK_HEX,
@@ -5343,7 +5450,7 @@ test_read_wifi_wpa_psk_hex (void)
 
 	/* ===== WIRELESS SECURITY SETTING ===== */
 
-	s_wsec = NM_SETTING_WIRELESS_SECURITY (nm_connection_get_setting (connection, NM_TYPE_SETTING_WIRELESS_SECURITY));
+	s_wsec = nm_connection_get_setting_wireless_security (connection);
 	ASSERT (s_wsec != NULL,
 	        "wifi-wpa-psk-hex-verify-wireless", "failed to verify %s: missing %s setting",
 	        TEST_IFCFG_WIFI_WPA_PSK_HEX,
@@ -5377,7 +5484,7 @@ test_read_wifi_wpa_psk_hex (void)
 
 	/* ===== IPv4 SETTING ===== */
 
-	s_ip4 = NM_SETTING_IP4_CONFIG (nm_connection_get_setting (connection, NM_TYPE_SETTING_IP4_CONFIG));
+	s_ip4 = nm_connection_get_setting_ip4_config (connection);
 	ASSERT (s_ip4 != NULL,
 	        "wifi-wpa-psk-hex-verify-ip4", "failed to verify %s: missing %s setting",
 	        TEST_IFCFG_WIFI_WPA_PSK_HEX,
@@ -5441,7 +5548,7 @@ test_read_wifi_wpa_eap_tls (void)
 
 	/* ===== WIRELESS SETTING ===== */
 
-	s_wireless = NM_SETTING_WIRELESS (nm_connection_get_setting (connection, NM_TYPE_SETTING_WIRELESS));
+	s_wireless = nm_connection_get_setting_wireless (connection);
 	ASSERT (s_wireless != NULL,
 	        "wifi-wpa-eap-tls-verify-wireless", "failed to verify %s: missing %s setting",
 	        TEST_IFCFG_WIFI_WPA_EAP_TLS,
@@ -5449,7 +5556,7 @@ test_read_wifi_wpa_eap_tls (void)
 
 	/* ===== IPv4 SETTING ===== */
 
-	s_ip4 = NM_SETTING_IP4_CONFIG (nm_connection_get_setting (connection, NM_TYPE_SETTING_IP4_CONFIG));
+	s_ip4 = nm_connection_get_setting_ip4_config (connection);
 	ASSERT (s_ip4 != NULL,
 	        "wifi-wpa-eap-tls-verify-ip4", "failed to verify %s: missing %s setting",
 	        TEST_IFCFG_WIFI_WPA_EAP_TLS,
@@ -5464,7 +5571,7 @@ test_read_wifi_wpa_eap_tls (void)
 	        NM_SETTING_IP4_CONFIG_METHOD);
 
 	/* ===== 802.1x SETTING ===== */
-	s_8021x = NM_SETTING_802_1X (nm_connection_get_setting (connection, NM_TYPE_SETTING_802_1X));
+	s_8021x = nm_connection_get_setting_802_1x (connection);
 	ASSERT (s_8021x != NULL,
 	        "wifi-wpa-eap-tls-verify-8021x", "failed to verify %s: missing %s setting",
 	        TEST_IFCFG_WIFI_WPA_EAP_TLS,
@@ -5591,7 +5698,7 @@ test_read_wifi_wpa_eap_ttls_tls (void)
 
 	/* ===== WIRELESS SETTING ===== */
 
-	s_wireless = NM_SETTING_WIRELESS (nm_connection_get_setting (connection, NM_TYPE_SETTING_WIRELESS));
+	s_wireless = nm_connection_get_setting_wireless (connection);
 	ASSERT (s_wireless != NULL,
 	        "wifi-wpa-eap-ttls-tls-verify-wireless", "failed to verify %s: missing %s setting",
 	        TEST_IFCFG_WIFI_WPA_EAP_TTLS_TLS,
@@ -5599,7 +5706,7 @@ test_read_wifi_wpa_eap_ttls_tls (void)
 
 	/* ===== IPv4 SETTING ===== */
 
-	s_ip4 = NM_SETTING_IP4_CONFIG (nm_connection_get_setting (connection, NM_TYPE_SETTING_IP4_CONFIG));
+	s_ip4 = nm_connection_get_setting_ip4_config (connection);
 	ASSERT (s_ip4 != NULL,
 	        "wifi-wpa-eap-ttls-tls-verify-ip4", "failed to verify %s: missing %s setting",
 	        TEST_IFCFG_WIFI_WPA_EAP_TTLS_TLS,
@@ -5614,7 +5721,7 @@ test_read_wifi_wpa_eap_ttls_tls (void)
 	        NM_SETTING_IP4_CONFIG_METHOD);
 
 	/* ===== 802.1x SETTING ===== */
-	s_8021x = NM_SETTING_802_1X (nm_connection_get_setting (connection, NM_TYPE_SETTING_802_1X));
+	s_8021x = nm_connection_get_setting_802_1x (connection);
 	ASSERT (s_8021x != NULL,
 	        "wifi-wpa-eap-ttls-tls-verify-8021x", "failed to verify %s: missing %s setting",
 	        TEST_IFCFG_WIFI_WPA_EAP_TTLS_TLS,
@@ -5756,13 +5863,13 @@ test_read_wifi_dynamic_wep_leap (void)
 
 	/* ===== WIRELESS SETTING ===== */
 
-	s_wifi = (NMSettingWireless *) nm_connection_get_setting (connection, NM_TYPE_SETTING_WIRELESS);
+	s_wifi = nm_connection_get_setting_wireless (connection);
 	g_assert (s_wifi);
 
 	g_assert_cmpstr (nm_setting_wireless_get_security (s_wifi), ==, NM_SETTING_WIRELESS_SECURITY_SETTING_NAME);
 
 	/* ===== WiFi SECURITY SETTING ===== */
-	s_wsec = (NMSettingWirelessSecurity *) nm_connection_get_setting (connection, NM_TYPE_SETTING_WIRELESS_SECURITY);
+	s_wsec = nm_connection_get_setting_wireless_security (connection);
 	g_assert (s_wsec);
 
 	/* Key management */
@@ -5778,7 +5885,7 @@ test_read_wifi_dynamic_wep_leap (void)
 	g_assert_cmpstr (nm_setting_wireless_security_get_leap_password (s_wsec), ==, NULL);
 
 	/* ===== 802.1x SETTING ===== */
-	s_8021x = (NMSetting8021x *) nm_connection_get_setting (connection, NM_TYPE_SETTING_802_1X);
+	s_8021x = nm_connection_get_setting_802_1x (connection);
 	g_assert (s_8021x);
 
 	/* EAP method should be "leap" */
@@ -5839,7 +5946,7 @@ test_read_wifi_wep_eap_ttls_chap (void)
 
 	/* ===== WIRELESS SETTING ===== */
 
-	s_wireless = NM_SETTING_WIRELESS (nm_connection_get_setting (connection, NM_TYPE_SETTING_WIRELESS));
+	s_wireless = nm_connection_get_setting_wireless (connection);
 	ASSERT (s_wireless != NULL,
 	        "wifi-wep-eap-ttls-chap-verify-wireless", "failed to verify %s: missing %s setting",
 	        TEST_IFCFG_WIFI_WEP_EAP_TTLS_CHAP,
@@ -5847,7 +5954,7 @@ test_read_wifi_wep_eap_ttls_chap (void)
 
 	/* ===== IPv4 SETTING ===== */
 
-	s_ip4 = NM_SETTING_IP4_CONFIG (nm_connection_get_setting (connection, NM_TYPE_SETTING_IP4_CONFIG));
+	s_ip4 = nm_connection_get_setting_ip4_config (connection);
 	ASSERT (s_ip4 != NULL,
 	        "wifi-wep-eap-ttls-chap-verify-ip4", "failed to verify %s: missing %s setting",
 	        TEST_IFCFG_WIFI_WEP_EAP_TTLS_CHAP,
@@ -5862,7 +5969,7 @@ test_read_wifi_wep_eap_ttls_chap (void)
 	        NM_SETTING_IP4_CONFIG_METHOD);
 
 	/* ===== 802.1x SETTING ===== */
-	s_wsec = NM_SETTING_WIRELESS_SECURITY (nm_connection_get_setting (connection, NM_TYPE_SETTING_WIRELESS_SECURITY));
+	s_wsec = nm_connection_get_setting_wireless_security (connection);
 	ASSERT (s_wsec != NULL,
 	        "wifi-wep-eap-ttls-chap-verify-wireless-security", "failed to verify %s: missing %s setting",
 	        TEST_IFCFG_WIFI_WEP_EAP_TTLS_CHAP,
@@ -5882,7 +5989,7 @@ test_read_wifi_wep_eap_ttls_chap (void)
 	        NM_SETTING_WIRELESS_SECURITY_KEY_MGMT);
 
 	/* ===== 802.1x SETTING ===== */
-	s_8021x = NM_SETTING_802_1X (nm_connection_get_setting (connection, NM_TYPE_SETTING_802_1X));
+	s_8021x = nm_connection_get_setting_802_1x (connection);
 	ASSERT (s_8021x != NULL,
 	        "wifi-wep-eap-ttls-chap-verify-8021x", "failed to verify %s: missing %s setting",
 	        TEST_IFCFG_WIFI_WEP_EAP_TTLS_CHAP,
@@ -6005,7 +6112,7 @@ test_read_wired_qeth_static (void)
 
 	/* ===== CONNECTION SETTING ===== */
 
-	s_con = NM_SETTING_CONNECTION (nm_connection_get_setting (connection, NM_TYPE_SETTING_CONNECTION));
+	s_con = nm_connection_get_setting_connection (connection);
 	ASSERT (s_con != NULL,
 	        "wired-qeth-static-verify-connection", "failed to verify %s: missing %s setting",
 	        TEST_IFCFG_WIRED_QETH_STATIC,
@@ -6026,7 +6133,7 @@ test_read_wired_qeth_static (void)
 
 	/* ===== WIRED SETTING ===== */
 
-	s_wired = NM_SETTING_WIRED (nm_connection_get_setting (connection, NM_TYPE_SETTING_WIRED));
+	s_wired = nm_connection_get_setting_wired (connection);
 	ASSERT (s_wired != NULL,
 	        "wired-qeth-static-verify-wired", "failed to verify %s: missing %s setting",
 	        TEST_IFCFG_WIRED_QETH_STATIC,
@@ -6116,7 +6223,7 @@ test_read_wired_qeth_static (void)
 
 	/* ===== IPv4 SETTING ===== */
 
-	s_ip4 = NM_SETTING_IP4_CONFIG (nm_connection_get_setting (connection, NM_TYPE_SETTING_IP4_CONFIG));
+	s_ip4 = nm_connection_get_setting_ip4_config (connection);
 	ASSERT (s_ip4 != NULL,
 	        "wired-qeth-static-verify-ip4", "failed to verify %s: missing %s setting",
 	        TEST_IFCFG_WIRED_QETH_STATIC,
@@ -6247,7 +6354,7 @@ test_read_wifi_wep_no_keys (void)
 
 	/* ===== CONNECTION SETTING ===== */
 
-	s_con = NM_SETTING_CONNECTION (nm_connection_get_setting (connection, NM_TYPE_SETTING_CONNECTION));
+	s_con = nm_connection_get_setting_connection (connection);
 	ASSERT (s_con != NULL,
 	        "wifi-wep-no-keys-verify-connection", "failed to verify %s: missing %s setting",
 	        TEST_IFCFG_WIFI_WEP_NO_KEYS,
@@ -6273,7 +6380,7 @@ test_read_wifi_wep_no_keys (void)
 
 	/* ===== WIRELESS SETTING ===== */
 
-	s_wireless = NM_SETTING_WIRELESS (nm_connection_get_setting (connection, NM_TYPE_SETTING_WIRELESS));
+	s_wireless = nm_connection_get_setting_wireless (connection);
 	ASSERT (s_wireless != NULL,
 	        "wifi-wep-no-keys-verify-wireless", "failed to verify %s: missing %s setting",
 	        TEST_IFCFG_WIFI_WEP_NO_KEYS,
@@ -6295,7 +6402,7 @@ test_read_wifi_wep_no_keys (void)
 
 	/* ===== WIRELESS SECURITY SETTING ===== */
 
-	s_wsec = NM_SETTING_WIRELESS_SECURITY (nm_connection_get_setting (connection, NM_TYPE_SETTING_WIRELESS_SECURITY));
+	s_wsec = nm_connection_get_setting_wireless_security (connection);
 	ASSERT (s_wsec != NULL,
 	        "wifi-wep-no-keys-verify-wireless", "failed to verify %s: missing %s setting",
 	        TEST_IFCFG_WIFI_WEP_NO_KEYS,
@@ -6371,7 +6478,7 @@ test_read_permissions (void)
 
 	/* ===== CONNECTION SETTING ===== */
 
-	s_con = NM_SETTING_CONNECTION (nm_connection_get_setting (connection, NM_TYPE_SETTING_CONNECTION));
+	s_con = nm_connection_get_setting_connection (connection);
 	ASSERT (s_con != NULL,
 	        "permissions-verify-connection", "failed to verify %s: missing %s setting",
 	        TEST_IFCFG_PERMISSIONS,
@@ -6451,13 +6558,13 @@ test_read_wifi_wep_agent_keys (void)
 	 */
 
 	/* ===== WIRELESS SETTING ===== */
-	s_wifi = (NMSettingWireless *) nm_connection_get_setting (connection, NM_TYPE_SETTING_WIRELESS);
+	s_wifi = nm_connection_get_setting_wireless (connection);
 	g_assert (s_wifi);
 	tmp = nm_setting_wireless_get_security (s_wifi);
 	g_assert (g_strcmp0 (tmp, NM_SETTING_WIRELESS_SECURITY_SETTING_NAME) == 0);
 
 	/* ===== WIRELESS SECURITY SETTING ===== */
-	s_wsec = (NMSettingWirelessSecurity *) nm_connection_get_setting (connection, NM_TYPE_SETTING_WIRELESS_SECURITY);
+	s_wsec = nm_connection_get_setting_wireless_security (connection);
 	g_assert (s_wsec);
 
 	g_assert (strcmp (nm_setting_wireless_security_get_key_mgmt (s_wsec), "none") == 0);
@@ -6692,8 +6799,8 @@ test_write_wired_static (void)
 	 * However after re-reading they are dropped into IPv4 setting.
 	 * So, in order to comparison succeeded, move DNS domains back to IPv6 setting.
 	 */
-	reread_s_ip4 = NM_SETTING_IP4_CONFIG (nm_connection_get_setting (reread, NM_TYPE_SETTING_IP4_CONFIG));
-	reread_s_ip6 = NM_SETTING_IP6_CONFIG (nm_connection_get_setting (reread, NM_TYPE_SETTING_IP6_CONFIG));
+	reread_s_ip4 = nm_connection_get_setting_ip4_config (reread);
+	reread_s_ip6 = nm_connection_get_setting_ip6_config (reread);
 	nm_setting_ip6_config_add_dns_search (reread_s_ip6, nm_setting_ip4_config_get_dns_search (reread_s_ip4, 2));
 	nm_setting_ip6_config_add_dns_search (reread_s_ip6, nm_setting_ip4_config_get_dns_search (reread_s_ip4, 3));
 	nm_setting_ip4_config_remove_dns_search (reread_s_ip4, 3);
@@ -7018,7 +7125,7 @@ test_read_write_static_routes_legacy (void)
 
 	/* ===== CONNECTION SETTING ===== */
 
-	s_con = NM_SETTING_CONNECTION (nm_connection_get_setting (connection, NM_TYPE_SETTING_CONNECTION));
+	s_con = nm_connection_get_setting_connection (connection);
 	ASSERT (s_con != NULL,
 	        "read-write-static-routes-legacy-verify-connection", "failed to verify %s: missing %s setting",
 	        TEST_IFCFG_READ_WRITE_STATIC_ROUTES_LEGACY,
@@ -7041,7 +7148,7 @@ test_read_write_static_routes_legacy (void)
 
 	/* ===== WIRED SETTING ===== */
 
-	s_wired = NM_SETTING_WIRED (nm_connection_get_setting (connection, NM_TYPE_SETTING_WIRED));
+	s_wired = nm_connection_get_setting_wired (connection);
 	ASSERT (s_wired != NULL,
 	        "read-write-static-routes-legacy-verify-wired", "failed to verify %s: missing %s setting",
 	        TEST_IFCFG_READ_WRITE_STATIC_ROUTES_LEGACY,
@@ -7049,7 +7156,7 @@ test_read_write_static_routes_legacy (void)
 
 	/* ===== IPv4 SETTING ===== */
 
-	s_ip4 = NM_SETTING_IP4_CONFIG (nm_connection_get_setting (connection, NM_TYPE_SETTING_IP4_CONFIG));
+	s_ip4 = nm_connection_get_setting_ip4_config (connection);
 	ASSERT (s_ip4 != NULL,
 	        "read-write-static-routes-legacy-verify-ip4", "failed to verify %s: missing %s setting",
 	        TEST_IFCFG_READ_WRITE_STATIC_ROUTES_LEGACY,
@@ -7628,7 +7735,7 @@ test_write_wired_8021x_tls (NMSetting8021xCKScheme scheme,
 	 * matter what scheme was used in the original connection they will be read
 	 * back in as paths.
 	 */
-	s_8021x = (NMSetting8021x *) nm_connection_get_setting (reread, NM_TYPE_SETTING_802_1X);
+	s_8021x = nm_connection_get_setting_802_1x (reread);
 	g_assert (s_8021x);
 	g_assert_cmpint (nm_setting_802_1x_get_ca_cert_scheme (s_8021x), ==, NM_SETTING_802_1X_CK_SCHEME_PATH);
 	g_assert_cmpint (nm_setting_802_1x_get_client_cert_scheme (s_8021x), ==, NM_SETTING_802_1X_CK_SCHEME_PATH);
@@ -7657,7 +7764,7 @@ test_write_wired_8021x_tls (NMSetting8021xCKScheme scheme,
 			 * say it's not system-owned, and therefore it should not show up
 			 * in the re-read connection.
 			 */
-			s_8021x = (NMSetting8021x *) nm_connection_get_setting (connection, NM_TYPE_SETTING_802_1X);
+			s_8021x = nm_connection_get_setting_802_1x (connection);
 			g_object_set (s_8021x, NM_SETTING_802_1X_PRIVATE_KEY_PASSWORD, NULL, NULL);
 		}
 
@@ -10085,7 +10192,7 @@ test_write_wifi_wpa_then_open (void)
 	g_object_unref (reread);
 
 	/* Now change the connection to open and recheck */
-	s_wifi = (NMSettingWireless *) nm_connection_get_setting (connection, NM_TYPE_SETTING_WIRELESS);
+	s_wifi = nm_connection_get_setting_wireless (connection);
 	g_assert (s_wifi);
 	g_object_set (s_wifi, NM_SETTING_WIRELESS_SEC, NULL, NULL);
 	nm_connection_remove_setting (connection, NM_TYPE_SETTING_WIRELESS_SECURITY);
@@ -10534,7 +10641,7 @@ test_read_ibft_dhcp (void)
 
 	/* ===== CONNECTION SETTING ===== */
 
-	s_con = NM_SETTING_CONNECTION (nm_connection_get_setting (connection, NM_TYPE_SETTING_CONNECTION));
+	s_con = nm_connection_get_setting_connection (connection);
 	ASSERT (s_con != NULL,
 	        "ibft-dhcp-verify-connection", "failed to verify %s: missing %s setting",
 	        TEST_IFCFG_IBFT_DHCP,
@@ -10581,7 +10688,7 @@ test_read_ibft_dhcp (void)
 
 	/* ===== WIRED SETTING ===== */
 
-	s_wired = NM_SETTING_WIRED (nm_connection_get_setting (connection, NM_TYPE_SETTING_WIRED));
+	s_wired = nm_connection_get_setting_wired (connection);
 	ASSERT (s_wired != NULL,
 	        "ibft-dhcp-verify-wired", "failed to verify %s: missing %s setting",
 	        TEST_IFCFG_IBFT_DHCP,
@@ -10613,7 +10720,7 @@ test_read_ibft_dhcp (void)
 
 	/* ===== IPv4 SETTING ===== */
 
-	s_ip4 = NM_SETTING_IP4_CONFIG (nm_connection_get_setting (connection, NM_TYPE_SETTING_IP4_CONFIG));
+	s_ip4 = nm_connection_get_setting_ip4_config (connection);
 	ASSERT (s_ip4 != NULL,
 	        "ibft-dhcp-verify-ip4", "failed to verify %s: missing %s setting",
 	        TEST_IFCFG_IBFT_DHCP,
@@ -10679,7 +10786,7 @@ test_read_ibft_static (void)
 
 	/* ===== CONNECTION SETTING ===== */
 
-	s_con = NM_SETTING_CONNECTION (nm_connection_get_setting (connection, NM_TYPE_SETTING_CONNECTION));
+	s_con = nm_connection_get_setting_connection (connection);
 	ASSERT (s_con != NULL,
 	        "ibft-static-verify-connection", "failed to verify %s: missing %s setting",
 	        TEST_IFCFG_IBFT_STATIC,
@@ -10726,7 +10833,7 @@ test_read_ibft_static (void)
 
 	/* ===== WIRED SETTING ===== */
 
-	s_wired = NM_SETTING_WIRED (nm_connection_get_setting (connection, NM_TYPE_SETTING_WIRED));
+	s_wired = nm_connection_get_setting_wired (connection);
 	ASSERT (s_wired != NULL,
 	        "ibft-static-verify-wired", "failed to verify %s: missing %s setting",
 	        TEST_IFCFG_IBFT_STATIC,
@@ -10758,7 +10865,7 @@ test_read_ibft_static (void)
 
 	/* ===== IPv4 SETTING ===== */
 
-	s_ip4 = NM_SETTING_IP4_CONFIG (nm_connection_get_setting (connection, NM_TYPE_SETTING_IP4_CONFIG));
+	s_ip4 = nm_connection_get_setting_ip4_config (connection);
 	ASSERT (s_ip4 != NULL,
 	        "ibft-static-verify-ip4", "failed to verify %s: missing %s setting",
 	        TEST_IFCFG_IBFT_STATIC,
@@ -11754,6 +11861,8 @@ test_read_vlan_interface (void)
 	char *route6file = NULL;
 	gboolean ignore_error = FALSE;
 	GError *error = NULL;
+	NMSettingVlan *s_vlan;
+	guint32 from = 0, to = 0;
 
 	connection = connection_from_file (TEST_IFCFG_VLAN_INTERFACE,
 	                                   NULL,
@@ -11765,13 +11874,844 @@ test_read_vlan_interface (void)
 	                                   &route6file,
 	                                   &error,
 	                                   &ignore_error);
-	ASSERT (connection == NULL,
-	        "vlan-interface-read", "unexpected success reading %s", TEST_IFCFG_VLAN_INTERFACE);
+	g_assert_no_error (error);
+	g_assert (connection != NULL);
+
+	g_free (unmanaged);
+	g_free (keyfile);
+	g_free (routefile);
+	g_free (route6file);
+
+	s_vlan = nm_connection_get_setting_vlan (connection);
+	g_assert (s_vlan);
+
+	g_assert_cmpstr (nm_setting_vlan_get_interface_name (s_vlan), ==, "vlan43");
+	g_assert_cmpstr (nm_setting_vlan_get_parent (s_vlan), ==, "eth9");
+	g_assert_cmpint (nm_setting_vlan_get_id (s_vlan), ==, 43);
+	g_assert_cmpint (nm_setting_vlan_get_flags (s_vlan), ==,
+	                 NM_VLAN_FLAG_GVRP | NM_VLAN_FLAG_LOOSE_BINDING);
+
+	/* Ingress map */
+	g_assert_cmpint (nm_setting_vlan_get_num_priorities (s_vlan, NM_VLAN_INGRESS_MAP), ==, 2);
+
+	g_assert (nm_setting_vlan_get_priority (s_vlan, NM_VLAN_INGRESS_MAP, 0, &from, &to));
+	g_assert_cmpint (from, ==, 0);
+	g_assert_cmpint (to, ==, 1);
+
+	g_assert (nm_setting_vlan_get_priority (s_vlan, NM_VLAN_INGRESS_MAP, 1, &from, &to));
+	g_assert_cmpint (from, ==, 2);
+	g_assert_cmpint (to, ==, 5);
+
+	/* Egress map */
+	g_assert_cmpint (nm_setting_vlan_get_num_priorities (s_vlan, NM_VLAN_EGRESS_MAP), ==, 3);
+
+	g_assert (nm_setting_vlan_get_priority (s_vlan, NM_VLAN_EGRESS_MAP, 0, &from, &to));
+	g_assert_cmpint (from, ==, 12);
+	g_assert_cmpint (to, ==, 3);
+
+	g_assert (nm_setting_vlan_get_priority (s_vlan, NM_VLAN_EGRESS_MAP, 1, &from, &to));
+	g_assert_cmpint (from, ==, 14);
+	g_assert_cmpint (to, ==, 7);
+
+	g_assert (nm_setting_vlan_get_priority (s_vlan, NM_VLAN_EGRESS_MAP, 2, &from, &to));
+	g_assert_cmpint (from, ==, 3);
+	g_assert_cmpint (to, ==, 1);
+
+	g_object_unref (connection);
+}
+
+#define TEST_IFCFG_VLAN_ONLY_VLANID TEST_IFCFG_DIR"/network-scripts/ifcfg-test-vlan-only-vlanid"
+
+static void
+test_read_vlan_only_vlan_id (void)
+{
+	NMConnection *connection;
+	char *unmanaged = NULL;
+	char *keyfile = NULL;
+	char *routefile = NULL;
+	char *route6file = NULL;
+	gboolean ignore_error = FALSE;
+	GError *error = NULL;
+	NMSettingVlan *s_vlan;
+
+	connection = connection_from_file (TEST_IFCFG_VLAN_ONLY_VLANID,
+	                                   NULL,
+	                                   TYPE_ETHERNET,
+	                                   NULL,
+	                                   &unmanaged,
+	                                   &keyfile,
+	                                   &routefile,
+	                                   &route6file,
+	                                   &error,
+	                                   &ignore_error);
+	g_assert_no_error (error);
+	g_assert (connection != NULL);
+
+	g_free (unmanaged);
+	g_free (keyfile);
+	g_free (routefile);
+	g_free (route6file);
+
+	s_vlan = nm_connection_get_setting_vlan (connection);
+	g_assert (s_vlan);
+
+	g_assert (nm_setting_vlan_get_interface_name (s_vlan) == NULL);
+	g_assert_cmpstr (nm_setting_vlan_get_parent (s_vlan), ==, "eth9");
+	g_assert_cmpint (nm_setting_vlan_get_id (s_vlan), ==, 43);
+
+	g_object_unref (connection);
+}
+
+#define TEST_IFCFG_VLAN_ONLY_DEVICE TEST_IFCFG_DIR"/network-scripts/ifcfg-test-vlan-only-device"
+
+static void
+test_read_vlan_only_device (void)
+{
+	NMConnection *connection;
+	char *unmanaged = NULL;
+	char *keyfile = NULL;
+	char *routefile = NULL;
+	char *route6file = NULL;
+	gboolean ignore_error = FALSE;
+	GError *error = NULL;
+	NMSettingVlan *s_vlan;
+
+	connection = connection_from_file (TEST_IFCFG_VLAN_ONLY_DEVICE,
+	                                   NULL,
+	                                   TYPE_ETHERNET,
+	                                   NULL,
+	                                   &unmanaged,
+	                                   &keyfile,
+	                                   &routefile,
+	                                   &route6file,
+	                                   &error,
+	                                   &ignore_error);
+	g_assert_no_error (error);
+	g_assert (connection != NULL);
+
+	g_free (unmanaged);
+	g_free (keyfile);
+	g_free (routefile);
+	g_free (route6file);
+
+	s_vlan = nm_connection_get_setting_vlan (connection);
+	g_assert (s_vlan);
+
+	g_assert_cmpstr (nm_setting_vlan_get_interface_name (s_vlan), ==, "eth0.9");
+	g_assert_cmpstr (nm_setting_vlan_get_parent (s_vlan), ==, "eth0");
+	g_assert_cmpint (nm_setting_vlan_get_id (s_vlan), ==, 9);
+
+	g_object_unref (connection);
+}
+
+static void
+test_write_vlan (void)
+{
+	NMConnection *connection;
+	char *unmanaged = NULL;
+	char *keyfile = NULL;
+	char *routefile = NULL;
+	char *route6file = NULL;
+	char *written = NULL;
+	gboolean ignore_error = FALSE;
+	GError *error = NULL;
+	gboolean success = FALSE;
+
+	connection = connection_from_file (TEST_IFCFG_VLAN_INTERFACE,
+	                                   NULL,
+	                                   TYPE_VLAN,
+	                                   NULL,
+	                                   &unmanaged,
+	                                   &keyfile,
+	                                   &routefile,
+	                                   &route6file,
+	                                   &error,
+	                                   &ignore_error);
+	g_assert (connection != NULL);
+
+	success = writer_new_connection (connection,
+	                                 TEST_SCRATCH_DIR "/network-scripts/",
+	                                 &written,
+	                                 &error);
+	g_assert (success);
+
+	unlink (written);
+	g_free (written);
+
+	g_free (unmanaged);
+	g_free (keyfile);
+	g_free (routefile);
+	g_free (route6file);
+}
+
+static void
+test_write_vlan_only_vlanid (void)
+{
+	NMConnection *connection, *reread;
+	char *unmanaged = NULL;
+	char *keyfile = NULL;
+	char *routefile = NULL;
+	char *route6file = NULL;
+	char *written = NULL;
+	gboolean ignore_error = FALSE;
+	GError *error = NULL;
+	gboolean success = FALSE;
+
+	connection = connection_from_file (TEST_IFCFG_VLAN_ONLY_VLANID,
+	                                   NULL,
+	                                   TYPE_VLAN,
+	                                   NULL,
+	                                   &unmanaged,
+	                                   &keyfile,
+	                                   &routefile,
+	                                   &route6file,
+	                                   &error,
+	                                   &ignore_error);
+	g_assert_no_error (error);
+	g_assert (connection != NULL);
+
+	g_free (unmanaged);
+	unmanaged = NULL;
+	g_free (keyfile);
+	keyfile = NULL;
+	g_free (routefile);
+	routefile = NULL;
+	g_free (route6file);
+	route6file = NULL;
+
+	success = writer_new_connection (connection,
+	                                 TEST_SCRATCH_DIR "/network-scripts/",
+	                                 &written,
+	                                 &error);
+	g_assert (success);
+
+	/* re-read the connection for comparison */
+	reread = connection_from_file (written,
+	                               NULL,
+	                               TYPE_ETHERNET,
+	                               NULL,
+	                               &unmanaged,
+	                               &keyfile,
+	                               &routefile,
+	                               &route6file,
+	                               &error,
+	                               &ignore_error);
+	unlink (written);
+	g_free (written);
+	g_free (unmanaged);
+	g_free (keyfile);
+	g_free (routefile);
+	g_free (route6file);
+
+	g_assert_no_error (error);
+	g_assert (reread != NULL);
+
+	success = nm_connection_verify (reread, &error);
+	g_assert_no_error (error);
+	g_assert (success);
+
+	success = nm_connection_compare (connection, reread, NM_SETTING_COMPARE_FLAG_EXACT);
+	g_assert (success);
+
+	g_object_unref (connection);
+	g_object_unref (reread);
+}
+
+#define TEST_IFCFG_BOND_MAIN TEST_IFCFG_DIR"/network-scripts/ifcfg-test-bond-main"
+
+static void
+test_read_bond_main (void)
+{
+	NMConnection *connection;
+	NMSettingBond *s_bond;
+	char *unmanaged = NULL;
+	char *keyfile = NULL;
+	char *routefile = NULL;
+	char *route6file = NULL;
+	gboolean ignore_error = FALSE;
+	GError *error = NULL;
+
+	connection = connection_from_file (TEST_IFCFG_BOND_MAIN,
+	                                   NULL,
+	                                   TYPE_ETHERNET,
+	                                   NULL,
+	                                   &unmanaged,
+	                                   &keyfile,
+	                                   &routefile,
+	                                   &route6file,
+	                                   &error,
+	                                   &ignore_error);
+	ASSERT (connection != NULL,
+	        "bond-main-read", "unexpected failure reading %s", TEST_IFCFG_BOND_MAIN);
+
+	ASSERT (nm_connection_verify (connection, &error),
+	        "bond-main-read", "failed to verify %s: %s", TEST_IFCFG_BOND_MAIN, error->message);
+
+	/* ===== Bonding SETTING ===== */
+
+	s_bond = nm_connection_get_setting_bond (connection);
+	ASSERT (s_bond != NULL,
+	        "bond-main", "failed to verify %s: missing %s setting",
+	        TEST_IFCFG_BOND_MAIN,
+	        NM_SETTING_BOND_SETTING_NAME);
+
+	ASSERT (g_strcmp0 (nm_setting_bond_get_interface_name (s_bond), "bond0") == 0,
+	        "bond-main", "failed to verify %s: DEVICE=%s does not match bond0",
+	        TEST_IFCFG_BOND_MAIN, nm_setting_bond_get_interface_name (s_bond));
+
+	ASSERT (g_strcmp0 (nm_setting_bond_get_option_by_name (s_bond, NM_SETTING_BOND_OPTION_MIIMON), "100") == 0,
+	        "bond-main", "failed to verify %s: miimon=%s does not match 100",
+	        TEST_IFCFG_BOND_MAIN, nm_setting_bond_get_option_by_name (s_bond, NM_SETTING_BOND_OPTION_MIIMON));
 
 	g_free (unmanaged);
 	g_free (keyfile);
 	g_free (routefile);
 	g_free (route6file);
+	g_object_unref (connection);
+}
+
+static void
+test_write_bond_main (void)
+{
+	NMConnection *connection;
+	NMConnection *reread;
+	NMSettingConnection *s_con;
+	NMSettingBond *s_bond;
+	NMSettingIP4Config *s_ip4;
+	NMSettingIP6Config *s_ip6;
+	NMSettingWired *s_wired;
+	char *uuid;
+	const guint32 ip1 = htonl (0x01010103);
+	const guint32 gw = htonl (0x01010101);
+	const guint32 prefix = 24;
+	NMIP4Address *addr;
+	gboolean success;
+	GError *error = NULL;
+	char *testfile = NULL;
+	char *unmanaged = NULL;
+	char *keyfile = NULL;
+	char *routefile = NULL;
+	char *route6file = NULL;
+	gboolean ignore_error = FALSE;
+
+	connection = nm_connection_new ();
+	ASSERT (connection != NULL,
+	        "bond-main-write", "failed to allocate new connection");
+
+	/* Connection setting */
+	s_con = (NMSettingConnection *) nm_setting_connection_new ();
+	ASSERT (s_con != NULL,
+	        "bond-main-write", "failed to allocate new %s setting",
+	        NM_SETTING_CONNECTION_SETTING_NAME);
+	nm_connection_add_setting (connection, NM_SETTING (s_con));
+
+	uuid = nm_utils_uuid_generate ();
+	g_object_set (s_con,
+	              NM_SETTING_CONNECTION_ID, "Test Write Bond Main",
+	              NM_SETTING_CONNECTION_UUID, uuid,
+	              NM_SETTING_CONNECTION_AUTOCONNECT, TRUE,
+	              NM_SETTING_CONNECTION_TYPE, NM_SETTING_BOND_SETTING_NAME,
+	              NULL);
+	g_free (uuid);
+
+	/* Wired setting */
+	s_wired = (NMSettingWired *) nm_setting_wired_new ();
+	ASSERT (s_wired != NULL,
+	        "bond-main-write", "failed to allocate new %s setting",
+	        NM_SETTING_WIRED_SETTING_NAME);
+	nm_connection_add_setting (connection, NM_SETTING (s_wired));
+
+	/* bond setting */
+	s_bond = (NMSettingBond *) nm_setting_bond_new ();
+	ASSERT (s_bond != NULL,
+	        "bond-main-write", "failed to allocate new %s setting",
+	        NM_SETTING_BOND_SETTING_NAME);
+	nm_connection_add_setting (connection, NM_SETTING (s_bond));
+
+	g_object_set (s_bond,
+	              NM_SETTING_BOND_INTERFACE_NAME, "bond0",
+	              NULL);
+
+	/* IP4 setting */
+	s_ip4 = (NMSettingIP4Config *) nm_setting_ip4_config_new ();
+	ASSERT (s_ip4 != NULL,
+			"bond-main-write", "failed to allocate new %s setting",
+			NM_SETTING_IP4_CONFIG_SETTING_NAME);
+	nm_connection_add_setting (connection, NM_SETTING (s_ip4));
+
+	g_object_set (s_ip4,
+	              NM_SETTING_IP4_CONFIG_METHOD, NM_SETTING_IP4_CONFIG_METHOD_MANUAL,
+	              NM_SETTING_IP4_CONFIG_MAY_FAIL, TRUE,
+	              NULL);
+
+	addr = nm_ip4_address_new ();
+	nm_ip4_address_set_address (addr, ip1);
+	nm_ip4_address_set_prefix (addr, prefix);
+	nm_ip4_address_set_gateway (addr, gw);
+	nm_setting_ip4_config_add_address (s_ip4, addr);
+	nm_ip4_address_unref (addr);
+
+	/* IP6 setting */
+	s_ip6 = (NMSettingIP6Config *) nm_setting_ip6_config_new ();
+	ASSERT (s_ip6 != NULL,
+	        "bond-main-write", "failed to allocate new %s setting",
+	        NM_SETTING_IP6_CONFIG_SETTING_NAME);
+	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,
+	              NULL);
+
+	ASSERT (nm_connection_verify (connection, &error) == TRUE,
+	        "bond-main-write", "failed to verify connection: %s",
+	        (error && error->message) ? error->message : "(unknown)");
+
+	/* Save the ifcfg */
+	success = writer_new_connection (connection,
+	                                 TEST_SCRATCH_DIR "/network-scripts/",
+	                                 &testfile,
+	                                 &error);
+	ASSERT (success == TRUE,
+	        "bond-main-write", "failed to write connection to disk: %s",
+	        (error && error->message) ? error->message : "(unknown)");
+
+	ASSERT (testfile != NULL,
+	        "bond-main-write", "didn't get ifcfg file path back after writing connection");
+
+	/* re-read the connection for comparison */
+	reread = connection_from_file (testfile,
+	                               NULL,
+	                               TYPE_BOND,
+	                               NULL,
+	                               &unmanaged,
+	                               &keyfile,
+	                               &routefile,
+	                               &route6file,
+	                               &error,
+	                               &ignore_error);
+	unlink (testfile);
+
+	ASSERT (reread != NULL,
+	        "bond-main-write-reread", "failed to read %s: %s", testfile, error->message);
+
+	ASSERT (nm_connection_verify (reread, &error),
+	        "bond-main-write-reread-verify", "failed to verify %s: %s", testfile, error->message);
+
+	ASSERT (nm_connection_compare (connection, reread, NM_SETTING_COMPARE_FLAG_EXACT) == TRUE,
+	        "bond-main-write", "written and re-read connection weren't the same.");
+
+	g_free (testfile);
+	g_free (unmanaged);
+	g_free (keyfile);
+	g_free (routefile);
+	g_free (route6file);
+	g_object_unref (connection);
+	g_object_unref (reread);
+}
+
+#define TEST_IFCFG_BOND_SLAVE TEST_IFCFG_DIR"/network-scripts/ifcfg-test-bond-slave"
+
+static void
+test_read_bond_slave (void)
+{
+	NMConnection *connection;
+	NMSettingConnection *s_con;
+	char *unmanaged = NULL;
+	char *keyfile = NULL;
+	char *routefile = NULL;
+	char *route6file = NULL;
+	gboolean ignore_error = FALSE;
+	GError *error = NULL;
+
+	connection = connection_from_file (TEST_IFCFG_BOND_SLAVE,
+	                                   NULL,
+	                                   TYPE_ETHERNET,
+	                                   NULL,
+	                                   &unmanaged,
+	                                   &keyfile,
+	                                   &routefile,
+	                                   &route6file,
+	                                   &error,
+	                                   &ignore_error);
+	ASSERT (connection != NULL,
+	        "bond-slave-read", "unexpected failure reading %s", TEST_IFCFG_BOND_MAIN);
+
+	ASSERT (nm_connection_verify (connection, &error),
+	        "bond-slave-read", "failed to verify %s: %s", TEST_IFCFG_BOND_MAIN, error->message);
+
+	s_con = nm_connection_get_setting_connection (connection);
+	ASSERT (s_con != NULL,
+	        "bond-slave-read", "failed to verify %s: missing %s setting",
+	        TEST_IFCFG_BOND_SLAVE, NM_SETTING_CONNECTION_SETTING_NAME);
+
+	ASSERT (g_strcmp0 (nm_setting_connection_get_master (s_con), "bond0") == 0,
+	        "bond-slave-read", "failed to verify %s: master is not bond0",
+	        TEST_IFCFG_BOND_SLAVE);
+
+	ASSERT (g_strcmp0 (nm_setting_connection_get_slave_type (s_con), NM_SETTING_BOND_SETTING_NAME) == 0,
+	        "bond-slave-read", "failed to verify %s: slave-type is not bond",
+	        TEST_IFCFG_BOND_SLAVE);
+
+	g_free (unmanaged);
+	g_free (keyfile);
+	g_free (routefile);
+	g_free (route6file);
+	g_object_unref (connection);
+}
+
+static void
+test_write_bond_slave (void)
+{
+	NMConnection *connection;
+	NMConnection *reread;
+	NMSettingConnection *s_con;
+	NMSettingWired *s_wired;
+	NMSettingIP4Config *s_ip4;
+	NMSettingIP6Config *s_ip6;
+	static unsigned char tmpmac[] = { 0x31, 0x33, 0x33, 0x37, 0xbe, 0xcd };
+	GByteArray *mac;
+	guint32 mtu = 1492;
+	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;
+
+	connection = nm_connection_new ();
+	ASSERT (connection != NULL,
+	        "bond-slave-write", "failed to allocate new connection");
+
+	/* Connection setting */
+	s_con = (NMSettingConnection *) nm_setting_connection_new ();
+	ASSERT (s_con != NULL,
+	        "bond-slave-write", "failed to allocate new %s setting",
+	        NM_SETTING_CONNECTION_SETTING_NAME);
+	nm_connection_add_setting (connection, NM_SETTING (s_con));
+
+	uuid = nm_utils_uuid_generate ();
+	g_object_set (s_con,
+	              NM_SETTING_CONNECTION_ID, "Test Write Bond Slave",
+	              NM_SETTING_CONNECTION_UUID, uuid,
+	              NM_SETTING_CONNECTION_AUTOCONNECT, TRUE,
+	              NM_SETTING_CONNECTION_TYPE, NM_SETTING_WIRED_SETTING_NAME,
+				  NM_SETTING_CONNECTION_MASTER, "bond0",
+				  NM_SETTING_CONNECTION_SLAVE_TYPE, NM_SETTING_BOND_SETTING_NAME,
+	              NULL);
+	g_free (uuid);
+
+	/* Wired setting */
+	s_wired = (NMSettingWired *) nm_setting_wired_new ();
+	ASSERT (s_wired != NULL,
+	        "bond-main-write", "failed to allocate new %s setting",
+	        NM_SETTING_WIRED_SETTING_NAME);
+	nm_connection_add_setting (connection, NM_SETTING (s_wired));
+
+	mac = g_byte_array_sized_new (sizeof (tmpmac));
+	g_byte_array_append (mac, &tmpmac[0], sizeof (tmpmac));
+
+	g_object_set (s_wired,
+	              NM_SETTING_WIRED_MAC_ADDRESS, mac,
+	              NM_SETTING_WIRED_MTU, mtu,
+	              NULL);
+	g_byte_array_free (mac, TRUE);
+
+	/* IP4 setting */
+	s_ip4 = (NMSettingIP4Config *) nm_setting_ip4_config_new ();
+	ASSERT (s_ip4 != NULL,
+			"bond-slave-write", "failed to allocate new %s setting",
+			NM_SETTING_IP4_CONFIG_SETTING_NAME);
+	nm_connection_add_setting (connection, NM_SETTING (s_ip4));
+
+	g_object_set (s_ip4,
+	              NM_SETTING_IP4_CONFIG_METHOD, NM_SETTING_IP4_CONFIG_METHOD_DISABLED,
+	              NULL);
+
+	/* IP6 setting */
+	s_ip6 = (NMSettingIP6Config *) nm_setting_ip6_config_new ();
+	ASSERT (s_ip6 != NULL,
+	        "bond-slave-write", "failed to allocate new %s setting",
+	        NM_SETTING_IP6_CONFIG_SETTING_NAME);
+	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);
+
+	ASSERT (nm_connection_verify (connection, &error) == TRUE,
+	        "bond-slave-write", "failed to verify connection: %s",
+	        (error && error->message) ? error->message : "(unknown)");
+
+	/* Save the ifcfg */
+	success = writer_new_connection (connection,
+	                                 TEST_SCRATCH_DIR "/network-scripts/",
+	                                 &testfile,
+	                                 &error);
+	ASSERT (success == TRUE,
+	        "bond-slave-write", "failed to write connection to disk: %s",
+	        (error && error->message) ? error->message : "(unknown)");
+
+	ASSERT (testfile != NULL,
+	        "bond-slave-write", "didn't get ifcfg file path back after writing connection");
+
+	/* re-read the connection for comparison */
+	reread = connection_from_file (testfile,
+	                               NULL,
+	                               TYPE_ETHERNET,
+	                               NULL,
+	                               &unmanaged,
+	                               &keyfile,
+	                               &routefile,
+	                               &route6file,
+	                               &error,
+	                               &ignore_error);
+	unlink (testfile);
+
+	ASSERT (reread != NULL,
+	        "bond-slave-write-reread", "failed to read %s: %s", testfile, error->message);
+
+	ASSERT (nm_connection_verify (reread, &error),
+	        "bond-slave-write-reread-verify", "failed to verify %s: %s", testfile, error->message);
+
+	ASSERT (nm_connection_compare (connection, reread, NM_SETTING_COMPARE_FLAG_EXACT) == TRUE,
+	        "bond-slave-write", "written and re-read connection weren't the same.");
+
+	if (route6file)
+		unlink (route6file);
+
+	g_free (testfile);
+	g_free (unmanaged);
+	g_free (keyfile);
+	g_free (routefile);
+	g_free (route6file);
+	g_object_unref (connection);
+	g_object_unref (reread);
+}
+
+#define TEST_IFCFG_INFINIBAND TEST_IFCFG_DIR"/network-scripts/ifcfg-test-infiniband"
+
+static void
+test_read_infiniband (void)
+{
+	NMConnection *connection;
+	NMSettingInfiniband *s_infiniband;
+	char *unmanaged = NULL;
+	char *keyfile = NULL;
+	char *routefile = NULL;
+	char *route6file = NULL;
+	gboolean ignore_error = FALSE;
+	GError *error = NULL;
+	const GByteArray *array;
+	char expected_mac_address[INFINIBAND_ALEN] = { 0x80, 0x00, 0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77, 0x88, 0x99, 0xaa, 0xbb, 0xcc, 0xdd, 0xee, 0xff, 0x00, 0x11, 0x22 };
+	const char *transport_mode;
+
+	connection = connection_from_file (TEST_IFCFG_INFINIBAND,
+	                                   NULL,
+	                                   TYPE_INFINIBAND,
+	                                   NULL,
+	                                   &unmanaged,
+	                                   &keyfile,
+	                                   &routefile,
+	                                   &route6file,
+	                                   &error,
+	                                   &ignore_error);
+	ASSERT (connection != NULL,
+	        "infiniband-read", "failed to read %s: %s", TEST_IFCFG_INFINIBAND, error->message);
+
+	ASSERT (nm_connection_verify (connection, &error),
+	        "infiniband-verify", "failed to verify %s: %s", TEST_IFCFG_INFINIBAND, error->message);
+
+	ASSERT (unmanaged == NULL,
+	        "infiniband-verify", "failed to verify %s: unexpected unmanaged value", TEST_IFCFG_INFINIBAND);
+
+	/* ===== INFINIBAND SETTING ===== */
+
+	s_infiniband = nm_connection_get_setting_infiniband (connection);
+	ASSERT (s_infiniband != NULL,
+	        "infiniband-verify-wired", "failed to verify %s: missing %s setting",
+	        TEST_IFCFG_INFINIBAND,
+	        NM_SETTING_INFINIBAND_SETTING_NAME);
+
+	/* MAC address */
+	array = nm_setting_infiniband_get_mac_address (s_infiniband);
+	ASSERT (array != NULL,
+	        "infiniband-verify-infiniband", "failed to verify %s: missing %s / %s key",
+	        TEST_IFCFG_INFINIBAND,
+	        NM_SETTING_INFINIBAND_SETTING_NAME,
+	        NM_SETTING_INFINIBAND_MAC_ADDRESS);
+	ASSERT (array->len == INFINIBAND_ALEN,
+	        "infiniband-verify-infiniband", "failed to verify %s: unexpected %s / %s key value length",
+	        TEST_IFCFG_INFINIBAND,
+	        NM_SETTING_INFINIBAND_SETTING_NAME,
+	        NM_SETTING_INFINIBAND_MAC_ADDRESS);
+	ASSERT (memcmp (array->data, &expected_mac_address[0], sizeof (expected_mac_address)) == 0,
+	        "infiniband-verify-infiniband", "failed to verify %s: unexpected %s / %s key value",
+	        TEST_IFCFG_INFINIBAND,
+	        NM_SETTING_INFINIBAND_SETTING_NAME,
+	        NM_SETTING_INFINIBAND_MAC_ADDRESS);
+
+	/* Transport mode */
+	transport_mode = nm_setting_infiniband_get_transport_mode (s_infiniband);
+	ASSERT (transport_mode != NULL,
+	        "infiniband-verify-infiniband", "failed to verify %s: missing %s / %s key",
+	        TEST_IFCFG_INFINIBAND,
+	        NM_SETTING_INFINIBAND_SETTING_NAME,
+	        NM_SETTING_INFINIBAND_TRANSPORT_MODE);
+	ASSERT (strcmp (transport_mode, "connected") == 0,
+	        "infiniband-verify-infiniband", "failed to verify %s: unexpected %s / %s key value",
+	        TEST_IFCFG_INFINIBAND,
+	        NM_SETTING_INFINIBAND_SETTING_NAME,
+	        NM_SETTING_INFINIBAND_TRANSPORT_MODE);
+
+	g_free (unmanaged);
+	g_free (keyfile);
+	g_free (routefile);
+	g_free (route6file);
+	g_object_unref (connection);
+}
+
+static void
+test_write_infiniband (void)
+{
+	NMConnection *connection;
+	NMConnection *reread;
+	NMSettingConnection *s_con;
+	NMSettingInfiniband *s_infiniband;
+	NMSettingIP4Config *s_ip4;
+	NMSettingIP6Config *s_ip6;
+	unsigned char tmpmac[INFINIBAND_ALEN] = { 0x80, 0x00, 0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77, 0x88, 0x99, 0xaa, 0xbb, 0xcc, 0xdd, 0xee, 0xff, 0x00, 0x11, 0x22 };
+	GByteArray *mac;
+	guint32 mtu = 65520;
+	char *uuid;
+	const guint32 ip1 = htonl (0x01010103);
+	const guint32 gw = htonl (0x01010101);
+	const guint32 prefix = 24;
+	NMIP4Address *addr;
+	gboolean success;
+	GError *error = NULL;
+	char *testfile = NULL;
+	char *unmanaged = NULL;
+	char *keyfile = NULL;
+	char *routefile = NULL;
+	char *route6file = NULL;
+	gboolean ignore_error = FALSE;
+
+	connection = nm_connection_new ();
+	ASSERT (connection != NULL,
+	        "infiniband-write", "failed to allocate new connection");
+
+	/* Connection setting */
+	s_con = (NMSettingConnection *) nm_setting_connection_new ();
+	ASSERT (s_con != NULL,
+	        "infiniband-write", "failed to allocate new %s setting",
+	        NM_SETTING_CONNECTION_SETTING_NAME);
+	nm_connection_add_setting (connection, NM_SETTING (s_con));
+
+	uuid = nm_utils_uuid_generate ();
+	g_object_set (s_con,
+	              NM_SETTING_CONNECTION_ID, "Test Write InfiniBand",
+	              NM_SETTING_CONNECTION_UUID, uuid,
+	              NM_SETTING_CONNECTION_AUTOCONNECT, TRUE,
+	              NM_SETTING_CONNECTION_TYPE, NM_SETTING_INFINIBAND_SETTING_NAME,
+	              NULL);
+	g_free (uuid);
+
+	/* InfiniBand setting */
+	s_infiniband = (NMSettingInfiniband *) nm_setting_infiniband_new ();
+	ASSERT (s_infiniband != NULL,
+	        "infiniband-write", "failed to allocate new %s setting",
+	        NM_SETTING_INFINIBAND_SETTING_NAME);
+	nm_connection_add_setting (connection, NM_SETTING (s_infiniband));
+
+	mac = g_byte_array_sized_new (sizeof (tmpmac));
+	g_byte_array_append (mac, &tmpmac[0], sizeof (tmpmac));
+
+	g_object_set (s_infiniband,
+	              NM_SETTING_INFINIBAND_MAC_ADDRESS, mac,
+	              NM_SETTING_INFINIBAND_MTU, mtu,
+	              NM_SETTING_INFINIBAND_TRANSPORT_MODE, "connected",
+	              NULL);
+	g_byte_array_free (mac, TRUE);
+
+	/* IP4 setting */
+	s_ip4 = (NMSettingIP4Config *) nm_setting_ip4_config_new ();
+	ASSERT (s_ip4 != NULL,
+			"infiniband-write", "failed to allocate new %s setting",
+			NM_SETTING_IP4_CONFIG_SETTING_NAME);
+	nm_connection_add_setting (connection, NM_SETTING (s_ip4));
+
+	g_object_set (s_ip4,
+	              NM_SETTING_IP4_CONFIG_METHOD, NM_SETTING_IP4_CONFIG_METHOD_MANUAL,
+	              NM_SETTING_IP4_CONFIG_MAY_FAIL, TRUE,
+	              NULL);
+
+	addr = nm_ip4_address_new ();
+	nm_ip4_address_set_address (addr, ip1);
+	nm_ip4_address_set_prefix (addr, prefix);
+	nm_ip4_address_set_gateway (addr, gw);
+	nm_setting_ip4_config_add_address (s_ip4, addr);
+	nm_ip4_address_unref (addr);
+
+	/* IP6 setting */
+	s_ip6 = (NMSettingIP6Config *) nm_setting_ip6_config_new ();
+	ASSERT (s_ip6 != NULL,
+	        "wired-static-write", "failed to allocate new %s setting",
+	        NM_SETTING_IP6_CONFIG_SETTING_NAME);
+	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,
+	              NULL);
+
+	ASSERT (nm_connection_verify (connection, &error) == TRUE,
+	        "infiniband-write", "failed to verify connection: %s",
+	        (error && error->message) ? error->message : "(unknown)");
+
+	/* Save the ifcfg */
+	success = writer_new_connection (connection,
+	                                 TEST_SCRATCH_DIR "/network-scripts/",
+	                                 &testfile,
+	                                 &error);
+	ASSERT (success == TRUE,
+	        "infiniband-write", "failed to write connection to disk: %s",
+	        (error && error->message) ? error->message : "(unknown)");
+
+	ASSERT (testfile != NULL,
+	        "infiniband-write", "didn't get ifcfg file path back after writing connection");
+
+	/* re-read the connection for comparison */
+	reread = connection_from_file (testfile,
+	                               NULL,
+	                               TYPE_INFINIBAND,
+	                               NULL,
+	                               &unmanaged,
+	                               &keyfile,
+	                               &routefile,
+	                               &route6file,
+	                               &error,
+	                               &ignore_error);
+	unlink (testfile);
+
+	ASSERT (reread != NULL,
+	        "infiniband-write-reread", "failed to read %s: %s", testfile, error->message);
+
+	ASSERT (nm_connection_verify (reread, &error),
+	        "infiniband-write-reread-verify", "failed to verify %s: %s", testfile, error->message);
+
+	ASSERT (nm_connection_compare (connection, reread, NM_SETTING_COMPARE_FLAG_EXACT) == TRUE,
+	        "infiniband-write", "written and re-read connection weren't the same.");
+
+	g_free (testfile);
+	g_free (unmanaged);
+	g_free (keyfile);
+	g_free (routefile);
+	g_free (route6file);
+	g_object_unref (connection);
+	g_object_unref (reread);
 }
 
 #define TEST_IFCFG_WIFI_OPEN_SSID_BAD_HEX TEST_IFCFG_DIR"/network-scripts/ifcfg-test-wifi-open-ssid-bad-hex"
@@ -11843,6 +12783,7 @@ int main (int argc, char **argv)
 	test_read_wifi_leap_secret_flags (TEST_IFCFG_WIFI_LEAP_ALWAYS,
 	                                  NM_SETTING_SECRET_FLAG_AGENT_OWNED | NM_SETTING_SECRET_FLAG_NOT_SAVED);
 	test_read_wifi_wpa_psk ();
+	test_read_wifi_wpa_psk_2 ();
 	test_read_wifi_wpa_psk_unquoted ();
 	test_read_wifi_wpa_psk_unquoted2 ();
 	test_read_wifi_wpa_psk_adhoc ();
@@ -11856,6 +12797,10 @@ int main (int argc, char **argv)
 	test_read_wifi_wep_no_keys ();
 	test_read_permissions ();
 	test_read_wifi_wep_agent_keys ();
+	test_read_infiniband ();
+	test_read_vlan_interface ();
+	test_read_vlan_only_vlan_id ();
+	test_read_vlan_only_device ();
 
 	test_write_wired_static ();
 	test_write_wired_static_ip6_only ();
@@ -11908,6 +12853,12 @@ int main (int argc, char **argv)
 	                         TRUE,
 	                         TRUE,
 	                         "really insecure passphrase04!");
+	test_write_wifi_wpa_psk ("Test Write Wifi WPA WPA2 PSK Passphrase Special Chars",
+	                         "wifi-wpa-wpa2-psk-passphrase-write-spec-chars",
+	                         FALSE,
+	                         TRUE,
+	                         TRUE,
+	                         "blah`oops\"grr'$*@~!%");
 	test_write_wifi_wpa_psk_adhoc ();
 	test_write_wifi_wpa_eap_tls ();
 	test_write_wifi_wpa_eap_ttls_tls ();
@@ -11919,6 +12870,9 @@ int main (int argc, char **argv)
 	test_write_wired_ctc_dhcp ();
 	test_write_permissions ();
 	test_write_wifi_wep_agent_keys ();
+	test_write_infiniband ();
+	test_write_vlan ();
+	test_write_vlan_only_vlanid ();
 
 	/* iSCSI / ibft */
 	test_read_ibft_dhcp ();
@@ -11930,6 +12884,12 @@ int main (int argc, char **argv)
 	test_read_ibft_malformed ("ibft-bad-dns1-read", TEST_IFCFG_DIR "/iscsiadm-test-bad-dns1");
 	test_read_ibft_malformed ("ibft-bad-dns2-read", TEST_IFCFG_DIR "/iscsiadm-test-bad-dns2");
 
+	/* bonding */
+	test_read_bond_main ();
+	test_read_bond_slave ();
+	test_write_bond_main ();
+	test_write_bond_slave ();
+
 	/* Stuff we expect to fail for now */
 	test_write_wired_pppoe ();
 	test_write_vpn ();
@@ -11937,7 +12897,6 @@ int main (int argc, char **argv)
 	test_write_mobile_broadband (FALSE);
 	test_read_bridge_main ();
 	test_read_bridge_component ();
-	test_read_vlan_interface ();
 
 	base = g_path_get_basename (argv[0]);
 	fprintf (stdout, "%s: SUCCESS\n", base);
diff --git a/src/settings/plugins/ifcfg-rh/utils.c b/src/settings/plugins/ifcfg-rh/utils.c
index 92a0b802..0b7ddf36 100644
--- a/src/settings/plugins/ifcfg-rh/utils.c
+++ b/src/settings/plugins/ifcfg-rh/utils.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.
  *
- * (C) Copyright 2008 - 2010 Red Hat, Inc.
+ * (C) Copyright 2008 - 2012 Red Hat, Inc.
  */
 
 #include <glib.h>
@@ -116,6 +116,89 @@ utils_hexstr2bin (const char *hex, size_t len)
 /* End from hostap */
 
 /*
+ * utils_single_quote_string
+ *
+ * Put string inside single quotes and remove CR, LF characters. If single quote
+ * is present, escape it with a backslash and prepend the whole string with $
+ * in order to have $'string'. That allows us to use single quote inside
+ * single quotes without breaking bash syntax. (man bash, section QUOTING).
+ *
+ * Caller is responsible for freeing the returned string.
+ */
+char *
+utils_single_quote_string (const char *str)
+{
+	static const char const drop_chars[] = "\r\n"; /* drop CR and LF */
+	static const char escape_char = '\\'; /* escape char is backslash */
+	static const char quote_char = '\'';  /* quote char is single quote */
+	size_t i, slen, j = 0;
+	size_t drop = 0, extra = 0;
+	char *new_str;
+
+	slen = strlen (str);
+	for (i = 0; i < slen; i++) {
+		if (str[i] == quote_char)
+			extra++;
+		if (strchr (drop_chars, str[i]))
+			drop++;
+	}
+	new_str = g_malloc0 (slen + extra - drop + 4); /* 4 is for $''\0*/
+	if (!new_str) return NULL;
+
+	if (extra > 0)
+		new_str[j++] = '$';
+	new_str[j++] = quote_char;
+	for (i = 0; i < slen; i++) {
+		if (strchr (drop_chars, str[i]))
+			continue;
+		if (str[i] == quote_char)
+			new_str[j++] = escape_char;
+		new_str[j++] = str[i];
+	}
+	new_str[j] = quote_char;
+
+	return new_str;
+}
+
+/*
+ * utils_single_unquote_string
+ *
+ * Remove string from single (or double) quotes, and remove escaping of '.
+ * Also remove first $ if the string is in the form of $'string'.
+ *
+ * Caller is responsible for freeing the returned string.
+ */
+char *
+utils_single_unquote_string (const char *str)
+{
+	static const char escape_char = '\\'; /* escape char is backslash */
+	static const char q_char = '\''; /* quote char is single quote */
+	static const char dq_char = '"'; /* double quote char */
+	size_t i, slen, j = 0, quote = 0, dollar = 0;
+	char *new_str;
+
+	slen = strlen (str);
+	new_str = g_malloc0 (slen + 1);
+	if (!new_str) return NULL;
+
+	if (   (slen >= 2 && (str[0] == dq_char || str[0] == q_char) && str[0] == str[slen-1])
+	    || (slen >= 3 && str[0] == '$' && str[1] == q_char && str[1] == str[slen-1])) {
+		quote = 1;
+		if (str[0] == '$') dollar = 1;
+	}
+
+	i = quote + dollar;
+	while (i < slen - quote) {
+		if (str[i] == escape_char && str[i+1] == q_char)
+			i++;
+		new_str[j++] = str[i++];
+	}
+	new_str[j] = '\0';
+
+	return new_str;
+}
+
+/*
  * Check ';[a-fA-F0-9]{8}' file suffix used for temporary files by rpm when
  * installing packages.
  *
@@ -360,3 +443,17 @@ gone:
 	return ret;
 }
 
+gboolean
+utils_disabling_ip4_config_allowed (NMConnection *connection)
+{
+	NMSettingConnection *s_con;
+
+	s_con = nm_connection_get_setting_connection (connection);
+	g_assert (s_con);
+
+	/* bonding slaves are allowed to have no ip configuration */
+	if (nm_setting_connection_is_slave_type (s_con, NM_SETTING_BOND_SETTING_NAME))
+		return TRUE;
+
+	return FALSE;
+}
diff --git a/src/settings/plugins/ifcfg-rh/utils.h b/src/settings/plugins/ifcfg-rh/utils.h
index d5e3a133..4fe7303b 100644
--- a/src/settings/plugins/ifcfg-rh/utils.h
+++ b/src/settings/plugins/ifcfg-rh/utils.h
@@ -15,13 +15,14 @@
  * with this program; if not, write to the Free Software Foundation, Inc.,
  * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
  *
- * (C) Copyright 2008 - 2009 Red Hat, Inc.
+ * (C) Copyright 2008 - 2012 Red Hat, Inc.
  */
 
 #ifndef _UTILS_H_
 #define _UTILS_H_
 
 #include <glib.h>
+#include <nm-connection.h>
 #include "shvar.h"
 #include "common.h"
 
@@ -29,6 +30,10 @@ char *utils_bin2hexstr (const char *bytes, int len, int final_len);
 
 char *utils_hexstr2bin (const char *hex, size_t len);
 
+char *utils_single_quote_string (const char *str);
+
+char *utils_single_unquote_string (const char *str);
+
 char *utils_cert_path (const char *parent, const char *suffix);
 
 const char *utils_get_ifcfg_name (const char *file, gboolean only_ifcfg);
@@ -47,5 +52,7 @@ shvarFile *utils_get_route6_ifcfg (const char *parent, gboolean should_create);
 
 gboolean utils_has_route_file_new_syntax (const char *filename);
 
+gboolean utils_disabling_ip4_config_allowed (NMConnection *connection);
+
 #endif  /* _UTILS_H_ */
 
diff --git a/src/settings/plugins/ifcfg-rh/writer.c b/src/settings/plugins/ifcfg-rh/writer.c
index 068bcda2..e2aa57dd 100644
--- a/src/settings/plugins/ifcfg-rh/writer.c
+++ b/src/settings/plugins/ifcfg-rh/writer.c
@@ -15,7 +15,7 @@
  * with this program; if not, write to the Free Software Foundation, Inc.,
  * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
  *
- * Copyright (C) 2009 - 2011 Red Hat, Inc.
+ * Copyright (C) 2009 - 2012 Red Hat, Inc.
  */
 
 #include <ctype.h>
@@ -28,6 +28,7 @@
 #include <sys/stat.h>
 #include <unistd.h>
 #include <stdio.h>
+#include <netinet/ether.h>
 
 #include <nm-setting-connection.h>
 #include <nm-setting-wired.h>
@@ -36,6 +37,7 @@
 #include <nm-setting-ip4-config.h>
 #include <nm-setting-ip6-config.h>
 #include <nm-setting-pppoe.h>
+#include <nm-setting-vlan.h>
 #include <nm-utils.h>
 
 #include "common.h"
@@ -456,7 +458,7 @@ write_8021x_setting (NMConnection *connection,
 	gboolean success = FALSE;
 	GString *phase2_auth;
 
-	s_8021x = (NMSetting8021x *) nm_connection_get_setting (connection, NM_TYPE_SETTING_802_1X);
+	s_8021x = nm_connection_get_setting_802_1x (connection);
 	if (!s_8021x) {
 		/* If wired, clear KEY_MGMT */
 		if (wired)
@@ -504,6 +506,24 @@ write_8021x_setting (NMConnection *connection,
 	if (value && !strcmp (value, "1"))
 		svSetValue (ifcfg, "IEEE_8021X_PEAP_FORCE_NEW_LABEL", "yes", FALSE);
 
+	/* PAC file */
+	value = nm_setting_802_1x_get_pac_file (s_8021x);
+	svSetValue (ifcfg, "IEEE_8021X_PAC_FILE", NULL, FALSE);
+	if (value)
+		svSetValue (ifcfg, "IEEE_8021X_PAC_FILE", value, FALSE);
+
+	/* FAST PAC provisioning */
+	value = nm_setting_802_1x_get_phase1_fast_provisioning (s_8021x);
+	svSetValue (ifcfg, "IEEE_8021X_FAST_PROVISIONING", NULL, FALSE);
+	if (value) {
+		if (strcmp (value, "1") == 0)
+			svSetValue (ifcfg, "IEEE_8021X_FAST_PROVISIONING", "allow-unauth", FALSE);
+		else if (strcmp (value, "2") == 0)
+			svSetValue (ifcfg, "IEEE_8021X_FAST_PROVISIONING", "allow-auth", FALSE);
+		else if (strcmp (value, "3") == 0)
+			svSetValue (ifcfg, "IEEE_8021X_FAST_PROVISIONING", "allow-unauth allow-auth", FALSE);
+	}
+
 	/* Phase2 auth methods */
 	svSetValue (ifcfg, "IEEE_8021X_INNER_AUTH_METHODS", NULL, FALSE);
 	phase2_auth = g_string_new (NULL);
@@ -554,7 +574,7 @@ write_wireless_security_setting (NMConnection *connection,
 	guint32 i, num;
 	GString *str;
 
-	s_wsec = (NMSettingWirelessSecurity *) nm_connection_get_setting (connection, NM_TYPE_SETTING_WIRELESS_SECURITY);
+	s_wsec = nm_connection_get_setting_wireless_security (connection);
 	if (!s_wsec) {
 		g_set_error (error, IFCFG_PLUGIN_ERROR, 0,
 		             "Missing '%s' setting", NM_SETTING_WIRELESS_SECURITY_SETTING_NAME);
@@ -716,24 +736,20 @@ write_wireless_security_setting (NMConnection *connection,
 
 	/* WPA Passphrase */
 	if (wpa) {
-		GString *quoted = NULL;
+		char *quoted = NULL;
 
 		psk = nm_setting_wireless_security_get_psk (s_wsec);
 		if (psk && (strlen (psk) != 64)) {
 			/* Quote the PSK since it's a passphrase */
-			quoted = g_string_sized_new (strlen (psk) + 2); /* 2 for quotes */
-			g_string_append_c (quoted, '"');
-			g_string_append (quoted, psk);
-			g_string_append_c (quoted, '"');
+			quoted = utils_single_quote_string (psk);
 		}
 		set_secret (ifcfg,
 		            "WPA_PSK",
-		            quoted ? quoted->str : psk,
+		            quoted ? quoted : psk,
 		            "WPA_PSK_FLAGS",
 		            nm_setting_wireless_security_get_psk_flags (s_wsec),
 		            TRUE);
-		if (quoted)
-			g_string_free (quoted, TRUE);
+		g_free (quoted);
 	} else {
 		set_secret (ifcfg,
 		            "WPA_PSK",
@@ -761,7 +777,7 @@ write_wireless_setting (NMConnection *connection,
 	gboolean adhoc = FALSE, hex_ssid = FALSE;
 	const GSList *macaddr_blacklist;
 
-	s_wireless = (NMSettingWireless *) nm_connection_get_setting (connection, NM_TYPE_SETTING_WIRELESS);
+	s_wireless = nm_connection_get_setting_wireless (connection);
 	if (!s_wireless) {
 		g_set_error (error, IFCFG_PLUGIN_ERROR, 0,
 		             "Missing '%s' setting", NM_SETTING_WIRELESS_SETTING_NAME);
@@ -944,6 +960,48 @@ write_wireless_setting (NMConnection *connection,
 }
 
 static gboolean
+write_infiniband_setting (NMConnection *connection, shvarFile *ifcfg, GError **error)
+{
+	NMSettingInfiniband *s_infiniband;
+	const GByteArray *mac;
+	char *tmp;
+	const char *transport_mode;
+	guint32 mtu;
+
+	s_infiniband = nm_connection_get_setting_infiniband (connection);
+	if (!s_infiniband) {
+		g_set_error (error, IFCFG_PLUGIN_ERROR, 0,
+		             "Missing '%s' setting", NM_SETTING_INFINIBAND_SETTING_NAME);
+		return FALSE;
+	}
+
+	svSetValue (ifcfg, "HWADDR", NULL, FALSE);
+	mac = nm_setting_infiniband_get_mac_address (s_infiniband);
+	if (mac) {
+		tmp = nm_utils_hwaddr_ntoa (mac->data, ARPHRD_INFINIBAND);
+		svSetValue (ifcfg, "HWADDR", tmp, FALSE);
+		g_free (tmp);
+	}
+
+	svSetValue (ifcfg, "MTU", NULL, FALSE);
+	mtu = nm_setting_infiniband_get_mtu (s_infiniband);
+	if (mtu) {
+		tmp = g_strdup_printf ("%u", mtu);
+		svSetValue (ifcfg, "MTU", tmp, FALSE);
+		g_free (tmp);
+	}
+
+	transport_mode = nm_setting_infiniband_get_transport_mode (s_infiniband);
+	svSetValue (ifcfg, "CONNECTED_MODE",
+	            strcmp (transport_mode, "connected") == 0 ? "yes" : "no",
+	            FALSE);
+
+	svSetValue (ifcfg, "TYPE", TYPE_INFINIBAND, FALSE);
+
+	return TRUE;
+}
+
+static gboolean
 write_wired_setting (NMConnection *connection, shvarFile *ifcfg, GError **error)
 {
 	NMSettingWired *s_wired;
@@ -955,7 +1013,7 @@ write_wired_setting (NMConnection *connection, shvarFile *ifcfg, GError **error)
 	GString *str;
 	const GSList *macaddr_blacklist;
 
-	s_wired = (NMSettingWired *) nm_connection_get_setting (connection, NM_TYPE_SETTING_WIRED);
+	s_wired = nm_connection_get_setting_wired (connection);
 	if (!s_wired) {
 		g_set_error (error, IFCFG_PLUGIN_ERROR, 0,
 		             "Missing '%s' setting", NM_SETTING_WIRED_SETTING_NAME);
@@ -1064,11 +1122,143 @@ write_wired_setting (NMConnection *connection, shvarFile *ifcfg, GError **error)
 	return TRUE;
 }
 
+static GString *vlan_priority_maplist_to_stringlist (NMSettingVlan *s_vlan, NMVlanPriorityMap map)
+{
+	GSList *strlist = NULL, *iter;
+	GString *value = NULL;
+
+	if (map == NM_VLAN_INGRESS_MAP)
+		g_object_get (G_OBJECT (s_vlan), NM_SETTING_VLAN_INGRESS_PRIORITY_MAP, &strlist, NULL);
+	else if (map == NM_VLAN_EGRESS_MAP)
+		g_object_get (G_OBJECT (s_vlan), NM_SETTING_VLAN_EGRESS_PRIORITY_MAP, &strlist, NULL);
+	else
+		return NULL;
+
+	value = g_string_new ("");
+	for (iter = strlist; iter; iter = g_slist_next (iter))
+		g_string_append_printf (value, "%s%s", value->len ? "," : "", (const char *) iter->data);
+
+	nm_utils_slist_free (strlist, g_free);
+
+	return value;
+}
+
+static gboolean
+write_vlan_setting (NMConnection *connection, shvarFile *ifcfg, GError **error)
+{
+	NMSettingVlan *s_vlan;
+	NMSettingConnection *s_con;
+	char *tmp;
+	guint32 vlan_flags = 0;
+	GString *text = NULL;
+
+	s_con = nm_connection_get_setting_connection (connection);
+	if (!s_con) {
+		g_set_error_literal (error, IFCFG_PLUGIN_ERROR, 0, "Missing connection setting");
+		return FALSE;
+	}
+
+	s_vlan = nm_connection_get_setting_vlan (connection);
+	if (!s_vlan) {
+		g_set_error_literal (error, IFCFG_PLUGIN_ERROR, 0, "Missing VLAN setting");
+		return FALSE;
+	}
+
+	svSetValue (ifcfg, "VLAN", "yes", FALSE);
+	svSetValue (ifcfg, "TYPE", TYPE_VLAN, FALSE);
+	svSetValue (ifcfg, "DEVICE", nm_setting_vlan_get_interface_name (s_vlan), FALSE);
+	svSetValue (ifcfg, "PHYSDEV", nm_setting_vlan_get_parent (s_vlan), FALSE);
+	svSetValue (ifcfg, "MASTER", nm_setting_connection_get_master (s_con), FALSE);
+
+	tmp = g_strdup_printf ("%d", nm_setting_vlan_get_id (s_vlan));
+	svSetValue (ifcfg, "VLAN_ID", tmp, FALSE);
+	g_free (tmp);
+
+	vlan_flags = nm_setting_vlan_get_flags (s_vlan);
+	if (vlan_flags & NM_VLAN_FLAG_REORDER_HEADERS)
+		svSetValue (ifcfg, "REORDER_HDR", "1", FALSE);
+	else
+		svSetValue (ifcfg, "REORDER_HDR", "0", FALSE);
+
+	svSetValue (ifcfg, "VLAN_FLAGS", NULL, FALSE);
+	if (vlan_flags & NM_VLAN_FLAG_GVRP) {
+		if (vlan_flags & NM_VLAN_FLAG_LOOSE_BINDING)
+			svSetValue (ifcfg, "VLAN_FLAGS", "GVRP,LOOSE_BINDING", FALSE);
+		else
+			svSetValue (ifcfg, "VLAN_FLAGS", "GVRP", FALSE);
+	} else if (vlan_flags & NM_VLAN_FLAG_LOOSE_BINDING)
+		svSetValue (ifcfg, "VLAN_FLAGS", "LOOSE_BINDING", FALSE);
+
+	text = vlan_priority_maplist_to_stringlist (s_vlan, NM_VLAN_INGRESS_MAP);
+	svSetValue (ifcfg, "VLAN_INGRESS_PRIORITY_MAP", text ? text->str : NULL, FALSE);
+	if (text)
+		g_string_free (text, TRUE);
+
+	text = vlan_priority_maplist_to_stringlist (s_vlan, NM_VLAN_EGRESS_MAP);
+	svSetValue (ifcfg, "VLAN_EGRESS_PRIORITY_MAP", text ? text->str : NULL, FALSE);
+	if (text)
+		g_string_free (text, TRUE);
+
+	return TRUE;
+}
+
+static gboolean
+write_bonding_setting (NMConnection *connection, shvarFile *ifcfg, GError **error)
+{
+	NMSettingBond *s_bond;
+	const char *iface;
+	guint32 i, num_opts;
+
+	s_bond = nm_connection_get_setting_bond (connection);
+	if (!s_bond) {
+		g_set_error (error, IFCFG_PLUGIN_ERROR, 0,
+		             "Missing '%s' setting", NM_SETTING_BOND_SETTING_NAME);
+		return FALSE;
+	}
+
+	iface = nm_setting_bond_get_interface_name (s_bond);
+	if (!iface) {
+		g_set_error (error, IFCFG_PLUGIN_ERROR, 0, "Missing interface name");
+		return FALSE;
+	}
+
+	svSetValue (ifcfg, "DEVICE", iface, FALSE);
+	svSetValue (ifcfg, "BONDING_OPTS", NULL, FALSE);
+
+	num_opts = nm_setting_bond_get_num_options (s_bond);
+	if (num_opts > 0) {
+		GString *str = g_string_sized_new (64);
+
+		for (i = 0; i < nm_setting_bond_get_num_options (s_bond); i++) {
+			const char *key, *value;
+
+			if (!nm_setting_bond_get_option (s_bond, i, &key, &value))
+				continue;
+
+			if (str->len)
+				g_string_append_c (str, ' ');
+
+			g_string_append_printf (str, "%s=%s", key, value);
+		}
+
+		if (str->len)
+			svSetValue (ifcfg, "BONDING_OPTS", str->str, FALSE);
+
+		g_string_free (str, TRUE);
+	}
+
+	svSetValue (ifcfg, "TYPE", TYPE_BOND, FALSE);
+	svSetValue (ifcfg, "BONDING_MASTER", "yes", FALSE);
+
+	return TRUE;
+}
+
 static void
 write_connection_setting (NMSettingConnection *s_con, shvarFile *ifcfg)
 {
 	guint32 n, i;
 	GString *str;
+	const char *master;
 
 	svSetValue (ifcfg, "NAME", nm_setting_connection_get_id (s_con), FALSE);
 	svSetValue (ifcfg, "UUID", nm_setting_connection_get_uuid (s_con), FALSE);
@@ -1097,6 +1287,14 @@ write_connection_setting (NMSettingConnection *s_con, shvarFile *ifcfg)
 		svSetValue (ifcfg, "USERS", str->str, FALSE);
 		g_string_free (str, TRUE);
 	}
+
+	svSetValue (ifcfg, "ZONE", nm_setting_connection_get_zone(s_con), FALSE);
+
+	master = nm_setting_connection_get_master (s_con);
+	if (master) {
+		if (nm_setting_connection_is_slave_type (s_con, NM_SETTING_BOND_SETTING_NAME))
+			svSetValue (ifcfg, "MASTER", master, FALSE);
+	}
 }
 
 static gboolean
@@ -1172,7 +1370,7 @@ write_ip4_setting (NMConnection *connection, shvarFile *ifcfg, GError **error)
 	gboolean fake_ip4 = FALSE;
 	const char *method = NULL;
 
-	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)
 		method = nm_setting_ip4_config_get_method (s_ip4);
 
@@ -1509,7 +1707,7 @@ write_ip6_setting (NMConnection *connection, shvarFile *ifcfg, GError **error)
 	GString *ip_str1, *ip_str2, *ip_ptr;
 	char *route6_path;
 
-	s_ip6 = (NMSettingIP6Config *) nm_connection_get_setting (connection, NM_TYPE_SETTING_IP6_CONFIG);
+	s_ip6 = nm_connection_get_setting_ip6_config (connection);
 	if (!s_ip6) {
 		g_set_error (error, IFCFG_PLUGIN_ERROR, 0,
 		             "Missing '%s' setting", NM_SETTING_IP6_CONFIG_SETTING_NAME);
@@ -1587,7 +1785,7 @@ write_ip6_setting (NMConnection *connection, shvarFile *ifcfg, GError **error)
 	}
 
 	/* Write out DNS - 'DNS' key is used both for IPv4 and IPv6 */
-	s_ip4 = (NMSettingIP4Config *) nm_connection_get_setting (connection, NM_TYPE_SETTING_IP4_CONFIG);
+	s_ip4 = nm_connection_get_setting_ip4_config (connection);
 	num4 = s_ip4 ? nm_setting_ip4_config_get_num_dns (s_ip4) : 0; /* from where to start with IPv6 entries */
 	num = nm_setting_ip6_config_get_num_dns (s_ip6);
 	for (i = 0; i < 254; i++) {
@@ -1644,6 +1842,24 @@ write_ip6_setting (NMConnection *connection, shvarFile *ifcfg, GError **error)
 	            nm_setting_ip6_config_get_may_fail (s_ip6) ? "no" : "yes",
 	            FALSE);
 
+	/* IPv6 Privacy Extensions */
+	svSetValue (ifcfg, "IPV6_PRIVACY", NULL, FALSE);
+	svSetValue (ifcfg, "IPV6_PRIVACY_PREFER_PUBLIC_IP", NULL, FALSE);
+	switch (nm_setting_ip6_config_get_ip6_privacy (s_ip6)){
+	case NM_SETTING_IP6_CONFIG_PRIVACY_DISABLED:
+		svSetValue (ifcfg, "IPV6_PRIVACY", "no", FALSE);
+	break;
+	case NM_SETTING_IP6_CONFIG_PRIVACY_PREFER_PUBLIC_ADDR:
+		svSetValue (ifcfg, "IPV6_PRIVACY", "rfc3041", FALSE);
+		svSetValue (ifcfg, "IPV6_PRIVACY_PREFER_PUBLIC_IP", "yes", FALSE);
+	break;
+	case NM_SETTING_IP6_CONFIG_PRIVACY_PREFER_TEMP_ADDR:
+		svSetValue (ifcfg, "IPV6_PRIVACY", "rfc3041", FALSE);
+	break;
+	default:
+	break;
+	}
+
 	/* Static routes go to route6-<dev> file */
 	route6_path = utils_get_route6_path (ifcfg->fileName);
 	if (!route6_path) {
@@ -1665,6 +1881,7 @@ error:
 static char *
 escape_id (const char *id)
 {
+	static const char const as_dash[] = "\\][|/=()!";
 	char *escaped = g_strdup (id);
 	char *p = escaped;
 
@@ -1672,9 +1889,7 @@ escape_id (const char *id)
 	while (*p) {
 		if (*p == ' ')
 			*p = '_';
-		else if (*p == '/')
-			*p = '-';
-		else if (*p == '\\')
+		else if (strchr (as_dash, *p))
 			*p = '-';
 		p++;
 	}
@@ -1691,6 +1906,7 @@ write_connection (NMConnection *connection,
                   GError **error)
 {
 	NMSettingConnection *s_con;
+	NMSettingIP4Config *s_ip4;
 	NMSettingIP6Config *s_ip6;
 	gboolean success = FALSE;
 	shvarFile *ifcfg = NULL;
@@ -1699,7 +1915,7 @@ write_connection (NMConnection *connection,
 	gboolean no_8021x = FALSE;
 	gboolean wired = FALSE;
 
-	s_con = NM_SETTING_CONNECTION (nm_connection_get_setting (connection, NM_TYPE_SETTING_CONNECTION));
+	s_con = nm_connection_get_setting_connection (connection);
 	if (!s_con) {
 		g_set_error (error, IFCFG_PLUGIN_ERROR, 0,
 		             "Missing '%s' setting", NM_SETTING_CONNECTION_SETTING_NAME);
@@ -1759,7 +1975,7 @@ write_connection (NMConnection *connection,
 
 	if (!strcmp (type, NM_SETTING_WIRED_SETTING_NAME)) {
 		// FIXME: can't write PPPoE at this time
-		if (nm_connection_get_setting (connection, NM_TYPE_SETTING_PPPOE)) {
+		if (nm_connection_get_setting_pppoe (connection)) {
 			g_set_error (error, IFCFG_PLUGIN_ERROR, 0,
 			             "Can't write connection type '%s'",
 			             NM_SETTING_PPPOE_SETTING_NAME);
@@ -1769,9 +1985,18 @@ write_connection (NMConnection *connection,
 		if (!write_wired_setting (connection, ifcfg, error))
 			goto out;
 		wired = TRUE;
+	} else if (!strcmp (type, NM_SETTING_VLAN_SETTING_NAME)) {
+		if (!write_vlan_setting (connection, ifcfg, error))
+			goto out;
 	} else if (!strcmp (type, NM_SETTING_WIRELESS_SETTING_NAME)) {
 		if (!write_wireless_setting (connection, ifcfg, &no_8021x, error))
 			goto out;
+	} else if (!strcmp (type, NM_SETTING_INFINIBAND_SETTING_NAME)) {
+		if (!write_infiniband_setting (connection, ifcfg, error))
+			goto out;
+	} else if (!strcmp (type, NM_SETTING_BOND_SETTING_NAME)) {
+		if (!write_bonding_setting (connection, ifcfg, error))
+			goto out;
 	} else {
 		g_set_error (error, IFCFG_PLUGIN_ERROR, 0,
 		             "Can't write connection type '%s'", type);
@@ -1783,10 +2008,13 @@ write_connection (NMConnection *connection,
 			goto out;
 	}
 
-	if (!write_ip4_setting (connection, ifcfg, error))
-		goto out;
+	s_ip4 = nm_connection_get_setting_ip4_config (connection);
+	if (s_ip4 || !utils_disabling_ip4_config_allowed (connection)) {
+		if (!write_ip4_setting (connection, ifcfg, error))
+			goto out;
+	}
 
-	s_ip6 = (NMSettingIP6Config *) nm_connection_get_setting (connection, NM_TYPE_SETTING_IP6_CONFIG);
+	s_ip6 = nm_connection_get_setting_ip6_config (connection);
 	if (s_ip6) {
 		if (!write_ip6_setting (connection, ifcfg, error))
 			goto out;
diff --git a/src/settings/plugins/ifcfg-suse/Makefile.in b/src/settings/plugins/ifcfg-suse/Makefile.in
index dfa84086..ac528342 100644
--- a/src/settings/plugins/ifcfg-suse/Makefile.in
+++ b/src/settings/plugins/ifcfg-suse/Makefile.in
@@ -170,6 +170,8 @@ GIO_LIBS = @GIO_LIBS@
 GLIB_CFLAGS = @GLIB_CFLAGS@
 GLIB_GENMARSHAL = @GLIB_GENMARSHAL@
 GLIB_LIBS = @GLIB_LIBS@
+GLIB_MAKEFILE = @GLIB_MAKEFILE@
+GLIB_MKENUMS = @GLIB_MKENUMS@
 GMODULE_CFLAGS = @GMODULE_CFLAGS@
 GMODULE_LIBS = @GMODULE_LIBS@
 GMSGFMT = @GMSGFMT@
@@ -224,11 +226,15 @@ LIBNL2_LIBS = @LIBNL2_LIBS@
 LIBNL3_CFLAGS = @LIBNL3_CFLAGS@
 LIBNL3_LIBS = @LIBNL3_LIBS@
 LIBNL_CFLAGS = @LIBNL_CFLAGS@
+LIBNL_GENL3_CFLAGS = @LIBNL_GENL3_CFLAGS@
+LIBNL_GENL3_LIBS = @LIBNL_GENL3_LIBS@
 LIBNL_LIBS = @LIBNL_LIBS@
 LIBNL_ROUTE3_CFLAGS = @LIBNL_ROUTE3_CFLAGS@
 LIBNL_ROUTE3_LIBS = @LIBNL_ROUTE3_LIBS@
 LIBOBJS = @LIBOBJS@
 LIBS = @LIBS@
+LIBSOUP_CFLAGS = @LIBSOUP_CFLAGS@
+LIBSOUP_LIBS = @LIBSOUP_LIBS@
 LIBTOOL = @LIBTOOL@
 LIPO = @LIPO@
 LN_S = @LN_S@
@@ -239,6 +245,7 @@ MAINT = @MAINT@
 MAKEINFO = @MAKEINFO@
 MANIFEST_TOOL = @MANIFEST_TOOL@
 MKDIR_P = @MKDIR_P@
+MOC = @MOC@
 MSGFMT = @MSGFMT@
 MSGFMT_015 = @MSGFMT_015@
 MSGMERGE = @MSGMERGE@
@@ -278,6 +285,8 @@ SED = @SED@
 SET_MAKE = @SET_MAKE@
 SHELL = @SHELL@
 STRIP = @STRIP@
+SYSTEMD_CFLAGS = @SYSTEMD_CFLAGS@
+SYSTEMD_LIBS = @SYSTEMD_LIBS@
 SYSTEM_CA_PATH = @SYSTEM_CA_PATH@
 UDEV_BASE_DIR = @UDEV_BASE_DIR@
 USE_NLS = @USE_NLS@
diff --git a/src/settings/plugins/ifcfg-suse/plugin.c b/src/settings/plugins/ifcfg-suse/plugin.c
index 78db56e5..2ec90d81 100644
--- a/src/settings/plugins/ifcfg-suse/plugin.c
+++ b/src/settings/plugins/ifcfg-suse/plugin.c
@@ -18,7 +18,7 @@
  * with this program; if not, write to the Free Software Foundation, Inc.,
  * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
  *
- * (C) Copyright 2007 - 2009 Red Hat, Inc.
+ * (C) Copyright 2007 - 2011 Red Hat, Inc.
  * (C) Copyright 2007 - 2008 Novell, Inc.
  */
 
@@ -309,7 +309,7 @@ system_config_interface_init (NMSystemConfigInterface *system_config_interface_c
 }
 
 G_MODULE_EXPORT GObject *
-nm_system_config_factory (void)
+nm_system_config_factory (const char *config_file)
 {
 	static SCPluginIfcfg *singleton = NULL;
 
diff --git a/src/settings/plugins/ifnet/Makefile.am b/src/settings/plugins/ifnet/Makefile.am
index 9bf8a79a..84deda5b 100644
--- a/src/settings/plugins/ifnet/Makefile.am
+++ b/src/settings/plugins/ifnet/Makefile.am
@@ -45,13 +45,13 @@ lib_ifnet_io_la_SOURCES = \
 	wpa_parser.c
 
 lib_ifnet_io_la_CPPFLAGS = \
-			   $(GLIB_CFLAGS) \
-		           $(DBUS_CFLAGS) \
-		           -DG_DISABLE_DEPRECATED \
-		           -DSYSCONFDIR=\"$(sysconfdir)\" \
-		           -DSBINDIR=\"$(sbindir)\"
+	$(GLIB_CFLAGS) \
+	$(DBUS_CFLAGS) \
+	-DG_DISABLE_DEPRECATED \
+	-DSYSCONFDIR=\"$(sysconfdir)\" \
+	-DSBINDIR=\"$(sbindir)\"
 
 lib_ifnet_io_la_LIBADD = \
-			 $(top_builddir)/libnm-util/libnm-util.la \
-			 $(GLIB_LIBS)\
-			 $(GIO_LIBS)
+	 $(top_builddir)/libnm-util/libnm-util.la \
+	 $(GLIB_LIBS)\
+	 $(GIO_LIBS)
diff --git a/src/settings/plugins/ifnet/Makefile.in b/src/settings/plugins/ifnet/Makefile.in
index 8218b85a..322adbf8 100644
--- a/src/settings/plugins/ifnet/Makefile.in
+++ b/src/settings/plugins/ifnet/Makefile.in
@@ -218,6 +218,8 @@ GIO_LIBS = @GIO_LIBS@
 GLIB_CFLAGS = @GLIB_CFLAGS@
 GLIB_GENMARSHAL = @GLIB_GENMARSHAL@
 GLIB_LIBS = @GLIB_LIBS@
+GLIB_MAKEFILE = @GLIB_MAKEFILE@
+GLIB_MKENUMS = @GLIB_MKENUMS@
 GMODULE_CFLAGS = @GMODULE_CFLAGS@
 GMODULE_LIBS = @GMODULE_LIBS@
 GMSGFMT = @GMSGFMT@
@@ -272,11 +274,15 @@ LIBNL2_LIBS = @LIBNL2_LIBS@
 LIBNL3_CFLAGS = @LIBNL3_CFLAGS@
 LIBNL3_LIBS = @LIBNL3_LIBS@
 LIBNL_CFLAGS = @LIBNL_CFLAGS@
+LIBNL_GENL3_CFLAGS = @LIBNL_GENL3_CFLAGS@
+LIBNL_GENL3_LIBS = @LIBNL_GENL3_LIBS@
 LIBNL_LIBS = @LIBNL_LIBS@
 LIBNL_ROUTE3_CFLAGS = @LIBNL_ROUTE3_CFLAGS@
 LIBNL_ROUTE3_LIBS = @LIBNL_ROUTE3_LIBS@
 LIBOBJS = @LIBOBJS@
 LIBS = @LIBS@
+LIBSOUP_CFLAGS = @LIBSOUP_CFLAGS@
+LIBSOUP_LIBS = @LIBSOUP_LIBS@
 LIBTOOL = @LIBTOOL@
 LIPO = @LIPO@
 LN_S = @LN_S@
@@ -287,6 +293,7 @@ MAINT = @MAINT@
 MAKEINFO = @MAKEINFO@
 MANIFEST_TOOL = @MANIFEST_TOOL@
 MKDIR_P = @MKDIR_P@
+MOC = @MOC@
 MSGFMT = @MSGFMT@
 MSGFMT_015 = @MSGFMT_015@
 MSGMERGE = @MSGMERGE@
@@ -326,6 +333,8 @@ SED = @SED@
 SET_MAKE = @SET_MAKE@
 SHELL = @SHELL@
 STRIP = @STRIP@
+SYSTEMD_CFLAGS = @SYSTEMD_CFLAGS@
+SYSTEMD_LIBS = @SYSTEMD_LIBS@
 SYSTEM_CA_PATH = @SYSTEM_CA_PATH@
 UDEV_BASE_DIR = @UDEV_BASE_DIR@
 USE_NLS = @USE_NLS@
@@ -433,16 +442,16 @@ lib_ifnet_io_la_SOURCES = \
 	wpa_parser.c
 
 lib_ifnet_io_la_CPPFLAGS = \
-			   $(GLIB_CFLAGS) \
-		           $(DBUS_CFLAGS) \
-		           -DG_DISABLE_DEPRECATED \
-		           -DSYSCONFDIR=\"$(sysconfdir)\" \
-		           -DSBINDIR=\"$(sbindir)\"
+	$(GLIB_CFLAGS) \
+	$(DBUS_CFLAGS) \
+	-DG_DISABLE_DEPRECATED \
+	-DSYSCONFDIR=\"$(sysconfdir)\" \
+	-DSBINDIR=\"$(sbindir)\"
 
 lib_ifnet_io_la_LIBADD = \
-			 $(top_builddir)/libnm-util/libnm-util.la \
-			 $(GLIB_LIBS)\
-			 $(GIO_LIBS)
+	 $(top_builddir)/libnm-util/libnm-util.la \
+	 $(GLIB_LIBS)\
+	 $(GIO_LIBS)
 
 all: all-recursive
 
diff --git a/src/settings/plugins/ifnet/connection_parser.c b/src/settings/plugins/ifnet/connection_parser.c
index b4aaa8d2..78812f97 100644
--- a/src/settings/plugins/ifnet/connection_parser.c
+++ b/src/settings/plugins/ifnet/connection_parser.c
@@ -45,12 +45,6 @@
 #include "connection_parser.h"
 #include "nm-ifnet-connection.h"
 
-static const char *
-get_prefix (void)
-{
-	return _("System");
-}
-
 static void
 update_connection_id (NMConnection *connection, const char *conn_name)
 {
@@ -62,16 +56,12 @@ update_connection_id (NMConnection *connection, const char *conn_name)
 
 	name_len = strlen (conn_name);
 	if ((name_len > 2) && (g_str_has_prefix (conn_name, "0x"))) {
-		gchar * conn_name_printable = utils_hexstr2bin (conn_name + 2, name_len - 2);
-		idstr = g_strdup_printf ("%s (%s)", get_prefix (), conn_name_printable);
-		g_free (conn_name_printable);
+		idstr = utils_hexstr2bin (conn_name + 2, name_len - 2);
 	} else
-		idstr = g_strdup_printf ("%s (%s)", get_prefix (), conn_name);
+		idstr = g_strdup_printf ("%s", conn_name);
 	uuid_base = idstr;
 	uuid = nm_utils_uuid_generate_from_string (uuid_base);
-	setting =
-	    (NMSettingConnection *) nm_connection_get_setting (connection,
-							       NM_TYPE_SETTING_CONNECTION);
+	setting = nm_connection_get_setting_connection (connection);
 	g_object_set (setting, NM_SETTING_CONNECTION_ID, idstr,
 		      NM_SETTING_CONNECTION_UUID, uuid, NULL);
 	PLUGIN_PRINT (IFNET_PLUGIN_NAME,
@@ -509,20 +499,17 @@ static gboolean
 read_mac_address (const char *conn_name, GByteArray **array, GError **error)
 {
 	const char *value = ifnet_get_data (conn_name, "mac");
-	struct ether_addr *mac;
 
 	if (!value || !strlen (value))
 		return TRUE;
 
-	mac = ether_aton (value);
-	if (!mac) {
+	*array = nm_utils_hwaddr_atoba (value, ARPHRD_ETHER);
+	if (!*array) {
 		g_set_error (error, ifnet_plugin_error_quark (), 0,
-			     "The MAC address '%s' was invalid.", value);
+					 "The MAC address '%s' was invalid.", value);
 		return FALSE;
 	}
 
-	*array = g_byte_array_sized_new (ETH_ALEN);
-	g_byte_array_append (*array, (guint8 *) mac->ether_addr_octet, ETH_ALEN);
 	return TRUE;
 }
 
@@ -567,7 +554,7 @@ make_wired_connection_setting (NMConnection *connection,
 		nm_connection_add_setting (connection, NM_SETTING (s_wired));
 }
 
-/* add NM_SETTING_IP4_CONFIG_DHCP_HOSTNAME, 
+/* add NM_SETTING_IP4_CONFIG_DHCP_HOSTNAME,
  * NM_SETTING_IP4_CONFIG_DHCP_CLIENT_ID in future*/
 static void
 make_ip4_setting (NMConnection *connection,
@@ -596,19 +583,19 @@ make_ip4_setting (NMConnection *connection,
 			g_object_unref (ip4_setting);
 			return;
 		}
-		if (!strcmp (method, "dhcp"))
+		if (strstr (method, "dhcp"))
 			g_object_set (ip4_setting,
 						  NM_SETTING_IP4_CONFIG_METHOD,
 						  NM_SETTING_IP4_CONFIG_METHOD_AUTO,
 						  NM_SETTING_IP4_CONFIG_NEVER_DEFAULT, FALSE, NULL);
-		else if (!strcmp (method, "autoip")){
+		else if (strstr (method, "autoip")) {
 			g_object_set (ip4_setting,
 						  NM_SETTING_IP4_CONFIG_METHOD,
 						  NM_SETTING_IP4_CONFIG_METHOD_LINK_LOCAL,
 						  NM_SETTING_IP4_CONFIG_NEVER_DEFAULT, FALSE, NULL);
 			nm_connection_add_setting (connection, NM_SETTING (ip4_setting));
 			return;
-		} else if (!strcmp (method, "shared")){
+		} else if (strstr (method, "shared")) {
 			g_object_set (ip4_setting,
 						  NM_SETTING_IP4_CONFIG_METHOD,
 						  NM_SETTING_IP4_CONFIG_METHOD_SHARED,
@@ -663,7 +650,7 @@ make_ip4_setting (NMConnection *connection,
 	}
 
 	/* add dhcp hostname and client id */
-	if (!is_static_block && !strcmp (method, "dhcp")) {
+	if (!is_static_block && strstr (method, "dhcp")) {
 		gchar *dhcp_hostname, *client_id;
 
 		get_dhcp_hostname_and_client_id (&dhcp_hostname, &client_id);
@@ -868,7 +855,7 @@ make_ip6_setting (NMConnection *connection,
 		nm_ip6_route_set_dest (route, iblock->ip);
 		nm_ip6_route_set_next_hop (route, iblock->next_hop);
 		nm_ip6_route_set_prefix (route, iblock->prefix);
-		/* metric is not per routes configuration right now 
+		/* metric is not per routes configuration right now
 		 * global metric is also supported (metric="x") */
 		if ((metric_str = ifnet_get_data (conn_name, "metric")) != NULL) {
 			metric = strtol (metric_str, NULL, 10);
@@ -995,7 +982,7 @@ make_wireless_connection_setting (const char *conn_name,
 		goto error;
 	}
 
-	/* mode=0: infrastructure 
+	/* mode=0: infrastructure
 	 * mode=1: adhoc */
 	value = wpa_get_value (conn_name, "mode");
 	if (value)
@@ -1012,18 +999,15 @@ make_wireless_connection_setting (const char *conn_name,
 	/* BSSID setting */
 	value = wpa_get_value (conn_name, "bssid");
 	if (value) {
-		struct ether_addr *eth;
 		GByteArray *bssid;
 
-		eth = ether_aton (value);
-		if (!eth) {
+		bssid = nm_utils_hwaddr_atoba (value, ARPHRD_ETHER);
+		if (!bssid) {
 			g_set_error (error, ifnet_plugin_error_quark (), 0,
-				     "Invalid BSSID '%s'", value);
+						 "Invalid BSSID '%s'", value);
 			goto error;
 		}
 
-		bssid = g_byte_array_sized_new (ETH_ALEN);
-		g_byte_array_append (bssid, eth->ether_addr_octet, ETH_ALEN);
 		g_object_set (wireless_setting, NM_SETTING_WIRELESS_BSSID,
 			      bssid, NULL);
 		g_byte_array_free (bssid, TRUE);
@@ -1666,9 +1650,7 @@ ifnet_update_connection_from_config_block (const char *conn_name, GError **error
 	connection = nm_connection_new ();
 	if (!connection)
 		return NULL;
-	setting =
-	    (NMSettingConnection *) nm_connection_get_setting (connection,
-							       NM_TYPE_SETTING_CONNECTION);
+	setting = nm_connection_get_setting_connection (connection);
 	if (!setting) {
 		setting = NM_SETTING_CONNECTION (nm_setting_connection_new ());
 		g_assert (setting);
@@ -2021,10 +2003,7 @@ write_8021x_setting (NMConnection *connection,
 	GString *phase2_auth;
 	GString *phase1;
 
-	s_8021x =
-	    (NMSetting8021x *) nm_connection_get_setting (connection,
-							  NM_TYPE_SETTING_802_1X);
-
+	s_8021x = nm_connection_get_setting_802_1x (connection);
 	if (!s_8021x) {
 		return TRUE;
 	}
@@ -2119,9 +2098,7 @@ write_wireless_security_setting (NMConnection * connection,
 	guint32 i, num;
 	GString *str;
 
-	s_wsec =
-	    (NMSettingWirelessSecurity *) nm_connection_get_setting (connection,
-								     NM_TYPE_SETTING_WIRELESS_SECURITY);
+	s_wsec = nm_connection_get_setting_wireless_security (connection);
 	if (!s_wsec) {
 		g_set_error (error, ifnet_plugin_error_quark (), 0,
 			     "Missing '%s' setting",
@@ -2171,7 +2148,6 @@ write_wireless_security_setting (NMConnection * connection,
 		wpa_set_data (conn_name, "auth_alg", NULL);
 
 	/* Default WEP TX key index */
-	wpa_set_data (conn_name, "wep_tx_keyidx", NULL);
 	if (wep) {
 		tmp =
 		    g_strdup_printf ("%d",
@@ -2179,7 +2155,8 @@ write_wireless_security_setting (NMConnection * connection,
 				     (s_wsec));
 		wpa_set_data (conn_name, "wep_tx_keyidx", tmp);
 		g_free (tmp);
-	}
+	} else
+		wpa_set_data (conn_name, "wep_tx_keyidx", NULL);
 
 	/* WEP keys */
 	for (i = 0; i < 4; i++) {
@@ -2287,7 +2264,7 @@ write_wireless_setting (NMConnection *connection,
 	gboolean adhoc = FALSE, hex_ssid = FALSE;
 	gchar *ssid_str, *tmp;
 
-	s_wireless = (NMSettingWireless *) nm_connection_get_setting (connection, NM_TYPE_SETTING_WIRELESS);
+	s_wireless = nm_connection_get_setting_wireless (connection);
 	if (!s_wireless) {
 		g_set_error (error, ifnet_plugin_error_quark (), 0,
 			     "Missing '%s' setting",
@@ -2406,9 +2383,7 @@ write_wired_setting (NMConnection *connection,
 	char *tmp;
 	guint32 mtu;
 
-	s_wired =
-	    (NMSettingWired *) nm_connection_get_setting (connection,
-							  NM_TYPE_SETTING_WIRED);
+	s_wired = nm_connection_get_setting_wired (connection);
 	if (!s_wired) {
 		g_set_error (error, ifnet_plugin_error_quark (), 0,
 			     "Missing '%s' setting",
@@ -2462,9 +2437,7 @@ write_ip4_setting (NMConnection *connection, const char *conn_name, GError **err
 	gboolean has_def_route = FALSE;
 	gboolean success = FALSE;
 
-	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) {
 		g_set_error (error, ifnet_plugin_error_quark (), 0,
 			     "Missing '%s' setting",
@@ -2668,9 +2641,7 @@ write_ip6_setting (NMConnection *connection, const char *conn_name, GError **err
 	NMIP6Address *addr;
 	const struct in6_addr *ip;
 
-	s_ip6 =
-	    (NMSettingIP6Config *) nm_connection_get_setting (connection,
-							      NM_TYPE_SETTING_IP6_CONFIG);
+	s_ip6 = nm_connection_get_setting_ip6_config (connection);
 	if (!s_ip6) {
 		g_set_error (error, ifnet_plugin_error_quark (), 0,
 			     "Missing '%s' setting",
@@ -2856,7 +2827,7 @@ ifnet_update_parsers_by_connection (NMConnection *connection,
 		NMSettingPPPOE *s_pppoe;
 
 		/* Writing pppoe setting */
-		s_pppoe = NM_SETTING_PPPOE (nm_connection_get_setting (connection, NM_TYPE_SETTING_PPPOE));
+		s_pppoe = nm_connection_get_setting_pppoe (connection);
 		if (!write_pppoe_setting (conn_name, s_pppoe))
 			goto out;
 		pppoe = TRUE;
@@ -2884,7 +2855,7 @@ ifnet_update_parsers_by_connection (NMConnection *connection,
 	if (!write_ip4_setting (connection, conn_name, error))
 		goto out;
 
-	s_ip6 = (NMSettingIP6Config *) nm_connection_get_setting (connection, NM_TYPE_SETTING_IP6_CONFIG);
+	s_ip6 = nm_connection_get_setting_ip6_config (connection);
 	if (s_ip6) {
 		/* IPv6 Setting */
 		if (!write_ip6_setting (connection, conn_name, error))
@@ -2972,9 +2943,7 @@ get_wireless_name (NMConnection * connection)
 	char buf[33];
 	int i = 0;
 
-	s_wireless =
-	    (NMSettingWireless *) nm_connection_get_setting (connection,
-							     NM_TYPE_SETTING_WIRELESS);
+	s_wireless = nm_connection_get_setting_wireless (connection);
 	if (!s_wireless)
 		return NULL;
 
@@ -3020,7 +2989,7 @@ ifnet_add_new_connection (NMConnection *connection,
 	const char *type;
 	gchar *new_type, *new_name = NULL;
 
-	s_con = NM_SETTING_CONNECTION (nm_connection_get_setting (connection, NM_TYPE_SETTING_CONNECTION));
+	s_con = nm_connection_get_setting_connection (connection);
 	g_assert (s_con);
 	type = nm_setting_connection_get_connection_type (s_con);
 	g_assert (type);
diff --git a/src/settings/plugins/ifnet/net_parser.c b/src/settings/plugins/ifnet/net_parser.c
index a48103db..38765f5f 100644
--- a/src/settings/plugins/ifnet/net_parser.c
+++ b/src/settings/plugins/ifnet/net_parser.c
@@ -22,6 +22,7 @@
 #include <string.h>
 #include <nm-system-config-interface.h>
 #include <stdio.h>
+#include "plugin.h"
 #include "net_parser.h"
 #include "net_utils.h"
 
@@ -106,7 +107,6 @@ ignore_connection_name (const char *name)
 	if (strlen (name) == 12 && is_hex (name))
 		result = TRUE;
 	return result;
-
 }
 
 static gboolean
@@ -169,12 +169,10 @@ init_block_by_line (gchar * buf)
 			conn = add_new_connection_config ("wireless", pos);
 	}
 	data = g_strdup (key_value[1]);
-	tmp = strip_string (data, '(');
-	tmp = strip_string (tmp, ')');
-	strip_string (tmp, '"');
+	tmp = strip_string (data, '"');
 	strip_string (tmp, '\'');
 	if (conn)
-		g_hash_table_insert (conn, g_strdup (key_value[0]),
+		g_hash_table_insert (conn, strip_string (g_strdup (key_value[0]), ' '),
 				     g_strdup (tmp));
 	g_free (data);
 	g_strfreev (key_value);
@@ -195,26 +193,31 @@ destroy_connection_config (GHashTable * conn)
 	g_hash_table_destroy (conn);
 }
 
-// read settings from /etc/NetworkManager/nm-system-settings.conf
+/* Read settings from NetworkManager's config file */
 const char *
 ifnet_get_global_setting (const char *group, const char *key)
 {
 	GError *error = NULL;
 	GKeyFile *keyfile = g_key_file_new ();
 	gchar *result = NULL;
+	const char *conf_file;
+
+	/* Get confing file name from plugin. */
+	conf_file = ifnet_plugin_get_conf_file ();
 
 	if (!g_key_file_load_from_file (keyfile,
-					IFNET_SYSTEM_SETTINGS_KEY_FILE,
+					conf_file,
 					G_KEY_FILE_NONE, &error)) {
 		PLUGIN_WARN (IFNET_PLUGIN_NAME,
 			     "loading system config file (%s) caused error: (%d) %s",
-			     IFNET_SYSTEM_SETTINGS_KEY_FILE,
+			     conf_file,
 			     error ? error->code : -1, error
 			     && error->message ? error->message : "(unknown)");
 	} else {
 		result = g_key_file_get_string (keyfile, group, key, &error);
 	}
 	g_key_file_free (keyfile);
+
 	return result;
 }
 
@@ -283,6 +286,20 @@ is_function (gchar * line)
 	return FALSE;
 }
 
+static void
+append_line (GString *buf, gchar* line)
+{
+	gchar *pos = NULL;
+
+	if ((pos = strchr (line, '#')) != NULL)
+		*pos = '\0';
+	g_strstrip (line);
+
+	if (line[0] != '\0')
+		g_string_append_printf (buf, " %s", line);
+	g_free (line);
+}
+
 gboolean
 ifnet_init (gchar * config_file)
 {
@@ -292,6 +309,8 @@ ifnet_init (gchar * config_file)
 	/* Handle multiple lines with brackets */
 	gboolean complete = TRUE;
 
+	gboolean openrc_style = TRUE;
+
 	/* line buffer */
 	GString *buf;
 
@@ -319,36 +338,60 @@ ifnet_init (gchar * config_file)
 			strip_function (channel, line);
 			continue;
 		}
-		if (line[0] != '#' && line[0] != '\0') {
-			gchar *pos = NULL;
 
+		// New openrc style, bash arrays are not allowed. We only care about '"'
+		if (openrc_style && line[0] != '#' && line[0] != '\0'
+				&& !strchr (line, '(') && !strchr (line, ')')) {
+			gchar *tmp = line;
+
+			while ((tmp = strchr (tmp, '"')) != NULL) {
+				complete = !complete;
+				++tmp;
+			}
+
+			append_line (buf, line);
+			// Add "(separator) for routes. It will be easier for later parsing
+			if (strstr (buf->str, "via"))
+				g_string_append_printf (buf, "\"");
+
+			if (!complete)
+				continue;
+
+			strip_string (buf->str, '"');
+
+			init_block_by_line (buf->str);
+			g_string_free (buf, TRUE);
+			buf = g_string_new (NULL);
+		}
+		// Old bash arrays for baselayout-1, to be deleted
+		else if (line[0] != '#' && line[0] != '\0') {
 			if (!complete) {
 				complete =
 				    g_strrstr (line,
 					       ")") == NULL ? FALSE : TRUE;
-				if ((pos = strchr (line, '#')) != NULL)
-					*pos = '\0';
-				g_strstrip (line);
-				if (line[0] != '\0') {
-					g_string_append_printf (buf,
-								" %s", line);
-				}
-				g_free (line);
-				if (!complete)
+
+				append_line (buf, line);
+				if (!complete) {
+					openrc_style = FALSE;
 					continue;
+				}
+				else {
+					openrc_style = TRUE;
+				}
 			} else {
 				complete =
 				    (g_strrstr (line, "(") != NULL
 				     && g_strrstr (line, ")") != NULL)
 				    || g_strrstr (line, "(") == NULL;
-				if ((pos = strchr (line, '#')) != NULL)
-					*pos = '\0';
-				g_strstrip (line);
-				if (line[0] != '\0')
-					g_string_append (buf, line);
-				g_free (line);
+
+				append_line (buf, line);
 				if (!complete)
+				{
+					openrc_style = FALSE;
 					continue;
+				} else {
+					openrc_style = TRUE;
+				}
 			}
 			init_block_by_line (buf->str);
 			g_string_free (buf, TRUE);
@@ -374,6 +417,34 @@ ifnet_get_data (const char *conn_name, const char *key)
 	return NULL;
 }
 
+/* format ip values for comparison */
+static gchar*
+format_ip_for_comparison (const gchar * value)
+{
+	gchar **ipset;
+	guint length, i;
+	GString *formated_string = g_string_new (NULL);
+	gchar *formatted = NULL;
+
+	ipset = g_strsplit (value, "\"", 0);
+	length = g_strv_length (ipset);
+
+	for (i = 0; i < length; i++)
+	{
+		strip_string (ipset[i], ' ');
+		if (ipset[i][0] != '\0')
+			g_string_append_printf (formated_string,
+						"%s ", ipset[i]);
+	}
+	formatted = g_strdup (formated_string->str);
+	formatted[formated_string->len - 1] = '\0';
+
+	g_string_free (formated_string, TRUE);
+	g_strfreev (ipset);
+
+	return formatted;
+}
+
 void
 ifnet_set_data (const char *conn_name, const char *key, const char *value)
 {
@@ -391,7 +462,31 @@ ifnet_set_data (const char *conn_name, const char *key, const char *value)
 	}
 	/* Remove existing key value pair */
 	if (g_hash_table_lookup_extended (conn, key, &old_key, &old_value)) {
-		if (stripped && !strcmp(old_value, stripped)){
+
+		/* This ugly hack is due to baselayout compatibility. We have to
+		 * deal with different ip format. So sometimes we have the same ips
+		 * but different strings.
+		 */
+		if (stripped &&
+			(!strcmp (key, "config")
+			|| !strcmp (key, "routes")
+			|| !strcmp (key, "pppd")
+			|| !strcmp (key, "chat")))
+		{
+			gchar *old_ips = format_ip_for_comparison (old_value);
+			gchar *new_ips = format_ip_for_comparison (value);
+			if(!strcmp (old_ips, new_ips))
+			{
+				g_free (stripped);
+				g_free (old_ips);
+				g_free (new_ips);
+				return;
+			}
+			g_free (old_ips);
+			g_free (new_ips);
+		}
+
+		if (stripped && !strcmp (old_value, stripped)) {
 			g_free (stripped);
 			return;
 		}
@@ -436,22 +531,28 @@ format_ips (gchar * value, gchar ** out_line, gchar * key, gchar * name)
 	guint length, i;
 	GString *formated_string = g_string_new (NULL);
 
+	strip_string (value, '(');
+	strip_string (value, ')');
 	strip_string (value, '"');
-	ipset = g_strsplit (value, "\" \"", 0);
+	ipset = g_strsplit (value, "\"", 0);
 	length = g_strv_length (ipset);
 
 	//only one line
 	if (length < 2) {
 		*out_line =
-		    g_strdup_printf ("%s_%s=( \"%s\" )\n", key, name, value);
+		    g_strdup_printf ("%s_%s=\"%s\"\n", key, name, value);
 		goto done;
 	}
 	// Multiple lines
-	g_string_append_printf (formated_string, "%s_%s=(\n", key, name);
+	g_string_append_printf (formated_string, "%s_%s=\"\n", key, name);
 	for (i = 0; i < length; i++)
-		g_string_append_printf (formated_string,
-					"\t\"%s\"\n", ipset[i]);
-	g_string_append (formated_string, ")\n");
+	{
+		strip_string (ipset[i], ' ');
+		if (ipset[i][0] != '\0')
+			g_string_append_printf (formated_string,
+						"%s\n", ipset[i]);
+	}
+	g_string_append (formated_string, "\"\n");
 	*out_line = g_strdup (formated_string->str);
 done:
 	g_string_free (formated_string, TRUE);
@@ -466,7 +567,7 @@ ifnet_flush_to_file (const char *config_file)
 	gpointer key, value, name, network;
 	GHashTableIter iter, iter_network;
 	GList *list_iter;
-	gchar *out_line;
+	gchar *out_line = NULL;
 	gsize bytes_written;
 	gboolean result = FALSE;
 
@@ -475,6 +576,8 @@ ifnet_flush_to_file (const char *config_file)
 	if (!conn_table || !global_settings_table)
 		return FALSE;
 
+	backup_file (config_file);
+
 	channel = g_io_channel_new_file (config_file, "w", NULL);
 	if (!channel) {
 		PLUGIN_WARN (IFNET_PLUGIN_NAME,
diff --git a/src/settings/plugins/ifnet/net_parser.h b/src/settings/plugins/ifnet/net_parser.h
index 0411e939..5dcc7e25 100644
--- a/src/settings/plugins/ifnet/net_parser.h
+++ b/src/settings/plugins/ifnet/net_parser.h
@@ -24,8 +24,8 @@
 
 #include <glib.h>
 
-#define CONF_NET_FILE "/etc/conf.d/net"
-#define IFNET_SYSTEM_SETTINGS_KEY_FILE "/etc/NetworkManager/nm-system-settings.conf"
+#define CONF_NET_FILE SYSCONFDIR "/conf.d/net"
+#define IFNET_SYSTEM_SETTINGS_KEY_FILE SYSCONFDIR "/NetworkManager/nm-system-settings.conf"
 #define IFNET_KEY_FILE_GROUP "ifnet"
 
 gboolean ifnet_init (gchar * config_file);
diff --git a/src/settings/plugins/ifnet/net_utils.c b/src/settings/plugins/ifnet/net_utils.c
index b533ae3f..f1687479 100644
--- a/src/settings/plugins/ifnet/net_utils.c
+++ b/src/settings/plugins/ifnet/net_utils.c
@@ -26,6 +26,7 @@
 #include <errno.h>
 #include <nm-utils.h>
 #include <nm-system-config-interface.h>
+#include <gio/gio.h>
 #include "net_utils.h"
 #include "wpa_parser.h"
 #include "net_parser.h"
@@ -242,8 +243,7 @@ read_hostname (const char *path)
 		if (g_str_has_prefix (all_lines[i], "hostname")) {
 			tmp = strstr (all_lines[i], "=");
 			tmp++;
-			tmp = strip_string (tmp, '"');
-			result = g_strdup (tmp);
+			result = g_shell_unquote (tmp, NULL);
 			break;
 		}
 
@@ -352,6 +352,49 @@ is_ip6_address (const char *in_address)
 
 }
 
+// 'c' is only used for openrc style
+static gchar **
+split_addresses_by_char (const gchar *addresses, const gchar *c)
+{
+	gchar **ipset;
+
+	if (addresses == NULL)
+		return NULL;
+
+	if (strchr (addresses, '(') != NULL) { // old baselayout style
+		gchar *tmp = g_strdup (addresses);
+		strip_string (tmp, '(');
+		strip_string (tmp, ')');
+		strip_string (tmp, '"');
+		strip_string (tmp, '\'');
+		ipset = g_strsplit (tmp, "\" \"", 0);
+		g_free(tmp);
+	} else { // openrc style
+		if (strstr (addresses, "netmask"))
+			// There is only one ip address if "netmask" is specified.
+			// '\n' is not used in config so there will be only one split.
+			ipset = g_strsplit (addresses, "\n", 0);
+		else
+			ipset = g_strsplit (addresses, c, 0);
+	}
+
+	return ipset;
+}
+
+static gchar **
+split_addresses (const gchar* addresses)
+{
+	// " " is only used by openrc style
+	return split_addresses_by_char (addresses, " ");
+}
+
+static gchar **
+split_routes (const gchar* routes)
+{
+	// "\"" is only used by openrc style
+	return split_addresses_by_char (routes, "\"");
+}
+
 gboolean
 has_ip6_address (const char *conn_name)
 {
@@ -360,7 +403,7 @@ has_ip6_address (const char *conn_name)
 	guint i;
 
 	g_return_val_if_fail (conn_name != NULL, FALSE);
-	ipset = g_strsplit (ifnet_get_data (conn_name, "config"), "\" \"", 0);
+	ipset = split_addresses (ifnet_get_data (conn_name, "config"));
 	length = g_strv_length (ipset);
 	for (i = 0; i < length; i++) {
 		if (!is_ip6_address (ipset[i]))
@@ -512,8 +555,11 @@ get_ip4_gateway (gchar * gateway)
 	tmp = g_strdup (tmp);
 	strip_string (tmp, ' ');
 	strip_string (tmp, '"');
+
+	// Only one gateway is selected
 	if ((split = strstr (tmp, "\"")) != NULL)
 		*split = '\0';
+
 	if (!inet_pton (AF_INET, tmp, &tmp_ip4_addr))
 		goto error;
 	g_free (tmp);
@@ -567,14 +613,11 @@ convert_ip4_config_block (const char *conn_name)
 	gchar *ip;
 	guint32 def_gateway = 0;
 	const char *routes;
-	gchar *pos;
 	ip_block *start = NULL, *current = NULL, *iblock = NULL;
-	const char *pattern =
-	    "((\\d{1,3}\\.\\d{1,3}\\.\\d{1,3}\\.)\\{(\\d{1,3})\\.\\.(\\d{1,3})\\}(/\\d{1,2}))";
 
 	g_return_val_if_fail (conn_name != NULL, NULL);
 
-	ipset = g_strsplit (ifnet_get_data (conn_name, "config"), "\" \"", 0);
+	ipset = split_addresses (ifnet_get_data (conn_name, "config"));
 	length = g_strv_length (ipset);
 
 	routes = ifnet_get_data (conn_name, "routes");
@@ -584,73 +627,16 @@ convert_ip4_config_block (const char *conn_name)
 	for (i = 0; i < length; i++) {
 		ip = ipset[i];
 		ip = strip_string (ip, '"');
-		//Handle ip like 192.168.4.{1..3}
-		if ((pos = strchr (ip, '{')) != NULL) {
-			gchar *ip_start, *ip_prefix;
-			gchar *begin_str, *end_str;
-			int begin, end, j;
-			GRegex *regex;
-			GMatchInfo *match_info;
-
-			regex = g_regex_new (pattern, 0, 0, NULL);
-			g_regex_match (regex, ip, 0, &match_info);
-			g_regex_unref (regex);
-
-			if (!g_match_info_matches (match_info)) {
-				g_match_info_free (match_info);
-				continue;
-			}
-			begin_str = g_match_info_fetch (match_info, 3);
-			end_str = g_match_info_fetch (match_info, 4);
-			begin = atoi (begin_str);
-			end = atoi (end_str);
-			ip_start = g_match_info_fetch (match_info, 2);
-			ip_prefix = g_match_info_fetch (match_info, 5);
-			if (end < begin || begin < 1 || end > 254) {
-				g_match_info_free (match_info);
-				continue;
-			}
-
-			for (j = begin; j <= end; j++) {
-				char suf[4];
-				gchar *newip;
-
-				sprintf (suf, "%d", j);
-				newip =
-				    g_strconcat (ip_start, suf, ip_prefix,
-						 NULL);
-				iblock = create_ip4_block (newip);
-				if (iblock == NULL) {
-					g_free (newip);
-					continue;
-				}
-				if (!iblock->gateway && def_gateway != 0)
-					iblock->gateway = def_gateway;
-				if (start == NULL)
-					start = current = iblock;
-				else {
-					current->next = iblock;
-					current = iblock;
-				}
-				g_free (newip);
-			}
-			g_free (begin_str);
-			g_free (end_str);
-			g_free (ip_start);
-			g_free (ip_prefix);
-			g_match_info_free (match_info);
-		} else {
-			iblock = create_ip4_block (ip);
-			if (iblock == NULL)
-				continue;
-			if (!iblock->gateway && def_gateway != 0)
-				iblock->gateway = def_gateway;
-			if (start == NULL)
-				start = current = iblock;
-			else {
-				current->next = iblock;
-				current = iblock;
-			}
+		iblock = create_ip4_block (ip);
+		if (iblock == NULL)
+			continue;
+		if (!iblock->gateway && def_gateway != 0)
+			iblock->gateway = def_gateway;
+		if (start == NULL)
+			start = current = iblock;
+		else {
+			current->next = iblock;
+			current = iblock;
 		}
 	}
 	g_strfreev (ipset);
@@ -667,7 +653,7 @@ convert_ip6_config_block (const char *conn_name)
 	ip6_block *start = NULL, *current = NULL, *iblock = NULL;
 
 	g_return_val_if_fail (conn_name != NULL, NULL);
-	ipset = g_strsplit (ifnet_get_data (conn_name, "config"), "\" \"", 0);
+	ipset = split_addresses (ifnet_get_data (conn_name, "config"));
 	length = g_strv_length (ipset);
 	for (i = 0; i < length; i++) {
 		ip = ipset[i];
@@ -693,15 +679,11 @@ convert_ip4_routes_block (const char *conn_name)
 	guint length;
 	guint i;
 	gchar *ip;
-	const char *routes;
 	ip_block *start = NULL, *current = NULL, *iblock = NULL;
 
 	g_return_val_if_fail (conn_name != NULL, NULL);
 
-	routes = ifnet_get_data (conn_name, "routes");
-	if (!routes)
-		return NULL;
-	ipset = g_strsplit (routes, "\" \"", 0);
+	ipset = split_routes (ifnet_get_data (conn_name, "routes"));
 	length = g_strv_length (ipset);
 	for (i = 0; i < length; i++) {
 		ip = ipset[i];
@@ -731,15 +713,11 @@ convert_ip6_routes_block (const char *conn_name)
 	guint length;
 	guint i;
 	gchar *ip, *tmp_addr;
-	const char *routes;
 	ip6_block *start = NULL, *current = NULL, *iblock = NULL;
 	struct in6_addr *tmp_ip6_addr;
 
 	g_return_val_if_fail (conn_name != NULL, NULL);
-	routes = ifnet_get_data (conn_name, "routes");
-	if (!routes)
-		return NULL;
-	ipset = g_strsplit (routes, "\" \"", 0);
+	ipset = split_routes (ifnet_get_data (conn_name, "routes"));
 	length = g_strv_length (ipset);
 	for (i = 0; i < length; i++) {
 		ip = ipset[i];
@@ -897,8 +875,8 @@ void
 get_dhcp_hostname_and_client_id (char **hostname, char **client_id)
 {
 	const char *dhcp_client;
-	const gchar *dhcpcd_conf = "/etc/dhcpcd.conf";
-	const gchar *dhclient_conf = "/etc/dhcp/dhclient.conf";
+	const gchar *dhcpcd_conf = SYSCONFDIR "/dhcpcd.conf";
+	const gchar *dhclient_conf = SYSCONFDIR "/dhcp/dhclient.conf";
 	gchar *line = NULL, *tmp = NULL, *contents = NULL;
 	gchar **all_lines;
 	guint line_num, i;
@@ -972,3 +950,20 @@ get_dhcp_hostname_and_client_id (char **hostname, char **client_id)
 	g_strfreev (all_lines);
 	g_free (contents);
 }
+
+void backup_file (const gchar* target)
+{
+	GFile *source, *backup;
+	gchar* backup_path;
+	GError **error = NULL;
+
+	source = g_file_new_for_path (target);
+	backup_path = g_strdup_printf ("%s.bak", target);
+	backup = g_file_new_for_path (backup_path);
+
+	g_file_copy (source, backup, G_FILE_COPY_OVERWRITE, NULL, NULL, NULL, error);
+	if (error && *error)
+		PLUGIN_WARN (IFNET_PLUGIN_NAME, "Backup failed: %s", (*error)->message);
+
+	g_free (backup_path);
+}
diff --git a/src/settings/plugins/ifnet/net_utils.h b/src/settings/plugins/ifnet/net_utils.h
index 42f8d672..dee49143 100644
--- a/src/settings/plugins/ifnet/net_utils.h
+++ b/src/settings/plugins/ifnet/net_utils.h
@@ -77,4 +77,5 @@ gboolean is_true (const char *str);
 
 void get_dhcp_hostname_and_client_id (char **hostname, char **client_id);
 
+void backup_file (const gchar* target);
 #endif
diff --git a/src/settings/plugins/ifnet/plugin.c b/src/settings/plugins/ifnet/plugin.c
index 59083688..fff83805 100644
--- a/src/settings/plugins/ifnet/plugin.c
+++ b/src/settings/plugins/ifnet/plugin.c
@@ -48,6 +48,7 @@
 typedef struct {
 	GHashTable *config_connections;
 	gchar *hostname;
+	char *conf_file;
 	gboolean unmanaged_well_known;
 
 	GFileMonitor *hostname_monitor;
@@ -180,7 +181,7 @@ monitor_file_changes (const char *filename,
 /* Callback for nm_settings_connection_replace_and_commit. Report any errors
  * encountered when commiting connection settings updates. */
 static void
-commit_cb (NMSettingsConnection *connection, GError *error, gpointer unused) 
+commit_cb (NMSettingsConnection *connection, GError *error, gpointer unused)
 {
 	if (error) {
 		PLUGIN_WARN (IFNET_PLUGIN_NAME, "    error updating: %s",
@@ -188,8 +189,7 @@ commit_cb (NMSettingsConnection *connection, GError *error, gpointer unused)
 	} else {
 		NMSettingConnection *s_con;
 
-		s_con = (NMSettingConnection *) nm_connection_get_setting (NM_CONNECTION (connection),
-		                                                           NM_TYPE_SETTING_CONNECTION);
+		s_con = nm_connection_get_setting_connection (NM_CONNECTION (connection));
 		g_assert (s_con);
 		PLUGIN_PRINT (IFNET_PLUGIN_NAME, "Connection %s updated",
 		              nm_setting_connection_get_id (s_con));
@@ -317,6 +317,26 @@ reload_connections (gpointer config)
 	g_list_free (conn_names);
 }
 
+static void
+check_flagged_secrets (NMSetting  *setting,
+                       const char *key,
+                       const GValue *value,
+                       GParamFlags flags,
+                       gpointer user_data)
+{
+	gboolean *is_system_secret = user_data;
+
+	if (flags & NM_SETTING_PARAM_SECRET) {
+		NMSettingSecretFlags secret_flags = NM_SETTING_SECRET_FLAG_NONE;
+
+		nm_setting_get_secret_flags (setting, key, &secret_flags, NULL);
+
+		if (secret_flags != NM_SETTING_SECRET_FLAG_NONE) {
+			*is_system_secret = TRUE;
+		}
+	}
+}
+
 static NMSettingsConnection *
 add_connection (NMSystemConfigInterface *config,
                 NMConnection *source,
@@ -324,11 +344,28 @@ add_connection (NMSystemConfigInterface *config,
 {
 	NMIfnetConnection *connection = NULL;
 	char *conn_name;
+	gboolean has_flagged_secrets = FALSE;
+	NMSettingConnection *s_con;
+
+	s_con = nm_connection_get_setting_connection (source);
+	g_assert (s_con);
+
+	/* If the connection is not available for all users, ignore
+	 * it as this plugin only deals with System Connections */
+	if (nm_setting_connection_get_num_permissions (s_con))
+		return NULL;
+
+	/* If the connection has flagged secrets, ignore
+	 * it as this plugin does not deal with user agent service */
+	nm_connection_for_each_setting_value (source, check_flagged_secrets, &has_flagged_secrets);
+
+	if (!has_flagged_secrets) {
+		conn_name = ifnet_add_new_connection (source, CONF_NET_FILE, WPA_SUPPLICANT_CONF, error);
+		if (conn_name)
+			connection = nm_ifnet_connection_new (conn_name, source);
+		reload_connections (config);
+	}
 
-	conn_name = ifnet_add_new_connection (source, CONF_NET_FILE, WPA_SUPPLICANT_CONF, error);
-	if (conn_name)
-		connection = nm_ifnet_connection_new (conn_name, source);
-	reload_connections (config);
 	return connection ? NM_SETTINGS_CONNECTION (connection) : NULL;
 }
 
@@ -494,6 +531,7 @@ dispose (GObject * object)
 	}
 
 	g_free (priv->hostname);
+	g_free (priv->conf_file);
 	ifnet_destroy ();
 	wpa_parser_destroy ();
 	G_OBJECT_CLASS (sc_plugin_ifnet_parent_class)->dispose (object);
@@ -527,16 +565,37 @@ sc_plugin_ifnet_class_init (SCPluginIfnetClass * req_class)
 					  NM_SYSTEM_CONFIG_INTERFACE_HOSTNAME);
 }
 
+const char *
+ifnet_plugin_get_conf_file (void)
+{
+	SCPluginIfnet *ifnet_plugin;
+	SCPluginIfnetPrivate *priv;
+
+	/* Get config file name. Plugin's singleton has already been created
+	 * with correct config file path, so the string passed here has no efect
+	 * and we get the valid file name.
+	 */
+	ifnet_plugin = SC_PLUGIN_IFNET (nm_system_config_factory ("fake string"));
+	priv = SC_PLUGIN_IFNET_GET_PRIVATE (ifnet_plugin);
+	g_object_unref (ifnet_plugin);
+
+	return priv->conf_file;
+}
+
 G_MODULE_EXPORT GObject *
-nm_system_config_factory (void)
+nm_system_config_factory (const char *config_file)
 {
 	static SCPluginIfnet *singleton = NULL;
+	SCPluginIfnetPrivate *priv;
 
-	if (!singleton)
-		singleton
-		    =
-		    SC_PLUGIN_IFNET (g_object_new (SC_TYPE_PLUGIN_IFNET, NULL));
-	else
+	if (!singleton) {
+		singleton = SC_PLUGIN_IFNET (g_object_new (SC_TYPE_PLUGIN_IFNET, NULL));
+		if (singleton) {
+			priv = SC_PLUGIN_IFNET_GET_PRIVATE (singleton);
+			priv->conf_file = strdup (config_file);
+		}
+	} else
 		g_object_ref (singleton);
+
 	return G_OBJECT (singleton);
 }
diff --git a/src/settings/plugins/ifnet/plugin.h b/src/settings/plugins/ifnet/plugin.h
index 83099b63..eecab159 100644
--- a/src/settings/plugins/ifnet/plugin.h
+++ b/src/settings/plugins/ifnet/plugin.h
@@ -43,5 +43,7 @@ struct _SCPluginIfnetClass {
 	GObjectClass parent;
 };
 
+const char * ifnet_plugin_get_conf_file (void);
+
 GType sc_plugin_ifnet_get_type (void);
 #endif
diff --git a/src/settings/plugins/ifnet/tests/Makefile.in b/src/settings/plugins/ifnet/tests/Makefile.in
index fe7f40e2..02ee121f 100644
--- a/src/settings/plugins/ifnet/tests/Makefile.in
+++ b/src/settings/plugins/ifnet/tests/Makefile.in
@@ -141,6 +141,8 @@ GIO_LIBS = @GIO_LIBS@
 GLIB_CFLAGS = @GLIB_CFLAGS@
 GLIB_GENMARSHAL = @GLIB_GENMARSHAL@
 GLIB_LIBS = @GLIB_LIBS@
+GLIB_MAKEFILE = @GLIB_MAKEFILE@
+GLIB_MKENUMS = @GLIB_MKENUMS@
 GMODULE_CFLAGS = @GMODULE_CFLAGS@
 GMODULE_LIBS = @GMODULE_LIBS@
 GMSGFMT = @GMSGFMT@
@@ -195,11 +197,15 @@ LIBNL2_LIBS = @LIBNL2_LIBS@
 LIBNL3_CFLAGS = @LIBNL3_CFLAGS@
 LIBNL3_LIBS = @LIBNL3_LIBS@
 LIBNL_CFLAGS = @LIBNL_CFLAGS@
+LIBNL_GENL3_CFLAGS = @LIBNL_GENL3_CFLAGS@
+LIBNL_GENL3_LIBS = @LIBNL_GENL3_LIBS@
 LIBNL_LIBS = @LIBNL_LIBS@
 LIBNL_ROUTE3_CFLAGS = @LIBNL_ROUTE3_CFLAGS@
 LIBNL_ROUTE3_LIBS = @LIBNL_ROUTE3_LIBS@
 LIBOBJS = @LIBOBJS@
 LIBS = @LIBS@
+LIBSOUP_CFLAGS = @LIBSOUP_CFLAGS@
+LIBSOUP_LIBS = @LIBSOUP_LIBS@
 LIBTOOL = @LIBTOOL@
 LIPO = @LIPO@
 LN_S = @LN_S@
@@ -210,6 +216,7 @@ MAINT = @MAINT@
 MAKEINFO = @MAKEINFO@
 MANIFEST_TOOL = @MANIFEST_TOOL@
 MKDIR_P = @MKDIR_P@
+MOC = @MOC@
 MSGFMT = @MSGFMT@
 MSGFMT_015 = @MSGFMT_015@
 MSGMERGE = @MSGMERGE@
@@ -249,6 +256,8 @@ SED = @SED@
 SET_MAKE = @SET_MAKE@
 SHELL = @SHELL@
 STRIP = @STRIP@
+SYSTEMD_CFLAGS = @SYSTEMD_CFLAGS@
+SYSTEMD_LIBS = @SYSTEMD_LIBS@
 SYSTEM_CA_PATH = @SYSTEM_CA_PATH@
 UDEV_BASE_DIR = @UDEV_BASE_DIR@
 USE_NLS = @USE_NLS@
diff --git a/src/settings/plugins/ifnet/tests/net b/src/settings/plugins/ifnet/tests/net
index 0eef399a..27d39f44 100644
--- a/src/settings/plugins/ifnet/tests/net
+++ b/src/settings/plugins/ifnet/tests/net
@@ -27,10 +27,9 @@ config_eth2=(
 routes_eth2=("default via  4321:0:1:2:3:4:567:89ab")
 enable_ipv6_eth2="true"
 config_eth3=("nufjlsjlll")
-managed_eth4=("false")
+managed_eth4="false"
 routes_eth4=("default via 4321:0:1:2:3:4:567:89ab")
 config_eth5=("dhcp")
-config_eth6=("192.168.4.{1..101}/24")
 
 config_eth7=( "dhcp" )
 auto_eth7="true"
@@ -38,6 +37,14 @@ auto_eth7="true"
 # missing config_eth8
 auto_eth8="true"
 
+#new openrc style
+config_eth9="202.117.16.10/24 202.117.17.10/24"
+routes_eth9="default via 202.117.16.1
+10.0.0.0/8 via 192.168.0.1
+"
+config_eth10="202.117.16.2 netmask 255.255.255.0"
+routes_eth10="10.0.0.0/8 via 192.168.0.1"
+
 config_myxjtu2=("202.117.16.121/24 brd 202.117.16.255")
 routes_myxjtu2=("default via 202.117.16.1")
 dns_servers_myxjtu2="202.117.0.20 202.117.0.21"
diff --git a/src/settings/plugins/ifnet/tests/test_all.c b/src/settings/plugins/ifnet/tests/test_all.c
index 52d9ce2a..50441d4e 100644
--- a/src/settings/plugins/ifnet/tests/test_all.c
+++ b/src/settings/plugins/ifnet/tests/test_all.c
@@ -33,11 +33,21 @@
 #include "wpa_parser.h"
 #include "connection_parser.h"
 
+/* Fake config file function to make the linker happy */
+const char *ifnet_plugin_get_conf_file (void);
+
+const char *
+ifnet_plugin_get_conf_file (void)
+{
+	return "/etc/foo/barasdfasdfasdfasdf";
+}
+
+
 static void
 test_getdata ()
 {
 	ASSERT (ifnet_get_data ("eth1", "config")
-		&& strcmp (ifnet_get_data ("eth1", "config"), "dhcp") == 0,
+		&& strcmp (ifnet_get_data ("eth1", "config"), "( \"dhcp\" )") == 0,
 		"get data", "config_eth1 is not correct");
 	ASSERT (ifnet_get_data ("ppp0", "username")
 		&& strcmp (ifnet_get_data ("ppp0", "username"), "user") == 0,
@@ -84,7 +94,7 @@ test_is_static ()
 	ASSERT (is_static_ip4 ("eth0") == TRUE, "is static",
 		"a static interface is recognized as dhcp");
 	ASSERT (!is_static_ip6 ("eth0") == TRUE, "is static",
-		"a static interface is recognized as dhcp");
+		"a dhcp interface is recognized as static");
 }
 
 static void
@@ -182,10 +192,6 @@ test_convert_ipv4_config_block ()
 	ASSERT (iblock == NULL, "convert config_block",
 		"convert error configuration");
 	destroy_ip_block (iblock);
-	iblock = convert_ip4_config_block ("eth6");
-	ASSERT (iblock != NULL, "convert config_block",
-		"convert error configuration");
-	destroy_ip_block (iblock);
 }
 
 static void
@@ -200,6 +206,16 @@ test_convert_ipv4_routes_block ()
 	destroy_ip_block (tmp);
 	ASSERT (iblock == NULL, "convert ip4 routes",
 		"should only get one route");
+
+	iblock = convert_ip4_routes_block ("eth9");
+	tmp = iblock;
+
+	ASSERT (iblock != NULL, "convert ip4 routes", "should get one route");
+	check_ip_block (iblock, "10.0.0.0", "255.0.0.0", "192.168.0.1");
+	iblock = iblock->next;
+	destroy_ip_block (tmp);
+	ASSERT (iblock == NULL, "convert ip4 routes",
+		"should only get one route");
 }
 
 static void
@@ -222,6 +238,9 @@ test_wpa_parser ()
 		"wep_key0 of static-wep-test should be abcde, find %s", value);
 	ASSERT (exist_ssid ("leap-example"), "get wsec",
 		"ssid leap-example is not found");
+
+	value = wpa_get_value ("test-with-hash-in-psk", "psk");
+	g_assert_cmpstr (value, ==, "\"xjtudlc3731###asdfasdfasdf\"");
 }
 
 static void
@@ -272,6 +291,18 @@ test_new_connection ()
 		"new connection failed: %s",
 		error ? error->message : "NONE");
 	g_object_unref (connection);
+
+	connection = ifnet_update_connection_from_config_block ("eth9", &error);
+	ASSERT (connection != NULL, "new connection",
+		"new connection(eth9) failed: %s",
+		error ? error->message : "NONE");
+	g_object_unref (connection);
+
+	connection = ifnet_update_connection_from_config_block ("eth10", &error);
+	ASSERT (connection != NULL, "new connection",
+		"new connection(eth10) failed: %s",
+		error ? error->message : "NONE");
+	g_object_unref (connection);
 }
 
 #define NET_GEN_NAME "net.generate"
diff --git a/src/settings/plugins/ifnet/tests/wpa_supplicant.conf b/src/settings/plugins/ifnet/tests/wpa_supplicant.conf
index 4f5f68cf..609ee0e1 100644
--- a/src/settings/plugins/ifnet/tests/wpa_supplicant.conf
+++ b/src/settings/plugins/ifnet/tests/wpa_supplicant.conf
@@ -863,3 +863,10 @@ network={
 	phase2="auth=CHAP"
 	priority=20
 }
+
+network={
+  ssid="test-with-hash-in-psk"
+  key_mgmt=WPA-PSK
+  psk="xjtudlc3731###asdfasdfasdf"
+}
+
diff --git a/src/settings/plugins/ifnet/wpa_parser.c b/src/settings/plugins/ifnet/wpa_parser.c
index da2bc3bb..0fd7d16b 100644
--- a/src/settings/plugins/ifnet/wpa_parser.c
+++ b/src/settings/plugins/ifnet/wpa_parser.c
@@ -124,7 +124,7 @@ add_key_value (GHashTable * network, gchar * line)
 	g_strstrip (key_value[0]);
 	g_strstrip (key_value[1]);
 
-	/* Reserve quotes for psk, wep_key, ssid 
+	/* Reserve quotes for psk, wep_key, ssid
 	 * Quotes will determine whether they are hex format */
 	if (strcmp (key_value[0], "psk") != 0
 	    && !g_str_has_prefix (key_value[0], "wep_key")
@@ -162,7 +162,7 @@ add_one_wep_key (GHashTable * table, int key_num, gchar * one_wep_key)
 	}
 }
 
-/* Reading wep security information from /etc/conf.d/net. 
+/* Reading wep security information from /etc/conf.d/net.
  * This should not be used in futre, use wpa_supplicant instead. */
 static void
 add_keys_from_net ()
@@ -279,16 +279,21 @@ wpa_parser_init (const char *wpa_supplicant_conf)
 			} else {
 				GHashTable *network =
 				    g_hash_table_new (g_str_hash, g_str_equal);
-				gchar *tmp;
 
 				do {
+					gchar *quote_start, *quote_end = NULL, *comment;
+
 					if (line[0] == '#' || line[0] == '\0') {
 						g_free (line);
 						continue;
 					}
-					/* ignore inline comments */
-					if ((tmp = strchr (line, '#')) != NULL)
-						*tmp = '\0';
+					/* ignore inline comments unless inside
+					   a double-quoted string */
+					if ((quote_start = strchr (line, '"')) != NULL)
+						quote_end = strrchr (quote_start + 1, '"');
+					if ((comment = strchr ((quote_end != NULL) ?
+					                       quote_end : line, '#')) != NULL)
+						*comment = '\0';
 					if (strstr (line, "}") != NULL)
 						complete = TRUE;
 					add_key_value (network, line);
@@ -371,6 +376,8 @@ wpa_flush_to_file (const char *config_file)
 	if (!wsec_table || !wsec_global_table)
 		return FALSE;
 
+	backup_file (config_file);
+
 	channel = g_io_channel_new_file (config_file, "w", NULL);
 	if (!channel) {
 		PLUGIN_WARN (IFNET_PLUGIN_NAME,
diff --git a/src/settings/plugins/ifnet/wpa_parser.h b/src/settings/plugins/ifnet/wpa_parser.h
index 7fd77a05..3a0d377e 100644
--- a/src/settings/plugins/ifnet/wpa_parser.h
+++ b/src/settings/plugins/ifnet/wpa_parser.h
@@ -21,8 +21,11 @@
 
 #ifndef _WPA_PARSER_H
 #define _WPA_PARSER_H
-#define WPA_SUPPLICANT_CONF "/etc/wpa_supplicant/wpa_supplicant.conf"
+
 #include <glib.h>
+
+#define WPA_SUPPLICANT_CONF SYSCONFDIR "/wpa_supplicant/wpa_supplicant.conf"
+
 void wpa_parser_init (const char *wpa_supplicant_conf);
 void wpa_parser_destroy (void);
 
diff --git a/src/settings/plugins/ifupdown/Makefile.in b/src/settings/plugins/ifupdown/Makefile.in
index 98dded68..f5087648 100644
--- a/src/settings/plugins/ifupdown/Makefile.in
+++ b/src/settings/plugins/ifupdown/Makefile.in
@@ -217,6 +217,8 @@ GIO_LIBS = @GIO_LIBS@
 GLIB_CFLAGS = @GLIB_CFLAGS@
 GLIB_GENMARSHAL = @GLIB_GENMARSHAL@
 GLIB_LIBS = @GLIB_LIBS@
+GLIB_MAKEFILE = @GLIB_MAKEFILE@
+GLIB_MKENUMS = @GLIB_MKENUMS@
 GMODULE_CFLAGS = @GMODULE_CFLAGS@
 GMODULE_LIBS = @GMODULE_LIBS@
 GMSGFMT = @GMSGFMT@
@@ -271,11 +273,15 @@ LIBNL2_LIBS = @LIBNL2_LIBS@
 LIBNL3_CFLAGS = @LIBNL3_CFLAGS@
 LIBNL3_LIBS = @LIBNL3_LIBS@
 LIBNL_CFLAGS = @LIBNL_CFLAGS@
+LIBNL_GENL3_CFLAGS = @LIBNL_GENL3_CFLAGS@
+LIBNL_GENL3_LIBS = @LIBNL_GENL3_LIBS@
 LIBNL_LIBS = @LIBNL_LIBS@
 LIBNL_ROUTE3_CFLAGS = @LIBNL_ROUTE3_CFLAGS@
 LIBNL_ROUTE3_LIBS = @LIBNL_ROUTE3_LIBS@
 LIBOBJS = @LIBOBJS@
 LIBS = @LIBS@
+LIBSOUP_CFLAGS = @LIBSOUP_CFLAGS@
+LIBSOUP_LIBS = @LIBSOUP_LIBS@
 LIBTOOL = @LIBTOOL@
 LIPO = @LIPO@
 LN_S = @LN_S@
@@ -286,6 +292,7 @@ MAINT = @MAINT@
 MAKEINFO = @MAKEINFO@
 MANIFEST_TOOL = @MANIFEST_TOOL@
 MKDIR_P = @MKDIR_P@
+MOC = @MOC@
 MSGFMT = @MSGFMT@
 MSGFMT_015 = @MSGFMT_015@
 MSGMERGE = @MSGMERGE@
@@ -325,6 +332,8 @@ SED = @SED@
 SET_MAKE = @SET_MAKE@
 SHELL = @SHELL@
 STRIP = @STRIP@
+SYSTEMD_CFLAGS = @SYSTEMD_CFLAGS@
+SYSTEMD_LIBS = @SYSTEMD_LIBS@
 SYSTEM_CA_PATH = @SYSTEM_CA_PATH@
 UDEV_BASE_DIR = @UDEV_BASE_DIR@
 USE_NLS = @USE_NLS@
diff --git a/src/settings/plugins/ifupdown/interface_parser.c b/src/settings/plugins/ifupdown/interface_parser.c
index b7c64242..38ed1479 100644
--- a/src/settings/plugins/ifupdown/interface_parser.c
+++ b/src/settings/plugins/ifupdown/interface_parser.c
@@ -294,6 +294,19 @@ const char *ifparser_getkey(if_block* iface, const char *key)
 	return NULL;
 }
 
+gboolean
+ifparser_haskey(if_block* iface, const char *key)
+{
+	if_data *curr = iface->info;
+
+	while (curr != NULL) {
+		if (strcmp (curr->key, key) == 0)
+			return TRUE;
+		curr = curr->next;
+	}
+	return FALSE;
+}
+
 int ifparser_get_num_info(if_block* iface)
 {
 	int i = 0;
diff --git a/src/settings/plugins/ifupdown/interface_parser.h b/src/settings/plugins/ifupdown/interface_parser.h
index 0c1de23a..e68abcf6 100644
--- a/src/settings/plugins/ifupdown/interface_parser.h
+++ b/src/settings/plugins/ifupdown/interface_parser.h
@@ -24,6 +24,8 @@
 #ifndef _INTERFACE_PARSER_H
 #define _INTERFACE_PARSER_H
 
+#include <glib.h>
+
 typedef struct _if_data
 {
 	char *key;
@@ -45,6 +47,7 @@ void ifparser_destroy(void);
 if_block *ifparser_getif(const char* iface);
 if_block *ifparser_getfirst(void);
 const char *ifparser_getkey(if_block* iface, const char *key);
+gboolean ifparser_haskey(if_block* iface, const char *key);
 int ifparser_get_num_blocks(void);
 int ifparser_get_num_info(if_block* iface);
 
diff --git a/src/settings/plugins/ifupdown/parser.c b/src/settings/plugins/ifupdown/parser.c
index dc2f8abf..6927f43f 100644
--- a/src/settings/plugins/ifupdown/parser.c
+++ b/src/settings/plugins/ifupdown/parser.c
@@ -25,6 +25,7 @@
 #include <arpa/inet.h>
 #include <stdlib.h>
 #include <errno.h>
+#include <ctype.h>
 
 #include <nm-connection.h>
 #include <NetworkManager.h>
@@ -311,8 +312,7 @@ update_wireless_security_setting_from_if_block(NMConnection *connection,
 		return;
 	}
 
-	s_wireless = NM_SETTING_WIRELESS(nm_connection_get_setting(connection,
-												    NM_TYPE_SETTING_WIRELESS));
+	s_wireless = nm_connection_get_setting_wireless(connection);
 	g_return_if_fail(s_wireless);
 
 	PLUGIN_PRINT ("SCPlugin-Ifupdown","update wireless security settings (%s).", block->name);
@@ -433,96 +433,263 @@ eni_plugin_error_quark() {
 
 	return error_quark;
 }
-	
 
 static void
+ifupdown_ip4_add_dns (NMSettingIP4Config *s_ip4, const char *dns)
+{
+	struct in_addr addr;
+	char **list, **iter;
+
+	if (dns == NULL)
+		return;
+
+	list = g_strsplit_set (dns, " \t", -1);
+	for (iter = list; iter && *iter; iter++) {
+		g_strstrip (*iter);
+		if (isblank (*iter[0]))
+			continue;
+		if (!inet_pton (AF_INET, *iter, &addr)) {
+			PLUGIN_WARN ("SCPlugin-Ifupdown",
+					   "    warning: ignoring invalid nameserver '%s'", *iter);
+			continue;
+		}
+
+		if (!nm_setting_ip4_config_add_dns (s_ip4, addr.s_addr)) {
+			PLUGIN_WARN ("SCPlugin-Ifupdown",
+					   "    warning: duplicate DNS domain '%s'", *iter);
+		}
+	}
+	g_strfreev (list);
+}
+
+static gboolean
 update_ip4_setting_from_if_block(NMConnection *connection,
-						   if_block *block)
+						   if_block *block,
+						   GError **error)
 {
 
-	NMSettingIP4Config *ip4_setting = NM_SETTING_IP4_CONFIG (nm_setting_ip4_config_new());
+	NMSettingIP4Config *s_ip4 = NM_SETTING_IP4_CONFIG (nm_setting_ip4_config_new());
 	const char *type = ifparser_getkey(block, "inet");
 	gboolean is_static = type && !strcmp("static", type);
 
-	if(!is_static) {
-		g_object_set(ip4_setting,
-				   NM_SETTING_IP4_CONFIG_METHOD, NM_SETTING_IP4_CONFIG_METHOD_AUTO,
-				   NULL);
+	if (!is_static) {
+		g_object_set (s_ip4, NM_SETTING_IP4_CONFIG_METHOD, NM_SETTING_IP4_CONFIG_METHOD_AUTO, NULL);
 	} else {
- 		struct in_addr tmp_ip4_addr;
-		NMIP4Address *ip4_addr = nm_ip4_address_new ();
-
-		const char *address_v = ifparser_getkey(block, "address");
-		const char *netmask_v = ifparser_getkey(block, "netmask");
-		const char *gateway_v = ifparser_getkey(block, "gateway");
-		const char *nameserver_v = ifparser_getkey(block, "dns-nameserver");
-		const char *nameservers_v = ifparser_getkey(block, "dns-nameservers");
-		GSList* nameservers_list = NULL;
-		GSList* nameservers_list_i = NULL;
-		GError *error = NULL;
-
-		if(nameservers_v)
-			nameservers_list_i = nameservers_list = string_to_glist_of_strings (nameservers_v);
-		if(nameserver_v)
-			nameservers_list_i = nameservers_list = g_slist_append(nameservers_list, g_strdup(nameserver_v));
-
-		if (!address_v)
-			address_v = g_strdup ("0.0.0.0");
-
-		if (inet_pton (AF_INET, address_v, &tmp_ip4_addr))
-			nm_ip4_address_set_address (ip4_addr, tmp_ip4_addr.s_addr);
-		else
-			g_set_error (&error, eni_plugin_error_quark (), 0,
-					   "Invalid %s IP4 address '%s'", "address", address_v);
-		if (!netmask_v)
-			netmask_v = g_strdup( "255.255.255.255");
-
-		if (inet_pton (AF_INET, netmask_v, &tmp_ip4_addr))
-			nm_ip4_address_set_prefix (ip4_addr, nm_utils_ip4_netmask_to_prefix(tmp_ip4_addr.s_addr));
-		else
-			g_set_error (&error, eni_plugin_error_quark (), 0,
-					   "Invalid %s IP4 address '%s'", "netmask", netmask_v);
+		struct in_addr tmp_addr, tmp_mask, tmp_gw;
+		NMIP4Address *addr;
+		const char *address_v;
+		const char *netmask_v;
+		const char *gateway_v;
+		const char *nameserver_v;
+		const char *nameservers_v;
+		const char *search_v;
+		char **list, **iter;
+		guint32 netmask_int = 32;
+
+		/* Address */
+		address_v = ifparser_getkey (block, "address");
+		if (!address_v || !inet_pton (AF_INET, address_v, &tmp_addr)) {
+			g_set_error (error, eni_plugin_error_quark (), 0,
+			             "Missing IPv4 address '%s'",
+			             address_v ? address_v : "(none)");
+			goto error;
+		}
 
+		/* mask/prefix */
+		netmask_v = ifparser_getkey (block, "netmask");
+		if (netmask_v) {
+			if (!inet_pton (AF_INET, netmask_v, &tmp_mask)) {
+				g_set_error (error, eni_plugin_error_quark (), 0,
+						   "Invalid IPv4 netmask '%s'", netmask_v);
+				goto error;
+			}
+			netmask_int = nm_utils_ip4_netmask_to_prefix (tmp_mask.s_addr);
+		}
+
+		/* gateway */
+		gateway_v = ifparser_getkey (block, "gateway");
 		if (!gateway_v)
-			gateway_v = g_strdup (address_v);
+			gateway_v = address_v;  /* dcbw: whaaa?? */
+		if (!inet_pton (AF_INET, gateway_v, &tmp_gw)) {
+			g_set_error (error, eni_plugin_error_quark (), 0,
+					   "Invalid IPv4 gateway '%s'", gateway_v);
+			goto error;
+		}
 
-		if (inet_pton (AF_INET, gateway_v, &tmp_ip4_addr))
-			nm_ip4_address_set_gateway (ip4_addr, tmp_ip4_addr.s_addr);
-		else
-			g_set_error (&error, eni_plugin_error_quark (), 0,
-					   "Invalid %s IP4 address '%s'", "gateway", gateway_v);
+		/* Add the new address to the setting */
+		addr = nm_ip4_address_new ();
+		nm_ip4_address_set_address (addr, tmp_addr.s_addr);
+		nm_ip4_address_set_prefix (addr, netmask_int);
+		nm_ip4_address_set_gateway (addr, tmp_gw.s_addr);
 
-		if (nm_setting_ip4_config_add_address (ip4_setting, ip4_addr)) {
+		if (nm_setting_ip4_config_add_address (s_ip4, addr)) {
 			PLUGIN_PRINT("SCPlugin-Ifupdown", "addresses count: %d",
-			             nm_setting_ip4_config_get_num_addresses (ip4_setting));
+			             nm_setting_ip4_config_get_num_addresses (s_ip4));
 		} else {
 			PLUGIN_PRINT("SCPlugin-Ifupdown", "ignoring duplicate IP4 address");
 		}
 
-		while(nameservers_list_i) {
-			gchar *dns = nameservers_list_i->data;
-			nameservers_list_i = nameservers_list_i -> next;
-			if(!dns)
-				continue;
-			if (inet_pton (AF_INET, dns, &tmp_ip4_addr)) {
-				if (!nm_setting_ip4_config_add_dns (ip4_setting, tmp_ip4_addr.s_addr))
-					PLUGIN_PRINT("SCPlugin-Ifupdown", "ignoring duplicate DNS server '%s'", dns);
-			} else
-				g_set_error (&error, eni_plugin_error_quark (), 0,
-						   "Invalid %s IP4 address nameserver '%s'", "nameserver", dns);
+		nameserver_v = ifparser_getkey (block, "dns-nameserver");
+		ifupdown_ip4_add_dns (s_ip4, nameserver_v);
+
+		nameservers_v = ifparser_getkey (block, "dns-nameservers");
+		ifupdown_ip4_add_dns (s_ip4, nameservers_v);
+
+		if (!nm_setting_ip4_config_get_num_dns (s_ip4))
+			PLUGIN_PRINT("SCPlugin-Ifupdown", "No dns-nameserver configured in /etc/network/interfaces");
+
+		/* DNS searches */
+		search_v = ifparser_getkey (block, "dns-search");
+		if (search_v) {
+			list = g_strsplit_set (search_v, " \t", -1);
+			for (iter = list; iter && *iter; iter++) {
+				g_strstrip (*iter);
+				if (isblank (*iter[0]))
+					continue;
+				if (!nm_setting_ip4_config_add_dns_search (s_ip4, *iter)) {
+					PLUGIN_WARN ("SCPlugin-Ifupdown",
+							   "    warning: duplicate DNS domain '%s'", *iter);
+				}
+			}
+			g_strfreev (list);
 		}
-		if (!nm_setting_ip4_config_get_num_dns (ip4_setting))
+
+		g_object_set (s_ip4, NM_SETTING_IP4_CONFIG_METHOD, NM_SETTING_IP4_CONFIG_METHOD_MANUAL, NULL);
+	}
+
+	nm_connection_add_setting (connection, NM_SETTING (s_ip4));
+	return TRUE;
+
+error:
+	g_object_unref (s_ip4);
+	return FALSE;
+}
+
+static void
+ifupdown_ip6_add_dns (NMSettingIP6Config *s_ip6, const char *dns)
+{
+	struct in6_addr addr;
+	char **list, **iter;
+
+	if (dns == NULL)
+		return;
+
+	list = g_strsplit_set (dns, " \t", -1);
+	for (iter = list; iter && *iter; iter++) {
+		g_strstrip (*iter);
+		if (isblank (*iter[0]))
+			continue;
+		if (!inet_pton (AF_INET6, *iter, &addr)) {
+			PLUGIN_WARN ("SCPlugin-Ifupdown",
+					   "    warning: ignoring invalid nameserver '%s'", *iter);
+			continue;
+		}
+
+		if (!nm_setting_ip6_config_add_dns (s_ip6, &addr)) {
+			PLUGIN_WARN ("SCPlugin-Ifupdown",
+					   "    warning: duplicate DNS domain '%s'", *iter);
+		}
+	}
+	g_strfreev (list);
+}
+
+static gboolean
+update_ip6_setting_from_if_block(NMConnection *connection,
+						   if_block *block,
+						   GError **error)
+{
+	NMSettingIP6Config *s_ip6 = NM_SETTING_IP6_CONFIG (nm_setting_ip6_config_new());
+	const char *type = ifparser_getkey(block, "inet6");
+	gboolean is_static = type && (!strcmp("static", type) ||
+							!strcmp("v4tunnel", type));
+
+	if (!is_static) {
+		g_object_set(s_ip6, NM_SETTING_IP6_CONFIG_METHOD, NM_SETTING_IP6_CONFIG_METHOD_AUTO, NULL);
+	} else {
+		struct in6_addr tmp_addr, tmp_gw;
+		NMIP6Address *addr;
+		const char *address_v;
+		const char *prefix_v;
+		const char *gateway_v;
+		const char *nameserver_v;
+		const char *nameservers_v;
+		const char *search_v;
+		int prefix_int = 128;
+		char **list, **iter;
+
+		/* Address */
+		address_v = ifparser_getkey(block, "address");
+		if (!address_v || !inet_pton (AF_INET6, address_v, &tmp_addr)) {
+			g_set_error (error, eni_plugin_error_quark (), 0,
+			             "Missing IPv6 address '%s'",
+			             address_v ? address_v : "(none)");
+			goto error;
+		}
+
+		/* Prefix */
+		prefix_v = ifparser_getkey(block, "netmask");
+		if (prefix_v)
+			prefix_int = g_ascii_strtoll (prefix_v, NULL, 10);
+
+		/* Gateway */
+		gateway_v = ifparser_getkey (block, "gateway");
+		if (!gateway_v)
+			gateway_v = address_v;  /* dcbw: whaaa?? */
+		if (!inet_pton (AF_INET6, gateway_v, &tmp_gw)) {
+			g_set_error (error, eni_plugin_error_quark (), 0,
+					   "Invalid IPv6 gateway '%s'", gateway_v);
+			goto error;
+		}
+
+		/* Add the new address to the setting */
+		addr = nm_ip6_address_new ();
+		nm_ip6_address_set_address (addr, &tmp_addr);
+		nm_ip6_address_set_prefix (addr, prefix_int);
+		nm_ip6_address_set_gateway (addr, &tmp_gw);
+
+		if (nm_setting_ip6_config_add_address (s_ip6, addr)) {
+			PLUGIN_PRINT("SCPlugin-Ifupdown", "addresses count: %d",
+					   nm_setting_ip6_config_get_num_addresses (s_ip6));
+		} else {
+			PLUGIN_PRINT("SCPlugin-Ifupdown", "ignoring duplicate IP6 address");
+		}
+
+		nameserver_v = ifparser_getkey(block, "dns-nameserver");
+		ifupdown_ip6_add_dns (s_ip6, nameserver_v);
+
+		nameservers_v = ifparser_getkey(block, "dns-nameservers");
+		ifupdown_ip6_add_dns (s_ip6, nameservers_v);
+
+		if (!nm_setting_ip6_config_get_num_dns (s_ip6))
 			PLUGIN_PRINT("SCPlugin-Ifupdown", "No dns-nameserver configured in /etc/network/interfaces");
 
-		g_object_set(ip4_setting,
-				   NM_SETTING_IP4_CONFIG_METHOD, NM_SETTING_IP4_CONFIG_METHOD_MANUAL,
-				   NULL);
+		/* DNS searches */
+		search_v = ifparser_getkey (block, "dns-search");
+		if (search_v) {
+			list = g_strsplit_set (search_v, " \t", -1);
+			for (iter = list; iter && *iter; iter++) {
+				g_strstrip (*iter);
+				if (isblank (*iter[0]))
+					continue;
+				if (!nm_setting_ip6_config_add_dns_search (s_ip6, *iter)) {
+					PLUGIN_WARN ("SCPlugin-Ifupdown",
+							   "    warning: duplicate DNS domain '%s'", *iter);
+				}
+			}
+			g_strfreev (list);
+		}
 
-		g_slist_foreach (nameservers_list, (GFunc) g_free, NULL);
-		g_slist_free (nameservers_list);
+		g_object_set (s_ip6,
+		              NM_SETTING_IP6_CONFIG_METHOD, NM_SETTING_IP6_CONFIG_METHOD_MANUAL,
+		              NULL);
 	}
 
-	nm_connection_add_setting(connection, NM_SETTING(ip4_setting));
+	nm_connection_add_setting (connection, NM_SETTING (s_ip6));
+	return TRUE;
+
+error:
+	g_object_unref (s_ip6);
+	return FALSE;
 }
 
 gboolean
@@ -537,7 +704,7 @@ ifupdown_update_connection_from_if_block (NMConnection *connection,
 	NMSettingConnection *s_con;
 	gboolean success = FALSE;
 
-	s_con = (NMSettingConnection *) nm_connection_get_setting (connection, NM_TYPE_SETTING_CONNECTION);
+	s_con = nm_connection_get_setting_connection (connection);
 	if(!s_con) {
 		s_con = NM_SETTING_CONNECTION (nm_setting_connection_new());
 		g_assert (s_con);
@@ -562,15 +729,19 @@ ifupdown_update_connection_from_if_block (NMConnection *connection,
 			   block->name, type, idstr, nm_setting_connection_get_uuid (s_con));
 
 	if (!strcmp (NM_SETTING_WIRED_SETTING_NAME, type))
-		update_wired_setting_from_if_block (connection, block);	
+		update_wired_setting_from_if_block (connection, block);
 	else if (!strcmp (NM_SETTING_WIRELESS_SETTING_NAME, type)) {
 		update_wireless_setting_from_if_block (connection, block);
 		update_wireless_security_setting_from_if_block (connection, block);
 	}
 
-	update_ip4_setting_from_if_block (connection, block);
+	if (ifparser_haskey(block, "inet6"))
+		success = update_ip6_setting_from_if_block (connection, block, error);
+	else
+		success = update_ip4_setting_from_if_block (connection, block, error);
 
-	success = nm_connection_verify (connection, error);
+	if (success == TRUE)
+		success = nm_connection_verify (connection, error);
 
 	g_free (idstr);
 	return success;
diff --git a/src/settings/plugins/ifupdown/plugin.c b/src/settings/plugins/ifupdown/plugin.c
index 9679edea..4dbb0aa2 100644
--- a/src/settings/plugins/ifupdown/plugin.c
+++ b/src/settings/plugins/ifupdown/plugin.c
@@ -19,7 +19,7 @@
  * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
  *
  * (C) Copyright 2007,2008 Canonical Ltd.
- * (C) Copyright 2009 Red Hat, Inc.
+ * (C) Copyright 2009 - 2011 Red Hat, Inc.
  */
 
 #include <string.h>
@@ -42,6 +42,7 @@
 #include "nm-setting-wireless.h"
 #include "nm-setting-wired.h"
 #include "nm-setting-ppp.h"
+#include "nm-utils.h"
 
 #include "nm-ifupdown-connection.h"
 #include "plugin.h"
@@ -60,9 +61,6 @@
 #define IFUPDOWN_PLUGIN_INFO "(C) 2008 Canonical Ltd.  To report bugs please use the NetworkManager mailing list."
 #define IFUPDOWN_SYSTEM_HOSTNAME_FILE "/etc/hostname"
 
-#define IFUPDOWN_SYSTEM_SETTINGS_KEY_FILE SYSCONFDIR "/NetworkManager/NetworkManager.conf"
-#define IFUPDOWN_OLD_SYSTEM_SETTINGS_KEY_FILE SYSCONFDIR "/NetworkManager/nm-system-settings.conf"
-
 #define IFUPDOWN_KEY_FILE_GROUP "ifupdown"
 #define IFUPDOWN_KEY_FILE_KEY_MANAGED "managed"
 #define IFUPDOWN_UNMANAGE_WELL_KNOWN_DEFAULT TRUE
@@ -81,7 +79,7 @@ typedef struct {
 	GHashTable *well_known_interfaces;
 	GHashTable *well_known_ifaces;
 	gboolean unmanage_well_known;
-	const char *conf_file;
+	char *conf_file;
 
 	gulong inotify_event_id;
 	int inotify_system_hostname_wd;
@@ -190,10 +188,9 @@ bind_device_to_connection (SCPluginIfupdown *self,
                            NMIfupdownConnection *exported)
 {
 	GByteArray *mac_address;
-	NMSetting *s_wired = NULL;
-	NMSetting *s_wifi = NULL;
+	NMSettingWired *s_wired;
+	NMSettingWireless *s_wifi;
 	const char *iface, *address;
-	struct ether_addr *tmp_mac;
 
 	iface = g_udev_device_get_name (device);
 	if (!iface) {
@@ -207,18 +204,15 @@ bind_device_to_connection (SCPluginIfupdown *self,
 		return;
 	}
 
-	tmp_mac = ether_aton (address);
-	if (!tmp_mac) {
+	mac_address = nm_utils_hwaddr_atoba (address, ARPHRD_ETHER);
+	if (!mac_address) {
 		PLUGIN_WARN ("SCPluginIfupdown", "failed to parse MAC address '%s' for %s",
 		             address, iface);
 		return;
 	}
 
-	mac_address = g_byte_array_sized_new (ETH_ALEN);
-	g_byte_array_append (mac_address, &(tmp_mac->ether_addr_octet[0]), ETH_ALEN);
-
-	s_wired = nm_connection_get_setting (NM_CONNECTION (exported), NM_TYPE_SETTING_WIRED);
-	s_wifi = nm_connection_get_setting (NM_CONNECTION (exported), NM_TYPE_SETTING_WIRELESS);
+	s_wired = nm_connection_get_setting_wired (NM_CONNECTION (exported));
+	s_wifi = nm_connection_get_setting_wireless (NM_CONNECTION (exported));
 	if (s_wired) {
 		PLUGIN_PRINT ("SCPluginIfupdown", "locking wired connection setting");
 		g_object_set (s_wired, NM_SETTING_WIRED_MAC_ADDRESS, mac_address, NULL);
@@ -432,13 +426,13 @@ SCPluginIfupdown_init (NMSystemConfigInterface *config)
 	keys = g_hash_table_get_keys (priv->iface_connections);
 	for (iter = keys; iter; iter = g_list_next (iter)) {
 		NMIfupdownConnection *exported;
-		NMSetting *setting;
+		NMSettingConnection *setting;
 
 		if (!g_hash_table_lookup (auto_ifaces, iter->data))
 			continue;
 
 		exported = g_hash_table_lookup (priv->iface_connections, iter->data);
-		setting = NM_SETTING (nm_connection_get_setting (NM_CONNECTION (exported), NM_TYPE_SETTING_CONNECTION));
+		setting = nm_connection_get_setting_connection (NM_CONNECTION (exported));
 		g_object_set (setting, NM_SETTING_CONNECTION_AUTOCONNECT, TRUE, NULL);
 
 		nm_settings_connection_commit_changes (NM_SETTINGS_CONNECTION (exported), ignore_cb, NULL);
@@ -448,12 +442,7 @@ SCPluginIfupdown_init (NMSystemConfigInterface *config)
 	g_list_free (keys);
 	g_hash_table_destroy (auto_ifaces);
 
-	/* Find the config file */
-	if (g_file_test (IFUPDOWN_SYSTEM_SETTINGS_KEY_FILE, G_FILE_TEST_EXISTS))
-		priv->conf_file = IFUPDOWN_SYSTEM_SETTINGS_KEY_FILE;
-	else
-		priv->conf_file = IFUPDOWN_OLD_SYSTEM_SETTINGS_KEY_FILE;
-
+	/* Read the config file to find out whether to manage interfaces */
 	keyfile = g_key_file_new ();
 	if (!g_key_file_load_from_file (keyfile,
 	                                priv->conf_file,
@@ -706,20 +695,28 @@ GObject__dispose (GObject *object)
 	if (priv->well_known_interfaces)
 		g_hash_table_destroy(priv->well_known_interfaces);
 
+	g_free (priv->conf_file);
+
 	if (priv->client)
 		g_object_unref (priv->client);
 
+
 	G_OBJECT_CLASS (sc_plugin_ifupdown_parent_class)->dispose (object);
 }
 
 G_MODULE_EXPORT GObject *
-nm_system_config_factory (void)
+nm_system_config_factory (const char *config_file)
 {
 	static SCPluginIfupdown *singleton = NULL;
+	SCPluginIfupdownPrivate *priv;
 
-	if (!singleton)
+	if (!singleton) {
 		singleton = SC_PLUGIN_IFUPDOWN (g_object_new (SC_TYPE_PLUGIN_IFUPDOWN, NULL));
-	else
+		if (singleton) {
+			priv = SC_PLUGIN_IFUPDOWN_GET_PRIVATE (singleton);
+			priv->conf_file = strdup (config_file);
+		}
+	} else
 		g_object_ref (singleton);
 
 	return G_OBJECT (singleton);
diff --git a/src/settings/plugins/ifupdown/tests/Makefile.am b/src/settings/plugins/ifupdown/tests/Makefile.am
index aed86197..ff219d5d 100644
--- a/src/settings/plugins/ifupdown/tests/Makefile.am
+++ b/src/settings/plugins/ifupdown/tests/Makefile.am
@@ -29,4 +29,4 @@ endif
 
 EXTRA_DIST = \
 	test1 test2 test3 test4 test5 test6 test7 test8 test9 test11 test12 \
-	test13 test14 test15 test16
+	test13 test14 test15 test16 test17-wired-static-verify-ip4
diff --git a/src/settings/plugins/ifupdown/tests/Makefile.in b/src/settings/plugins/ifupdown/tests/Makefile.in
index aca48837..a03be1bd 100644
--- a/src/settings/plugins/ifupdown/tests/Makefile.in
+++ b/src/settings/plugins/ifupdown/tests/Makefile.in
@@ -141,6 +141,8 @@ GIO_LIBS = @GIO_LIBS@
 GLIB_CFLAGS = @GLIB_CFLAGS@
 GLIB_GENMARSHAL = @GLIB_GENMARSHAL@
 GLIB_LIBS = @GLIB_LIBS@
+GLIB_MAKEFILE = @GLIB_MAKEFILE@
+GLIB_MKENUMS = @GLIB_MKENUMS@
 GMODULE_CFLAGS = @GMODULE_CFLAGS@
 GMODULE_LIBS = @GMODULE_LIBS@
 GMSGFMT = @GMSGFMT@
@@ -195,11 +197,15 @@ LIBNL2_LIBS = @LIBNL2_LIBS@
 LIBNL3_CFLAGS = @LIBNL3_CFLAGS@
 LIBNL3_LIBS = @LIBNL3_LIBS@
 LIBNL_CFLAGS = @LIBNL_CFLAGS@
+LIBNL_GENL3_CFLAGS = @LIBNL_GENL3_CFLAGS@
+LIBNL_GENL3_LIBS = @LIBNL_GENL3_LIBS@
 LIBNL_LIBS = @LIBNL_LIBS@
 LIBNL_ROUTE3_CFLAGS = @LIBNL_ROUTE3_CFLAGS@
 LIBNL_ROUTE3_LIBS = @LIBNL_ROUTE3_LIBS@
 LIBOBJS = @LIBOBJS@
 LIBS = @LIBS@
+LIBSOUP_CFLAGS = @LIBSOUP_CFLAGS@
+LIBSOUP_LIBS = @LIBSOUP_LIBS@
 LIBTOOL = @LIBTOOL@
 LIPO = @LIPO@
 LN_S = @LN_S@
@@ -210,6 +216,7 @@ MAINT = @MAINT@
 MAKEINFO = @MAKEINFO@
 MANIFEST_TOOL = @MANIFEST_TOOL@
 MKDIR_P = @MKDIR_P@
+MOC = @MOC@
 MSGFMT = @MSGFMT@
 MSGFMT_015 = @MSGFMT_015@
 MSGMERGE = @MSGMERGE@
@@ -249,6 +256,8 @@ SED = @SED@
 SET_MAKE = @SET_MAKE@
 SHELL = @SHELL@
 STRIP = @STRIP@
+SYSTEMD_CFLAGS = @SYSTEMD_CFLAGS@
+SYSTEMD_LIBS = @SYSTEMD_LIBS@
 SYSTEM_CA_PATH = @SYSTEM_CA_PATH@
 UDEV_BASE_DIR = @UDEV_BASE_DIR@
 USE_NLS = @USE_NLS@
@@ -334,7 +343,7 @@ test_ifupdown_LDADD = \
 
 EXTRA_DIST = \
 	test1 test2 test3 test4 test5 test6 test7 test8 test9 test11 test12 \
-	test13 test14 test15 test16
+	test13 test14 test15 test16 test17-wired-static-verify-ip4
 
 all: all-am
 
diff --git a/src/settings/plugins/ifupdown/tests/test-ifupdown.c b/src/settings/plugins/ifupdown/tests/test-ifupdown.c
index 16465364..01020bdf 100644
--- a/src/settings/plugins/ifupdown/tests/test-ifupdown.c
+++ b/src/settings/plugins/ifupdown/tests/test-ifupdown.c
@@ -21,6 +21,9 @@
 #include <glib.h>
 #include <string.h>
 
+#include <nm-utils.h>
+
+#include "nm-test-helpers.h"
 #include "interface_parser.h"
 #include "parser.h"
 
@@ -455,6 +458,386 @@ test16_missing_newline (const char *path)
 	ifparser_destroy ();
 	expected_free (e);
 }
+static void
+test17_read_static_ipv4 (const char *path)
+{
+	NMConnection *connection;
+	NMSettingConnection *s_con;
+	NMSettingIP4Config *s_ip4;
+	NMSettingWired *s_wired;
+	char *unmanaged = NULL;
+	GError *error = NULL;
+	const char* tmp;
+	const char *expected_address = "10.0.0.3";
+	const char *expected_id = "Ifupdown (eth0)";
+	const char *expected_dns1 = "10.0.0.1";
+	const char *expected_dns2 = "10.0.0.2";
+	const char *expected_search1 = "example.com";
+	const char *expected_search2 = "foo.example.com";
+	guint32 expected_prefix = 8;
+	NMIP4Address *ip4_addr;
+	struct in_addr addr;
+#define TEST17_NAME "wired-static-verify-ip4"
+	if_block *block = NULL;
+
+	const char* file = "test17-" TEST17_NAME;
+
+	init_ifparser_with_file (path, file);
+	block = ifparser_getfirst ();
+	connection = nm_connection_new();
+	ifupdown_update_connection_from_if_block(connection, block, &error);
+
+	ASSERT (connection != NULL,
+			TEST17_NAME, "failed to read %s: %s", file, error->message);
+
+	ASSERT (nm_connection_verify (connection, &error),
+			TEST17_NAME, "failed to verify %s: %s", file, error->message);
+
+	ASSERT (unmanaged == NULL,
+			TEST17_NAME, "failed to verify %s: unexpected unmanaged value", file);
+
+	/* ===== CONNECTION SETTING ===== */
+
+	s_con = nm_connection_get_setting_connection (connection);
+	ASSERT (s_con != NULL,
+			TEST17_NAME, "failed to verify %s: missing %s setting",
+			file,
+			NM_SETTING_CONNECTION_SETTING_NAME);
+
+	/* ID */
+	tmp = nm_setting_connection_get_id (s_con);
+	ASSERT (tmp != NULL,
+			TEST17_NAME, "failed to verify %s: missing %s / %s key",
+			file,
+			NM_SETTING_CONNECTION_SETTING_NAME,
+			NM_SETTING_CONNECTION_ID);
+	ASSERT (strcmp (tmp, expected_id) == 0,
+			TEST17_NAME, "failed to verify %s: unexpected %s / %s key value: %s",
+			file,
+			NM_SETTING_CONNECTION_SETTING_NAME,
+			NM_SETTING_CONNECTION_ID, tmp);
+
+	/* ===== WIRED SETTING ===== */
+
+	s_wired = nm_connection_get_setting_wired (connection);
+	ASSERT (s_wired != NULL,
+			TEST17_NAME, "failed to verify %s: missing %s setting",
+			file,
+			NM_SETTING_WIRED_SETTING_NAME);
+
+	/* ===== IPv4 SETTING ===== */
+
+	ASSERT (inet_pton (AF_INET, expected_address, &addr) > 0,
+			TEST17_NAME, "failed to verify %s: couldn't convert IP address #1",
+			file);
+
+	s_ip4 = nm_connection_get_setting_ip4_config (connection);
+	ASSERT (s_ip4 != NULL,
+			TEST17_NAME, "failed to verify %s: missing %s setting",
+			file,
+			NM_SETTING_IP4_CONFIG_SETTING_NAME);
+
+	/* Method */
+	tmp = nm_setting_ip4_config_get_method (s_ip4);
+	ASSERT (strcmp (tmp, NM_SETTING_IP4_CONFIG_METHOD_MANUAL) == 0,
+			TEST17_NAME, "failed to verify %s: unexpected %s / %s key value",
+			file,
+			NM_SETTING_IP4_CONFIG_SETTING_NAME,
+			NM_SETTING_IP4_CONFIG_METHOD);
+
+	/* IP addresses */
+	ASSERT (nm_setting_ip4_config_get_num_addresses (s_ip4) == 1,
+			TEST17_NAME, "failed to verify %s: unexpected %s / %s key value",
+			file,
+			NM_SETTING_IP4_CONFIG_SETTING_NAME,
+			NM_SETTING_IP4_CONFIG_ADDRESSES);
+
+	ip4_addr = nm_setting_ip4_config_get_address (s_ip4, 0);
+	ASSERT (ip4_addr,
+			TEST17_NAME, "failed to verify %s: missing IP4 address #1",
+			file);
+
+	ASSERT (nm_ip4_address_get_prefix (ip4_addr) == expected_prefix,
+			TEST17_NAME, "failed to verify %s: unexpected IP4 address prefix",
+			file);
+
+	ASSERT (nm_ip4_address_get_address (ip4_addr) == addr.s_addr,
+			TEST17_NAME, "failed to verify %s: unexpected IP4 address: %s",
+			file, addr.s_addr);
+
+	/* DNS Addresses */
+	ASSERT (nm_setting_ip4_config_get_num_dns (s_ip4) == 2,
+			TEST17_NAME, "failed to verify %s: unexpected %s / %s key value",
+			file,
+			NM_SETTING_IP4_CONFIG_SETTING_NAME,
+			NM_SETTING_IP4_CONFIG_DNS);
+
+	ASSERT (inet_pton (AF_INET, expected_dns1, &addr) > 0,
+			TEST17_NAME, "failed to verify %s: couldn't convert DNS IP address #1",
+			file,
+			NM_SETTING_IP4_CONFIG_SETTING_NAME,
+			NM_SETTING_IP4_CONFIG_DNS);
+
+	ASSERT (nm_setting_ip4_config_get_dns (s_ip4, 0) == addr.s_addr,
+			TEST17_NAME, "failed to verify %s: unexpected %s / %s key value #1",
+			file,
+			NM_SETTING_IP4_CONFIG_SETTING_NAME,
+			NM_SETTING_IP4_CONFIG_DNS);
+
+	ASSERT (inet_pton (AF_INET, expected_dns2, &addr) > 0,
+			TEST17_NAME, "failed to verify %s: couldn't convert DNS IP address #2",
+			file,
+			NM_SETTING_IP4_CONFIG_SETTING_NAME,
+			NM_SETTING_IP4_CONFIG_DNS);
+
+	ASSERT (nm_setting_ip4_config_get_dns (s_ip4, 1) == addr.s_addr,
+			TEST17_NAME, "failed to verify %s: unexpected %s / %s key value #2",
+			file,
+			NM_SETTING_IP4_CONFIG_SETTING_NAME,
+			NM_SETTING_IP4_CONFIG_DNS);
+
+	ASSERT (nm_setting_ip4_config_get_num_addresses (s_ip4) == 1,
+			TEST17_NAME, "failed to verify %s: unexpected %s / %s key value",
+			file,
+			NM_SETTING_IP4_CONFIG_SETTING_NAME,
+			NM_SETTING_IP4_CONFIG_DNS);
+
+	/* DNS search domains */
+	ASSERT (nm_setting_ip4_config_get_num_dns_searches (s_ip4) == 2,
+			TEST17_NAME, "failed to verify %s: unexpected %s / %s key value",
+			file,
+			NM_SETTING_IP4_CONFIG_SETTING_NAME,
+			NM_SETTING_IP4_CONFIG_DNS);
+
+	tmp = nm_setting_ip4_config_get_dns_search (s_ip4, 0);
+	ASSERT (tmp != NULL,
+			TEST17_NAME, "failed to verify %s: missing %s / %s key",
+			file,
+			NM_SETTING_IP4_CONFIG_SETTING_NAME,
+			NM_SETTING_IP4_CONFIG_DNS_SEARCH);
+	ASSERT (strcmp (tmp, expected_search1) == 0,
+			TEST17_NAME, "failed to verify %s: unexpected %s / %s key value",
+			file,
+			NM_SETTING_IP4_CONFIG_SETTING_NAME,
+			NM_SETTING_IP4_CONFIG_DNS_SEARCH);
+
+	tmp = nm_setting_ip4_config_get_dns_search (s_ip4, 1);
+	ASSERT (tmp != NULL,
+			TEST17_NAME, "failed to verify %s: missing %s / %s key",
+			file,
+			NM_SETTING_IP4_CONFIG_SETTING_NAME,
+			NM_SETTING_IP4_CONFIG_DNS_SEARCH);
+
+	ASSERT (strcmp (tmp, expected_search2) == 0,
+			TEST17_NAME, "failed to verify %s: unexpected %s / %s key value",
+			file,
+			NM_SETTING_IP4_CONFIG_SETTING_NAME,
+			NM_SETTING_IP4_CONFIG_DNS_SEARCH);
+
+	g_object_unref (connection);
+}
+
+static void
+test18_read_static_ipv6 (const char *path)
+{
+	NMConnection *connection;
+	NMSettingConnection *s_con;
+	NMSettingIP6Config *s_ip6;
+	NMSettingWired *s_wired;
+	char *unmanaged = NULL;
+	GError *error = NULL;
+	const char* tmp;
+	const char *expected_address = "fc00::1";
+	const char *expected_id = "Ifupdown (myip6tunnel)";
+	const char *expected_dns1 = "fc00::2";
+	const char *expected_dns2 = "fc00::3";
+	const char *expected_search1 = "example.com";
+	const char *expected_search2 = "foo.example.com";
+	guint32 expected_prefix = 64;
+	NMIP6Address *ip6_addr;
+	struct in6_addr addr;
+	if_block *block = NULL;
+#define TEST18_NAME "wired-static-verify-ip6"
+	const char* file = "test18-" TEST18_NAME;
+
+	init_ifparser_with_file (path, file);
+	block = ifparser_getfirst ();
+	connection = nm_connection_new();
+	ifupdown_update_connection_from_if_block(connection, block, &error);
+
+	ASSERT (connection != NULL,
+			TEST18_NAME
+			"failed to read %s: %s", file, error->message);
+
+	ASSERT (nm_connection_verify (connection, &error),
+			TEST18_NAME,
+			"failed to verify %s: %s", file, error->message);
+
+	ASSERT (unmanaged == NULL,
+			TEST18_NAME,
+			"failed to verify %s: unexpected unmanaged value", file);
+
+	/* ===== CONNECTION SETTING ===== */
+
+	s_con = nm_connection_get_setting_connection (connection);
+	ASSERT (s_con != NULL,
+			TEST18_NAME, "failed to verify %s: missing %s setting",
+			file,
+			NM_SETTING_CONNECTION_SETTING_NAME);
+
+	/* ID */
+	tmp = nm_setting_connection_get_id (s_con);
+	ASSERT (tmp != NULL,
+			TEST18_NAME,
+			"failed to verify %s: missing %s / %s key",
+			file,
+			NM_SETTING_CONNECTION_SETTING_NAME,
+			NM_SETTING_CONNECTION_ID);
+
+	ASSERT (strcmp (tmp, expected_id) == 0,
+			TEST18_NAME,
+			"failed to verify %s: unexpected %s / %s key value",
+			file,
+			NM_SETTING_CONNECTION_SETTING_NAME,
+			NM_SETTING_CONNECTION_ID);
+
+	/* ===== WIRED SETTING ===== */
+
+	s_wired = nm_connection_get_setting_wired (connection);
+	ASSERT (s_wired != NULL,
+			TEST18_NAME, "failed to verify %s: missing %s setting",
+			file,
+			NM_SETTING_WIRED_SETTING_NAME);
+
+	/* ===== IPv6 SETTING ===== */
+
+	ASSERT (inet_pton (AF_INET6, expected_address, &addr) > 0,
+			TEST18_NAME,
+			"failed to verify %s: couldn't convert IP address #1",
+			file);
+
+	s_ip6 = nm_connection_get_setting_ip6_config (connection);
+	ASSERT (s_ip6 != NULL,
+			TEST18_NAME,
+			"failed to verify %s: missing %s setting",
+			file,
+			NM_SETTING_IP6_CONFIG_SETTING_NAME);
+
+	/* Method */
+	tmp = nm_setting_ip6_config_get_method (s_ip6);
+	ASSERT (strcmp (tmp, NM_SETTING_IP6_CONFIG_METHOD_MANUAL) == 0,
+			TEST18_NAME,
+			"failed to verify %s: unexpected %s / %s key value",
+			file,
+			NM_SETTING_IP6_CONFIG_SETTING_NAME,
+			NM_SETTING_IP6_CONFIG_METHOD);
+
+	/* IP addresses */
+	ASSERT (nm_setting_ip6_config_get_num_addresses (s_ip6) == 1,
+			TEST18_NAME,
+			"failed to verify %s: unexpected number of %s / %s",
+			file,
+			NM_SETTING_IP6_CONFIG_SETTING_NAME,
+			NM_SETTING_IP6_CONFIG_ADDRESSES);
+
+	ip6_addr = nm_setting_ip6_config_get_address (s_ip6, 0);
+	ASSERT (ip6_addr,
+			TEST18_NAME,
+			"failed to verify %s: missing %s / %s #1",
+			file,
+			NM_SETTING_IP6_CONFIG_SETTING_NAME,
+			NM_SETTING_IP6_CONFIG_ADDRESSES);
+
+	ASSERT (nm_ip6_address_get_prefix (ip6_addr) == expected_prefix,
+			TEST18_NAME
+			"failed to verify %s: unexpected %s / %s prefix",
+			file,
+			NM_SETTING_IP6_CONFIG_SETTING_NAME,
+			NM_SETTING_IP6_CONFIG_ADDRESSES);
+
+	ASSERT (IN6_ARE_ADDR_EQUAL (nm_ip6_address_get_address (ip6_addr),
+								&addr),
+			TEST18_NAME,
+			"failed to verify %s: unexpected %s / %s",
+			file,
+			NM_SETTING_IP6_CONFIG_SETTING_NAME,
+			NM_SETTING_IP6_CONFIG_ADDRESSES);
+
+	/* DNS Addresses */
+	ASSERT (nm_setting_ip6_config_get_num_dns (s_ip6) == 2,
+			TEST18_NAME,
+			"failed to verify %s: unexpected number of %s / %s values",
+			file,
+			NM_SETTING_IP6_CONFIG_SETTING_NAME,
+			NM_SETTING_IP6_CONFIG_DNS);
+
+	ASSERT (inet_pton (AF_INET6, expected_dns1, &addr) > 0,
+			TEST18_NAME,
+			"failed to verify %s: couldn't convert DNS IP address #1",
+			file);
+
+	ASSERT (IN6_ARE_ADDR_EQUAL (nm_setting_ip6_config_get_dns (s_ip6, 0),
+								&addr),
+			TEST18_NAME,
+			"failed to verify %s: unexpected %s / %s #1",
+			file,
+			NM_SETTING_IP6_CONFIG_SETTING_NAME,
+			NM_SETTING_IP6_CONFIG_DNS);
+
+	ASSERT (inet_pton (AF_INET6, expected_dns2, &addr) > 0,
+			TEST18_NAME,
+			"failed to verify %s: couldn't convert DNS IP address #2",
+			file);
+
+	ASSERT (IN6_ARE_ADDR_EQUAL (nm_setting_ip6_config_get_dns (s_ip6, 1),
+								&addr),
+			TEST18_NAME, "failed to verify %s: unexpected %s / %s #2",
+			file,
+			NM_SETTING_IP6_CONFIG_SETTING_NAME,
+			NM_SETTING_IP6_CONFIG_DNS);
+
+	/* DNS search domains */
+	ASSERT (nm_setting_ip6_config_get_num_dns_searches (s_ip6) == 2,
+			TEST18_NAME,
+			"failed to verify %s: unexpected number of %s / %s values",
+			file,
+			NM_SETTING_IP6_CONFIG_SETTING_NAME,
+			NM_SETTING_IP6_CONFIG_DNS_SEARCH);
+
+	tmp = nm_setting_ip6_config_get_dns_search (s_ip6, 0);
+	ASSERT (tmp != NULL,
+			"wired-ipv6-manual-verify-ip6",
+			"failed to verify %s: missing %s / %s #1",
+			file,
+			NM_SETTING_IP6_CONFIG_SETTING_NAME,
+			NM_SETTING_IP6_CONFIG_DNS_SEARCH);
+
+	ASSERT (strcmp (tmp, expected_search1) == 0,
+			"wired-ipv6-manual-verify-ip6",
+			"failed to verify %s: unexpected %s / %s #1",
+			file,
+			NM_SETTING_IP6_CONFIG_SETTING_NAME,
+			NM_SETTING_IP6_CONFIG_DNS_SEARCH);
+
+	tmp = nm_setting_ip6_config_get_dns_search (s_ip6, 1);
+	ASSERT (tmp != NULL,
+			TEST18_NAME,
+			"failed to verify %s: missing %s / %s #2",
+			file,
+			NM_SETTING_IP6_CONFIG_SETTING_NAME,
+			NM_SETTING_IP6_CONFIG_DNS_SEARCH);
+
+	ASSERT (strcmp (tmp, expected_search2) == 0,
+			TEST18_NAME,
+			"failed to verify %s: unexpected %s / %s #2",
+			file,
+			NM_SETTING_IP6_CONFIG_SETTING_NAME,
+			NM_SETTING_IP6_CONFIG_DNS_SEARCH);
+
+	g_free (unmanaged);
+	g_object_unref (connection);
+}
+
 
 #if GLIB_CHECK_VERSION(2,25,12)
 typedef GTestFixtureFunc TCFunc;
@@ -467,6 +850,12 @@ typedef void (*TCFunc)(void);
 int main (int argc, char **argv)
 {
 	GTestSuite *suite;
+	GError *error = NULL;
+
+	g_type_init ();
+
+	if (!nm_utils_init (&error))
+		FAIL ("nm-utils-init", "failed to initialize libnm-util: %s", error->message);
 
 	g_test_init (&argc, &argv, NULL);
 
@@ -490,6 +879,8 @@ int main (int argc, char **argv)
 	g_test_suite_add (suite, TESTCASE (test14_mixed_whitespace_block_start, TEST_ENI_DIR));
 	g_test_suite_add (suite, TESTCASE (test15_trailing_space, TEST_ENI_DIR));
 	g_test_suite_add (suite, TESTCASE (test16_missing_newline, TEST_ENI_DIR));
+	g_test_suite_add (suite, TESTCASE (test17_read_static_ipv4, TEST_ENI_DIR));
+	g_test_suite_add (suite, TESTCASE (test18_read_static_ipv6, TEST_ENI_DIR));
 
 	return g_test_run ();
 }
diff --git a/src/settings/plugins/ifupdown/tests/test17-wired-static-verify-ip4 b/src/settings/plugins/ifupdown/tests/test17-wired-static-verify-ip4
new file mode 100644
index 00000000..9e5243a7
--- /dev/null
+++ b/src/settings/plugins/ifupdown/tests/test17-wired-static-verify-ip4
@@ -0,0 +1,5 @@
+iface eth0 inet static
+  address 10.0.0.3
+  netmask 255.0.0.0
+  dns-search example.com foo.example.com
+  dns-nameservers 10.0.0.1 10.0.0.2
diff --git a/src/settings/plugins/keyfile/Makefile.am b/src/settings/plugins/keyfile/Makefile.am
index 3b242142..83031c24 100644
--- a/src/settings/plugins/keyfile/Makefile.am
+++ b/src/settings/plugins/keyfile/Makefile.am
@@ -3,7 +3,9 @@ SUBDIRS=. tests
 INCLUDES = \
 	-I$(top_srcdir)/src/settings \
 	-I$(top_srcdir)/include \
-	-I$(top_srcdir)/libnm-util
+	-I$(top_builddir)/include \
+	-I$(top_srcdir)/libnm-util \
+	-I$(top_builddir)/libnm-util
 
 noinst_LTLIBRARIES = \
 	libkeyfile-io.la \
diff --git a/src/settings/plugins/keyfile/Makefile.in b/src/settings/plugins/keyfile/Makefile.in
index ae0c9f8e..c766e794 100644
--- a/src/settings/plugins/keyfile/Makefile.in
+++ b/src/settings/plugins/keyfile/Makefile.in
@@ -193,6 +193,8 @@ GIO_LIBS = @GIO_LIBS@
 GLIB_CFLAGS = @GLIB_CFLAGS@
 GLIB_GENMARSHAL = @GLIB_GENMARSHAL@
 GLIB_LIBS = @GLIB_LIBS@
+GLIB_MAKEFILE = @GLIB_MAKEFILE@
+GLIB_MKENUMS = @GLIB_MKENUMS@
 GMODULE_CFLAGS = @GMODULE_CFLAGS@
 GMODULE_LIBS = @GMODULE_LIBS@
 GMSGFMT = @GMSGFMT@
@@ -247,11 +249,15 @@ LIBNL2_LIBS = @LIBNL2_LIBS@
 LIBNL3_CFLAGS = @LIBNL3_CFLAGS@
 LIBNL3_LIBS = @LIBNL3_LIBS@
 LIBNL_CFLAGS = @LIBNL_CFLAGS@
+LIBNL_GENL3_CFLAGS = @LIBNL_GENL3_CFLAGS@
+LIBNL_GENL3_LIBS = @LIBNL_GENL3_LIBS@
 LIBNL_LIBS = @LIBNL_LIBS@
 LIBNL_ROUTE3_CFLAGS = @LIBNL_ROUTE3_CFLAGS@
 LIBNL_ROUTE3_LIBS = @LIBNL_ROUTE3_LIBS@
 LIBOBJS = @LIBOBJS@
 LIBS = @LIBS@
+LIBSOUP_CFLAGS = @LIBSOUP_CFLAGS@
+LIBSOUP_LIBS = @LIBSOUP_LIBS@
 LIBTOOL = @LIBTOOL@
 LIPO = @LIPO@
 LN_S = @LN_S@
@@ -262,6 +268,7 @@ MAINT = @MAINT@
 MAKEINFO = @MAKEINFO@
 MANIFEST_TOOL = @MANIFEST_TOOL@
 MKDIR_P = @MKDIR_P@
+MOC = @MOC@
 MSGFMT = @MSGFMT@
 MSGFMT_015 = @MSGFMT_015@
 MSGMERGE = @MSGMERGE@
@@ -301,6 +308,8 @@ SED = @SED@
 SET_MAKE = @SET_MAKE@
 SHELL = @SHELL@
 STRIP = @STRIP@
+SYSTEMD_CFLAGS = @SYSTEMD_CFLAGS@
+SYSTEMD_LIBS = @SYSTEMD_LIBS@
 SYSTEM_CA_PATH = @SYSTEM_CA_PATH@
 UDEV_BASE_DIR = @UDEV_BASE_DIR@
 USE_NLS = @USE_NLS@
@@ -368,7 +377,9 @@ SUBDIRS = . tests
 INCLUDES = \
 	-I$(top_srcdir)/src/settings \
 	-I$(top_srcdir)/include \
-	-I$(top_srcdir)/libnm-util
+	-I$(top_builddir)/include \
+	-I$(top_srcdir)/libnm-util \
+	-I$(top_builddir)/libnm-util
 
 noinst_LTLIBRARIES = \
 	libkeyfile-io.la \
diff --git a/src/settings/plugins/keyfile/plugin.c b/src/settings/plugins/keyfile/plugin.c
index af69c200..d53907a9 100644
--- a/src/settings/plugins/keyfile/plugin.c
+++ b/src/settings/plugins/keyfile/plugin.c
@@ -42,9 +42,6 @@
 #include "common.h"
 #include "utils.h"
 
-#define CONF_FILE SYSCONFDIR "/NetworkManager/NetworkManager.conf"
-#define OLD_CONF_FILE SYSCONFDIR "/NetworkManager/nm-system-settings.conf"
-
 static char *plugin_get_hostname (SCPluginKeyfile *plugin);
 static void system_config_interface_init (NMSystemConfigInterface *system_config_interface_class);
 
@@ -60,7 +57,7 @@ typedef struct {
 	GFileMonitor *monitor;
 	guint monitor_id;
 
-	const char *conf_file;
+	char *conf_file;
 	GFileMonitor *conf_file_monitor;
 	guint conf_file_monitor_id;
 
@@ -354,13 +351,15 @@ setup_monitoring (NMSystemConfigInterface *config)
 		priv->monitor = monitor;
 	}
 
-	file = g_file_new_for_path (priv->conf_file);
-	monitor = g_file_monitor_file (file, G_FILE_MONITOR_NONE, NULL, NULL);
-	g_object_unref (file);
+	if (priv->conf_file) {
+		file = g_file_new_for_path (priv->conf_file);
+		monitor = g_file_monitor_file (file, G_FILE_MONITOR_NONE, NULL, NULL);
+		g_object_unref (file);
 
-	if (monitor) {
-		priv->conf_file_monitor_id = g_signal_connect (monitor, "changed", G_CALLBACK (conf_file_changed), config);
-		priv->conf_file_monitor = monitor;
+		if (monitor) {
+			priv->conf_file_monitor_id = g_signal_connect (monitor, "changed", G_CALLBACK (conf_file_changed), config);
+			priv->conf_file_monitor = monitor;
+		}
 	}
 }
 
@@ -410,6 +409,9 @@ get_unmanaged_specs (NMSystemConfigInterface *config)
 	GSList *specs = NULL;
 	GError *error = NULL;
 
+	if (!priv->conf_file)
+		return NULL;
+
 	key_file = g_key_file_new ();
 	if (g_key_file_load_from_file (key_file, priv->conf_file, G_KEY_FILE_NONE, &error)) {
 		char *str;
@@ -460,6 +462,9 @@ plugin_get_hostname (SCPluginKeyfile *plugin)
 	char *hostname = NULL;
 	GError *error = NULL;
 
+	if (!priv->conf_file)
+		return NULL;
+
 	key_file = g_key_file_new ();
 	if (g_key_file_load_from_file (key_file, priv->conf_file, G_KEY_FILE_NONE, &error))
 		hostname = g_key_file_get_value (key_file, "keyfile", "hostname", NULL);
@@ -481,6 +486,11 @@ plugin_set_hostname (SCPluginKeyfile *plugin, const char *hostname)
 	GError *error = NULL;
 	gboolean result = FALSE;
 
+	if (!priv->conf_file) {
+		g_warning ("Error saving hostname: no config file");
+		return FALSE;
+	}
+
 	key_file = g_key_file_new ();
 	if (g_key_file_load_from_file (key_file, priv->conf_file, G_KEY_FILE_NONE, &error)) {
 		char *data;
@@ -517,14 +527,6 @@ plugin_set_hostname (SCPluginKeyfile *plugin, const char *hostname)
 static void
 sc_plugin_keyfile_init (SCPluginKeyfile *plugin)
 {
-	SCPluginKeyfilePrivate *priv = SC_PLUGIN_KEYFILE_GET_PRIVATE (plugin);
-
-	if (g_file_test (CONF_FILE, G_FILE_TEST_EXISTS))
-		priv->conf_file = CONF_FILE;
-	else
-		priv->conf_file = OLD_CONF_FILE;
-
-	priv->hostname = plugin_get_hostname (plugin);
 }
 
 static void
@@ -597,6 +599,7 @@ dispose (GObject *object)
 	}
 
 	g_free (priv->hostname);
+	g_free (priv->conf_file);
 
 	if (priv->hash)
 		g_hash_table_destroy (priv->hash);
@@ -642,13 +645,22 @@ system_config_interface_init (NMSystemConfigInterface *system_config_interface_c
 }
 
 GObject *
-nm_settings_keyfile_plugin_new (void)
+nm_settings_keyfile_plugin_new (const char *config_file)
 {
 	static SCPluginKeyfile *singleton = NULL;
+	SCPluginKeyfilePrivate *priv;
 
-	if (!singleton)
+	if (!singleton) {
 		singleton = SC_PLUGIN_KEYFILE (g_object_new (SC_TYPE_PLUGIN_KEYFILE, NULL));
-	else
+		if (singleton) {
+			priv = SC_PLUGIN_KEYFILE_GET_PRIVATE (singleton);
+
+			priv->conf_file = g_strdup (config_file);
+
+			/* plugin_set_hostname() has to be called *after* priv->conf_file is set */
+			priv->hostname = plugin_get_hostname (singleton);
+		}
+	} else
 		g_object_ref (singleton);
 
 	return G_OBJECT (singleton);
diff --git a/src/settings/plugins/keyfile/plugin.h b/src/settings/plugins/keyfile/plugin.h
index af5147ef..05d4e2b0 100644
--- a/src/settings/plugins/keyfile/plugin.h
+++ b/src/settings/plugins/keyfile/plugin.h
@@ -16,7 +16,7 @@
  * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
  *
  * Copyright (C) 2008 Novell, Inc.
- * Copyright (C) 2008 Red Hat, Inc.
+ * Copyright (C) 2008 - 2011 Red Hat, Inc.
  */
 
 #ifndef _PLUGIN_H_
@@ -43,6 +43,6 @@ GType sc_plugin_keyfile_get_type (void);
 
 GQuark keyfile_plugin_error_quark (void);
 
-GObject *nm_settings_keyfile_plugin_new (void);
+GObject *nm_settings_keyfile_plugin_new (const char *config_file);
 
 #endif	/* _PLUGIN_H_ */
diff --git a/src/settings/plugins/keyfile/reader.c b/src/settings/plugins/keyfile/reader.c
index 4128b9f2..c7889cfc 100644
--- a/src/settings/plugins/keyfile/reader.c
+++ b/src/settings/plugins/keyfile/reader.c
@@ -34,8 +34,10 @@
 #include <nm-setting-wireless.h>
 #include <nm-setting-bluetooth.h>
 #include <nm-setting-8021x.h>
+#include <nm-utils.h>
 #include <arpa/inet.h>
 #include <netinet/ether.h>
+#include <linux/if_infiniband.h>
 #include <string.h>
 #include <ctype.h>
 
@@ -650,12 +652,11 @@ static void
 mac_address_parser (NMSetting *setting, const char *key, GKeyFile *keyfile, const char *keyfile_path)
 {
 	const char *setting_name = nm_setting_get_name (setting);
-	struct ether_addr *eth;
 	char *tmp_string = NULL, *p;
 	gint *tmp_list;
 	GByteArray *array = NULL;
 	gsize length;
-	int i;
+	int i, type;
 
 	p = tmp_string = g_key_file_get_string (keyfile, setting_name, key, NULL);
 	if (tmp_string) {
@@ -666,43 +667,45 @@ mac_address_parser (NMSetting *setting, const char *key, GKeyFile *keyfile, cons
 				i++;
 			p++;
 		}
-		if (i == 5) {
-			/* parse as a MAC address */
-			eth = ether_aton (tmp_string);
-			if (eth) {
-				g_free (tmp_string);
-				array = g_byte_array_sized_new (ETH_ALEN);
-				g_byte_array_append (array, eth->ether_addr_octet, ETH_ALEN);
-				goto done;
-			}
-		}
+
+		/* If we found enough it's probably a string-format MAC address */
+		type = nm_utils_hwaddr_type (i + 1);
+		if (type > 0)
+			array = nm_utils_hwaddr_atoba (tmp_string, type);
 	}
 	g_free (tmp_string);
 
-	/* Old format; list of ints */
-	tmp_list = g_key_file_get_integer_list (keyfile, setting_name, key, &length, NULL);
-	array = g_byte_array_sized_new (length);
-	for (i = 0; i < length; i++) {
-		int val = tmp_list[i];
-		unsigned char v = (unsigned char) (val & 0xFF);
-
-		if (val < 0 || val > 255) {
-			g_warning ("%s: %s / %s ignoring invalid byte element '%d' (not "
-			           " between 0 and 255 inclusive)", __func__, setting_name,
-			           key, val);
-		} else
-			g_byte_array_append (array, (const unsigned char *) &v, sizeof (v));
+	if (array == NULL) {
+		/* Old format; list of ints */
+		tmp_list = g_key_file_get_integer_list (keyfile, setting_name, key, &length, NULL);
+		type = nm_utils_hwaddr_type (length);
+		if (type < 0) {
+			array = g_byte_array_sized_new (length);
+			for (i = 0; i < length; i++) {
+				int val = tmp_list[i];
+				const guint8 v = (guint8) (val & 0xFF);
+
+				if (val < 0 || val > 255) {
+					g_warning ("%s: %s / %s ignoring invalid byte element '%d' (not "
+							   " between 0 and 255 inclusive)", __func__, setting_name,
+							   key, val);
+					g_byte_array_free (array, TRUE);
+					array = NULL;
+					break;
+				}
+				g_byte_array_append (array, &v, 1);
+			}
+		}
+		g_free (tmp_list);
 	}
-	g_free (tmp_list);
 
-done:
-	if (array->len == ETH_ALEN) {
+	if (array) {
 		g_object_set (setting, key, array, NULL);
+		g_byte_array_free (array, TRUE);
 	} else {
 		g_warning ("%s: ignoring invalid MAC address for %s / %s",
 		           __func__, setting_name, key);
 	}
-	g_byte_array_free (array, TRUE);
 }
 
 static void
@@ -825,6 +828,22 @@ ssid_parser (NMSetting *setting, const char *key, GKeyFile *keyfile, const char
 	}
 }
 
+static void
+password_raw_parser (NMSetting *setting, const char *key, GKeyFile *keyfile, const char *keyfile_path)
+{
+	const char *setting_name = nm_setting_get_name (setting);
+	GByteArray *array;
+
+	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);
+	} else {
+		g_warning ("%s: ignoring invalid raw password for %s / %s",
+		           __func__, setting_name, key);
+	}
+}
+
 static char *
 get_cert_path (const char *keyfile_path, GByteArray *cert_path)
 {
@@ -1019,11 +1038,19 @@ static KeyParser key_parsers[] = {
 	  NM_SETTING_BLUETOOTH_BDADDR,
 	  TRUE,
 	  mac_address_parser },
+	{ NM_SETTING_INFINIBAND_SETTING_NAME,
+	  NM_SETTING_INFINIBAND_MAC_ADDRESS,
+	  TRUE,
+	  mac_address_parser },
 	{ NM_SETTING_WIRELESS_SETTING_NAME,
 	  NM_SETTING_WIRELESS_SSID,
 	  TRUE,
 	  ssid_parser },
 	{ NM_SETTING_802_1X_SETTING_NAME,
+	  NM_SETTING_802_1X_PASSWORD_RAW,
+	  TRUE,
+	  password_raw_parser },
+	{ NM_SETTING_802_1X_SETTING_NAME,
 	  NM_SETTING_802_1X_CA_CERT,
 	  TRUE,
 	  cert_parser },
@@ -1300,7 +1327,7 @@ nm_keyfile_plugin_connection_from_file (const char *filename, GError **error)
 	 * the keyfile didn't include it, which can happen when the base
 	 * device type setting is all default values (like ethernet).
 	 */
-	s_con = (NMSettingConnection *) nm_connection_get_setting (connection, NM_TYPE_SETTING_CONNECTION);
+	s_con = nm_connection_get_setting_connection (connection);
 	if (s_con) {
 		ctype = nm_setting_connection_get_connection_type (s_con);
 		setting = nm_connection_get_setting_by_name (connection, ctype);
@@ -1314,7 +1341,7 @@ nm_keyfile_plugin_connection_from_file (const char *filename, GError **error)
 	if (vpn_secrets) {
 		NMSettingVPN *s_vpn;
 
-		s_vpn = (NMSettingVPN *) nm_connection_get_setting (connection, NM_TYPE_SETTING_VPN);
+		s_vpn = nm_connection_get_setting_vpn (connection);
 		if (s_vpn)
 			read_vpn_secrets (key_file, s_vpn);
 	}
diff --git a/src/settings/plugins/keyfile/tests/Makefile.am b/src/settings/plugins/keyfile/tests/Makefile.am
index affe8dca..2adbf873 100644
--- a/src/settings/plugins/keyfile/tests/Makefile.am
+++ b/src/settings/plugins/keyfile/tests/Makefile.am
@@ -2,7 +2,9 @@ SUBDIRS=keyfiles
 
 INCLUDES = \
 	-I$(top_srcdir)/include \
+	-I$(top_builddir)/include \
 	-I$(top_srcdir)/libnm-util \
+	-I$(top_builddir)/libnm-util \
 	-I$(top_srcdir)/libnm-glib \
 	-I$(srcdir)/../
 
diff --git a/src/settings/plugins/keyfile/tests/Makefile.in b/src/settings/plugins/keyfile/tests/Makefile.in
index c1fc662d..ff08e529 100644
--- a/src/settings/plugins/keyfile/tests/Makefile.in
+++ b/src/settings/plugins/keyfile/tests/Makefile.in
@@ -179,6 +179,8 @@ GIO_LIBS = @GIO_LIBS@
 GLIB_CFLAGS = @GLIB_CFLAGS@
 GLIB_GENMARSHAL = @GLIB_GENMARSHAL@
 GLIB_LIBS = @GLIB_LIBS@
+GLIB_MAKEFILE = @GLIB_MAKEFILE@
+GLIB_MKENUMS = @GLIB_MKENUMS@
 GMODULE_CFLAGS = @GMODULE_CFLAGS@
 GMODULE_LIBS = @GMODULE_LIBS@
 GMSGFMT = @GMSGFMT@
@@ -233,11 +235,15 @@ LIBNL2_LIBS = @LIBNL2_LIBS@
 LIBNL3_CFLAGS = @LIBNL3_CFLAGS@
 LIBNL3_LIBS = @LIBNL3_LIBS@
 LIBNL_CFLAGS = @LIBNL_CFLAGS@
+LIBNL_GENL3_CFLAGS = @LIBNL_GENL3_CFLAGS@
+LIBNL_GENL3_LIBS = @LIBNL_GENL3_LIBS@
 LIBNL_LIBS = @LIBNL_LIBS@
 LIBNL_ROUTE3_CFLAGS = @LIBNL_ROUTE3_CFLAGS@
 LIBNL_ROUTE3_LIBS = @LIBNL_ROUTE3_LIBS@
 LIBOBJS = @LIBOBJS@
 LIBS = @LIBS@
+LIBSOUP_CFLAGS = @LIBSOUP_CFLAGS@
+LIBSOUP_LIBS = @LIBSOUP_LIBS@
 LIBTOOL = @LIBTOOL@
 LIPO = @LIPO@
 LN_S = @LN_S@
@@ -248,6 +254,7 @@ MAINT = @MAINT@
 MAKEINFO = @MAKEINFO@
 MANIFEST_TOOL = @MANIFEST_TOOL@
 MKDIR_P = @MKDIR_P@
+MOC = @MOC@
 MSGFMT = @MSGFMT@
 MSGFMT_015 = @MSGFMT_015@
 MSGMERGE = @MSGMERGE@
@@ -287,6 +294,8 @@ SED = @SED@
 SET_MAKE = @SET_MAKE@
 SHELL = @SHELL@
 STRIP = @STRIP@
+SYSTEMD_CFLAGS = @SYSTEMD_CFLAGS@
+SYSTEMD_LIBS = @SYSTEMD_LIBS@
 SYSTEM_CA_PATH = @SYSTEM_CA_PATH@
 UDEV_BASE_DIR = @UDEV_BASE_DIR@
 USE_NLS = @USE_NLS@
@@ -353,7 +362,9 @@ top_srcdir = @top_srcdir@
 SUBDIRS = keyfiles
 INCLUDES = \
 	-I$(top_srcdir)/include \
+	-I$(top_builddir)/include \
 	-I$(top_srcdir)/libnm-util \
+	-I$(top_builddir)/libnm-util \
 	-I$(top_srcdir)/libnm-glib \
 	-I$(srcdir)/../
 
diff --git a/src/settings/plugins/keyfile/tests/keyfiles/Makefile.am b/src/settings/plugins/keyfile/tests/keyfiles/Makefile.am
index 55dda7ee..f163312e 100644
--- a/src/settings/plugins/keyfile/tests/keyfiles/Makefile.am
+++ b/src/settings/plugins/keyfile/tests/keyfiles/Makefile.am
@@ -13,7 +13,8 @@ KEYFILES = \
 	Test_Wired_TLS_Old \
 	Test_Wired_TLS_New \
 	Test_Wired_TLS_Blob \
-	Test_Wired_TLS_Path_Missing
+	Test_Wired_TLS_Path_Missing \
+	Test_InfiniBand_Connection
 
 CERTS = \
 	test-ca-cert.pem \
diff --git a/src/settings/plugins/keyfile/tests/keyfiles/Makefile.in b/src/settings/plugins/keyfile/tests/keyfiles/Makefile.in
index 0ea23ebc..cf5b868f 100644
--- a/src/settings/plugins/keyfile/tests/keyfiles/Makefile.in
+++ b/src/settings/plugins/keyfile/tests/keyfiles/Makefile.in
@@ -107,6 +107,8 @@ GIO_LIBS = @GIO_LIBS@
 GLIB_CFLAGS = @GLIB_CFLAGS@
 GLIB_GENMARSHAL = @GLIB_GENMARSHAL@
 GLIB_LIBS = @GLIB_LIBS@
+GLIB_MAKEFILE = @GLIB_MAKEFILE@
+GLIB_MKENUMS = @GLIB_MKENUMS@
 GMODULE_CFLAGS = @GMODULE_CFLAGS@
 GMODULE_LIBS = @GMODULE_LIBS@
 GMSGFMT = @GMSGFMT@
@@ -161,11 +163,15 @@ LIBNL2_LIBS = @LIBNL2_LIBS@
 LIBNL3_CFLAGS = @LIBNL3_CFLAGS@
 LIBNL3_LIBS = @LIBNL3_LIBS@
 LIBNL_CFLAGS = @LIBNL_CFLAGS@
+LIBNL_GENL3_CFLAGS = @LIBNL_GENL3_CFLAGS@
+LIBNL_GENL3_LIBS = @LIBNL_GENL3_LIBS@
 LIBNL_LIBS = @LIBNL_LIBS@
 LIBNL_ROUTE3_CFLAGS = @LIBNL_ROUTE3_CFLAGS@
 LIBNL_ROUTE3_LIBS = @LIBNL_ROUTE3_LIBS@
 LIBOBJS = @LIBOBJS@
 LIBS = @LIBS@
+LIBSOUP_CFLAGS = @LIBSOUP_CFLAGS@
+LIBSOUP_LIBS = @LIBSOUP_LIBS@
 LIBTOOL = @LIBTOOL@
 LIPO = @LIPO@
 LN_S = @LN_S@
@@ -176,6 +182,7 @@ MAINT = @MAINT@
 MAKEINFO = @MAKEINFO@
 MANIFEST_TOOL = @MANIFEST_TOOL@
 MKDIR_P = @MKDIR_P@
+MOC = @MOC@
 MSGFMT = @MSGFMT@
 MSGFMT_015 = @MSGFMT_015@
 MSGMERGE = @MSGMERGE@
@@ -215,6 +222,8 @@ SED = @SED@
 SET_MAKE = @SET_MAKE@
 SHELL = @SHELL@
 STRIP = @STRIP@
+SYSTEMD_CFLAGS = @SYSTEMD_CFLAGS@
+SYSTEMD_LIBS = @SYSTEMD_LIBS@
 SYSTEM_CA_PATH = @SYSTEM_CA_PATH@
 UDEV_BASE_DIR = @UDEV_BASE_DIR@
 USE_NLS = @USE_NLS@
@@ -293,7 +302,8 @@ KEYFILES = \
 	Test_Wired_TLS_Old \
 	Test_Wired_TLS_New \
 	Test_Wired_TLS_Blob \
-	Test_Wired_TLS_Path_Missing
+	Test_Wired_TLS_Path_Missing \
+	Test_InfiniBand_Connection
 
 CERTS = \
 	test-ca-cert.pem \
diff --git a/src/settings/plugins/keyfile/tests/keyfiles/Test_InfiniBand_Connection b/src/settings/plugins/keyfile/tests/keyfiles/Test_InfiniBand_Connection
new file mode 100644
index 00000000..3a984b77
--- /dev/null
+++ b/src/settings/plugins/keyfile/tests/keyfiles/Test_InfiniBand_Connection
@@ -0,0 +1,13 @@
+[connection]
+id=Test InfiniBand Connection
+uuid=4e80a56d-c99f-4aad-a6dd-b449bc398c57
+type=infiniband
+
+[infiniband]
+mac-address=00:11:22:33:44:55:66:77:88:99:01:12:23:34:45:56:67:78:89:90
+transport-mode=datagram
+mtu=1400
+
+[ipv4]
+method=auto
+
diff --git a/src/settings/plugins/keyfile/tests/test-keyfile.c b/src/settings/plugins/keyfile/tests/test-keyfile.c
index 2859cb3e..79fa2f9c 100644
--- a/src/settings/plugins/keyfile/tests/test-keyfile.c
+++ b/src/settings/plugins/keyfile/tests/test-keyfile.c
@@ -26,6 +26,7 @@
 #include <netinet/in.h>
 #include <arpa/inet.h>
 #include <sys/socket.h>
+#include <linux/if_infiniband.h>
 
 #include <nm-utils.h>
 #include <nm-setting-connection.h>
@@ -38,6 +39,7 @@
 #include <nm-setting-ppp.h>
 #include <nm-setting-gsm.h>
 #include <nm-setting-8021x.h>
+#include <nm-setting-infiniband.h>
 
 #include "nm-test-helpers.h"
 
@@ -93,7 +95,7 @@ test_read_valid_wired_connection (void)
 
 	/* ===== CONNECTION SETTING ===== */
 
-	s_con = NM_SETTING_CONNECTION (nm_connection_get_setting (connection, NM_TYPE_SETTING_CONNECTION));
+	s_con = nm_connection_get_setting_connection (connection);
 	ASSERT (s_con != NULL,
 	        "connection-verify-connection", "failed to verify %s: missing %s setting",
 	        TEST_WIRED_FILE,
@@ -142,7 +144,7 @@ test_read_valid_wired_connection (void)
 
 	/* ===== WIRED SETTING ===== */
 
-	s_wired = NM_SETTING_WIRED (nm_connection_get_setting (connection, NM_TYPE_SETTING_WIRED));
+	s_wired = nm_connection_get_setting_wired (connection);
 	ASSERT (s_wired != NULL,
 	        "connection-verify-wired", "failed to verify %s: missing %s setting",
 	        TEST_WIRED_FILE,
@@ -174,7 +176,7 @@ test_read_valid_wired_connection (void)
 
 	/* ===== IPv4 SETTING ===== */
 
-	s_ip4 = NM_SETTING_IP4_CONFIG (nm_connection_get_setting (connection, NM_TYPE_SETTING_IP4_CONFIG));
+	s_ip4 = nm_connection_get_setting_ip4_config (connection);
 	ASSERT (s_ip4 != NULL,
 	        "connection-verify-ip4", "failed to verify %s: missing %s setting",
 	        TEST_WIRED_FILE,
@@ -297,7 +299,7 @@ test_read_valid_wired_connection (void)
 
 	/* ===== IPv6 SETTING ===== */
 
-	s_ip6 = NM_SETTING_IP6_CONFIG (nm_connection_get_setting (connection, NM_TYPE_SETTING_IP6_CONFIG));
+	s_ip6 = nm_connection_get_setting_ip6_config (connection);
 	ASSERT (s_ip6 != NULL,
 	        "connection-verify-ip6", "failed to verify %s: missing %s setting",
 	        TEST_WIRED_FILE,
@@ -745,7 +747,7 @@ test_read_ip6_wired_connection (void)
 
 	/* ===== CONNECTION SETTING ===== */
 
-	s_con = NM_SETTING_CONNECTION (nm_connection_get_setting (connection, NM_TYPE_SETTING_CONNECTION));
+	s_con = nm_connection_get_setting_connection (connection);
 	ASSERT (s_con != NULL,
 	        "connection-verify-connection", "failed to verify %s: missing %s setting",
 	        TEST_WIRED_IP6_FILE,
@@ -779,7 +781,7 @@ test_read_ip6_wired_connection (void)
 
 	/* ===== WIRED SETTING ===== */
 
-	s_wired = NM_SETTING_WIRED (nm_connection_get_setting (connection, NM_TYPE_SETTING_WIRED));
+	s_wired = nm_connection_get_setting_wired (connection);
 	ASSERT (s_wired != NULL,
 	        "connection-verify-wired", "failed to verify %s: missing %s setting",
 	        TEST_WIRED_IP6_FILE,
@@ -787,7 +789,7 @@ test_read_ip6_wired_connection (void)
 
 	/* ===== IPv4 SETTING ===== */
 
-	s_ip4 = NM_SETTING_IP4_CONFIG (nm_connection_get_setting (connection, NM_TYPE_SETTING_IP4_CONFIG));
+	s_ip4 = nm_connection_get_setting_ip4_config (connection);
 	ASSERT (s_ip4 != NULL,
 	        "connection-verify-ip4", "failed to verify %s: missing %s setting",
 	        TEST_WIRED_IP6_FILE,
@@ -809,7 +811,7 @@ test_read_ip6_wired_connection (void)
 
 	/* ===== IPv6 SETTING ===== */
 
-	s_ip6 = NM_SETTING_IP6_CONFIG (nm_connection_get_setting (connection, NM_TYPE_SETTING_IP6_CONFIG));
+	s_ip6 = nm_connection_get_setting_ip6_config (connection);
 	ASSERT (s_ip6 != NULL,
 	        "connection-verify-ip6", "failed to verify %s: missing %s setting",
 	        TEST_WIRED_IP6_FILE,
@@ -1001,7 +1003,7 @@ test_read_wired_mac_case (void)
 
 	/* ===== CONNECTION SETTING ===== */
 
-	s_con = NM_SETTING_CONNECTION (nm_connection_get_setting (connection, NM_TYPE_SETTING_CONNECTION));
+	s_con = nm_connection_get_setting_connection (connection);
 	ASSERT (s_con != NULL,
 	        "connection-verify-connection", "failed to verify %s: missing %s setting",
 	        TEST_WIRED_MAC_CASE_FILE,
@@ -1035,7 +1037,7 @@ test_read_wired_mac_case (void)
 
 	/* ===== WIRED SETTING ===== */
 
-	s_wired = NM_SETTING_WIRED (nm_connection_get_setting (connection, NM_TYPE_SETTING_WIRED));
+	s_wired = nm_connection_get_setting_wired (connection);
 	ASSERT (s_wired != NULL,
 	        "connection-verify-wired", "failed to verify %s: missing %s setting",
 	        TEST_WIRED_MAC_CASE_FILE,
@@ -1087,7 +1089,7 @@ test_read_valid_wireless_connection (void)
 
 	/* ===== CONNECTION SETTING ===== */
 
-	s_con = NM_SETTING_CONNECTION (nm_connection_get_setting (connection, NM_TYPE_SETTING_CONNECTION));
+	s_con = nm_connection_get_setting_connection (connection);
 	ASSERT (s_con != NULL,
 	        "connection-verify-connection", "failed to verify %s: missing %s setting",
 	        TEST_WIRELESS_FILE,
@@ -1136,7 +1138,7 @@ test_read_valid_wireless_connection (void)
 
 	/* ===== WIRED SETTING ===== */
 
-	s_wireless = NM_SETTING_WIRELESS (nm_connection_get_setting (connection, NM_TYPE_SETTING_WIRELESS));
+	s_wireless = nm_connection_get_setting_wireless (connection);
 	ASSERT (s_wireless != NULL,
 	        "connection-verify-wireless", "failed to verify %s: missing %s setting",
 	        TEST_WIRELESS_FILE,
@@ -1162,7 +1164,7 @@ test_read_valid_wireless_connection (void)
 
 	/* ===== IPv4 SETTING ===== */
 
-	s_ip4 = NM_SETTING_IP4_CONFIG (nm_connection_get_setting (connection, NM_TYPE_SETTING_IP4_CONFIG));
+	s_ip4 = nm_connection_get_setting_ip4_config (connection);
 	ASSERT (s_ip4 != NULL,
 	        "connection-verify-ip4", "failed to verify %s: missing %s setting",
 	        TEST_WIRELESS_FILE,
@@ -1315,7 +1317,7 @@ test_read_string_ssid (void)
 
 	/* ===== WIRELESS SETTING ===== */
 
-	s_wireless = NM_SETTING_WIRELESS (nm_connection_get_setting (connection, NM_TYPE_SETTING_WIRELESS));
+	s_wireless = nm_connection_get_setting_wireless (connection);
 	ASSERT (s_wireless != NULL,
 	        "connection-verify-wireless", "failed to verify %s: missing %s setting",
 	        TEST_STRING_SSID_FILE,
@@ -1832,7 +1834,7 @@ test_read_bt_dun_connection (void)
 
 	/* ===== CONNECTION SETTING ===== */
 
-	s_con = NM_SETTING_CONNECTION (nm_connection_get_setting (connection, NM_TYPE_SETTING_CONNECTION));
+	s_con = nm_connection_get_setting_connection (connection);
 	ASSERT (s_con != NULL,
 	        "connection-verify-connection", "failed to verify %s: missing %s setting",
 	        TEST_BT_DUN_FILE,
@@ -1866,7 +1868,7 @@ test_read_bt_dun_connection (void)
 
 	/* ===== BLUETOOTH SETTING ===== */
 
-	s_bluetooth = NM_SETTING_BLUETOOTH (nm_connection_get_setting (connection, NM_TYPE_SETTING_BLUETOOTH));
+	s_bluetooth = nm_connection_get_setting_bluetooth (connection);
 	ASSERT (s_bluetooth != NULL,
 	        "connection-verify-bt", "failed to verify %s: missing %s setting",
 	        TEST_WIRELESS_FILE,
@@ -1905,7 +1907,7 @@ test_read_bt_dun_connection (void)
 
 	/* ===== GSM SETTING ===== */
 
-	s_gsm = NM_SETTING_GSM (nm_connection_get_setting (connection, NM_TYPE_SETTING_GSM));
+	s_gsm = nm_connection_get_setting_gsm (connection);
 	ASSERT (s_gsm != NULL,
 	        "connection-verify-gsm", "failed to verify %s: missing %s setting",
 	        TEST_BT_DUN_FILE,
@@ -1952,7 +1954,7 @@ test_read_bt_dun_connection (void)
 
 	/* ===== SERIAL SETTING ===== */
 
-	s_serial = NM_SETTING_SERIAL (nm_connection_get_setting (connection, NM_TYPE_SETTING_SERIAL));
+	s_serial = nm_connection_get_setting_serial (connection);
 	ASSERT (s_serial != NULL,
 	        "connection-verify-serial", "failed to verify %s: missing %s setting",
 	        TEST_BT_DUN_FILE,
@@ -2081,7 +2083,7 @@ test_read_gsm_connection (void)
 	NMSettingConnection *s_con;
 	NMSettingSerial *s_serial;
 	NMSettingGsm *s_gsm;
-	NMSetting *s_bluetooth;
+	NMSettingBluetooth *s_bluetooth;
 	GError *error = NULL;
 	const char *tmp;
 	const char *expected_id = "AT&T Data Connect";
@@ -2100,7 +2102,7 @@ test_read_gsm_connection (void)
 
 	/* ===== CONNECTION SETTING ===== */
 
-	s_con = NM_SETTING_CONNECTION (nm_connection_get_setting (connection, NM_TYPE_SETTING_CONNECTION));
+	s_con = nm_connection_get_setting_connection (connection);
 	ASSERT (s_con != NULL,
 	        "connection-verify-connection", "failed to verify %s: missing %s setting",
 	        TEST_GSM_FILE,
@@ -2134,7 +2136,7 @@ test_read_gsm_connection (void)
 	/* ===== BLUETOOTH SETTING ===== */
 
 	/* Plain GSM, so no BT setting expected */
-	s_bluetooth = nm_connection_get_setting (connection, NM_TYPE_SETTING_BLUETOOTH);
+	s_bluetooth = nm_connection_get_setting_bluetooth (connection);
 	ASSERT (s_bluetooth == NULL,
 	        "connection-verify-bt", "unexpected %s setting",
 	        TEST_GSM_FILE,
@@ -2142,7 +2144,7 @@ test_read_gsm_connection (void)
 
 	/* ===== GSM SETTING ===== */
 
-	s_gsm = NM_SETTING_GSM (nm_connection_get_setting (connection, NM_TYPE_SETTING_GSM));
+	s_gsm = nm_connection_get_setting_gsm (connection);
 	ASSERT (s_gsm != NULL,
 	        "connection-verify-gsm", "failed to verify %s: missing %s setting",
 	        TEST_GSM_FILE,
@@ -2215,7 +2217,7 @@ test_read_gsm_connection (void)
 
 	/* ===== SERIAL SETTING ===== */
 
-	s_serial = NM_SETTING_SERIAL (nm_connection_get_setting (connection, NM_TYPE_SETTING_SERIAL));
+	s_serial = nm_connection_get_setting_serial (connection);
 	ASSERT (s_serial != NULL,
 	        "connection-verify-serial", "failed to verify %s: missing %s setting",
 	        TEST_GSM_FILE,
@@ -2324,7 +2326,7 @@ static void
 test_read_wired_8021x_tls_blob_connection (void)
 {
 	NMConnection *connection;
-	NMSetting *s_wired;
+	NMSettingWired *s_wired;
 	NMSetting8021x *s_8021x;
 	GError *error = NULL;
 	const char *tmp;
@@ -2346,11 +2348,11 @@ test_read_wired_8021x_tls_blob_connection (void)
 	}
 
 	/* ===== Wired Setting ===== */
-	s_wired = nm_connection_get_setting (connection, NM_TYPE_SETTING_WIRED);
+	s_wired = nm_connection_get_setting_wired (connection);
 	g_assert (s_wired != NULL);
 
 	/* ===== 802.1x Setting ===== */
-	s_8021x = (NMSetting8021x *) nm_connection_get_setting (connection, NM_TYPE_SETTING_802_1X);
+	s_8021x = nm_connection_get_setting_802_1x (connection);
 	g_assert (s_8021x != NULL);
 
 	g_assert (nm_setting_802_1x_get_num_eap_methods (s_8021x) == 1);
@@ -2389,7 +2391,7 @@ static void
 test_read_wired_8021x_tls_bad_path_connection (void)
 {
 	NMConnection *connection;
-	NMSetting *s_wired;
+	NMSettingWired *s_wired;
 	NMSetting8021x *s_8021x;
 	GError *error = NULL;
 	const char *tmp;
@@ -2411,11 +2413,11 @@ test_read_wired_8021x_tls_bad_path_connection (void)
 	}
 
 	/* ===== Wired Setting ===== */
-	s_wired = nm_connection_get_setting (connection, NM_TYPE_SETTING_WIRED);
+	s_wired = nm_connection_get_setting_wired (connection);
 	g_assert (s_wired != NULL);
 
 	/* ===== 802.1x Setting ===== */
-	s_8021x = (NMSetting8021x *) nm_connection_get_setting (connection, NM_TYPE_SETTING_802_1X);
+	s_8021x = nm_connection_get_setting_802_1x (connection);
 	g_assert (s_8021x != NULL);
 
 	g_assert (nm_setting_802_1x_get_num_eap_methods (s_8021x) == 1);
@@ -2451,7 +2453,7 @@ static void
 test_read_wired_8021x_tls_old_connection (void)
 {
 	NMConnection *connection;
-	NMSetting *s_wired;
+	NMSettingWired *s_wired;
 	NMSetting8021x *s_8021x;
 	GError *error = NULL;
 	const char *tmp;
@@ -2472,11 +2474,11 @@ test_read_wired_8021x_tls_old_connection (void)
 	}
 
 	/* ===== Wired Setting ===== */
-	s_wired = nm_connection_get_setting (connection, NM_TYPE_SETTING_WIRED);
+	s_wired = nm_connection_get_setting_wired (connection);
 	g_assert (s_wired != NULL);
 
 	/* ===== 802.1x Setting ===== */
-	s_8021x = (NMSetting8021x *) nm_connection_get_setting (connection, NM_TYPE_SETTING_802_1X);
+	s_8021x = nm_connection_get_setting_802_1x (connection);
 	g_assert (s_8021x != NULL);
 
 	g_assert (nm_setting_802_1x_get_num_eap_methods (s_8021x) == 1);
@@ -2507,7 +2509,7 @@ static void
 test_read_wired_8021x_tls_new_connection (void)
 {
 	NMConnection *connection;
-	NMSetting *s_wired;
+	NMSettingWired *s_wired;
 	NMSetting8021x *s_8021x;
 	GError *error = NULL;
 	const char *tmp;
@@ -2529,11 +2531,11 @@ test_read_wired_8021x_tls_new_connection (void)
 	}
 
 	/* ===== Wired Setting ===== */
-	s_wired = nm_connection_get_setting (connection, NM_TYPE_SETTING_WIRED);
+	s_wired = nm_connection_get_setting_wired (connection);
 	g_assert (s_wired != NULL);
 
 	/* ===== 802.1x Setting ===== */
-	s_8021x = (NMSetting8021x *) nm_connection_get_setting (connection, NM_TYPE_SETTING_802_1X);
+	s_8021x = nm_connection_get_setting_802_1x (connection);
 	g_assert (s_8021x != NULL);
 
 	g_assert (nm_setting_802_1x_get_num_eap_methods (s_8021x) == 1);
@@ -2779,7 +2781,7 @@ test_write_wired_8021x_tls_connection_blob (void)
 	g_assert (testfile);
 
 	/* Check that the new certs got written out */
-	s_con = (NMSettingConnection *) nm_connection_get_setting (connection, NM_TYPE_SETTING_CONNECTION);
+	s_con = nm_connection_get_setting_connection (connection);
 	g_assert (s_con);
 	uuid = nm_setting_connection_get_uuid (s_con);
 	g_assert (uuid);
@@ -2805,7 +2807,7 @@ test_write_wired_8021x_tls_connection_blob (void)
 	}
 
 	/* Ensure the re-read connection's certificates use the path scheme */
-	s_8021x = (NMSetting8021x *) nm_connection_get_setting (reread, NM_TYPE_SETTING_802_1X);
+	s_8021x = nm_connection_get_setting_802_1x (reread);
 	g_assert (s_8021x);
 	g_assert (nm_setting_802_1x_get_ca_cert_scheme (s_8021x) == NM_SETTING_802_1X_CK_SCHEME_PATH);
 	g_assert (nm_setting_802_1x_get_client_cert_scheme (s_8021x) == NM_SETTING_802_1X_CK_SCHEME_PATH);
@@ -2828,6 +2830,134 @@ test_write_wired_8021x_tls_connection_blob (void)
 	g_object_unref (connection);
 }
 
+#define TEST_INFINIBAND_FILE    TEST_KEYFILES_DIR"/Test_InfiniBand_Connection"
+
+static void
+test_read_infiniband_connection (void)
+{
+	NMConnection *connection;
+	NMSettingConnection *s_con;
+	NMSettingInfiniband *s_ib;
+	GError *error = NULL;
+	const GByteArray *array;
+	guint8 expected_mac[INFINIBAND_ALEN] = { 0x00, 0x11, 0x22, 0x33, 0x44, 0x55, 0x66,
+		0x77, 0x88, 0x99, 0x01, 0x12, 0x23, 0x34, 0x45, 0x56, 0x67, 0x78, 0x89,
+		0x90 };
+	const char *expected_id = "Test InfiniBand Connection";
+	const char *expected_uuid = "4e80a56d-c99f-4aad-a6dd-b449bc398c57";
+	gboolean success;
+
+	connection = nm_keyfile_plugin_connection_from_file (TEST_INFINIBAND_FILE, &error);
+	g_assert_no_error (error);
+	g_assert (connection);
+	success = nm_connection_verify (connection, &error);
+	g_assert_no_error (error);
+	g_assert (success);
+
+	/* Connection setting */
+	s_con = nm_connection_get_setting_connection (connection);
+	g_assert (s_con);
+	g_assert_cmpstr (nm_setting_connection_get_id (s_con), ==, expected_id);
+	g_assert_cmpstr (nm_setting_connection_get_uuid (s_con), ==, expected_uuid);
+
+	/* InfiniBand setting */
+	s_ib = nm_connection_get_setting_infiniband (connection);
+	g_assert (s_ib);
+
+	array = nm_setting_infiniband_get_mac_address (s_ib);
+	g_assert (array);
+	g_assert_cmpint (array->len, ==, INFINIBAND_ALEN);
+	g_assert_cmpint (memcmp (array->data, expected_mac, sizeof (expected_mac)), ==, 0);
+
+	g_object_unref (connection);
+}
+
+static void
+test_write_infiniband_connection (void)
+{
+	NMConnection *connection;
+	NMSettingConnection *s_con;
+	NMSettingInfiniband *s_ib;
+	NMSettingIP4Config *s_ip4;
+	NMSettingIP6Config *s_ip6;
+	char *uuid;
+	GByteArray *mac;
+	guint8 tmpmac[] = { 0x99, 0x88, 0x77, 0x66, 0x55, 0x44, 0xab, 0xbc,
+		0xcd, 0xde, 0xef, 0xf0, 0x0a, 0x1b, 0x2c, 0x3d, 0x4e, 0x5f, 0x6f, 0xba
+	};
+	gboolean success;
+	NMConnection *reread;
+	char *testfile = NULL;
+	GError *error = NULL;
+	pid_t owner_grp;
+	uid_t owner_uid;
+
+	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 ();
+	g_object_set (s_con,
+	              NM_SETTING_CONNECTION_ID, "Work InfiniBand",
+	              NM_SETTING_CONNECTION_UUID, uuid,
+	              NM_SETTING_CONNECTION_AUTOCONNECT, FALSE,
+	              NM_SETTING_CONNECTION_TYPE, NM_SETTING_INFINIBAND_SETTING_NAME,
+	              NULL);
+	g_free (uuid);
+
+	/* InfiniBand setting */
+	s_ib = (NMSettingInfiniband *) nm_setting_infiniband_new ();
+	g_assert (s_ib);
+	nm_connection_add_setting (connection, NM_SETTING (s_ib));
+
+	mac = g_byte_array_sized_new (sizeof (tmpmac));
+	g_byte_array_append (mac, &tmpmac[0], sizeof (tmpmac));
+	g_object_set (s_ib,
+	              NM_SETTING_INFINIBAND_MAC_ADDRESS, mac,
+	              NM_SETTING_INFINIBAND_MTU, 900,
+	              NM_SETTING_INFINIBAND_TRANSPORT_MODE, "datagram",
+	              NULL);
+	g_byte_array_free (mac, TRUE);
+
+	/* 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_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);
+
+	/* 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);
+
+	g_assert (nm_connection_compare (connection, reread, NM_SETTING_COMPARE_FLAG_EXACT));
+
+	unlink (testfile);
+	g_free (testfile);
+
+	g_object_unref (reread);
+	g_object_unref (connection);
+}
+
 int main (int argc, char **argv)
 {
 	GError *error = NULL;
@@ -2876,6 +3006,9 @@ int main (int argc, char **argv)
 	test_write_wired_8021x_tls_connection_path ();
 	test_write_wired_8021x_tls_connection_blob ();
 
+	test_read_infiniband_connection ();
+	test_write_infiniband_connection ();
+
 	base = g_path_get_basename (argv[0]);
 	fprintf (stdout, "%s: SUCCESS\n", base);
 	g_free (base);
diff --git a/src/settings/plugins/keyfile/writer.c b/src/settings/plugins/keyfile/writer.c
index 2babe267..bbd6a7c3 100644
--- a/src/settings/plugins/keyfile/writer.c
+++ b/src/settings/plugins/keyfile/writer.c
@@ -416,7 +416,7 @@ mac_address_writer (GKeyFile *file,
 	GByteArray *array;
 	const char *setting_name = nm_setting_get_name (setting);
 	char *mac;
-	struct ether_addr tmp;
+	int type;
 
 	g_return_if_fail (G_VALUE_HOLDS (value, DBUS_TYPE_G_UCHAR_ARRAY));
 
@@ -424,15 +424,16 @@ mac_address_writer (GKeyFile *file,
 	if (!array)
 		return;
 
-	if (array->len != ETH_ALEN) {
+	type = nm_utils_hwaddr_type (array->len);
+	if (type < 0) {
 		g_warning ("%s: invalid %s / %s MAC address length %d",
 		           __func__, setting_name, key, array->len);
 		return;
 	}
 
-	memcpy (tmp.ether_addr_octet, array->data, ETH_ALEN);
-	mac = ether_ntoa (&tmp);
+	mac = nm_utils_hwaddr_ntoa (array->data, type);
 	g_key_file_set_string (file, setting_name, key, mac);
+	g_free (mac);
 }
 
 static void
@@ -532,6 +533,31 @@ ssid_writer (GKeyFile *file,
 	}
 }
 
+static void
+password_raw_writer (GKeyFile *file,
+                     const char *keyfile_dir,
+                     const char *uuid,
+                     NMSetting *setting,
+                     const char *key,
+                     const GValue *value)
+{
+	const char *setting_name = nm_setting_get_name (setting);
+	GByteArray *array;
+	int i, *tmp_array;
+
+	g_return_if_fail (G_VALUE_HOLDS (value, DBUS_TYPE_G_UCHAR_ARRAY));
+
+	array = (GByteArray *) g_value_get_boxed (value);
+	if (!array || !array->len)
+		return;
+
+	tmp_array = g_new (gint, array->len);
+	for (i = 0; i < array->len; i++)
+		tmp_array[i] = (int) array->data[i];
+	g_key_file_set_integer_list (file, setting_name, key, tmp_array, array->len);
+	g_free (tmp_array);
+}
+
 typedef struct ObjectType {
 	const char *key;
 	const char *suffix;
@@ -787,10 +813,16 @@ static KeyWriter key_writers[] = {
 	{ NM_SETTING_BLUETOOTH_SETTING_NAME,
 	  NM_SETTING_BLUETOOTH_BDADDR,
 	  mac_address_writer },
+	{ NM_SETTING_INFINIBAND_SETTING_NAME,
+	  NM_SETTING_INFINIBAND_MAC_ADDRESS,
+	  mac_address_writer },
 	{ NM_SETTING_WIRELESS_SETTING_NAME,
 	  NM_SETTING_WIRELESS_SSID,
 	  ssid_writer },
 	{ NM_SETTING_802_1X_SETTING_NAME,
+	  NM_SETTING_802_1X_PASSWORD_RAW,
+	  password_raw_writer },
+	{ NM_SETTING_802_1X_SETTING_NAME,
 	  NM_SETTING_802_1X_CA_CERT,
 	  cert_writer },
 	{ NM_SETTING_802_1X_SETTING_NAME,
diff --git a/src/settings/tests/Makefile.am b/src/settings/tests/Makefile.am
index 4a451398..57d56fc4 100644
--- a/src/settings/tests/Makefile.am
+++ b/src/settings/tests/Makefile.am
@@ -1,5 +1,6 @@
 INCLUDES = \
 	-I$(top_srcdir)/include \
+	-I$(top_builddir)/include \
 	-I$(top_srcdir)/libnm-util \
 	-I$(top_srcdir)/src/settings
 
diff --git a/src/settings/tests/Makefile.in b/src/settings/tests/Makefile.in
index 7c966ba2..de5474d4 100644
--- a/src/settings/tests/Makefile.in
+++ b/src/settings/tests/Makefile.in
@@ -143,6 +143,8 @@ GIO_LIBS = @GIO_LIBS@
 GLIB_CFLAGS = @GLIB_CFLAGS@
 GLIB_GENMARSHAL = @GLIB_GENMARSHAL@
 GLIB_LIBS = @GLIB_LIBS@
+GLIB_MAKEFILE = @GLIB_MAKEFILE@
+GLIB_MKENUMS = @GLIB_MKENUMS@
 GMODULE_CFLAGS = @GMODULE_CFLAGS@
 GMODULE_LIBS = @GMODULE_LIBS@
 GMSGFMT = @GMSGFMT@
@@ -197,11 +199,15 @@ LIBNL2_LIBS = @LIBNL2_LIBS@
 LIBNL3_CFLAGS = @LIBNL3_CFLAGS@
 LIBNL3_LIBS = @LIBNL3_LIBS@
 LIBNL_CFLAGS = @LIBNL_CFLAGS@
+LIBNL_GENL3_CFLAGS = @LIBNL_GENL3_CFLAGS@
+LIBNL_GENL3_LIBS = @LIBNL_GENL3_LIBS@
 LIBNL_LIBS = @LIBNL_LIBS@
 LIBNL_ROUTE3_CFLAGS = @LIBNL_ROUTE3_CFLAGS@
 LIBNL_ROUTE3_LIBS = @LIBNL_ROUTE3_LIBS@
 LIBOBJS = @LIBOBJS@
 LIBS = @LIBS@
+LIBSOUP_CFLAGS = @LIBSOUP_CFLAGS@
+LIBSOUP_LIBS = @LIBSOUP_LIBS@
 LIBTOOL = @LIBTOOL@
 LIPO = @LIPO@
 LN_S = @LN_S@
@@ -212,6 +218,7 @@ MAINT = @MAINT@
 MAKEINFO = @MAKEINFO@
 MANIFEST_TOOL = @MANIFEST_TOOL@
 MKDIR_P = @MKDIR_P@
+MOC = @MOC@
 MSGFMT = @MSGFMT@
 MSGFMT_015 = @MSGFMT_015@
 MSGMERGE = @MSGMERGE@
@@ -251,6 +258,8 @@ SED = @SED@
 SET_MAKE = @SET_MAKE@
 SHELL = @SHELL@
 STRIP = @STRIP@
+SYSTEMD_CFLAGS = @SYSTEMD_CFLAGS@
+SYSTEMD_LIBS = @SYSTEMD_LIBS@
 SYSTEM_CA_PATH = @SYSTEM_CA_PATH@
 UDEV_BASE_DIR = @UDEV_BASE_DIR@
 USE_NLS = @USE_NLS@
@@ -316,6 +325,7 @@ top_builddir = @top_builddir@
 top_srcdir = @top_srcdir@
 INCLUDES = \
 	-I$(top_srcdir)/include \
+	-I$(top_builddir)/include \
 	-I$(top_srcdir)/libnm-util \
 	-I$(top_srcdir)/src/settings
 
diff --git a/src/supplicant-manager/Makefile.am b/src/supplicant-manager/Makefile.am
index 359fc70a..e8a2ce74 100644
--- a/src/supplicant-manager/Makefile.am
+++ b/src/supplicant-manager/Makefile.am
@@ -2,10 +2,13 @@ SUBDIRS=. tests
 
 INCLUDES = \
 	-I${top_srcdir}/src \
+	-I${top_srcdir}/src/generated \
+	-I${top_builddir}/src/generated \
 	-I${top_srcdir}/src/logging \
 	-I${top_srcdir}/include \
+	-I${top_builddir}/include \
 	-I${top_srcdir}/libnm-util \
-	-I${top_builddir}/marshallers
+	-I${top_builddir}/libnm-util
 
 noinst_LTLIBRARIES = libsupplicant-manager.la
 
@@ -27,7 +30,6 @@ libsupplicant_manager_la_CPPFLAGS = \
 	-DNM_LOCALSTATEDIR=\"$(localstatedir)\"
 
 libsupplicant_manager_la_LIBADD = \
-	$(top_builddir)/marshallers/libmarshallers.la \
 	$(top_builddir)/src/logging/libnm-logging.la \
 	$(DBUS_LIBS) \
 	$(GLIB_LIBS)
diff --git a/src/supplicant-manager/Makefile.in b/src/supplicant-manager/Makefile.in
index 5a7a2f2f..fbb43bde 100644
--- a/src/supplicant-manager/Makefile.in
+++ b/src/supplicant-manager/Makefile.in
@@ -57,7 +57,6 @@ CONFIG_CLEAN_VPATH_FILES =
 LTLIBRARIES = $(noinst_LTLIBRARIES)
 am__DEPENDENCIES_1 =
 libsupplicant_manager_la_DEPENDENCIES =  \
-	$(top_builddir)/marshallers/libmarshallers.la \
 	$(top_builddir)/src/logging/libnm-logging.la \
 	$(am__DEPENDENCIES_1) $(am__DEPENDENCIES_1)
 am_libsupplicant_manager_la_OBJECTS =  \
@@ -184,6 +183,8 @@ GIO_LIBS = @GIO_LIBS@
 GLIB_CFLAGS = @GLIB_CFLAGS@
 GLIB_GENMARSHAL = @GLIB_GENMARSHAL@
 GLIB_LIBS = @GLIB_LIBS@
+GLIB_MAKEFILE = @GLIB_MAKEFILE@
+GLIB_MKENUMS = @GLIB_MKENUMS@
 GMODULE_CFLAGS = @GMODULE_CFLAGS@
 GMODULE_LIBS = @GMODULE_LIBS@
 GMSGFMT = @GMSGFMT@
@@ -238,11 +239,15 @@ LIBNL2_LIBS = @LIBNL2_LIBS@
 LIBNL3_CFLAGS = @LIBNL3_CFLAGS@
 LIBNL3_LIBS = @LIBNL3_LIBS@
 LIBNL_CFLAGS = @LIBNL_CFLAGS@
+LIBNL_GENL3_CFLAGS = @LIBNL_GENL3_CFLAGS@
+LIBNL_GENL3_LIBS = @LIBNL_GENL3_LIBS@
 LIBNL_LIBS = @LIBNL_LIBS@
 LIBNL_ROUTE3_CFLAGS = @LIBNL_ROUTE3_CFLAGS@
 LIBNL_ROUTE3_LIBS = @LIBNL_ROUTE3_LIBS@
 LIBOBJS = @LIBOBJS@
 LIBS = @LIBS@
+LIBSOUP_CFLAGS = @LIBSOUP_CFLAGS@
+LIBSOUP_LIBS = @LIBSOUP_LIBS@
 LIBTOOL = @LIBTOOL@
 LIPO = @LIPO@
 LN_S = @LN_S@
@@ -253,6 +258,7 @@ MAINT = @MAINT@
 MAKEINFO = @MAKEINFO@
 MANIFEST_TOOL = @MANIFEST_TOOL@
 MKDIR_P = @MKDIR_P@
+MOC = @MOC@
 MSGFMT = @MSGFMT@
 MSGFMT_015 = @MSGFMT_015@
 MSGMERGE = @MSGMERGE@
@@ -292,6 +298,8 @@ SED = @SED@
 SET_MAKE = @SET_MAKE@
 SHELL = @SHELL@
 STRIP = @STRIP@
+SYSTEMD_CFLAGS = @SYSTEMD_CFLAGS@
+SYSTEMD_LIBS = @SYSTEMD_LIBS@
 SYSTEM_CA_PATH = @SYSTEM_CA_PATH@
 UDEV_BASE_DIR = @UDEV_BASE_DIR@
 USE_NLS = @USE_NLS@
@@ -358,10 +366,13 @@ top_srcdir = @top_srcdir@
 SUBDIRS = . tests
 INCLUDES = \
 	-I${top_srcdir}/src \
+	-I${top_srcdir}/src/generated \
+	-I${top_builddir}/src/generated \
 	-I${top_srcdir}/src/logging \
 	-I${top_srcdir}/include \
+	-I${top_builddir}/include \
 	-I${top_srcdir}/libnm-util \
-	-I${top_builddir}/marshallers
+	-I${top_builddir}/libnm-util
 
 noinst_LTLIBRARIES = libsupplicant-manager.la
 libsupplicant_manager_la_SOURCES = \
@@ -382,7 +393,6 @@ libsupplicant_manager_la_CPPFLAGS = \
 	-DNM_LOCALSTATEDIR=\"$(localstatedir)\"
 
 libsupplicant_manager_la_LIBADD = \
-	$(top_builddir)/marshallers/libmarshallers.la \
 	$(top_builddir)/src/logging/libnm-logging.la \
 	$(DBUS_LIBS) \
 	$(GLIB_LIBS)
diff --git a/src/supplicant-manager/nm-supplicant-config.c b/src/supplicant-manager/nm-supplicant-config.c
index 4860314b..a8e4ab9d 100644
--- a/src/supplicant-manager/nm-supplicant-config.c
+++ b/src/supplicant-manager/nm-supplicant-config.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) 2006 - 2010 Red Hat, Inc.
+ * Copyright (C) 2006 - 2012 Red Hat, Inc.
  * Copyright (C) 2007 - 2008 Novell, Inc.
  */
 
@@ -54,6 +54,7 @@ typedef struct
 	GHashTable *config;
 	GHashTable *blobs;
 	guint32    ap_scan;
+	gboolean   fast_required;
 	gboolean   dispose_has_run;
 } NMSupplicantConfigPrivate;
 
@@ -278,6 +279,14 @@ nm_supplicant_config_set_ap_scan (NMSupplicantConfig * self,
 	NM_SUPPLICANT_CONFIG_GET_PRIVATE (self)->ap_scan = ap_scan;
 }
 
+gboolean
+nm_supplicant_config_fast_required (NMSupplicantConfig *self)
+{
+	g_return_val_if_fail (NM_IS_SUPPLICANT_CONFIG (self), FALSE);
+
+	return NM_SUPPLICANT_CONFIG_GET_PRIVATE (self)->fast_required;
+}
+
 static void
 get_hash_cb (gpointer key, gpointer value, gpointer user_data)
 {
@@ -293,6 +302,7 @@ get_hash_cb (gpointer key, gpointer value, gpointer user_data)
 		g_value_set_int (variant, atoi (opt->value));
 		break;
 	case TYPE_BYTES:
+	case TYPE_UTF8:
 		array = g_byte_array_sized_new (opt->len);
 		g_byte_array_append (array, (const guint8 *) opt->value, opt->len);
 		g_value_init (variant, DBUS_TYPE_G_UCHAR_ARRAY);
@@ -583,7 +593,7 @@ gboolean
 nm_supplicant_config_add_setting_wireless_security (NMSupplicantConfig *self,
                                                     NMSettingWirelessSecurity *setting,
                                                     NMSetting8021x *setting_8021x,
-                                                    const char *connection_uid)
+                                                    const char *con_uuid)
 {
 	char *value;
 	gboolean success;
@@ -592,7 +602,7 @@ nm_supplicant_config_add_setting_wireless_security (NMSupplicantConfig *self,
 
 	g_return_val_if_fail (NM_IS_SUPPLICANT_CONFIG (self), FALSE);
 	g_return_val_if_fail (setting != NULL, FALSE);
-	g_return_val_if_fail (connection_uid != NULL, FALSE);
+	g_return_val_if_fail (con_uuid != NULL, FALSE);
 
 	key_mgmt = nm_setting_wireless_security_get_key_mgmt (setting);
 	if (!add_string_val (self, key_mgmt, "key_mgmt", TRUE, FALSE))
@@ -692,7 +702,7 @@ nm_supplicant_config_add_setting_wireless_security (NMSupplicantConfig *self,
 		if (!strcmp (key_mgmt, "ieee8021x") || !strcmp (key_mgmt, "wpa-eap")) {
 		    if (!setting_8021x)
 		    	return FALSE;
-			if (!nm_supplicant_config_add_setting_8021x (self, setting_8021x, connection_uid, FALSE))
+			if (!nm_supplicant_config_add_setting_8021x (self, setting_8021x, con_uuid, FALSE))
 				return FALSE;
 		}
 
@@ -711,24 +721,43 @@ nm_supplicant_config_add_setting_wireless_security (NMSupplicantConfig *self,
 gboolean
 nm_supplicant_config_add_setting_8021x (NMSupplicantConfig *self,
                                         NMSetting8021x *setting,
-                                        const char *connection_uid,
+                                        const char *con_uuid,
                                         gboolean wired)
 {
+	NMSupplicantConfigPrivate *priv;
 	char *tmp;
 	const char *peapver, *value, *path;
 	gboolean success, added;
 	GString *phase1, *phase2;
 	const GByteArray *array;
-	gboolean peap = FALSE;
+	gboolean peap = FALSE, fast = FALSE;
 	guint32 i, num_eap;
+	gboolean fast_provisoning_allowed = FALSE;
 
 	g_return_val_if_fail (NM_IS_SUPPLICANT_CONFIG (self), FALSE);
 	g_return_val_if_fail (setting != NULL, FALSE);
-	g_return_val_if_fail (connection_uid != NULL, FALSE);
+	g_return_val_if_fail (con_uuid != NULL, FALSE);
+
+	priv = NM_SUPPLICANT_CONFIG_GET_PRIVATE (self);
 
 	value = nm_setting_802_1x_get_password (setting);
-	if (!add_string_val (self, value, "password", FALSE, TRUE))
-		return FALSE;
+	if (value) {
+		if (!add_string_val (self, value, "password", FALSE, TRUE))
+			return FALSE;
+	} else {
+		array = nm_setting_802_1x_get_password_raw (setting);
+		if (array) {
+			success = nm_supplicant_config_add_option (self,
+			                                           "password",
+			                                           (const char *)array->data,
+			                                           array->len,
+			                                           TRUE);
+			if (!success) {
+				nm_log_warn (LOGD_SUPPLICANT, "Error adding password-raw to supplicant config.");
+				return FALSE;
+			}
+		}
+	}
 	value = nm_setting_802_1x_get_pin (setting);
 	if (!add_string_val (self, value, "pin", FALSE, TRUE))
 		return FALSE;
@@ -744,14 +773,16 @@ nm_supplicant_config_add_setting_8021x (NMSupplicantConfig *self,
 
 	ADD_STRING_LIST_VAL (setting, 802_1x, eap_method, eap_methods, "eap", ' ', TRUE, FALSE);
 
-	/* Check for PEAP + GTC */
+	/* Check EAP method for special handling: PEAP + GTC, FAST */
 	num_eap = nm_setting_802_1x_get_num_eap_methods (setting);
 	for (i = 0; i < num_eap; i++) {
 		const char *method = nm_setting_802_1x_get_eap_method (setting, i);
 
-		if (method && (strcasecmp (method, "peap") == 0)) {
+		if (method && (strcasecmp (method, "peap") == 0))
 			peap = TRUE;
-			break;
+		if (method && (strcasecmp (method, "fast") == 0)) {
+			fast = TRUE;
+			priv->fast_required = TRUE;
 		}
 	}
 
@@ -785,6 +816,16 @@ nm_supplicant_config_add_setting_8021x (NMSupplicantConfig *self,
 		g_string_append_printf (phase1, "peaplabel=%s", nm_setting_802_1x_get_phase1_peaplabel (setting));
 	}
 
+	value = nm_setting_802_1x_get_phase1_fast_provisioning (setting);
+	if (value) {
+		if (phase1->len)
+			g_string_append_c (phase1, ' ');
+		g_string_append_printf (phase1, "fast_provisioning=%s", value);
+		
+		if (strcmp (value, "0") != 0)
+			fast_provisoning_allowed = TRUE;
+	}
+
 	if (phase1->len) {
 		if (!add_string_val (self, phase1->str, "phase1", FALSE, FALSE)) {
 			g_string_free (phase1, TRUE);
@@ -794,7 +835,7 @@ nm_supplicant_config_add_setting_8021x (NMSupplicantConfig *self,
 	g_string_free (phase1, TRUE);
 
 	phase2 = g_string_new (NULL);
-	if (nm_setting_802_1x_get_phase2_auth (setting)) {
+	if (nm_setting_802_1x_get_phase2_auth (setting) && !fast_provisoning_allowed) {
 		tmp = g_ascii_strup (nm_setting_802_1x_get_phase2_auth (setting), -1);
 		g_string_append_printf (phase2, "auth=%s", tmp);
 		g_free (tmp);
@@ -816,6 +857,32 @@ nm_supplicant_config_add_setting_8021x (NMSupplicantConfig *self,
 	}
 	g_string_free (phase2, TRUE);
 
+	/* PAC file */
+	path = nm_setting_802_1x_get_pac_file (setting);
+	if (path) {
+		if (!add_string_val (self, path, "pac_file", FALSE, FALSE))
+			return FALSE;
+	} else {
+		/* PAC file is not specified.
+		 * If provisioning is allowed, use an blob format.
+		 */
+		if (fast_provisoning_allowed) {
+			char *blob_name = g_strdup_printf ("blob://pac-blob-%s", con_uuid);
+			if (!add_string_val (self, blob_name, "pac_file", FALSE, FALSE)) {
+				g_free (blob_name);
+				return FALSE;
+			}
+			g_free (blob_name);
+		} else {
+			/* This is only error for EAP-FAST; don't disturb other methods. */
+			if (fast) {
+				nm_log_err (LOGD_SUPPLICANT, "EAP-FAST error: no PAC file provided and "
+				                              "automatic PAC provisioning is disabled.");
+				return FALSE;
+			}
+		}
+	}
+
 	/* CA path */
 	path = nm_setting_802_1x_get_ca_path (setting);
 	if (nm_setting_802_1x_get_system_ca_certs (setting))
@@ -838,7 +905,7 @@ nm_supplicant_config_add_setting_8021x (NMSupplicantConfig *self,
 	switch (nm_setting_802_1x_get_ca_cert_scheme (setting)) {
 	case NM_SETTING_802_1X_CK_SCHEME_BLOB:
 		array = nm_setting_802_1x_get_ca_cert_blob (setting);
-		ADD_BLOB_VAL (array, "ca_cert", connection_uid);
+		ADD_BLOB_VAL (array, "ca_cert", con_uuid);
 		break;
 	case NM_SETTING_802_1X_CK_SCHEME_PATH:
 		path = nm_setting_802_1x_get_ca_cert_path (setting);
@@ -853,7 +920,7 @@ nm_supplicant_config_add_setting_8021x (NMSupplicantConfig *self,
 	switch (nm_setting_802_1x_get_phase2_ca_cert_scheme (setting)) {
 	case NM_SETTING_802_1X_CK_SCHEME_BLOB:
 		array = nm_setting_802_1x_get_phase2_ca_cert_blob (setting);
-		ADD_BLOB_VAL (array, "ca_cert2", connection_uid);
+		ADD_BLOB_VAL (array, "ca_cert2", con_uuid);
 		break;
 	case NM_SETTING_802_1X_CK_SCHEME_PATH:
 		path = nm_setting_802_1x_get_phase2_ca_cert_path (setting);
@@ -881,7 +948,7 @@ nm_supplicant_config_add_setting_8021x (NMSupplicantConfig *self,
 	switch (nm_setting_802_1x_get_private_key_scheme (setting)) {
 	case NM_SETTING_802_1X_CK_SCHEME_BLOB:
 		array = nm_setting_802_1x_get_private_key_blob (setting);
-		ADD_BLOB_VAL (array, "private_key", connection_uid);
+		ADD_BLOB_VAL (array, "private_key", con_uuid);
 		added = TRUE;
 		break;
 	case NM_SETTING_802_1X_CK_SCHEME_PATH:
@@ -919,7 +986,7 @@ nm_supplicant_config_add_setting_8021x (NMSupplicantConfig *self,
 			switch (nm_setting_802_1x_get_client_cert_scheme (setting)) {
 			case NM_SETTING_802_1X_CK_SCHEME_BLOB:
 				array = nm_setting_802_1x_get_client_cert_blob (setting);
-				ADD_BLOB_VAL (array, "client_cert", connection_uid);
+				ADD_BLOB_VAL (array, "client_cert", con_uuid);
 				break;
 			case NM_SETTING_802_1X_CK_SCHEME_PATH:
 				path = nm_setting_802_1x_get_client_cert_path (setting);
@@ -937,7 +1004,7 @@ nm_supplicant_config_add_setting_8021x (NMSupplicantConfig *self,
 	switch (nm_setting_802_1x_get_phase2_private_key_scheme (setting)) {
 	case NM_SETTING_802_1X_CK_SCHEME_BLOB:
 		array = nm_setting_802_1x_get_phase2_private_key_blob (setting);
-		ADD_BLOB_VAL (array, "private_key2", connection_uid);
+		ADD_BLOB_VAL (array, "private_key2", con_uuid);
 		added = TRUE;
 		break;
 	case NM_SETTING_802_1X_CK_SCHEME_PATH:
@@ -975,7 +1042,7 @@ nm_supplicant_config_add_setting_8021x (NMSupplicantConfig *self,
 			switch (nm_setting_802_1x_get_phase2_client_cert_scheme (setting)) {
 			case NM_SETTING_802_1X_CK_SCHEME_BLOB:
 				array = nm_setting_802_1x_get_phase2_client_cert_blob (setting);
-				ADD_BLOB_VAL (array, "client_cert2", connection_uid);
+				ADD_BLOB_VAL (array, "client_cert2", con_uuid);
 				break;
 			case NM_SETTING_802_1X_CK_SCHEME_PATH:
 				path = nm_setting_802_1x_get_phase2_client_cert_path (setting);
diff --git a/src/supplicant-manager/nm-supplicant-config.h b/src/supplicant-manager/nm-supplicant-config.h
index dad23e29..a8d30470 100644
--- a/src/supplicant-manager/nm-supplicant-config.h
+++ b/src/supplicant-manager/nm-supplicant-config.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) 2006 - 2008 Red Hat, Inc.
+ * Copyright (C) 2006 - 2012 Red Hat, Inc.
  * Copyright (C) 2007 - 2008 Novell, Inc.
  */
 
@@ -57,6 +57,8 @@ guint32 nm_supplicant_config_get_ap_scan (NMSupplicantConfig *self);
 void nm_supplicant_config_set_ap_scan (NMSupplicantConfig *self,
                                        guint32 ap_scan);
 
+gboolean nm_supplicant_config_fast_required (NMSupplicantConfig *self);
+
 GHashTable *nm_supplicant_config_get_hash (NMSupplicantConfig *self);
 
 GHashTable *nm_supplicant_config_get_blobs (NMSupplicantConfig *self);
@@ -70,13 +72,13 @@ gboolean nm_supplicant_config_add_setting_wireless (NMSupplicantConfig *self,
 gboolean nm_supplicant_config_add_setting_wireless_security (NMSupplicantConfig *self,
                                                              NMSettingWirelessSecurity *setting,
                                                              NMSetting8021x *setting_8021x,
-                                                             const char *connection_uid);
+                                                             const char *con_uuid);
 
 gboolean nm_supplicant_config_add_no_security (NMSupplicantConfig *self);
 
 gboolean nm_supplicant_config_add_setting_8021x (NMSupplicantConfig *self,
                                                  NMSetting8021x *setting,
-                                                 const char *connection_uid,
+                                                 const char *con_uuid,
                                                  gboolean wired);
 
 G_END_DECLS
diff --git a/src/supplicant-manager/nm-supplicant-interface.c b/src/supplicant-manager/nm-supplicant-interface.c
index 857cde51..f8ad8f18 100644
--- a/src/supplicant-manager/nm-supplicant-interface.c
+++ b/src/supplicant-manager/nm-supplicant-interface.c
@@ -15,10 +15,11 @@
  * with this program; if not, write to the Free Software Foundation, Inc.,
  * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
  *
- * Copyright (C) 2006 - 2010 Red Hat, Inc.
+ * Copyright (C) 2006 - 2012 Red Hat, Inc.
  * Copyright (C) 2006 - 2008 Novell, Inc.
  */
 
+#include <config.h>
 #include <stdio.h>
 #include <string.h>
 #include <glib.h>
@@ -55,11 +56,14 @@ static void wpas_iface_scan_done (DBusGProxy *proxy,
 
 /* Signals */
 enum {
-	STATE,             /* change in the interface's state */
-	REMOVED,           /* interface was removed by the supplicant */
-	NEW_BSS,           /* interface saw a new access point from a scan */
-	SCAN_DONE,         /* wifi scan is complete */
-	CONNECTION_ERROR,  /* an error occurred during a connection request */
+	STATE,               /* change in the interface's state */
+	REMOVED,             /* interface was removed by the supplicant */
+	NEW_BSS,             /* interface saw a new access point from a scan */
+	BSS_UPDATED,         /* a BSS property changed */
+	BSS_REMOVED,         /* supplicant removed BSS from its scan list */
+	SCAN_DONE,           /* wifi scan is complete */
+	CONNECTION_ERROR,    /* an error occurred during a connection request */
+	CREDENTIALS_REQUEST, /* 802.1x identity or password requested */
 	LAST_SIGNAL
 };
 static guint signals[LAST_SIGNAL] = { 0 };
@@ -79,6 +83,8 @@ typedef struct {
 	NMDBusManager *       dbus_mgr;
 	char *                dev;
 	gboolean              is_wireless;
+	gboolean              has_credreq;  /* Whether querying 802.1x credentials is supported */
+	gboolean              fast_supported;
 
 	char *                object_path;
 	guint32               state;
@@ -92,6 +98,7 @@ typedef struct {
 	DBusGProxy *          props_proxy;
 	char *                net_path;
 	guint32               blobs_left;
+	GHashTable *          bss_proxies;
 
 	guint32               last_scan;
 
@@ -100,6 +107,28 @@ typedef struct {
 	gboolean              disposed;
 } NMSupplicantInterfacePrivate;
 
+/* FIXME: remove this and just store the standard D-Bus properties
+ * proxy object in bss_proxies when we drop support for wpa_supplicant
+ * 0.7.x.
+ */
+typedef struct {
+	/* Proxy for standard D-Bus Properties interface */
+	DBusGProxy *props;
+	/* Proxy for old wpa_supplicant-specific PropertiesChanged signal */
+	DBusGProxy *old_props;
+} BssProxies;
+
+static void
+bss_proxies_free (gpointer data)
+{
+	BssProxies *proxies = data;
+
+	g_object_unref (proxies->props);
+	g_object_unref (proxies->old_props);
+	memset (proxies, 0, sizeof (*proxies));
+	g_free (proxies);
+}
+
 static gboolean
 cancel_all_cb (GObject *object, gpointer call_id, gpointer user_data)
 {
@@ -192,6 +221,14 @@ emit_error_helper (NMSupplicantInterface *self,
 }
 
 static void
+signal_new_bss (NMSupplicantInterface *self,
+                const char *object_path,
+                GHashTable *props)
+{
+	g_signal_emit (self, signals[NEW_BSS], 0, object_path, props);
+}
+
+static void
 bssid_properties_cb  (DBusGProxy *proxy, DBusGProxyCall *call_id, gpointer user_data)
 {
 	NMSupplicantInfo *info = (NMSupplicantInfo *) user_data;
@@ -201,7 +238,7 @@ bssid_properties_cb  (DBusGProxy *proxy, DBusGProxyCall *call_id, gpointer user_
 	if (dbus_g_proxy_end_call (proxy, call_id, &error,
 	                           DBUS_TYPE_G_MAP_OF_VARIANT, &props,
 	                           G_TYPE_INVALID)) {
-		g_signal_emit (info->interface, signals[NEW_BSS], 0, props);
+		signal_new_bss (info->interface, dbus_g_proxy_get_path (proxy), props);
 		g_hash_table_destroy (props);
 	} else {
 		if (!strstr (error->message, "The BSSID requested was invalid")) {
@@ -213,31 +250,93 @@ bssid_properties_cb  (DBusGProxy *proxy, DBusGProxyCall *call_id, gpointer user_
 }
 
 static void
-request_bss_properties (NMSupplicantInterface *self,
-                        GPtrArray *paths)
+bss_properties_changed (DBusGProxy *proxy,
+                        const char *interface,
+                        GHashTable *props,
+                        const char **unused,
+                        gpointer user_data)
+{
+	NMSupplicantInterface *self = NM_SUPPLICANT_INTERFACE (user_data);
+
+	if (g_strcmp0 (interface, WPAS_DBUS_IFACE_BSS) == 0)
+		g_signal_emit (self, signals[BSS_UPDATED], 0, dbus_g_proxy_get_path (proxy), props);
+}
+
+static void
+old_bss_properties_changed (DBusGProxy *proxy,
+                            GHashTable *props,
+                            gpointer user_data)
+{
+	NMSupplicantInterface *self = NM_SUPPLICANT_INTERFACE (user_data);
+
+	g_signal_emit (self, signals[BSS_UPDATED], 0, dbus_g_proxy_get_path (proxy), props);
+}
+
+static void
+handle_new_bss (NMSupplicantInterface *self,
+                const char *object_path,
+                GHashTable *props)
 {
 	NMSupplicantInterfacePrivate *priv = NM_SUPPLICANT_INTERFACE_GET_PRIVATE (self);
-	int i;
-
-	/* Fire off a "properties" call for each returned BSSID */
-	for (i = 0; i < paths->len; i++) {
-		NMSupplicantInfo *info;
-		DBusGProxy *proxy;
-		DBusGProxyCall *call;
-
-		proxy = dbus_g_proxy_new_for_name (nm_dbus_manager_get_connection (priv->dbus_mgr),
-			                               WPAS_DBUS_SERVICE,
-			                               g_ptr_array_index (paths, i),
-			                               DBUS_INTERFACE_PROPERTIES);
-		info = nm_supplicant_info_new (self, proxy, priv->other_pcalls);
-		call = dbus_g_proxy_begin_call (proxy, "GetAll",
-			                            bssid_properties_cb,
-			                            info,
-			                            nm_supplicant_info_destroy,
-			                            G_TYPE_STRING, WPAS_DBUS_IFACE_BSS,
-			                            G_TYPE_INVALID);
+	NMSupplicantInfo *info;
+	DBusGProxyCall *call;
+	BssProxies *proxies;
+
+	g_return_if_fail (object_path != NULL);
+
+	if (g_hash_table_lookup (priv->bss_proxies, object_path))
+		return;
+
+	proxies = g_malloc0 (sizeof (*proxies));
+	proxies->props = dbus_g_proxy_new_for_name (nm_dbus_manager_get_connection (priv->dbus_mgr),
+	                                            WPAS_DBUS_SERVICE,
+	                                            object_path,
+	                                            DBUS_INTERFACE_PROPERTIES);
+	proxies->old_props = dbus_g_proxy_new_for_name (nm_dbus_manager_get_connection (priv->dbus_mgr),
+	                                                WPAS_DBUS_SERVICE,
+	                                                object_path,
+	                                                WPAS_DBUS_IFACE_BSS);
+	g_hash_table_insert (priv->bss_proxies,
+	                     (gpointer) dbus_g_proxy_get_path (proxies->props),
+	                     proxies);
+
+	/* Standard D-Bus PropertiesChanged signal */
+	dbus_g_object_register_marshaller (_nm_marshal_VOID__STRING_BOXED_BOXED,
+	                                   G_TYPE_NONE,
+	                                   G_TYPE_STRING, DBUS_TYPE_G_MAP_OF_VARIANT, G_TYPE_STRV,
+	                                   G_TYPE_INVALID);
+	dbus_g_proxy_add_signal (proxies->props, "PropertiesChanged",
+	                         G_TYPE_STRING, DBUS_TYPE_G_MAP_OF_VARIANT, G_TYPE_STRV,
+	                         G_TYPE_INVALID);
+	dbus_g_proxy_connect_signal (proxies->props, "PropertiesChanged",
+	                             G_CALLBACK (bss_properties_changed),
+	                             self, NULL);
+
+	/* Old wpa_supplicant-specific PropertiesChanged signal; since it's using
+	 * a different interface, we have to use a different DBusGProxy
+	 */
+	dbus_g_object_register_marshaller (g_cclosure_marshal_VOID__BOXED,
+	                                   G_TYPE_NONE,
+	                                   DBUS_TYPE_G_MAP_OF_VARIANT,
+	                                   G_TYPE_INVALID);
+	dbus_g_proxy_add_signal (proxies->old_props, "PropertiesChanged",
+	                         DBUS_TYPE_G_MAP_OF_VARIANT,
+	                         G_TYPE_INVALID);
+	dbus_g_proxy_connect_signal (proxies->old_props, "PropertiesChanged",
+	                             G_CALLBACK (old_bss_properties_changed),
+	                             self, NULL);
+
+	if (props) {
+		signal_new_bss (self, object_path, props);
+	} else {
+		info = nm_supplicant_info_new (self, proxies->props, priv->other_pcalls);
+		call = dbus_g_proxy_begin_call (proxies->props, "GetAll",
+		                                bssid_properties_cb,
+		                                info,
+		                                nm_supplicant_info_destroy,
+		                                G_TYPE_STRING, WPAS_DBUS_IFACE_BSS,
+		                                G_TYPE_INVALID);
 		nm_supplicant_info_set_call (info, call);
-		g_object_unref (proxy);
 	}
 }
 
@@ -247,7 +346,20 @@ wpas_iface_bss_added (DBusGProxy *proxy,
                       GHashTable *props,
                       gpointer user_data)
 {
-	g_signal_emit (NM_SUPPLICANT_INTERFACE (user_data), signals[NEW_BSS], 0, props);
+	handle_new_bss (NM_SUPPLICANT_INTERFACE (user_data), object_path, props);
+}
+
+static void
+wpas_iface_bss_removed (DBusGProxy *proxy,
+                        const char *object_path,
+                        gpointer user_data)
+{
+	NMSupplicantInterface *self = NM_SUPPLICANT_INTERFACE (user_data);
+	NMSupplicantInterfacePrivate *priv = NM_SUPPLICANT_INTERFACE_GET_PRIVATE (self);
+
+	g_signal_emit (self, signals[BSS_REMOVED], 0, object_path);
+
+	g_hash_table_remove (priv->bss_proxies, object_path);
 }
 
 static int
@@ -318,6 +430,10 @@ set_state (NMSupplicantInterface *self, guint32 new_state)
 			                                "BSSAdded",
 			                                G_CALLBACK (wpas_iface_bss_added),
 			                                self);
+			dbus_g_proxy_disconnect_signal (priv->iface_proxy,
+			                                "BSSRemoved",
+			                                G_CALLBACK (wpas_iface_bss_removed),
+			                                self);
 		}
 	}
 
@@ -403,8 +519,13 @@ wpas_iface_properties_changed (DBusGProxy *proxy,
 		set_state_from_string (self, g_value_get_string (value));
 
 	value = g_hash_table_lookup (props, "BSSs");
-	if (value && G_VALUE_HOLDS (value, DBUS_TYPE_G_ARRAY_OF_OBJECT_PATH))
-		request_bss_properties (self, g_value_get_boxed (value));
+	if (value && G_VALUE_HOLDS (value, DBUS_TYPE_G_ARRAY_OF_OBJECT_PATH)) {
+		GPtrArray *paths = g_value_get_boxed (value);
+		int i;
+
+		for (i = 0; paths && (i < paths->len); i++)
+			handle_new_bss (self, g_ptr_array_index (paths, i), NULL);
+	}
 }
 
 static void
@@ -443,6 +564,92 @@ wpas_iface_get_props (NMSupplicantInterface *self)
 	nm_supplicant_info_set_call (info, call);
 }
 
+gboolean
+nm_supplicant_interface_credentials_reply (NMSupplicantInterface *self,
+                                           const char *field,
+                                           const char *value,
+                                           GError **error)
+{
+	NMSupplicantInterfacePrivate *priv;
+
+	g_return_val_if_fail (self != NULL, FALSE);
+	g_return_val_if_fail (NM_IS_SUPPLICANT_INTERFACE (self), FALSE);
+	g_return_val_if_fail (field != NULL, FALSE);
+	g_return_val_if_fail (value != NULL, FALSE);
+
+	priv = NM_SUPPLICANT_INTERFACE_GET_PRIVATE (self);
+	g_return_val_if_fail (priv->has_credreq == TRUE, FALSE);
+
+	/* Need a network block object path */
+	g_return_val_if_fail (priv->net_path, FALSE);
+	return dbus_g_proxy_call_with_timeout (priv->iface_proxy, "NetworkReply",
+	                                       5000,
+	                                       error,
+	                                       DBUS_TYPE_G_OBJECT_PATH, priv->net_path,
+	                                       G_TYPE_STRING, field,
+	                                       G_TYPE_STRING, value,
+	                                       G_TYPE_INVALID);
+}
+
+static void
+wpas_iface_network_request (DBusGProxy *proxy,
+                            const char *object_path,
+                            const char *field,
+                            const char *message,
+                            gpointer user_data)
+{
+	NMSupplicantInterface *self = NM_SUPPLICANT_INTERFACE (user_data);
+	NMSupplicantInterfacePrivate *priv = NM_SUPPLICANT_INTERFACE_GET_PRIVATE (self);
+
+	g_return_if_fail (priv->has_credreq == TRUE);
+	g_return_if_fail (priv->net_path != NULL);
+	g_return_if_fail (g_strcmp0 (object_path, priv->net_path) == 0);
+
+	g_signal_emit (self, signals[CREDENTIALS_REQUEST], 0, field, message);
+}
+
+static void
+iface_check_netreply_cb (DBusGProxy *proxy, DBusGProxyCall *call_id, gpointer user_data)
+{
+	NMSupplicantInfo *info = (NMSupplicantInfo *) user_data;
+	NMSupplicantInterfacePrivate *priv = NM_SUPPLICANT_INTERFACE_GET_PRIVATE (info->interface);
+	GError *error = NULL;
+
+	if (   dbus_g_proxy_end_call (proxy, call_id, &error, G_TYPE_INVALID)
+	    || dbus_g_error_has_name (error, "fi.w1.wpa_supplicant1.InvalidArgs")) {
+		/* We know NetworkReply is supported if the NetworkReply method returned
+		 * successfully (which is unexpected since we sent a bogus network
+		 * object path) or if we got an "InvalidArgs" (which indicates NetworkReply
+		 * is supported).  We know it's not supported if we get an
+		 * "UnknownMethod" error.
+		 */
+		priv->has_credreq = TRUE;
+
+		nm_log_dbg (LOGD_SUPPLICANT, "Supplicant %s network credentials requests",
+			        priv->has_credreq ? "supports" : "does not support");
+	}
+	g_clear_error (&error);
+}
+
+static void
+wpas_iface_check_network_reply (NMSupplicantInterface *self)
+{
+	NMSupplicantInterfacePrivate *priv = NM_SUPPLICANT_INTERFACE_GET_PRIVATE (self);
+	NMSupplicantInfo *info;
+	DBusGProxyCall *call;
+
+	info = nm_supplicant_info_new (self, priv->props_proxy, priv->other_pcalls);
+	call = dbus_g_proxy_begin_call (priv->iface_proxy, "NetworkReply",
+	                                iface_check_netreply_cb,
+	                                info,
+	                                nm_supplicant_info_destroy,
+	                                DBUS_TYPE_G_OBJECT_PATH, "/foobaraasdfasdf",
+	                                G_TYPE_STRING, "foobar",
+	                                G_TYPE_STRING, "foobar",
+	                                G_TYPE_INVALID);
+	nm_supplicant_info_set_call (info, call);
+}
+
 static void
 interface_add_done (NMSupplicantInterface *self, char *path)
 {
@@ -486,6 +693,30 @@ interface_add_done (NMSupplicantInterface *self, char *path)
 	                             self,
 	                             NULL);
 
+	dbus_g_object_register_marshaller (g_cclosure_marshal_VOID__BOXED,
+	                                   G_TYPE_NONE,
+	                                   DBUS_TYPE_G_OBJECT_PATH,
+	                                   G_TYPE_INVALID);
+	dbus_g_proxy_add_signal (priv->iface_proxy, "BSSRemoved",
+	                         DBUS_TYPE_G_OBJECT_PATH,
+	                         G_TYPE_INVALID);
+	dbus_g_proxy_connect_signal (priv->iface_proxy, "BSSRemoved",
+	                             G_CALLBACK (wpas_iface_bss_removed),
+	                             self,
+	                             NULL);
+
+	dbus_g_object_register_marshaller (_nm_marshal_VOID__STRING_STRING_STRING,
+	                                   G_TYPE_NONE,
+	                                   DBUS_TYPE_G_OBJECT_PATH, G_TYPE_STRING, G_TYPE_STRING,
+	                                   G_TYPE_INVALID);
+	dbus_g_proxy_add_signal (priv->iface_proxy, "NetworkRequest",
+	                         DBUS_TYPE_G_OBJECT_PATH, G_TYPE_STRING, G_TYPE_STRING,
+	                         G_TYPE_INVALID);
+	dbus_g_proxy_connect_signal (priv->iface_proxy, "NetworkRequest",
+	                             G_CALLBACK (wpas_iface_network_request),
+	                             self,
+	                             NULL);
+
 	priv->props_proxy = dbus_g_proxy_new_for_name (nm_dbus_manager_get_connection (priv->dbus_mgr),
 	                                               WPAS_DBUS_SERVICE,
 	                                               path,
@@ -493,6 +724,9 @@ interface_add_done (NMSupplicantInterface *self, char *path)
 	/* Get initial properties */
 	wpas_iface_get_props (self);
 
+	/* Check whether NetworkReply is supported */
+	wpas_iface_check_network_reply (self);
+
 	set_state (self, NM_SUPPLICANT_INTERFACE_STATE_READY);
 }
 
@@ -574,6 +808,12 @@ interface_add_cb (DBusGProxy *proxy,
 	}
 }
 
+#if HAVE_WEXT
+#define DEFAULT_WIFI_DRIVER "nl80211,wext"
+#else
+#define DEFAULT_WIFI_DRIVER "nl80211"
+#endif
+
 static void
 interface_add (NMSupplicantInterface *self, gboolean is_wireless)
 {
@@ -602,7 +842,7 @@ interface_add (NMSupplicantInterface *self, gboolean is_wireless)
 
 	driver = g_new0 (GValue, 1);
 	g_value_init (driver, G_TYPE_STRING);
-	g_value_set_string (driver, is_wireless ? "nl80211,wext" : "wired");
+	g_value_set_string (driver, is_wireless ? DEFAULT_WIFI_DRIVER : "wired");
 	g_hash_table_insert (hash, "Driver", driver);
 
 	ifname = g_new0 (GValue, 1);
@@ -851,7 +1091,15 @@ nm_supplicant_interface_set_config (NMSupplicantInterface * self,
 	priv = NM_SUPPLICANT_INTERFACE_GET_PRIVATE (self);
 
 	nm_supplicant_interface_disconnect (self);
-	
+
+	/* Make sure the supplicant supports EAP-FAST before trying to send
+	 * it an EAP-FAST configuration.
+	 */
+	if (nm_supplicant_config_fast_required (cfg) && !priv->fast_supported) {
+		nm_log_warn (LOGD_SUPPLICANT, "EAP-FAST is not supported by the supplicant");
+		return FALSE;
+	}
+
 	if (priv->cfg)
 		g_object_unref (priv->cfg);
 	priv->cfg = cfg;
@@ -1017,6 +1265,7 @@ NMSupplicantInterface *
 nm_supplicant_interface_new (NMSupplicantManager *smgr,
                              const char *ifname,
                              gboolean is_wireless,
+                             gboolean fast_supported,
                              gboolean start_now)
 {
 	NMSupplicantInterface *self;
@@ -1039,6 +1288,7 @@ nm_supplicant_interface_new (NMSupplicantManager *smgr,
 
 		priv->dev = g_strdup (ifname);
 		priv->is_wireless = is_wireless;
+		priv->fast_supported = fast_supported;
 
 		if (start_now)
 			interface_add (self, priv->is_wireless);
@@ -1063,6 +1313,8 @@ nm_supplicant_interface_init (NMSupplicantInterface * self)
 	                                              WPAS_DBUS_SERVICE,
 	                                              WPAS_DBUS_PATH,
 	                                              WPAS_DBUS_INTERFACE);
+
+	priv->bss_proxies = g_hash_table_new_full (g_str_hash, g_str_equal, NULL, bss_proxies_free);
 }
 
 static void
@@ -1123,6 +1375,8 @@ dispose (GObject *object)
 	if (priv->wpas_proxy)
 		g_object_unref (priv->wpas_proxy);
 
+	g_hash_table_destroy (priv->bss_proxies);
+
 	if (priv->smgr) {
 		if (priv->smgr_avail_id)
 			g_signal_handler_disconnect (priv->smgr, priv->smgr_avail_id);
@@ -1187,8 +1441,26 @@ nm_supplicant_interface_class_init (NMSupplicantInterfaceClass *klass)
 		              G_SIGNAL_RUN_LAST,
 		              G_STRUCT_OFFSET (NMSupplicantInterfaceClass, new_bss),
 		              NULL, NULL,
-		              g_cclosure_marshal_VOID__POINTER,
-		              G_TYPE_NONE, 1, G_TYPE_POINTER);
+		              _nm_marshal_VOID__STRING_POINTER,
+		              G_TYPE_NONE, 2, G_TYPE_STRING, G_TYPE_POINTER);
+
+	signals[BSS_UPDATED] =
+		g_signal_new (NM_SUPPLICANT_INTERFACE_BSS_UPDATED,
+		              G_OBJECT_CLASS_TYPE (object_class),
+		              G_SIGNAL_RUN_LAST,
+		              G_STRUCT_OFFSET (NMSupplicantInterfaceClass, bss_updated),
+		              NULL, NULL,
+		              _nm_marshal_VOID__STRING_POINTER,
+		              G_TYPE_NONE, 2, G_TYPE_STRING, G_TYPE_POINTER);
+
+	signals[BSS_REMOVED] =
+		g_signal_new (NM_SUPPLICANT_INTERFACE_BSS_REMOVED,
+		              G_OBJECT_CLASS_TYPE (object_class),
+		              G_SIGNAL_RUN_LAST,
+		              G_STRUCT_OFFSET (NMSupplicantInterfaceClass, bss_removed),
+		              NULL, NULL,
+		              g_cclosure_marshal_VOID__STRING,
+		              G_TYPE_NONE, 1, G_TYPE_STRING);
 
 	signals[SCAN_DONE] =
 		g_signal_new (NM_SUPPLICANT_INTERFACE_SCAN_DONE,
@@ -1207,5 +1479,14 @@ nm_supplicant_interface_class_init (NMSupplicantInterfaceClass *klass)
 		              NULL, NULL,
 		              _nm_marshal_VOID__STRING_STRING,
 		              G_TYPE_NONE, 2, G_TYPE_STRING, G_TYPE_STRING);
+
+	signals[CREDENTIALS_REQUEST] =
+		g_signal_new (NM_SUPPLICANT_INTERFACE_CREDENTIALS_REQUEST,
+		              G_OBJECT_CLASS_TYPE (object_class),
+		              G_SIGNAL_RUN_LAST,
+		              G_STRUCT_OFFSET (NMSupplicantInterfaceClass, credentials_request),
+		              NULL, NULL,
+		              _nm_marshal_VOID__STRING_STRING,
+		              G_TYPE_NONE, 2, G_TYPE_STRING, G_TYPE_STRING);
 }
 
diff --git a/src/supplicant-manager/nm-supplicant-interface.h b/src/supplicant-manager/nm-supplicant-interface.h
index e32411d7..608ee059 100644
--- a/src/supplicant-manager/nm-supplicant-interface.h
+++ b/src/supplicant-manager/nm-supplicant-interface.h
@@ -57,8 +57,11 @@ enum {
 #define NM_SUPPLICANT_INTERFACE_STATE            "state"
 #define NM_SUPPLICANT_INTERFACE_REMOVED          "removed"
 #define NM_SUPPLICANT_INTERFACE_NEW_BSS          "new-bss"
+#define NM_SUPPLICANT_INTERFACE_BSS_UPDATED      "bss-updated"
+#define NM_SUPPLICANT_INTERFACE_BSS_REMOVED      "bss-removed"
 #define NM_SUPPLICANT_INTERFACE_SCAN_DONE        "scan-done"
 #define NM_SUPPLICANT_INTERFACE_CONNECTION_ERROR "connection-error"
+#define NM_SUPPLICANT_INTERFACE_CREDENTIALS_REQUEST "credentials-request"
 
 struct _NMSupplicantInterface {
 	GObject parent;
@@ -79,8 +82,18 @@ typedef struct {
 
 	/* interface saw a new BSS */
 	void (*new_bss)          (NMSupplicantInterface *iface,
+	                          const char *object_path,
 	                          GHashTable *props);
 
+	/* a BSS property changed */
+	void (*bss_updated)      (NMSupplicantInterface *iface,
+	                          const char *object_path,
+	                          GHashTable *props);
+
+	/* supplicant removed a BSS from its scan list */
+	void (*bss_removed)      (NMSupplicantInterface *iface,
+	                          const char *object_path);
+
 	/* wireless scan is done */
 	void (*scan_done)        (NMSupplicantInterface *iface,
 	                          gboolean success);
@@ -89,6 +102,11 @@ typedef struct {
 	void (*connection_error) (NMSupplicantInterface * iface,
 	                          const char * name,
 	                          const char * message);
+
+	/* 802.1x credentials requested */
+	void (*credentials_request) (NMSupplicantInterface *iface,
+	                             const char *field,
+	                             const char *message);
 } NMSupplicantInterfaceClass;
 
 
@@ -97,6 +115,7 @@ GType nm_supplicant_interface_get_type (void);
 NMSupplicantInterface * nm_supplicant_interface_new (NMSupplicantManager * smgr,
                                                      const char *ifname,
                                                      gboolean is_wireless,
+                                                     gboolean fast_supported,
                                                      gboolean start_now);
 
 gboolean nm_supplicant_interface_set_config (NMSupplicantInterface * iface,
@@ -118,4 +137,11 @@ gboolean nm_supplicant_interface_get_scanning (NMSupplicantInterface *self);
 
 const char *nm_supplicant_interface_get_ifname (NMSupplicantInterface *self);
 
+gboolean nm_supplicant_interface_get_has_credentials_request (NMSupplicantInterface *self);
+
+gboolean nm_supplicant_interface_credentials_reply (NMSupplicantInterface *self,
+                                                    const char *field,
+                                                    const char *value,
+                                                    GError **error);
+
 #endif	/* NM_SUPPLICANT_INTERFACE_H */
diff --git a/src/supplicant-manager/nm-supplicant-manager.c b/src/supplicant-manager/nm-supplicant-manager.c
index 349f722a..ae150865 100644
--- a/src/supplicant-manager/nm-supplicant-manager.c
+++ b/src/supplicant-manager/nm-supplicant-manager.c
@@ -86,7 +86,7 @@ nm_supplicant_manager_iface_get (NMSupplicantManager * self,
 		start_now = !die_count_exceeded (priv->die_count);
 
 		nm_log_dbg (LOGD_SUPPLICANT, "(%s): creating new supplicant interface", ifname);
-		iface = nm_supplicant_interface_new (self, ifname, is_wireless, start_now);
+		iface = nm_supplicant_interface_new (self, ifname, is_wireless, priv->fast_supported, start_now);
 		if (iface)
 			g_hash_table_insert (priv->ifaces, g_strdup (ifname), iface);
 	} else {
diff --git a/src/supplicant-manager/nm-supplicant-settings-verify.c b/src/supplicant-manager/nm-supplicant-settings-verify.c
index aea5bfec..76de84d8 100644
--- a/src/supplicant-manager/nm-supplicant-settings-verify.c
+++ b/src/supplicant-manager/nm-supplicant-settings-verify.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) 2006 - 2008 Red Hat, Inc.
+ * Copyright (C) 2006 - 2012 Red Hat, Inc.
  */
 
 #include <glib.h>
@@ -44,6 +44,10 @@ static gboolean validate_type_bytes   (const struct Opt * opt,
                                        const char * value,
                                        const guint32 len);
 
+static gboolean validate_type_utf8    (const struct Opt *opt,
+                                       const char * value,
+                                       const guint32 len);
+
 static gboolean validate_type_keyword (const struct Opt * opt,
                                        const char * value,
                                        const guint32 len);
@@ -58,6 +62,7 @@ struct validate_entry {
 static const struct validate_entry validate_table[] = {
 	{ TYPE_INT,     validate_type_int     },
 	{ TYPE_BYTES,   validate_type_bytes   },
+	{ TYPE_UTF8,    validate_type_utf8    },
 	{ TYPE_KEYWORD, validate_type_keyword },
 };
 
@@ -73,7 +78,9 @@ const char * eap_allowed[] =      { "LEAP", "MD5", "TLS", "PEAP", "TTLS", "SIM",
 
 const char * phase1_allowed[] =   {"peapver=0", "peapver=1", "peaplabel=1",
                                     "peap_outer_success=0", "include_tls_length=1",
-                                    "sim_min_num_chal=3", NULL };
+                                    "sim_min_num_chal=3", "fast_provisioning=0",
+                                    "fast_provisioning=1", "fast_provisioning=2",
+                                    "fast_provisioning=3", NULL };
 const char * phase2_allowed[] =   {"auth=PAP", "auth=CHAP", "auth=MSCHAP",
                                    "auth=MSCHAPV2", "auth=GTC", "auth=OTP",
                                    "auth=MD5", "auth=TLS", "autheap=MD5",
@@ -100,7 +107,7 @@ static const struct Opt opt_table[] = {
 	{ "eapol_flags",        TYPE_INT,     0, 3, FALSE,  NULL },
 	{ "eap",                TYPE_KEYWORD, 0, 0, FALSE,  eap_allowed },
 	{ "identity",           TYPE_BYTES,   0, 0, FALSE,  NULL },
-	{ "password",           TYPE_BYTES,   0, 0, FALSE,  NULL },
+	{ "password",           TYPE_UTF8,    0, 0, FALSE,  NULL },
 	{ "ca_path",            TYPE_BYTES,   0, 0, FALSE,  NULL },
 	{ "subject_match",      TYPE_BYTES,   0, 0, FALSE,  NULL },
 	{ "altsubject_match",   TYPE_BYTES,   0, 0, FALSE,  NULL },
@@ -129,6 +136,7 @@ static const struct Opt opt_table[] = {
 	{ "fragment_size",      TYPE_INT,     1, 2000, FALSE,  NULL },
 	{ "proactive_key_caching", TYPE_INT,  0, 1, FALSE,  NULL },
 	{ "bgscan",             TYPE_BYTES,   0, 0, FALSE,  NULL },
+	{ "pac_file",           TYPE_BYTES,   0, 1024, FALSE,  NULL },
 };
 
 
@@ -174,6 +182,26 @@ validate_type_bytes (const struct Opt * opt,
 }
 
 static gboolean
+validate_type_utf8 (const struct Opt *opt,
+                    const char * value,
+                    const guint32 len)
+{
+	guint32 check_len;
+
+	g_return_val_if_fail (opt != NULL, FALSE);
+	g_return_val_if_fail (value != NULL, FALSE);
+
+	check_len = opt->int_high ? opt->int_high : 255;
+	/* Note that we deliberately don't validate the UTF-8, because
+	   some "UTF-8" fields, such as 8021x.password, do not actually
+	   have to be valid UTF-8 */
+	if (g_utf8_strlen (value, len) > check_len)
+		return FALSE;
+
+	return TRUE;
+}
+
+static gboolean
 validate_type_keyword (const struct Opt * opt,
                        const char * value,
                        const guint32 len)
diff --git a/src/supplicant-manager/nm-supplicant-settings-verify.h b/src/supplicant-manager/nm-supplicant-settings-verify.h
index 0939ebdb..eb213e0e 100644
--- a/src/supplicant-manager/nm-supplicant-settings-verify.h
+++ b/src/supplicant-manager/nm-supplicant-settings-verify.h
@@ -21,10 +21,11 @@
 #ifndef NM_SUPPLICANT_SETTINGS_VERIFY_H
 #define NM_SUPPLICANT_SETTINGS_VERIFY_H
 
-typedef enum OptType {
+typedef enum {
 	TYPE_INVALID = 0,
 	TYPE_INT,
 	TYPE_BYTES,
+	TYPE_UTF8,
 	TYPE_KEYWORD,
 	TYPE_STRING
 } OptType;
diff --git a/src/supplicant-manager/tests/Makefile.am b/src/supplicant-manager/tests/Makefile.am
index b5e4db61..47ae66c5 100644
--- a/src/supplicant-manager/tests/Makefile.am
+++ b/src/supplicant-manager/tests/Makefile.am
@@ -1,6 +1,8 @@
 INCLUDES = \
 	-I$(top_srcdir)/include \
+	-I$(top_builddir)/include \
 	-I$(top_srcdir)/libnm-util \
+	-I$(top_builddir)/libnm-util \
 	-I$(top_srcdir)/src \
 	-I$(top_srcdir)/src/supplicant-manager
 
diff --git a/src/supplicant-manager/tests/Makefile.in b/src/supplicant-manager/tests/Makefile.in
index 25e60e86..65be2b39 100644
--- a/src/supplicant-manager/tests/Makefile.in
+++ b/src/supplicant-manager/tests/Makefile.in
@@ -143,6 +143,8 @@ GIO_LIBS = @GIO_LIBS@
 GLIB_CFLAGS = @GLIB_CFLAGS@
 GLIB_GENMARSHAL = @GLIB_GENMARSHAL@
 GLIB_LIBS = @GLIB_LIBS@
+GLIB_MAKEFILE = @GLIB_MAKEFILE@
+GLIB_MKENUMS = @GLIB_MKENUMS@
 GMODULE_CFLAGS = @GMODULE_CFLAGS@
 GMODULE_LIBS = @GMODULE_LIBS@
 GMSGFMT = @GMSGFMT@
@@ -197,11 +199,15 @@ LIBNL2_LIBS = @LIBNL2_LIBS@
 LIBNL3_CFLAGS = @LIBNL3_CFLAGS@
 LIBNL3_LIBS = @LIBNL3_LIBS@
 LIBNL_CFLAGS = @LIBNL_CFLAGS@
+LIBNL_GENL3_CFLAGS = @LIBNL_GENL3_CFLAGS@
+LIBNL_GENL3_LIBS = @LIBNL_GENL3_LIBS@
 LIBNL_LIBS = @LIBNL_LIBS@
 LIBNL_ROUTE3_CFLAGS = @LIBNL_ROUTE3_CFLAGS@
 LIBNL_ROUTE3_LIBS = @LIBNL_ROUTE3_LIBS@
 LIBOBJS = @LIBOBJS@
 LIBS = @LIBS@
+LIBSOUP_CFLAGS = @LIBSOUP_CFLAGS@
+LIBSOUP_LIBS = @LIBSOUP_LIBS@
 LIBTOOL = @LIBTOOL@
 LIPO = @LIPO@
 LN_S = @LN_S@
@@ -212,6 +218,7 @@ MAINT = @MAINT@
 MAKEINFO = @MAKEINFO@
 MANIFEST_TOOL = @MANIFEST_TOOL@
 MKDIR_P = @MKDIR_P@
+MOC = @MOC@
 MSGFMT = @MSGFMT@
 MSGFMT_015 = @MSGFMT_015@
 MSGMERGE = @MSGMERGE@
@@ -251,6 +258,8 @@ SED = @SED@
 SET_MAKE = @SET_MAKE@
 SHELL = @SHELL@
 STRIP = @STRIP@
+SYSTEMD_CFLAGS = @SYSTEMD_CFLAGS@
+SYSTEMD_LIBS = @SYSTEMD_LIBS@
 SYSTEM_CA_PATH = @SYSTEM_CA_PATH@
 UDEV_BASE_DIR = @UDEV_BASE_DIR@
 USE_NLS = @USE_NLS@
@@ -316,7 +325,9 @@ top_builddir = @top_builddir@
 top_srcdir = @top_srcdir@
 INCLUDES = \
 	-I$(top_srcdir)/include \
+	-I$(top_builddir)/include \
 	-I$(top_srcdir)/libnm-util \
+	-I$(top_builddir)/libnm-util \
 	-I$(top_srcdir)/src \
 	-I$(top_srcdir)/src/supplicant-manager
 
diff --git a/src/tests/Makefile.am b/src/tests/Makefile.am
index 296668aa..90487042 100644
--- a/src/tests/Makefile.am
+++ b/src/tests/Makefile.am
@@ -1,6 +1,8 @@
 INCLUDES = \
 	-I$(top_srcdir)/include \
+	-I$(top_builddir)/include \
 	-I$(top_srcdir)/libnm-util \
+	-I$(top_builddir)/libnm-util \
 	-I$(top_srcdir)/src/dhcp-manager \
 	-I$(top_builddir)/marshallers \
 	-I$(top_srcdir)/src \
diff --git a/src/tests/Makefile.in b/src/tests/Makefile.in
index 39390e4b..7d367415 100644
--- a/src/tests/Makefile.in
+++ b/src/tests/Makefile.in
@@ -160,6 +160,8 @@ GIO_LIBS = @GIO_LIBS@
 GLIB_CFLAGS = @GLIB_CFLAGS@
 GLIB_GENMARSHAL = @GLIB_GENMARSHAL@
 GLIB_LIBS = @GLIB_LIBS@
+GLIB_MAKEFILE = @GLIB_MAKEFILE@
+GLIB_MKENUMS = @GLIB_MKENUMS@
 GMODULE_CFLAGS = @GMODULE_CFLAGS@
 GMODULE_LIBS = @GMODULE_LIBS@
 GMSGFMT = @GMSGFMT@
@@ -214,11 +216,15 @@ LIBNL2_LIBS = @LIBNL2_LIBS@
 LIBNL3_CFLAGS = @LIBNL3_CFLAGS@
 LIBNL3_LIBS = @LIBNL3_LIBS@
 LIBNL_CFLAGS = @LIBNL_CFLAGS@
+LIBNL_GENL3_CFLAGS = @LIBNL_GENL3_CFLAGS@
+LIBNL_GENL3_LIBS = @LIBNL_GENL3_LIBS@
 LIBNL_LIBS = @LIBNL_LIBS@
 LIBNL_ROUTE3_CFLAGS = @LIBNL_ROUTE3_CFLAGS@
 LIBNL_ROUTE3_LIBS = @LIBNL_ROUTE3_LIBS@
 LIBOBJS = @LIBOBJS@
 LIBS = @LIBS@
+LIBSOUP_CFLAGS = @LIBSOUP_CFLAGS@
+LIBSOUP_LIBS = @LIBSOUP_LIBS@
 LIBTOOL = @LIBTOOL@
 LIPO = @LIPO@
 LN_S = @LN_S@
@@ -229,6 +235,7 @@ MAINT = @MAINT@
 MAKEINFO = @MAKEINFO@
 MANIFEST_TOOL = @MANIFEST_TOOL@
 MKDIR_P = @MKDIR_P@
+MOC = @MOC@
 MSGFMT = @MSGFMT@
 MSGFMT_015 = @MSGFMT_015@
 MSGMERGE = @MSGMERGE@
@@ -268,6 +275,8 @@ SED = @SED@
 SET_MAKE = @SET_MAKE@
 SHELL = @SHELL@
 STRIP = @STRIP@
+SYSTEMD_CFLAGS = @SYSTEMD_CFLAGS@
+SYSTEMD_LIBS = @SYSTEMD_LIBS@
 SYSTEM_CA_PATH = @SYSTEM_CA_PATH@
 UDEV_BASE_DIR = @UDEV_BASE_DIR@
 USE_NLS = @USE_NLS@
@@ -333,7 +342,9 @@ top_builddir = @top_builddir@
 top_srcdir = @top_srcdir@
 INCLUDES = \
 	-I$(top_srcdir)/include \
+	-I$(top_builddir)/include \
 	-I$(top_srcdir)/libnm-util \
+	-I$(top_builddir)/libnm-util \
 	-I$(top_srcdir)/src/dhcp-manager \
 	-I$(top_builddir)/marshallers \
 	-I$(top_srcdir)/src \
diff --git a/src/tests/test-wifi-ap-utils.c b/src/tests/test-wifi-ap-utils.c
index 93bd325a..faa023fc 100644
--- a/src/tests/test-wifi-ap-utils.c
+++ b/src/tests/test-wifi-ap-utils.c
@@ -162,7 +162,7 @@ fill_wifi_empty (NMConnection *connection)
 {
 	NMSettingWireless *s_wifi;
 
-	s_wifi = (NMSettingWireless *) nm_connection_get_setting (connection, NM_TYPE_SETTING_WIRELESS);
+	s_wifi = nm_connection_get_setting_wireless (connection);
 	if (!s_wifi) {
 		s_wifi = (NMSettingWireless *) nm_setting_wireless_new ();
 		nm_connection_add_setting (connection, NM_SETTING (s_wifi));
@@ -175,7 +175,7 @@ fill_wifi (NMConnection *connection, const KeyData items[])
 {
 	NMSettingWireless *s_wifi;
 
-	s_wifi = (NMSettingWireless *) nm_connection_get_setting (connection, NM_TYPE_SETTING_WIRELESS);
+	s_wifi = nm_connection_get_setting_wireless (connection);
 	if (!s_wifi) {
 		s_wifi = (NMSettingWireless *) nm_setting_wireless_new ();
 		nm_connection_add_setting (connection, NM_SETTING (s_wifi));
@@ -190,7 +190,7 @@ fill_wsec (NMConnection *connection, const KeyData items[])
 {
 	NMSettingWirelessSecurity *s_wsec;
 
-	s_wsec = (NMSettingWirelessSecurity *) nm_connection_get_setting (connection, NM_TYPE_SETTING_WIRELESS_SECURITY);
+	s_wsec = nm_connection_get_setting_wireless_security (connection);
 	if (!s_wsec) {
 		s_wsec = (NMSettingWirelessSecurity *) nm_setting_wireless_security_new ();
 		nm_connection_add_setting (connection, NM_SETTING (s_wsec));
@@ -205,7 +205,7 @@ fill_8021x (NMConnection *connection, const KeyData items[])
 {
 	NMSetting8021x *s_8021x;
 
-	s_8021x = (NMSetting8021x *) nm_connection_get_setting (connection, NM_TYPE_SETTING_802_1X);
+	s_8021x = nm_connection_get_setting_802_1x (connection);
 	if (!s_8021x) {
 		s_8021x = (NMSetting8021x *) nm_setting_802_1x_new ();
 		nm_connection_add_setting (connection, NM_SETTING (s_8021x));
diff --git a/src/vpn-manager/Makefile.am b/src/vpn-manager/Makefile.am
index ce99728e..c3c5b525 100644
--- a/src/vpn-manager/Makefile.am
+++ b/src/vpn-manager/Makefile.am
@@ -1,10 +1,13 @@
 INCLUDES = \
 	-I${top_srcdir} \
 	-I${top_srcdir}/include \
+	-I${top_builddir}/include \
 	-I${top_srcdir}/libnm-util \
+	-I${top_builddir}/libnm-util \
+	-I${top_srcdir}/src/generated \
+	-I${top_builddir}/src/generated \
 	-I${top_srcdir}/src/logging \
 	-I${top_srcdir}/src \
-	-I${top_builddir}/marshallers \
 	-I${top_srcdir}/src/dns-manager \
 	-DVPN_NAME_FILES_DIR=\""$(sysconfdir)/NetworkManager/VPN"\"
 
@@ -16,8 +19,6 @@ libvpn_manager_la_SOURCES = \
 	nm-vpn-manager.h \
 	nm-vpn-service.c \
 	nm-vpn-service.h \
-	nm-vpn-connection-base.c \
-	nm-vpn-connection-base.h \
 	nm-vpn-connection.c \
 	nm-vpn-connection.h
 
@@ -28,16 +29,13 @@ libvpn_manager_la_CPPFLAGS =	\
 	-DG_DISABLE_DEPRECATED
 
 libvpn_manager_la_LIBADD = \
-	$(top_builddir)/marshallers/libmarshallers.la \
+	$(top_builddir)/src/generated/libnm-generated.la \
 	$(top_builddir)/src/logging/libnm-logging.la \
 	$(top_builddir)/libnm-util/libnm-util.la \
 	$(LIBNL_LIBS) \
 	$(DBUS_LIBS) \
 	$(GLIB_LIBS)
 
-nm-vpn-connection-base-glue.h: $(top_srcdir)/introspection/nm-active-connection.xml
-	$(AM_V_GEN) dbus-binding-tool --prefix=nm_vpn_connection_base --mode=glib-server --output=$@ $<
-
 nm-vpn-connection-glue.h: $(top_srcdir)/introspection/nm-vpn-connection.xml
 	$(AM_V_GEN) dbus-binding-tool --prefix=nm_vpn_connection --mode=glib-server --output=$@ $<
 
@@ -46,7 +44,6 @@ nm-vpn-plugin-bindings.h: $(top_srcdir)/introspection/nm-vpn-plugin.xml
 
 
 BUILT_SOURCES = \
-	nm-vpn-connection-base-glue.h \
 	nm-vpn-connection-glue.h \
 	nm-vpn-plugin-bindings.h
 
diff --git a/src/vpn-manager/Makefile.in b/src/vpn-manager/Makefile.in
index 51a12507..9a7e5e42 100644
--- a/src/vpn-manager/Makefile.in
+++ b/src/vpn-manager/Makefile.in
@@ -57,13 +57,12 @@ CONFIG_CLEAN_VPATH_FILES =
 LTLIBRARIES = $(noinst_LTLIBRARIES)
 am__DEPENDENCIES_1 =
 libvpn_manager_la_DEPENDENCIES =  \
-	$(top_builddir)/marshallers/libmarshallers.la \
+	$(top_builddir)/src/generated/libnm-generated.la \
 	$(top_builddir)/src/logging/libnm-logging.la \
 	$(top_builddir)/libnm-util/libnm-util.la $(am__DEPENDENCIES_1) \
 	$(am__DEPENDENCIES_1) $(am__DEPENDENCIES_1)
 am_libvpn_manager_la_OBJECTS = libvpn_manager_la-nm-vpn-manager.lo \
 	libvpn_manager_la-nm-vpn-service.lo \
-	libvpn_manager_la-nm-vpn-connection-base.lo \
 	libvpn_manager_la-nm-vpn-connection.lo
 libvpn_manager_la_OBJECTS = $(am_libvpn_manager_la_OBJECTS)
 AM_V_lt = $(am__v_lt_$(V))
@@ -145,6 +144,8 @@ GIO_LIBS = @GIO_LIBS@
 GLIB_CFLAGS = @GLIB_CFLAGS@
 GLIB_GENMARSHAL = @GLIB_GENMARSHAL@
 GLIB_LIBS = @GLIB_LIBS@
+GLIB_MAKEFILE = @GLIB_MAKEFILE@
+GLIB_MKENUMS = @GLIB_MKENUMS@
 GMODULE_CFLAGS = @GMODULE_CFLAGS@
 GMODULE_LIBS = @GMODULE_LIBS@
 GMSGFMT = @GMSGFMT@
@@ -199,11 +200,15 @@ LIBNL2_LIBS = @LIBNL2_LIBS@
 LIBNL3_CFLAGS = @LIBNL3_CFLAGS@
 LIBNL3_LIBS = @LIBNL3_LIBS@
 LIBNL_CFLAGS = @LIBNL_CFLAGS@
+LIBNL_GENL3_CFLAGS = @LIBNL_GENL3_CFLAGS@
+LIBNL_GENL3_LIBS = @LIBNL_GENL3_LIBS@
 LIBNL_LIBS = @LIBNL_LIBS@
 LIBNL_ROUTE3_CFLAGS = @LIBNL_ROUTE3_CFLAGS@
 LIBNL_ROUTE3_LIBS = @LIBNL_ROUTE3_LIBS@
 LIBOBJS = @LIBOBJS@
 LIBS = @LIBS@
+LIBSOUP_CFLAGS = @LIBSOUP_CFLAGS@
+LIBSOUP_LIBS = @LIBSOUP_LIBS@
 LIBTOOL = @LIBTOOL@
 LIPO = @LIPO@
 LN_S = @LN_S@
@@ -214,6 +219,7 @@ MAINT = @MAINT@
 MAKEINFO = @MAKEINFO@
 MANIFEST_TOOL = @MANIFEST_TOOL@
 MKDIR_P = @MKDIR_P@
+MOC = @MOC@
 MSGFMT = @MSGFMT@
 MSGFMT_015 = @MSGFMT_015@
 MSGMERGE = @MSGMERGE@
@@ -253,6 +259,8 @@ SED = @SED@
 SET_MAKE = @SET_MAKE@
 SHELL = @SHELL@
 STRIP = @STRIP@
+SYSTEMD_CFLAGS = @SYSTEMD_CFLAGS@
+SYSTEMD_LIBS = @SYSTEMD_LIBS@
 SYSTEM_CA_PATH = @SYSTEM_CA_PATH@
 UDEV_BASE_DIR = @UDEV_BASE_DIR@
 USE_NLS = @USE_NLS@
@@ -319,10 +327,13 @@ top_srcdir = @top_srcdir@
 INCLUDES = \
 	-I${top_srcdir} \
 	-I${top_srcdir}/include \
+	-I${top_builddir}/include \
 	-I${top_srcdir}/libnm-util \
+	-I${top_builddir}/libnm-util \
+	-I${top_srcdir}/src/generated \
+	-I${top_builddir}/src/generated \
 	-I${top_srcdir}/src/logging \
 	-I${top_srcdir}/src \
-	-I${top_builddir}/marshallers \
 	-I${top_srcdir}/src/dns-manager \
 	-DVPN_NAME_FILES_DIR=\""$(sysconfdir)/NetworkManager/VPN"\"
 
@@ -332,8 +343,6 @@ libvpn_manager_la_SOURCES = \
 	nm-vpn-manager.h \
 	nm-vpn-service.c \
 	nm-vpn-service.h \
-	nm-vpn-connection-base.c \
-	nm-vpn-connection-base.h \
 	nm-vpn-connection.c \
 	nm-vpn-connection.h
 
@@ -344,7 +353,7 @@ libvpn_manager_la_CPPFLAGS = \
 	-DG_DISABLE_DEPRECATED
 
 libvpn_manager_la_LIBADD = \
-	$(top_builddir)/marshallers/libmarshallers.la \
+	$(top_builddir)/src/generated/libnm-generated.la \
 	$(top_builddir)/src/logging/libnm-logging.la \
 	$(top_builddir)/libnm-util/libnm-util.la \
 	$(LIBNL_LIBS) \
@@ -352,7 +361,6 @@ libvpn_manager_la_LIBADD = \
 	$(GLIB_LIBS)
 
 BUILT_SOURCES = \
-	nm-vpn-connection-base-glue.h \
 	nm-vpn-connection-glue.h \
 	nm-vpn-plugin-bindings.h
 
@@ -410,7 +418,6 @@ mostlyclean-compile:
 distclean-compile:
 	-rm -f *.tab.c
 
-@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libvpn_manager_la-nm-vpn-connection-base.Plo@am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libvpn_manager_la-nm-vpn-connection.Plo@am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libvpn_manager_la-nm-vpn-manager.Plo@am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libvpn_manager_la-nm-vpn-service.Plo@am__quote@
@@ -458,14 +465,6 @@ libvpn_manager_la-nm-vpn-service.lo: nm-vpn-service.c
 @AMDEP_TRUE@@am__fastdepCC_FALSE@	DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
 @am__fastdepCC_FALSE@	$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libvpn_manager_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o libvpn_manager_la-nm-vpn-service.lo `test -f 'nm-vpn-service.c' || echo '$(srcdir)/'`nm-vpn-service.c
 
-libvpn_manager_la-nm-vpn-connection-base.lo: nm-vpn-connection-base.c
-@am__fastdepCC_TRUE@	$(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libvpn_manager_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT libvpn_manager_la-nm-vpn-connection-base.lo -MD -MP -MF $(DEPDIR)/libvpn_manager_la-nm-vpn-connection-base.Tpo -c -o libvpn_manager_la-nm-vpn-connection-base.lo `test -f 'nm-vpn-connection-base.c' || echo '$(srcdir)/'`nm-vpn-connection-base.c
-@am__fastdepCC_TRUE@	$(AM_V_at)$(am__mv) $(DEPDIR)/libvpn_manager_la-nm-vpn-connection-base.Tpo $(DEPDIR)/libvpn_manager_la-nm-vpn-connection-base.Plo
-@am__fastdepCC_FALSE@	$(AM_V_CC) @AM_BACKSLASH@
-@AMDEP_TRUE@@am__fastdepCC_FALSE@	source='nm-vpn-connection-base.c' object='libvpn_manager_la-nm-vpn-connection-base.lo' libtool=yes @AMDEPBACKSLASH@
-@AMDEP_TRUE@@am__fastdepCC_FALSE@	DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
-@am__fastdepCC_FALSE@	$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libvpn_manager_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o libvpn_manager_la-nm-vpn-connection-base.lo `test -f 'nm-vpn-connection-base.c' || echo '$(srcdir)/'`nm-vpn-connection-base.c
-
 libvpn_manager_la-nm-vpn-connection.lo: nm-vpn-connection.c
 @am__fastdepCC_TRUE@	$(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libvpn_manager_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT libvpn_manager_la-nm-vpn-connection.lo -MD -MP -MF $(DEPDIR)/libvpn_manager_la-nm-vpn-connection.Tpo -c -o libvpn_manager_la-nm-vpn-connection.lo `test -f 'nm-vpn-connection.c' || echo '$(srcdir)/'`nm-vpn-connection.c
 @am__fastdepCC_TRUE@	$(AM_V_at)$(am__mv) $(DEPDIR)/libvpn_manager_la-nm-vpn-connection.Tpo $(DEPDIR)/libvpn_manager_la-nm-vpn-connection.Plo
@@ -682,9 +681,6 @@ uninstall-am:
 	pdf pdf-am ps ps-am tags uninstall uninstall-am
 
 
-nm-vpn-connection-base-glue.h: $(top_srcdir)/introspection/nm-active-connection.xml
-	$(AM_V_GEN) dbus-binding-tool --prefix=nm_vpn_connection_base --mode=glib-server --output=$@ $<
-
 nm-vpn-connection-glue.h: $(top_srcdir)/introspection/nm-vpn-connection.xml
 	$(AM_V_GEN) dbus-binding-tool --prefix=nm_vpn_connection --mode=glib-server --output=$@ $<
 
diff --git a/src/vpn-manager/nm-vpn-connection-base.c b/src/vpn-manager/nm-vpn-connection-base.c
deleted file mode 100644
index bc2cffb2..00000000
--- a/src/vpn-manager/nm-vpn-connection-base.c
+++ /dev/null
@@ -1,209 +0,0 @@
-/* -*- Mode: C; tab-width: 4; indent-tabs-mode: t; c-basic-offset: 4 -*- */
-/* NetworkManager -- Network link manager
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License along
- * with this program; if not, write to the Free Software Foundation, Inc.,
- * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
- *
- * Copyright (C) 2005 - 2011 Red Hat, Inc.
- * Copyright (C) 2007 - 2008 Novell, Inc.
- */
-
-#include "NetworkManager.h"
-#include "nm-vpn-connection-base.h"
-#include "nm-active-connection.h"
-#include "nm-vpn-connection-base-glue.h"
-#include "nm-dbus-manager.h"
-
-G_DEFINE_ABSTRACT_TYPE (NMVpnConnectionBase, nm_vpn_connection_base, G_TYPE_OBJECT)
-
-#define NM_VPN_CONNECTION_BASE_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), \
-                                               NM_TYPE_VPN_CONNECTION_BASE, \
-                                               NMVpnConnectionBasePrivate))
-
-typedef struct {
-	gboolean disposed;
-
-	NMConnection *connection;
-	char *ac_path;
-	char *specific_object;
-	gboolean is_default;
-	gboolean is_default6;
-	NMActiveConnectionState state;
-} NMVpnConnectionBasePrivate;
-
-enum {
-	PROP_0,
-	PROP_CONNECTION,
-	PROP_UUID,
-	PROP_SPECIFIC_OBJECT,
-	PROP_DEVICES,
-	PROP_STATE,
-	PROP_DEFAULT,
-	PROP_DEFAULT6,
-	PROP_VPN,
-
-	LAST_PROP
-};
-
-/****************************************************************/
-
-void
-nm_vpn_connection_base_set_state (NMVpnConnectionBase *self,
-                                  NMVPNConnectionState vpn_state)
-{
-	NMVpnConnectionBasePrivate *priv = NM_VPN_CONNECTION_BASE_GET_PRIVATE (self);
-	NMActiveConnectionState new_ac_state = NM_ACTIVE_CONNECTION_STATE_UNKNOWN;
-
-	/* Set the NMActiveConnection state based on VPN state */
-	switch (vpn_state) {
-	case NM_VPN_CONNECTION_STATE_PREPARE:
-	case NM_VPN_CONNECTION_STATE_NEED_AUTH:
-	case NM_VPN_CONNECTION_STATE_CONNECT:
-	case NM_VPN_CONNECTION_STATE_IP_CONFIG_GET:
-		new_ac_state = NM_ACTIVE_CONNECTION_STATE_ACTIVATING;
-		break;
-	case NM_VPN_CONNECTION_STATE_ACTIVATED:
-		new_ac_state = NM_ACTIVE_CONNECTION_STATE_ACTIVATED;
-		break;
-	default:
-		break;
-	}
-
-	if (new_ac_state != priv->state) {
-		priv->state = new_ac_state;
-		g_object_notify (G_OBJECT (self), NM_ACTIVE_CONNECTION_STATE);
-	}
-}
-
-const char *
-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,
-                               const char *specific_object)
-{
-	NMVpnConnectionBasePrivate *priv = NM_VPN_CONNECTION_BASE_GET_PRIVATE (self);
-	NMDBusManager *dbus_mgr;
-
-	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),
-	                                     priv->ac_path, G_OBJECT (self));
-	g_object_unref (dbus_mgr);
-}
-
-/****************************************************************/
-
-static void
-nm_vpn_connection_base_init (NMVpnConnectionBase *self)
-{
-	NMVpnConnectionBasePrivate *priv = NM_VPN_CONNECTION_BASE_GET_PRIVATE (self);
-
-	priv->state = NM_ACTIVE_CONNECTION_STATE_UNKNOWN;
-	priv->ac_path = nm_active_connection_get_next_object_path ();
-}
-
-static void
-dispose (GObject *object)
-{
-	NMVpnConnectionBasePrivate *priv = NM_VPN_CONNECTION_BASE_GET_PRIVATE (object);
-
-	if (!priv->disposed) {
-		priv->disposed = TRUE;
-
-		g_free (priv->ac_path);
-		g_free (priv->specific_object);
-		g_object_unref (priv->connection);
-	}
-
-	G_OBJECT_CLASS (nm_vpn_connection_base_parent_class)->dispose (object);
-}
-
-static void
-get_property (GObject *object, guint prop_id,
-			  GValue *value, GParamSpec *pspec)
-{
-	NMVpnConnectionBasePrivate *priv = NM_VPN_CONNECTION_BASE_GET_PRIVATE (object);
-
-	switch (prop_id) {
-	case PROP_CONNECTION:
-		g_value_set_boxed (value, nm_connection_get_path (priv->connection));
-		break;
-	case PROP_UUID:
-		g_value_set_string (value, nm_connection_get_uuid (priv->connection));
-		break;
-	case PROP_SPECIFIC_OBJECT:
-		g_value_set_boxed (value, priv->specific_object);
-		break;
-	case PROP_DEVICES:
-		g_value_take_boxed (value, g_ptr_array_new ());
-		break;
-	case PROP_STATE:
-		g_value_set_uint (value, priv->state);
-		break;
-	case PROP_DEFAULT:
-		g_value_set_boolean (value, priv->is_default);
-		break;
-	case PROP_DEFAULT6:
-		g_value_set_boolean (value, priv->is_default6);
-		break;
-	case PROP_VPN:
-		g_value_set_boolean (value, TRUE);
-		break;
-	default:
-		G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
-		break;
-	}
-}
-
-static void
-nm_vpn_connection_base_class_init (NMVpnConnectionBaseClass *vpn_class)
-{
-	GObjectClass *object_class = G_OBJECT_CLASS (vpn_class);
-
-	g_type_class_add_private (vpn_class, sizeof (NMVpnConnectionBasePrivate));
-
-	/* virtual methods */
-	object_class->get_property = get_property;
-	object_class->dispose = dispose;
-
-	/* properties */
-    nm_active_connection_install_properties (object_class,
-                                             PROP_CONNECTION,
-                                             PROP_UUID,
-                                             PROP_SPECIFIC_OBJECT,
-                                             PROP_DEVICES,
-                                             PROP_STATE,
-                                             PROP_DEFAULT,
-                                             PROP_DEFAULT6,
-                                             PROP_VPN);
-
-	dbus_g_object_type_install_info (G_TYPE_FROM_CLASS (vpn_class),
-									 &dbus_glib_nm_vpn_connection_base_object_info);
-}
-
diff --git a/src/vpn-manager/nm-vpn-connection-base.h b/src/vpn-manager/nm-vpn-connection-base.h
deleted file mode 100644
index 6f19e7c5..00000000
--- a/src/vpn-manager/nm-vpn-connection-base.h
+++ /dev/null
@@ -1,57 +0,0 @@
-/* -*- Mode: C; tab-width: 4; indent-tabs-mode: t; c-basic-offset: 4 -*- */
-/* NetworkManager -- Network link manager
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License along
- * with this program; if not, write to the Free Software Foundation, Inc.,
- * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
- *
- * (C) Copyright 2005 - 2011 Red Hat, Inc.
- */
-
-#ifndef NM_VPN_CONNECTION_BASE_H
-#define NM_VPN_CONNECTION_BASE_H
-
-#include <glib-object.h>
-#include "NetworkManagerVPN.h"
-#include "nm-connection.h"
-
-#define NM_TYPE_VPN_CONNECTION_BASE            (nm_vpn_connection_base_get_type ())
-#define NM_VPN_CONNECTION_BASE(obj)            (G_TYPE_CHECK_INSTANCE_CAST ((obj), NM_TYPE_VPN_CONNECTION_BASE, NMVpnConnectionBase))
-#define NM_VPN_CONNECTION_BASE_CLASS(klass)    (G_TYPE_CHECK_CLASS_CAST ((klass), NM_TYPE_VPN_CONNECTION_BASE, NMVpnConnectionBaseClass))
-#define NM_IS_VPN_CONNECTION_BASE(obj)         (G_TYPE_CHECK_INSTANCE_TYPE ((obj), NM_TYPE_VPN_CONNECTION_BASE))
-#define NM_IS_VPN_CONNECTION_BASE_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((obj), NM_TYPE_VPN_CONNECTION_BASE))
-#define NM_VPN_CONNECTION_BASE_GET_CLASS(obj)  (G_TYPE_INSTANCE_GET_CLASS ((obj), NM_TYPE_VPN_CONNECTION_BASE, NMVpnConnectionBaseClass))
-
-typedef struct {
-	GObject parent;
-} NMVpnConnectionBase;
-
-typedef struct {
-	GObjectClass parent;
-} NMVpnConnectionBaseClass;
-
-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,
-                                    const char *specific_object);
-
-void nm_vpn_connection_base_set_state (NMVpnConnectionBase *self,
-                                       NMVPNConnectionState vpn_state);
-
-#endif /* NM_VPN_CONNECTION_BASE_H */
-
diff --git a/src/vpn-manager/nm-vpn-connection.c b/src/vpn-manager/nm-vpn-connection.c
index 73f2b553..b391f1ec 100644
--- a/src/vpn-manager/nm-vpn-connection.c
+++ b/src/vpn-manager/nm-vpn-connection.c
@@ -15,7 +15,7 @@
  * with this program; if not, write to the Free Software Foundation, Inc.,
  * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
  *
- * Copyright (C) 2005 - 2011 Red Hat, Inc.
+ * Copyright (C) 2005 - 2012 Red Hat, Inc.
  * Copyright (C) 2006 - 2008 Novell, Inc.
  */
 
@@ -30,7 +30,6 @@
 #include "NetworkManager.h"
 #include "NetworkManagerVPN.h"
 #include "nm-vpn-connection.h"
-#include "nm-device-interface.h"
 #include "nm-setting-connection.h"
 #include "nm-setting-vpn.h"
 #include "nm-setting-ip4-config.h"
@@ -52,7 +51,7 @@
 
 #include "nm-vpn-connection-glue.h"
 
-G_DEFINE_TYPE (NMVPNConnection, nm_vpn_connection, NM_TYPE_VPN_CONNECTION_BASE)
+G_DEFINE_TYPE (NMVPNConnection, nm_vpn_connection, NM_TYPE_ACTIVE_CONNECTION)
 
 typedef enum {
 	/* Only system secrets */
@@ -108,12 +107,31 @@ enum {
 	PROP_0,
 	PROP_VPN_STATE,
 	PROP_BANNER,
+	PROP_MASTER = 2000,
 
 	LAST_PROP
 };
 
 static void get_secrets (NMVPNConnection *self, SecretsReq secrets_idx);
 
+static NMActiveConnectionState
+ac_state_from_vpn_state (NMVPNConnectionState vpn_state)
+{
+	/* Set the NMActiveConnection state based on VPN state */
+	switch (vpn_state) {
+	case NM_VPN_CONNECTION_STATE_PREPARE:
+	case NM_VPN_CONNECTION_STATE_NEED_AUTH:
+	case NM_VPN_CONNECTION_STATE_CONNECT:
+	case NM_VPN_CONNECTION_STATE_IP_CONFIG_GET:
+		return NM_ACTIVE_CONNECTION_STATE_ACTIVATING;
+	case NM_VPN_CONNECTION_STATE_ACTIVATED:
+		return NM_ACTIVE_CONNECTION_STATE_ACTIVATED;
+	default:
+		break;
+	}
+	return NM_ACTIVE_CONNECTION_STATE_UNKNOWN;
+}
+
 static void
 nm_vpn_connection_set_vpn_state (NMVPNConnection *connection,
                                  NMVPNConnectionState vpn_state,
@@ -134,7 +152,8 @@ nm_vpn_connection_set_vpn_state (NMVPNConnection *connection,
 	priv->vpn_state = vpn_state;
 
 	/* Update active connection base class state */
-	nm_vpn_connection_base_set_state (NM_VPN_CONNECTION_BASE (connection), vpn_state);
+	nm_active_connection_set_state (NM_ACTIVE_CONNECTION (connection),
+	                                ac_state_from_vpn_state (vpn_state));
 
 	/* Save ip_iface since when the VPN goes down it may get freed
 	 * before we're done with it.
@@ -231,7 +250,10 @@ nm_vpn_connection_new (NMConnection *connection,
 	g_return_val_if_fail (NM_IS_CONNECTION (connection), NULL);
 	g_return_val_if_fail (NM_IS_DEVICE (parent_device), NULL);
 
-	self = (NMVPNConnection *) g_object_new (NM_TYPE_VPN_CONNECTION, NULL);
+	self = (NMVPNConnection *) g_object_new (NM_TYPE_VPN_CONNECTION,
+	                                         NM_ACTIVE_CONNECTION_SPECIFIC_OBJECT, specific_object,
+	                                         NM_ACTIVE_CONNECTION_VPN, TRUE,
+	                                         NULL);
 	if (!self)
 		return NULL;
 
@@ -246,11 +268,16 @@ nm_vpn_connection_new (NMConnection *connection,
 									 G_CALLBACK (device_state_changed),
 									 self);
 
-	priv->device_ip4 = g_signal_connect (parent_device, "notify::" NM_DEVICE_INTERFACE_IP4_CONFIG,
+	priv->device_ip4 = g_signal_connect (parent_device, "notify::" NM_DEVICE_IP4_CONFIG,
 	                                     G_CALLBACK (device_ip4_config_changed),
 	                                     self);
 
-	nm_vpn_connection_base_export (NM_VPN_CONNECTION_BASE (self), connection, specific_object);
+	if (!nm_active_connection_export (NM_ACTIVE_CONNECTION (self),
+	                                  connection,
+	                                  nm_device_get_path (parent_device))) {
+		g_object_unref (self);
+		self = NULL;
+	}
 
 	return self;
 }
@@ -259,10 +286,10 @@ static const char *
 nm_vpn_connection_get_service (NMVPNConnection *connection)
 {
 	NMVPNConnectionPrivate *priv = NM_VPN_CONNECTION_GET_PRIVATE (connection);
-	NMSettingVPN *setting;
+	NMSettingVPN *s_vpn;
 
-	setting = (NMSettingVPN *) nm_connection_get_setting (priv->connection, NM_TYPE_SETTING_VPN);
-	return nm_setting_vpn_get_service_type (setting);
+	s_vpn = nm_connection_get_setting_vpn (priv->connection);
+	return nm_setting_vpn_get_service_type (s_vpn);
 }
 
 static void
@@ -452,7 +479,7 @@ nm_vpn_connection_ip4_config_get (DBusGProxy *proxy,
 
 	/* Grab the interface index for address/routing operations */
 	priv->ip_ifindex = nm_netlink_iface_to_index (priv->ip_iface);
-	if (!priv->ip_ifindex) {
+	if (priv->ip_ifindex < 0) {
 		nm_log_err (LOGD_VPN, "(%s): failed to look up VPN interface index", priv->ip_iface);
 		goto error;
 	}
@@ -520,6 +547,15 @@ nm_vpn_connection_ip4_config_get (DBusGProxy *proxy,
 	if (val)
 		nm_ip4_config_add_domain (config, g_value_get_string (val));
 
+	val = (GValue *) g_hash_table_lookup (config_hash, NM_VPN_PLUGIN_IP4_CONFIG_DOMAINS);
+	if (val) {
+		const char **domains = g_value_get_boxed (val);
+		const char **domain;
+
+		for (domain = domains; domain && *domain; domain++)
+			nm_ip4_config_add_domain (config, *domain);
+	}
+
 	val = (GValue *) g_hash_table_lookup (config_hash, NM_VPN_PLUGIN_IP4_CONFIG_BANNER);
 	if (val) {
 		g_free (priv->banner);
@@ -559,7 +595,7 @@ nm_vpn_connection_ip4_config_get (DBusGProxy *proxy,
 	print_vpn_config (config, priv->ip4_internal_gw, priv->ip_iface, priv->banner);
 
 	/* Merge in user overrides from the NMConnection's IPv4 setting */
-	s_ip4 = NM_SETTING_IP4_CONFIG (nm_connection_get_setting (priv->connection, NM_TYPE_SETTING_IP4_CONFIG));
+	s_ip4 = nm_connection_get_setting_ip4_config (priv->connection);
 	nm_utils_merge_ip4_config (config, s_ip4);
 
 	nm_system_iface_set_up (priv->ip_ifindex, TRUE, NULL);
@@ -646,22 +682,22 @@ static GHashTable *
 _hash_with_username (NMConnection *connection, const char *username)
 {
 	NMConnection *dup;
-	NMSetting *s_vpn;
+	NMSettingVPN *s_vpn;
 	GHashTable *hash;
 	const char *existing;
 
 	/* Shortcut if we weren't given a username or if there already was one in
 	 * the VPN setting; don't bother duplicating the connection and everything.
 	 */
-	s_vpn = nm_connection_get_setting (connection, NM_TYPE_SETTING_VPN);
+	s_vpn = nm_connection_get_setting_vpn (connection);
 	g_assert (s_vpn);
-	existing = nm_setting_vpn_get_user_name (NM_SETTING_VPN (s_vpn));
+	existing = nm_setting_vpn_get_user_name (s_vpn);
 	if (username == NULL || existing)
 		return nm_connection_to_hash (connection, NM_SETTING_HASH_FLAG_ALL);
 
 	dup = nm_connection_duplicate (connection);
 	g_assert (dup);
-	s_vpn = nm_connection_get_setting (dup, NM_TYPE_SETTING_VPN);
+	s_vpn = nm_connection_get_setting_vpn (dup);
 	g_assert (s_vpn);
 	g_object_set (s_vpn, NM_SETTING_VPN_USER_NAME, username, NULL);
 	hash = nm_connection_to_hash (dup, NM_SETTING_HASH_FLAG_ALL);
@@ -737,25 +773,17 @@ nm_vpn_connection_activate (NMVPNConnection *connection)
 }
 
 const char *
-nm_vpn_connection_get_active_connection_path (NMVPNConnection *connection)
-{
-	g_return_val_if_fail (NM_IS_VPN_CONNECTION (connection), NULL);
-
-	return nm_vpn_connection_base_get_ac_path (NM_VPN_CONNECTION_BASE (connection));
-}
-
-const char *
 nm_vpn_connection_get_name (NMVPNConnection *connection)
 {
 	NMVPNConnectionPrivate *priv;
-	NMSettingConnection *setting;
+	NMSettingConnection *s_con;
 
 	g_return_val_if_fail (NM_IS_VPN_CONNECTION (connection), NULL);
 
 	priv = NM_VPN_CONNECTION_GET_PRIVATE (connection);
-	setting = (NMSettingConnection *) nm_connection_get_setting (priv->connection, NM_TYPE_SETTING_CONNECTION);
+	s_con = nm_connection_get_setting_connection (priv->connection);
 
-	return nm_setting_connection_get_id (setting);
+	return nm_setting_connection_get_id (s_con);
 }
 
 NMConnection *
@@ -1152,6 +1180,9 @@ get_property (GObject *object, guint prop_id,
 	case PROP_BANNER:
 		g_value_set_string (value, priv->banner ? priv->banner : "");
 		break;
+	case PROP_MASTER:
+		g_value_set_boxed (value, nm_device_get_path (priv->parent_dev));
+		break;
 	default:
 		G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
 		break;
@@ -1171,6 +1202,8 @@ nm_vpn_connection_class_init (NMVPNConnectionClass *connection_class)
 	object_class->dispose = dispose;
 	object_class->finalize = finalize;
 
+	g_object_class_override_property (object_class, PROP_MASTER, NM_ACTIVE_CONNECTION_MASTER);
+
 	/* properties */
 	g_object_class_install_property (object_class, PROP_VPN_STATE,
 		g_param_spec_uint (NM_VPN_CONNECTION_VPN_STATE,
@@ -1199,10 +1232,6 @@ nm_vpn_connection_class_init (NMVPNConnectionClass *connection_class)
 				    G_TYPE_NONE, 2,
 				    G_TYPE_UINT, G_TYPE_UINT);
 
-	signals[PROPERTIES_CHANGED] = 
-		nm_properties_changed_signal_new (object_class,
-								    G_STRUCT_OFFSET (NMVPNConnectionClass, properties_changed));
-
 	dbus_g_object_type_install_info (G_TYPE_FROM_CLASS (object_class),
 									 &dbus_glib_nm_vpn_connection_object_info);
 }
diff --git a/src/vpn-manager/nm-vpn-connection.h b/src/vpn-manager/nm-vpn-connection.h
index c0d15f8a..93cc06d1 100644
--- a/src/vpn-manager/nm-vpn-connection.h
+++ b/src/vpn-manager/nm-vpn-connection.h
@@ -26,7 +26,6 @@
 #include <glib-object.h>
 #include "NetworkManagerVPN.h"
 #include "nm-device.h"
-#include "nm-vpn-connection-base.h"
 
 #define NM_TYPE_VPN_CONNECTION            (nm_vpn_connection_get_type ())
 #define NM_VPN_CONNECTION(obj)            (G_TYPE_CHECK_INSTANCE_CAST ((obj), NM_TYPE_VPN_CONNECTION, NMVPNConnection))
@@ -39,18 +38,16 @@
 #define NM_VPN_CONNECTION_BANNER "banner"
 
 typedef struct {
-	NMVpnConnectionBase parent;
+	NMActiveConnection parent;
 } NMVPNConnection;
 
 typedef struct {
-	NMVpnConnectionBaseClass parent;
+	NMActiveConnectionClass parent;
 
 	/* Signals */
 	void (*vpn_state_changed) (NMVPNConnection *connection,
 	                           NMVPNConnectionState state,
 	                           NMVPNConnectionStateReason reason);
-
-	void (*properties_changed) (NMVPNConnection *connection, GHashTable *properties);
 } NMVPNConnectionClass;
 
 GType nm_vpn_connection_get_type (void);
@@ -63,8 +60,6 @@ NMVPNConnection * nm_vpn_connection_new (NMConnection *connection,
 
 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);
diff --git a/src/vpn-manager/nm-vpn-manager.c b/src/vpn-manager/nm-vpn-manager.c
index 41e96c0b..34131964 100644
--- a/src/vpn-manager/nm-vpn-manager.c
+++ b/src/vpn-manager/nm-vpn-manager.c
@@ -29,6 +29,7 @@
 #include "nm-dbus-manager.h"
 #include "NetworkManagerVPN.h"
 #include "nm-marshal.h"
+#include "nm-enum-types.h"
 #include "nm-logging.h"
 
 G_DEFINE_TYPE (NMVPNManager, nm_vpn_manager, G_TYPE_OBJECT)
@@ -61,31 +62,6 @@ nm_vpn_manager_error_quark (void)
 	return quark;
 }
 
-/* This should really be standard. */
-#define ENUM_ENTRY(NAME, DESC) { NAME, "" #NAME "", DESC }
-
-GType
-nm_vpn_manager_error_get_type (void)
-{
-	static GType etype = 0;
-
-	if (etype == 0) {
-		static const GEnumValue values[] = {
-			/* The base device for the VPN connection is not active. */
-			ENUM_ENTRY (NM_VPN_MANAGER_ERROR_DEVICE_NOT_ACTIVE, "BaseDeviceNotActive"),
-			/* The requested VPN connection was invalid. */
-			ENUM_ENTRY (NM_VPN_MANAGER_ERROR_CONNECTION_INVALID, "ConnectionInvalid"),
-			/* The VPN service required by this VPN connection did not exist or was invalid. */
-			ENUM_ENTRY (NM_VPN_MANAGER_ERROR_SERVICE_INVALID, "ServiceInvalid"),
-			/* The VPN service required by this VPN connection could not be started. */
-			ENUM_ENTRY (NM_VPN_MANAGER_ERROR_SERVICE_START_FAILED, "ServiceStartFailed"),
-			{ 0, 0, 0 }
-		};
-		etype = g_enum_register_static ("NMVPNManagerError", values);
-	}
-	return etype;
-}
-
 
 static NMVPNService *
 get_service_by_namefile (NMVPNManager *self, const char *namefile)
@@ -158,7 +134,7 @@ connection_vpn_state_changed (NMVPNConnection *connection,
 	}
 }
 
-NMVPNConnection *
+NMActiveConnection *
 nm_vpn_manager_activate_connection (NMVPNManager *manager,
                                     NMConnection *connection,
                                     NMDevice *device,
@@ -185,7 +161,7 @@ nm_vpn_manager_activate_connection (NMVPNManager *manager,
 		return NULL;
 	}
 
-	vpn_setting = (NMSettingVPN *) nm_connection_get_setting (connection, NM_TYPE_SETTING_VPN);
+	vpn_setting = nm_connection_get_setting_vpn (connection);
 	if (!vpn_setting) {
 		g_set_error (error,
 		             NM_VPN_MANAGER_ERROR, NM_VPN_MANAGER_ERROR_CONNECTION_INVALID,
@@ -217,7 +193,7 @@ nm_vpn_manager_activate_connection (NMVPNManager *manager,
 		                  manager);
 	}
 
-	return vpn;
+	return (NMActiveConnection *) vpn;
 }
 
 gboolean
@@ -243,7 +219,7 @@ nm_vpn_manager_deactivate_connection (NMVPNManager *self,
 			NMVPNConnection *vpn = NM_VPN_CONNECTION (aiter->data);
 			const char *vpn_path;
 
-			vpn_path = nm_vpn_connection_get_active_connection_path (vpn);
+			vpn_path = nm_active_connection_get_path (NM_ACTIVE_CONNECTION (vpn));
 			if (!strcmp (path, vpn_path)) {
 				nm_vpn_connection_disconnect (vpn, reason);
 				success = TRUE;
@@ -279,7 +255,7 @@ nm_vpn_manager_add_active_connections (NMVPNManager *self,
 			const char *path;
 
 			if (!filter || (nm_vpn_connection_get_connection (vpn) == filter)) {
-				path = nm_vpn_connection_get_active_connection_path (vpn);
+				path = nm_active_connection_get_path (NM_ACTIVE_CONNECTION (vpn));
 				g_ptr_array_add (array, g_strdup (path));
 			}
 		}
@@ -326,7 +302,7 @@ nm_vpn_manager_get_vpn_connection_for_active (NMVPNManager *manager,
 			NMVPNConnection *vpn = NM_VPN_CONNECTION (elt->data);
 			const char *ac_path;
 
-			ac_path = nm_vpn_connection_get_active_connection_path (vpn);
+			ac_path = nm_active_connection_get_path (NM_ACTIVE_CONNECTION (vpn));
 			if (ac_path && !strcmp (ac_path, active_path))
 				return vpn;
 		}
diff --git a/src/vpn-manager/nm-vpn-manager.h b/src/vpn-manager/nm-vpn-manager.h
index 78a5220b..cec370c8 100644
--- a/src/vpn-manager/nm-vpn-manager.h
+++ b/src/vpn-manager/nm-vpn-manager.h
@@ -35,14 +35,13 @@
 
 typedef enum
 {
-	NM_VPN_MANAGER_ERROR_DEVICE_NOT_ACTIVE = 0,
-	NM_VPN_MANAGER_ERROR_CONNECTION_INVALID,
-	NM_VPN_MANAGER_ERROR_SERVICE_INVALID,
-	NM_VPN_MANAGER_ERROR_SERVICE_START_FAILED,
+	NM_VPN_MANAGER_ERROR_DEVICE_NOT_ACTIVE = 0, /*< nick=BaseDeviceNotActive >*/
+	NM_VPN_MANAGER_ERROR_CONNECTION_INVALID,    /*< nick=ConnectionInvalid >*/
+	NM_VPN_MANAGER_ERROR_SERVICE_INVALID,       /*< nick=ServiceInvalid >*/
+	NM_VPN_MANAGER_ERROR_SERVICE_START_FAILED,  /*< nick=ServiceStartFailed >*/
 } NMVPNManagerError;
 
 #define NM_VPN_MANAGER_ERROR (nm_vpn_manager_error_quark ())
-#define NM_TYPE_VPN_MANAGER_ERROR (nm_vpn_manager_error_get_type ()) 
 
 GQuark nm_vpn_manager_error_quark (void);
 GType nm_vpn_manager_error_get_type (void);
@@ -66,13 +65,13 @@ GType nm_vpn_manager_get_type (void);
 
 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);
+NMActiveConnection *nm_vpn_manager_activate_connection (NMVPNManager *manager,
+                                                        NMConnection *connection,
+                                                        NMDevice *device,
+                                                        const char *specific_object,
+                                                        gboolean user_requested,
+                                                        gulong user_uid,
+                                                        GError **error);
 
 gboolean nm_vpn_manager_deactivate_connection (NMVPNManager *manager,
                                                const char *path,
diff --git a/src/wifi/Makefile.am b/src/wifi/Makefile.am
new file mode 100644
index 00000000..c9a1b474
--- /dev/null
+++ b/src/wifi/Makefile.am
@@ -0,0 +1,31 @@
+INCLUDES = \
+	-I${top_srcdir}/include \
+	-I${top_builddir}/include \
+	-I${top_srcdir}/src/logging \
+	-I${top_srcdir}/libnm-util \
+	-I${top_builddir}/libnm-util \
+	-I${top_srcdir}/src
+
+noinst_LTLIBRARIES = libwifi-utils.la
+
+libwifi_utils_la_SOURCES = \
+	wifi-utils.c \
+	wifi-utils.h \
+	wifi-utils-private.h \
+	wifi-utils-nl80211.c \
+	wifi-utils-nl80211.h
+
+if WITH_WEXT
+libwifi_utils_la_SOURCES += wifi-utils-wext.c wifi-utils-wext.h
+endif
+
+libwifi_utils_la_CPPFLAGS = \
+	$(GLIB_CFLAGS) \
+	$(LIBNL_CFLAGS)
+
+libwifi_utils_la_LIBADD = \
+	$(top_builddir)/src/logging/libnm-logging.la \
+	$(top_builddir)/libnm-util/libnm-util.la \
+	$(GLIB_LIBS) \
+	$(LIBNL_LIBS)
+
diff --git a/src/wifi/Makefile.in b/src/wifi/Makefile.in
new file mode 100644
index 00000000..028469bf
--- /dev/null
+++ b/src/wifi/Makefile.in
@@ -0,0 +1,665 @@
+# Makefile.in generated by automake 1.11.1 from Makefile.am.
+# @configure_input@
+
+# Copyright (C) 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002,
+# 2003, 2004, 2005, 2006, 2007, 2008, 2009  Free Software Foundation,
+# Inc.
+# This Makefile.in is free software; the Free Software Foundation
+# gives unlimited permission to copy and/or distribute it,
+# with or without modifications, as long as this notice is preserved.
+
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY, to the extent permitted by law; without
+# even the implied warranty of MERCHANTABILITY or FITNESS FOR A
+# PARTICULAR PURPOSE.
+
+@SET_MAKE@
+
+VPATH = @srcdir@
+pkgdatadir = $(datadir)/@PACKAGE@
+pkgincludedir = $(includedir)/@PACKAGE@
+pkglibdir = $(libdir)/@PACKAGE@
+pkglibexecdir = $(libexecdir)/@PACKAGE@
+am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd
+install_sh_DATA = $(install_sh) -c -m 644
+install_sh_PROGRAM = $(install_sh) -c
+install_sh_SCRIPT = $(install_sh) -c
+INSTALL_HEADER = $(INSTALL_DATA)
+transform = $(program_transform_name)
+NORMAL_INSTALL = :
+PRE_INSTALL = :
+POST_INSTALL = :
+NORMAL_UNINSTALL = :
+PRE_UNINSTALL = :
+POST_UNINSTALL = :
+build_triplet = @build@
+host_triplet = @host@
+@WITH_WEXT_TRUE@am__append_1 = wifi-utils-wext.c wifi-utils-wext.h
+subdir = src/wifi
+DIST_COMMON = $(srcdir)/Makefile.am $(srcdir)/Makefile.in
+ACLOCAL_M4 = $(top_srcdir)/aclocal.m4
+am__aclocal_m4_deps = $(top_srcdir)/m4/compiler_warnings.m4 \
+	$(top_srcdir)/m4/gettext.m4 $(top_srcdir)/m4/gtk-doc.m4 \
+	$(top_srcdir)/m4/iconv.m4 $(top_srcdir)/m4/intlmacosx.m4 \
+	$(top_srcdir)/m4/intltool.m4 $(top_srcdir)/m4/introspection.m4 \
+	$(top_srcdir)/m4/lib-ld.m4 $(top_srcdir)/m4/lib-link.m4 \
+	$(top_srcdir)/m4/lib-prefix.m4 $(top_srcdir)/m4/libnl-check.m4 \
+	$(top_srcdir)/m4/libtool.m4 $(top_srcdir)/m4/ltoptions.m4 \
+	$(top_srcdir)/m4/ltsugar.m4 $(top_srcdir)/m4/ltversion.m4 \
+	$(top_srcdir)/m4/lt~obsolete.m4 $(top_srcdir)/m4/nls.m4 \
+	$(top_srcdir)/m4/po.m4 $(top_srcdir)/m4/progtest.m4 \
+	$(top_srcdir)/configure.ac
+am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \
+	$(ACLOCAL_M4)
+mkinstalldirs = $(install_sh) -d
+CONFIG_HEADER = $(top_builddir)/config.h
+CONFIG_CLEAN_FILES =
+CONFIG_CLEAN_VPATH_FILES =
+LTLIBRARIES = $(noinst_LTLIBRARIES)
+am__DEPENDENCIES_1 =
+libwifi_utils_la_DEPENDENCIES =  \
+	$(top_builddir)/src/logging/libnm-logging.la \
+	$(top_builddir)/libnm-util/libnm-util.la $(am__DEPENDENCIES_1) \
+	$(am__DEPENDENCIES_1)
+am__libwifi_utils_la_SOURCES_DIST = wifi-utils.c wifi-utils.h \
+	wifi-utils-private.h wifi-utils-nl80211.c wifi-utils-nl80211.h \
+	wifi-utils-wext.c wifi-utils-wext.h
+@WITH_WEXT_TRUE@am__objects_1 = libwifi_utils_la-wifi-utils-wext.lo
+am_libwifi_utils_la_OBJECTS = libwifi_utils_la-wifi-utils.lo \
+	libwifi_utils_la-wifi-utils-nl80211.lo $(am__objects_1)
+libwifi_utils_la_OBJECTS = $(am_libwifi_utils_la_OBJECTS)
+AM_V_lt = $(am__v_lt_$(V))
+am__v_lt_ = $(am__v_lt_$(AM_DEFAULT_VERBOSITY))
+am__v_lt_0 = --silent
+DEFAULT_INCLUDES = -I.@am__isrc@ -I$(top_builddir)
+depcomp = $(SHELL) $(top_srcdir)/build-aux/depcomp
+am__depfiles_maybe = depfiles
+am__mv = mv -f
+COMPILE = $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) \
+	$(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS)
+LTCOMPILE = $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) \
+	$(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) \
+	$(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) \
+	$(AM_CFLAGS) $(CFLAGS)
+AM_V_CC = $(am__v_CC_$(V))
+am__v_CC_ = $(am__v_CC_$(AM_DEFAULT_VERBOSITY))
+am__v_CC_0 = @echo "  CC    " $@;
+AM_V_at = $(am__v_at_$(V))
+am__v_at_ = $(am__v_at_$(AM_DEFAULT_VERBOSITY))
+am__v_at_0 = @
+CCLD = $(CC)
+LINK = $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) \
+	$(LIBTOOLFLAGS) --mode=link $(CCLD) $(AM_CFLAGS) $(CFLAGS) \
+	$(AM_LDFLAGS) $(LDFLAGS) -o $@
+AM_V_CCLD = $(am__v_CCLD_$(V))
+am__v_CCLD_ = $(am__v_CCLD_$(AM_DEFAULT_VERBOSITY))
+am__v_CCLD_0 = @echo "  CCLD  " $@;
+AM_V_GEN = $(am__v_GEN_$(V))
+am__v_GEN_ = $(am__v_GEN_$(AM_DEFAULT_VERBOSITY))
+am__v_GEN_0 = @echo "  GEN   " $@;
+SOURCES = $(libwifi_utils_la_SOURCES)
+DIST_SOURCES = $(am__libwifi_utils_la_SOURCES_DIST)
+ETAGS = etags
+CTAGS = ctags
+DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST)
+ACLOCAL = @ACLOCAL@
+ALL_LINGUAS = @ALL_LINGUAS@
+AMTAR = @AMTAR@
+AM_DEFAULT_VERBOSITY = @AM_DEFAULT_VERBOSITY@
+AR = @AR@
+AUTOCONF = @AUTOCONF@
+AUTOHEADER = @AUTOHEADER@
+AUTOMAKE = @AUTOMAKE@
+AWK = @AWK@
+CC = @CC@
+CCDEPMODE = @CCDEPMODE@
+CFLAGS = @CFLAGS@
+CPP = @CPP@
+CPPFLAGS = @CPPFLAGS@
+CXX = @CXX@
+CXXCPP = @CXXCPP@
+CXXDEPMODE = @CXXDEPMODE@
+CXXFLAGS = @CXXFLAGS@
+CYGPATH_W = @CYGPATH_W@
+DATADIRNAME = @DATADIRNAME@
+DBUS_CFLAGS = @DBUS_CFLAGS@
+DBUS_LIBS = @DBUS_LIBS@
+DBUS_SYS_DIR = @DBUS_SYS_DIR@
+DEFS = @DEFS@
+DEPDIR = @DEPDIR@
+DHCLIENT_PATH = @DHCLIENT_PATH@
+DHCLIENT_VERSION = @DHCLIENT_VERSION@
+DHCPCD_PATH = @DHCPCD_PATH@
+DISABLE_DEPRECATED = @DISABLE_DEPRECATED@
+DLLTOOL = @DLLTOOL@
+DSYMUTIL = @DSYMUTIL@
+DUMPBIN = @DUMPBIN@
+ECHO_C = @ECHO_C@
+ECHO_N = @ECHO_N@
+ECHO_T = @ECHO_T@
+EGREP = @EGREP@
+EXEEXT = @EXEEXT@
+FGREP = @FGREP@
+GETTEXT_MACRO_VERSION = @GETTEXT_MACRO_VERSION@
+GETTEXT_PACKAGE = @GETTEXT_PACKAGE@
+GIO_CFLAGS = @GIO_CFLAGS@
+GIO_LIBS = @GIO_LIBS@
+GLIB_CFLAGS = @GLIB_CFLAGS@
+GLIB_GENMARSHAL = @GLIB_GENMARSHAL@
+GLIB_LIBS = @GLIB_LIBS@
+GLIB_MAKEFILE = @GLIB_MAKEFILE@
+GLIB_MKENUMS = @GLIB_MKENUMS@
+GMODULE_CFLAGS = @GMODULE_CFLAGS@
+GMODULE_LIBS = @GMODULE_LIBS@
+GMSGFMT = @GMSGFMT@
+GMSGFMT_015 = @GMSGFMT_015@
+GNUTLS_CFLAGS = @GNUTLS_CFLAGS@
+GNUTLS_LIBS = @GNUTLS_LIBS@
+GREP = @GREP@
+GTKDOC_CHECK = @GTKDOC_CHECK@
+GTKDOC_DEPS_CFLAGS = @GTKDOC_DEPS_CFLAGS@
+GTKDOC_DEPS_LIBS = @GTKDOC_DEPS_LIBS@
+GTKDOC_MKPDF = @GTKDOC_MKPDF@
+GTKDOC_REBASE = @GTKDOC_REBASE@
+GUDEV_CFLAGS = @GUDEV_CFLAGS@
+GUDEV_LIBS = @GUDEV_LIBS@
+HTML_DIR = @HTML_DIR@
+INSTALL = @INSTALL@
+INSTALL_DATA = @INSTALL_DATA@
+INSTALL_PROGRAM = @INSTALL_PROGRAM@
+INSTALL_SCRIPT = @INSTALL_SCRIPT@
+INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@
+INTLLIBS = @INTLLIBS@
+INTLTOOL_EXTRACT = @INTLTOOL_EXTRACT@
+INTLTOOL_MERGE = @INTLTOOL_MERGE@
+INTLTOOL_PERL = @INTLTOOL_PERL@
+INTLTOOL_UPDATE = @INTLTOOL_UPDATE@
+INTL_MACOSX_LIBS = @INTL_MACOSX_LIBS@
+INTROSPECTION_CFLAGS = @INTROSPECTION_CFLAGS@
+INTROSPECTION_COMPILER = @INTROSPECTION_COMPILER@
+INTROSPECTION_GENERATE = @INTROSPECTION_GENERATE@
+INTROSPECTION_GIRDIR = @INTROSPECTION_GIRDIR@
+INTROSPECTION_LIBS = @INTROSPECTION_LIBS@
+INTROSPECTION_MAKEFILE = @INTROSPECTION_MAKEFILE@
+INTROSPECTION_SCANNER = @INTROSPECTION_SCANNER@
+INTROSPECTION_TYPELIBDIR = @INTROSPECTION_TYPELIBDIR@
+IPTABLES_PATH = @IPTABLES_PATH@
+IWMX_SDK_CFLAGS = @IWMX_SDK_CFLAGS@
+IWMX_SDK_LIBS = @IWMX_SDK_LIBS@
+KERNEL_FIRMWARE_DIR = @KERNEL_FIRMWARE_DIR@
+LD = @LD@
+LDFLAGS = @LDFLAGS@
+LIBDL = @LIBDL@
+LIBGCRYPT_CFLAGS = @LIBGCRYPT_CFLAGS@
+LIBGCRYPT_CONFIG = @LIBGCRYPT_CONFIG@
+LIBGCRYPT_LIBS = @LIBGCRYPT_LIBS@
+LIBICONV = @LIBICONV@
+LIBINTL = @LIBINTL@
+LIBM = @LIBM@
+LIBNL1_CFLAGS = @LIBNL1_CFLAGS@
+LIBNL1_LIBS = @LIBNL1_LIBS@
+LIBNL2_CFLAGS = @LIBNL2_CFLAGS@
+LIBNL2_LIBS = @LIBNL2_LIBS@
+LIBNL3_CFLAGS = @LIBNL3_CFLAGS@
+LIBNL3_LIBS = @LIBNL3_LIBS@
+LIBNL_CFLAGS = @LIBNL_CFLAGS@
+LIBNL_GENL3_CFLAGS = @LIBNL_GENL3_CFLAGS@
+LIBNL_GENL3_LIBS = @LIBNL_GENL3_LIBS@
+LIBNL_LIBS = @LIBNL_LIBS@
+LIBNL_ROUTE3_CFLAGS = @LIBNL_ROUTE3_CFLAGS@
+LIBNL_ROUTE3_LIBS = @LIBNL_ROUTE3_LIBS@
+LIBOBJS = @LIBOBJS@
+LIBS = @LIBS@
+LIBSOUP_CFLAGS = @LIBSOUP_CFLAGS@
+LIBSOUP_LIBS = @LIBSOUP_LIBS@
+LIBTOOL = @LIBTOOL@
+LIPO = @LIPO@
+LN_S = @LN_S@
+LTLIBICONV = @LTLIBICONV@
+LTLIBINTL = @LTLIBINTL@
+LTLIBOBJS = @LTLIBOBJS@
+MAINT = @MAINT@
+MAKEINFO = @MAKEINFO@
+MANIFEST_TOOL = @MANIFEST_TOOL@
+MKDIR_P = @MKDIR_P@
+MOC = @MOC@
+MSGFMT = @MSGFMT@
+MSGFMT_015 = @MSGFMT_015@
+MSGMERGE = @MSGMERGE@
+NM = @NM@
+NMEDIT = @NMEDIT@
+NM_MAJOR_VERSION = @NM_MAJOR_VERSION@
+NM_MICRO_VERSION = @NM_MICRO_VERSION@
+NM_MINOR_VERSION = @NM_MINOR_VERSION@
+NM_VERSION = @NM_VERSION@
+NSS_CFLAGS = @NSS_CFLAGS@
+NSS_LIBS = @NSS_LIBS@
+OBJDUMP = @OBJDUMP@
+OBJEXT = @OBJEXT@
+OTOOL = @OTOOL@
+OTOOL64 = @OTOOL64@
+PACKAGE = @PACKAGE@
+PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@
+PACKAGE_NAME = @PACKAGE_NAME@
+PACKAGE_STRING = @PACKAGE_STRING@
+PACKAGE_TARNAME = @PACKAGE_TARNAME@
+PACKAGE_URL = @PACKAGE_URL@
+PACKAGE_VERSION = @PACKAGE_VERSION@
+PATH_SEPARATOR = @PATH_SEPARATOR@
+PKGCONFIG_PATH = @PKGCONFIG_PATH@
+PKG_CONFIG = @PKG_CONFIG@
+PKG_CONFIG_LIBDIR = @PKG_CONFIG_LIBDIR@
+PKG_CONFIG_PATH = @PKG_CONFIG_PATH@
+POLKIT_CFLAGS = @POLKIT_CFLAGS@
+POLKIT_LIBS = @POLKIT_LIBS@
+POSUB = @POSUB@
+PPPD_PLUGIN_DIR = @PPPD_PLUGIN_DIR@
+QT_CFLAGS = @QT_CFLAGS@
+QT_LIBS = @QT_LIBS@
+RANLIB = @RANLIB@
+RESOLVCONF_PATH = @RESOLVCONF_PATH@
+SED = @SED@
+SET_MAKE = @SET_MAKE@
+SHELL = @SHELL@
+STRIP = @STRIP@
+SYSTEMD_CFLAGS = @SYSTEMD_CFLAGS@
+SYSTEMD_LIBS = @SYSTEMD_LIBS@
+SYSTEM_CA_PATH = @SYSTEM_CA_PATH@
+UDEV_BASE_DIR = @UDEV_BASE_DIR@
+USE_NLS = @USE_NLS@
+UUID_CFLAGS = @UUID_CFLAGS@
+UUID_LIBS = @UUID_LIBS@
+VERSION = @VERSION@
+XGETTEXT = @XGETTEXT@
+XGETTEXT_015 = @XGETTEXT_015@
+XGETTEXT_EXTRA_OPTIONS = @XGETTEXT_EXTRA_OPTIONS@
+abs_builddir = @abs_builddir@
+abs_srcdir = @abs_srcdir@
+abs_top_builddir = @abs_top_builddir@
+abs_top_srcdir = @abs_top_srcdir@
+ac_ct_AR = @ac_ct_AR@
+ac_ct_CC = @ac_ct_CC@
+ac_ct_CXX = @ac_ct_CXX@
+ac_ct_DUMPBIN = @ac_ct_DUMPBIN@
+am__include = @am__include@
+am__leading_dot = @am__leading_dot@
+am__quote = @am__quote@
+am__tar = @am__tar@
+am__untar = @am__untar@
+bindir = @bindir@
+build = @build@
+build_alias = @build_alias@
+build_cpu = @build_cpu@
+build_os = @build_os@
+build_vendor = @build_vendor@
+builddir = @builddir@
+datadir = @datadir@
+datarootdir = @datarootdir@
+docdir = @docdir@
+dvidir = @dvidir@
+exec_prefix = @exec_prefix@
+host = @host@
+host_alias = @host_alias@
+host_cpu = @host_cpu@
+host_os = @host_os@
+host_vendor = @host_vendor@
+htmldir = @htmldir@
+includedir = @includedir@
+infodir = @infodir@
+install_sh = @install_sh@
+libdir = @libdir@
+libexecdir = @libexecdir@
+localedir = @localedir@
+localstatedir = @localstatedir@
+mandir = @mandir@
+mkdir_p = @mkdir_p@
+oldincludedir = @oldincludedir@
+pdfdir = @pdfdir@
+prefix = @prefix@
+program_transform_name = @program_transform_name@
+psdir = @psdir@
+sbindir = @sbindir@
+sharedstatedir = @sharedstatedir@
+srcdir = @srcdir@
+sysconfdir = @sysconfdir@
+systemdsystemunitdir = @systemdsystemunitdir@
+target_alias = @target_alias@
+top_build_prefix = @top_build_prefix@
+top_builddir = @top_builddir@
+top_srcdir = @top_srcdir@
+INCLUDES = \
+	-I${top_srcdir}/include \
+	-I${top_builddir}/include \
+	-I${top_srcdir}/src/logging \
+	-I${top_srcdir}/libnm-util \
+	-I${top_builddir}/libnm-util \
+	-I${top_srcdir}/src
+
+noinst_LTLIBRARIES = libwifi-utils.la
+libwifi_utils_la_SOURCES = wifi-utils.c wifi-utils.h \
+	wifi-utils-private.h wifi-utils-nl80211.c wifi-utils-nl80211.h \
+	$(am__append_1)
+libwifi_utils_la_CPPFLAGS = \
+	$(GLIB_CFLAGS) \
+	$(LIBNL_CFLAGS)
+
+libwifi_utils_la_LIBADD = \
+	$(top_builddir)/src/logging/libnm-logging.la \
+	$(top_builddir)/libnm-util/libnm-util.la \
+	$(GLIB_LIBS) \
+	$(LIBNL_LIBS)
+
+all: all-am
+
+.SUFFIXES:
+.SUFFIXES: .c .lo .o .obj
+$(srcdir)/Makefile.in: @MAINTAINER_MODE_TRUE@ $(srcdir)/Makefile.am  $(am__configure_deps)
+	@for dep in $?; do \
+	  case '$(am__configure_deps)' in \
+	    *$$dep*) \
+	      ( cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh ) \
+	        && { if test -f $@; then exit 0; else break; fi; }; \
+	      exit 1;; \
+	  esac; \
+	done; \
+	echo ' cd $(top_srcdir) && $(AUTOMAKE) --gnu src/wifi/Makefile'; \
+	$(am__cd) $(top_srcdir) && \
+	  $(AUTOMAKE) --gnu src/wifi/Makefile
+.PRECIOUS: Makefile
+Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status
+	@case '$?' in \
+	  *config.status*) \
+	    cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh;; \
+	  *) \
+	    echo ' cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe)'; \
+	    cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe);; \
+	esac;
+
+$(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES)
+	cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+
+$(top_srcdir)/configure: @MAINTAINER_MODE_TRUE@ $(am__configure_deps)
+	cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+$(ACLOCAL_M4): @MAINTAINER_MODE_TRUE@ $(am__aclocal_m4_deps)
+	cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+$(am__aclocal_m4_deps):
+
+clean-noinstLTLIBRARIES:
+	-test -z "$(noinst_LTLIBRARIES)" || rm -f $(noinst_LTLIBRARIES)
+	@list='$(noinst_LTLIBRARIES)'; for p in $$list; do \
+	  dir="`echo $$p | sed -e 's|/[^/]*$$||'`"; \
+	  test "$$dir" != "$$p" || dir=.; \
+	  echo "rm -f \"$${dir}/so_locations\""; \
+	  rm -f "$${dir}/so_locations"; \
+	done
+libwifi-utils.la: $(libwifi_utils_la_OBJECTS) $(libwifi_utils_la_DEPENDENCIES) 
+	$(AM_V_CCLD)$(LINK)  $(libwifi_utils_la_OBJECTS) $(libwifi_utils_la_LIBADD) $(LIBS)
+
+mostlyclean-compile:
+	-rm -f *.$(OBJEXT)
+
+distclean-compile:
+	-rm -f *.tab.c
+
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libwifi_utils_la-wifi-utils-nl80211.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libwifi_utils_la-wifi-utils-wext.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libwifi_utils_la-wifi-utils.Plo@am__quote@
+
+.c.o:
+@am__fastdepCC_TRUE@	$(AM_V_CC)depbase=`echo $@ | sed 's|[^/]*$$|$(DEPDIR)/&|;s|\.o$$||'`;\
+@am__fastdepCC_TRUE@	$(COMPILE) -MT $@ -MD -MP -MF $$depbase.Tpo -c -o $@ $< &&\
+@am__fastdepCC_TRUE@	$(am__mv) $$depbase.Tpo $$depbase.Po
+@am__fastdepCC_FALSE@	$(AM_V_CC) @AM_BACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@	source='$<' object='$@' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@	DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@	$(COMPILE) -c -o $@ $<
+
+.c.obj:
+@am__fastdepCC_TRUE@	$(AM_V_CC)depbase=`echo $@ | sed 's|[^/]*$$|$(DEPDIR)/&|;s|\.obj$$||'`;\
+@am__fastdepCC_TRUE@	$(COMPILE) -MT $@ -MD -MP -MF $$depbase.Tpo -c -o $@ `$(CYGPATH_W) '$<'` &&\
+@am__fastdepCC_TRUE@	$(am__mv) $$depbase.Tpo $$depbase.Po
+@am__fastdepCC_FALSE@	$(AM_V_CC) @AM_BACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@	source='$<' object='$@' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@	DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@	$(COMPILE) -c -o $@ `$(CYGPATH_W) '$<'`
+
+.c.lo:
+@am__fastdepCC_TRUE@	$(AM_V_CC)depbase=`echo $@ | sed 's|[^/]*$$|$(DEPDIR)/&|;s|\.lo$$||'`;\
+@am__fastdepCC_TRUE@	$(LTCOMPILE) -MT $@ -MD -MP -MF $$depbase.Tpo -c -o $@ $< &&\
+@am__fastdepCC_TRUE@	$(am__mv) $$depbase.Tpo $$depbase.Plo
+@am__fastdepCC_FALSE@	$(AM_V_CC) @AM_BACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@	source='$<' object='$@' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@	DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@	$(LTCOMPILE) -c -o $@ $<
+
+libwifi_utils_la-wifi-utils.lo: wifi-utils.c
+@am__fastdepCC_TRUE@	$(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libwifi_utils_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT libwifi_utils_la-wifi-utils.lo -MD -MP -MF $(DEPDIR)/libwifi_utils_la-wifi-utils.Tpo -c -o libwifi_utils_la-wifi-utils.lo `test -f 'wifi-utils.c' || echo '$(srcdir)/'`wifi-utils.c
+@am__fastdepCC_TRUE@	$(AM_V_at)$(am__mv) $(DEPDIR)/libwifi_utils_la-wifi-utils.Tpo $(DEPDIR)/libwifi_utils_la-wifi-utils.Plo
+@am__fastdepCC_FALSE@	$(AM_V_CC) @AM_BACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@	source='wifi-utils.c' object='libwifi_utils_la-wifi-utils.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@	DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@	$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libwifi_utils_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o libwifi_utils_la-wifi-utils.lo `test -f 'wifi-utils.c' || echo '$(srcdir)/'`wifi-utils.c
+
+libwifi_utils_la-wifi-utils-nl80211.lo: wifi-utils-nl80211.c
+@am__fastdepCC_TRUE@	$(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libwifi_utils_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT libwifi_utils_la-wifi-utils-nl80211.lo -MD -MP -MF $(DEPDIR)/libwifi_utils_la-wifi-utils-nl80211.Tpo -c -o libwifi_utils_la-wifi-utils-nl80211.lo `test -f 'wifi-utils-nl80211.c' || echo '$(srcdir)/'`wifi-utils-nl80211.c
+@am__fastdepCC_TRUE@	$(AM_V_at)$(am__mv) $(DEPDIR)/libwifi_utils_la-wifi-utils-nl80211.Tpo $(DEPDIR)/libwifi_utils_la-wifi-utils-nl80211.Plo
+@am__fastdepCC_FALSE@	$(AM_V_CC) @AM_BACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@	source='wifi-utils-nl80211.c' object='libwifi_utils_la-wifi-utils-nl80211.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@	DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@	$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libwifi_utils_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o libwifi_utils_la-wifi-utils-nl80211.lo `test -f 'wifi-utils-nl80211.c' || echo '$(srcdir)/'`wifi-utils-nl80211.c
+
+libwifi_utils_la-wifi-utils-wext.lo: wifi-utils-wext.c
+@am__fastdepCC_TRUE@	$(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libwifi_utils_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT libwifi_utils_la-wifi-utils-wext.lo -MD -MP -MF $(DEPDIR)/libwifi_utils_la-wifi-utils-wext.Tpo -c -o libwifi_utils_la-wifi-utils-wext.lo `test -f 'wifi-utils-wext.c' || echo '$(srcdir)/'`wifi-utils-wext.c
+@am__fastdepCC_TRUE@	$(AM_V_at)$(am__mv) $(DEPDIR)/libwifi_utils_la-wifi-utils-wext.Tpo $(DEPDIR)/libwifi_utils_la-wifi-utils-wext.Plo
+@am__fastdepCC_FALSE@	$(AM_V_CC) @AM_BACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@	source='wifi-utils-wext.c' object='libwifi_utils_la-wifi-utils-wext.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@	DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@	$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libwifi_utils_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o libwifi_utils_la-wifi-utils-wext.lo `test -f 'wifi-utils-wext.c' || echo '$(srcdir)/'`wifi-utils-wext.c
+
+mostlyclean-libtool:
+	-rm -f *.lo
+
+clean-libtool:
+	-rm -rf .libs _libs
+
+ID: $(HEADERS) $(SOURCES) $(LISP) $(TAGS_FILES)
+	list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \
+	unique=`for i in $$list; do \
+	    if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \
+	  done | \
+	  $(AWK) '{ files[$$0] = 1; nonempty = 1; } \
+	      END { if (nonempty) { for (i in files) print i; }; }'`; \
+	mkid -fID $$unique
+tags: TAGS
+
+TAGS:  $(HEADERS) $(SOURCES)  $(TAGS_DEPENDENCIES) \
+		$(TAGS_FILES) $(LISP)
+	set x; \
+	here=`pwd`; \
+	list='$(SOURCES) $(HEADERS)  $(LISP) $(TAGS_FILES)'; \
+	unique=`for i in $$list; do \
+	    if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \
+	  done | \
+	  $(AWK) '{ files[$$0] = 1; nonempty = 1; } \
+	      END { if (nonempty) { for (i in files) print i; }; }'`; \
+	shift; \
+	if test -z "$(ETAGS_ARGS)$$*$$unique"; then :; else \
+	  test -n "$$unique" || unique=$$empty_fix; \
+	  if test $$# -gt 0; then \
+	    $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \
+	      "$$@" $$unique; \
+	  else \
+	    $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \
+	      $$unique; \
+	  fi; \
+	fi
+ctags: CTAGS
+CTAGS:  $(HEADERS) $(SOURCES)  $(TAGS_DEPENDENCIES) \
+		$(TAGS_FILES) $(LISP)
+	list='$(SOURCES) $(HEADERS)  $(LISP) $(TAGS_FILES)'; \
+	unique=`for i in $$list; do \
+	    if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \
+	  done | \
+	  $(AWK) '{ files[$$0] = 1; nonempty = 1; } \
+	      END { if (nonempty) { for (i in files) print i; }; }'`; \
+	test -z "$(CTAGS_ARGS)$$unique" \
+	  || $(CTAGS) $(CTAGSFLAGS) $(AM_CTAGSFLAGS) $(CTAGS_ARGS) \
+	     $$unique
+
+GTAGS:
+	here=`$(am__cd) $(top_builddir) && pwd` \
+	  && $(am__cd) $(top_srcdir) \
+	  && gtags -i $(GTAGS_ARGS) "$$here"
+
+distclean-tags:
+	-rm -f TAGS ID GTAGS GRTAGS GSYMS GPATH tags
+
+distdir: $(DISTFILES)
+	@srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \
+	topsrcdirstrip=`echo "$(top_srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \
+	list='$(DISTFILES)'; \
+	  dist_files=`for file in $$list; do echo $$file; done | \
+	  sed -e "s|^$$srcdirstrip/||;t" \
+	      -e "s|^$$topsrcdirstrip/|$(top_builddir)/|;t"`; \
+	case $$dist_files in \
+	  */*) $(MKDIR_P) `echo "$$dist_files" | \
+			   sed '/\//!d;s|^|$(distdir)/|;s,/[^/]*$$,,' | \
+			   sort -u` ;; \
+	esac; \
+	for file in $$dist_files; do \
+	  if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \
+	  if test -d $$d/$$file; then \
+	    dir=`echo "/$$file" | sed -e 's,/[^/]*$$,,'`; \
+	    if test -d "$(distdir)/$$file"; then \
+	      find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \
+	    fi; \
+	    if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \
+	      cp -fpR $(srcdir)/$$file "$(distdir)$$dir" || exit 1; \
+	      find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \
+	    fi; \
+	    cp -fpR $$d/$$file "$(distdir)$$dir" || exit 1; \
+	  else \
+	    test -f "$(distdir)/$$file" \
+	    || cp -p $$d/$$file "$(distdir)/$$file" \
+	    || exit 1; \
+	  fi; \
+	done
+check-am: all-am
+check: check-am
+all-am: Makefile $(LTLIBRARIES)
+installdirs:
+install: install-am
+install-exec: install-exec-am
+install-data: install-data-am
+uninstall: uninstall-am
+
+install-am: all-am
+	@$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am
+
+installcheck: installcheck-am
+install-strip:
+	$(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \
+	  install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \
+	  `test -z '$(STRIP)' || \
+	    echo "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'"` install
+mostlyclean-generic:
+
+clean-generic:
+
+distclean-generic:
+	-test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES)
+	-test . = "$(srcdir)" || test -z "$(CONFIG_CLEAN_VPATH_FILES)" || rm -f $(CONFIG_CLEAN_VPATH_FILES)
+
+maintainer-clean-generic:
+	@echo "This command is intended for maintainers to use"
+	@echo "it deletes files that may require special tools to rebuild."
+clean: clean-am
+
+clean-am: clean-generic clean-libtool clean-noinstLTLIBRARIES \
+	mostlyclean-am
+
+distclean: distclean-am
+	-rm -rf ./$(DEPDIR)
+	-rm -f Makefile
+distclean-am: clean-am distclean-compile distclean-generic \
+	distclean-tags
+
+dvi: dvi-am
+
+dvi-am:
+
+html: html-am
+
+html-am:
+
+info: info-am
+
+info-am:
+
+install-data-am:
+
+install-dvi: install-dvi-am
+
+install-dvi-am:
+
+install-exec-am:
+
+install-html: install-html-am
+
+install-html-am:
+
+install-info: install-info-am
+
+install-info-am:
+
+install-man:
+
+install-pdf: install-pdf-am
+
+install-pdf-am:
+
+install-ps: install-ps-am
+
+install-ps-am:
+
+installcheck-am:
+
+maintainer-clean: maintainer-clean-am
+	-rm -rf ./$(DEPDIR)
+	-rm -f Makefile
+maintainer-clean-am: distclean-am maintainer-clean-generic
+
+mostlyclean: mostlyclean-am
+
+mostlyclean-am: mostlyclean-compile mostlyclean-generic \
+	mostlyclean-libtool
+
+pdf: pdf-am
+
+pdf-am:
+
+ps: ps-am
+
+ps-am:
+
+uninstall-am:
+
+.MAKE: install-am install-strip
+
+.PHONY: CTAGS GTAGS all all-am check check-am clean clean-generic \
+	clean-libtool clean-noinstLTLIBRARIES ctags distclean \
+	distclean-compile distclean-generic distclean-libtool \
+	distclean-tags distdir dvi dvi-am html html-am info info-am \
+	install install-am install-data install-data-am install-dvi \
+	install-dvi-am install-exec install-exec-am install-html \
+	install-html-am install-info install-info-am install-man \
+	install-pdf install-pdf-am install-ps install-ps-am \
+	install-strip installcheck installcheck-am installdirs \
+	maintainer-clean maintainer-clean-generic mostlyclean \
+	mostlyclean-compile mostlyclean-generic mostlyclean-libtool \
+	pdf pdf-am ps ps-am tags uninstall uninstall-am
+
+
+# Tell versions [3.59,3.63) of GNU make to not export all variables.
+# Otherwise a system limit (for SysV at least) may be exceeded.
+.NOEXPORT:
diff --git a/src/wifi/wifi-utils-nl80211.c b/src/wifi/wifi-utils-nl80211.c
new file mode 100644
index 00000000..4a4e661e
--- /dev/null
+++ b/src/wifi/wifi-utils-nl80211.c
@@ -0,0 +1,819 @@
+/* -*- 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) 2005 - 2011 Red Hat, Inc.
+ * Copyright (C) 2006 - 2008 Novell, Inc.
+ * Copyright (C) 2011 Intel Corporation. All rights reserved.
+ */
+
+#include <config.h>
+#include <errno.h>
+#include <string.h>
+#include <sys/ioctl.h>
+#include <net/ethernet.h>
+#include <unistd.h>
+#include <math.h>
+
+#include <glib.h>
+
+#include <netlink/genl/genl.h>
+#include <netlink/genl/family.h>
+#include <netlink/genl/ctrl.h>
+
+#include <linux/nl80211.h>
+
+#include "wifi-utils-private.h"
+#include "wifi-utils-nl80211.h"
+#include "nm-logging.h"
+#include "nm-utils.h"
+#include "nm-netlink-compat.h"
+
+typedef struct {
+	WifiData parent;
+	struct nl_sock *nl_sock;
+	int id;
+	struct nl_cb *nl_cb;
+	guint32 *freqs;
+	int num_freqs;
+} WifiDataNl80211;
+
+static int ack_handler (struct nl_msg *msg, void *arg)
+{
+	int *done = arg;
+	*done = 1;
+	return NL_STOP;
+}
+
+static int finish_handler (struct nl_msg *msg, void *arg)
+{
+	int *done = arg;
+	*done = 1;
+	return NL_SKIP;
+}
+
+static int error_handler (struct sockaddr_nl *nla, struct nlmsgerr *err,
+			  void *arg)
+{
+	int *done = arg;
+	*done = err->error;
+	return NL_SKIP;
+}
+
+static struct nl_msg *
+_nl80211_alloc_msg (int id, int ifindex, guint32 cmd, guint32 flags)
+{
+	struct nl_msg *msg;
+
+	msg = nlmsg_alloc ();
+	if (msg) {
+		genlmsg_put (msg, 0, 0, id, 0, flags, cmd, 0);
+		NLA_PUT_U32 (msg, NL80211_ATTR_IFINDEX, ifindex);
+	}
+	return msg;
+
+ nla_put_failure:
+	nlmsg_free (msg);
+	return NULL;
+}
+
+static struct nl_msg *
+nl80211_alloc_msg (WifiDataNl80211 *nl80211, guint32 cmd, guint32 flags)
+{
+	return _nl80211_alloc_msg (nl80211->id, nl80211->parent.ifindex, cmd, flags);
+}
+
+/* NOTE: this function consumes 'msg' */
+static int
+_nl80211_send_and_recv (struct nl_sock *nl_sock, 
+                        struct nl_cb *nl_cb,
+                        struct nl_msg *msg,
+                        int (*valid_handler)(struct nl_msg *, void *),
+                        void *valid_data)
+{
+	struct nl_cb *cb;
+	int err, done;
+
+	g_return_val_if_fail (msg != NULL, -ENOMEM);
+	g_return_val_if_fail (valid_handler != NULL, -EINVAL);
+
+	cb = nl_cb_clone (nl_cb);
+	if (!cb) {
+		err = -ENOMEM;
+		goto out;
+	}
+
+	err = nl_send_auto_complete (nl_sock, msg);
+	if (err < 0)
+		goto out;
+
+	done = 0;
+	nl_cb_err (cb, NL_CB_CUSTOM, error_handler, &done);
+	nl_cb_set (cb, NL_CB_FINISH, NL_CB_CUSTOM, finish_handler, &done);
+	nl_cb_set (cb, NL_CB_ACK, NL_CB_CUSTOM, ack_handler, &done);
+	nl_cb_set (cb, NL_CB_VALID, NL_CB_CUSTOM, valid_handler, valid_data);
+
+	/* Loop until one of our NL callbacks says we're done; on success
+	 * done will be 1, on error it will be < 0.
+	 */
+	while (!done) {
+		err = nl_recvmsgs (nl_sock, cb);
+		if (err && err != -NLE_AGAIN) {
+			nm_log_warn (LOGD_WIFI, "nl_recvmsgs() error: (%d) %s",
+			             err, nl_geterror (err));
+			break;
+		}
+	}
+	if (err == 0 && done < 0)
+		err = done;
+
+ out:
+	nl_cb_put (cb);
+	nlmsg_free (msg);
+	return err;
+}
+
+static int
+nl80211_send_and_recv (WifiDataNl80211 *nl80211,
+                       struct nl_msg *msg,
+                       int (*valid_handler)(struct nl_msg *, void *),
+                       void *valid_data)
+{
+	return _nl80211_send_and_recv (nl80211->nl_sock, nl80211->nl_cb, msg, valid_handler, valid_data);
+}
+
+static void
+wifi_nl80211_deinit (WifiData *parent)
+{
+	WifiDataNl80211 *nl80211 = (WifiDataNl80211 *) parent;
+
+	if (nl80211->nl_sock)
+		nl_socket_free (nl80211->nl_sock);
+	if (nl80211->nl_cb)
+		nl_cb_put (nl80211->nl_cb);
+}
+
+struct nl80211_iface_info {
+	NM80211Mode mode;
+};
+
+static int nl80211_iface_info_handler (struct nl_msg *msg, void *arg)
+{
+	struct nl80211_iface_info *info = arg;
+	struct genlmsghdr *gnlh = nlmsg_data (nlmsg_hdr (msg));
+	struct nlattr *tb[NL80211_ATTR_MAX + 1];
+                
+	if (nla_parse (tb, NL80211_ATTR_MAX, genlmsg_attrdata (gnlh, 0),
+		       genlmsg_attrlen (gnlh, 0), NULL) < 0)
+		return NL_SKIP;
+
+	if (!tb[NL80211_ATTR_IFTYPE])
+		return NL_SKIP;
+
+	switch (nla_get_u32 (tb[NL80211_ATTR_IFTYPE])) {
+	case NL80211_IFTYPE_ADHOC:
+		info->mode = NM_802_11_MODE_ADHOC;
+		break;
+	case NL80211_IFTYPE_STATION:
+		info->mode = NM_802_11_MODE_INFRA;
+		break;
+	}
+                          
+	return NL_SKIP;
+}
+
+static NM80211Mode
+wifi_nl80211_get_mode (WifiData *data)
+{
+	WifiDataNl80211 *nl80211 = (WifiDataNl80211 *) data;
+	struct nl80211_iface_info iface_info = {
+		.mode = NM_802_11_MODE_UNKNOWN,
+	};
+	struct nl_msg *msg;
+
+	msg = nl80211_alloc_msg (nl80211, NL80211_CMD_GET_INTERFACE, 0);
+
+	if (nl80211_send_and_recv (nl80211, msg, nl80211_iface_info_handler,
+				   &iface_info) < 0)
+		return NM_802_11_MODE_UNKNOWN;
+
+	return iface_info.mode;
+}
+
+static gboolean
+wifi_nl80211_set_mode (WifiData *data, const NM80211Mode mode)
+{
+	/*
+	 * Used only to set mode for scanning as some old cards
+	 * don't properly scan in IBSS mode, nl80211 cards are
+	 * expected to scan properly so ignore this.
+	 */
+	return TRUE;
+}
+
+/* @divisor: pass what value @xbm should be divided by to get dBm */
+static guint32 nl80211_xbm_to_percent (gint32 xbm, guint32 divisor)
+{
+#define NOISE_FLOOR_DBM  -90
+#define SIGNAL_MAX_DBM   -20
+
+	xbm /= divisor;
+	xbm = CLAMP(xbm, NOISE_FLOOR_DBM, SIGNAL_MAX_DBM);
+
+	return 100 - 70 * (((float) SIGNAL_MAX_DBM - (float) xbm) /
+			   ((float) SIGNAL_MAX_DBM - (float) NOISE_FLOOR_DBM));
+}
+
+struct nl80211_bss_info {
+	guint32 freq;
+	guint8 bssid[ETH_ALEN];
+	guint8 ssid[32];
+	guint32 ssid_len;
+	guint32 beacon_signal;
+	gboolean valid;
+};
+
+#define WLAN_EID_SSID	0
+
+static void find_ssid (guint8 *ies, guint32 ies_len,
+		       guint8 **ssid, guint32 *ssid_len)
+{
+	*ssid = NULL;
+	*ssid_len = 0;
+
+	while (ies_len > 2 && ies[0] != WLAN_EID_SSID) {
+		ies_len -= ies[1] + 2;
+		ies += ies[1] + 2;
+	}
+	if (ies_len < 2)
+		return;
+	if (ies_len < 2 + ies[1])
+		return;
+
+	*ssid_len = ies[1];
+	*ssid = ies + 2;
+}
+
+static int nl80211_bss_dump_handler (struct nl_msg *msg, void *arg)
+{
+	struct nl80211_bss_info *info = arg;
+	struct genlmsghdr *gnlh = nlmsg_data (nlmsg_hdr (msg));
+	struct nlattr *tb[NL80211_ATTR_MAX + 1];
+	struct nlattr *bss[NL80211_BSS_MAX + 1];
+	static struct nla_policy bss_policy[NL80211_BSS_MAX + 1] = {
+		[NL80211_BSS_TSF] = { .type = NLA_U64 },
+		[NL80211_BSS_FREQUENCY] = { .type = NLA_U32 },
+		[NL80211_BSS_BSSID] = { },
+		[NL80211_BSS_BEACON_INTERVAL] = { .type = NLA_U16 },
+		[NL80211_BSS_CAPABILITY] = { .type = NLA_U16 },
+		[NL80211_BSS_INFORMATION_ELEMENTS] = { },
+		[NL80211_BSS_SIGNAL_MBM] = { .type = NLA_U32 },
+		[NL80211_BSS_SIGNAL_UNSPEC] = { .type = NLA_U8 },
+		[NL80211_BSS_STATUS] = { .type = NLA_U32 },
+	};
+	guint32 status;
+                
+	if (nla_parse (tb, NL80211_ATTR_MAX, genlmsg_attrdata (gnlh, 0),
+		       genlmsg_attrlen (gnlh, 0), NULL) < 0)
+		return NL_SKIP;
+
+	if (tb[NL80211_ATTR_BSS] == NULL)
+		return NL_SKIP;
+
+	if (nla_parse_nested (bss, NL80211_BSS_MAX,
+			      tb[NL80211_ATTR_BSS],
+			      bss_policy))
+		return NL_SKIP;
+
+	if (bss[NL80211_BSS_STATUS] == NULL)
+		return NL_SKIP;
+
+	status = nla_get_u32 (bss[NL80211_BSS_STATUS]);
+
+	if (status != NL80211_BSS_STATUS_ASSOCIATED &&
+	    status != NL80211_BSS_STATUS_IBSS_JOINED)
+		return NL_SKIP;
+
+	if (bss[NL80211_BSS_BSSID] == NULL)
+		return NL_SKIP;
+	memcpy(info->bssid, nla_data (bss[NL80211_BSS_BSSID]), ETH_ALEN);
+
+	if (bss[NL80211_BSS_FREQUENCY])
+		info->freq = nla_get_u32 (bss[NL80211_BSS_FREQUENCY]);
+
+	if (bss[NL80211_BSS_SIGNAL_UNSPEC])
+		info->beacon_signal =
+			nla_get_u8 (bss[NL80211_BSS_SIGNAL_UNSPEC]);
+
+	if (bss[NL80211_BSS_SIGNAL_MBM])
+		info->beacon_signal =
+			nl80211_xbm_to_percent (nla_get_u32 (bss[NL80211_BSS_SIGNAL_MBM]), 100);
+
+	if (bss[NL80211_BSS_INFORMATION_ELEMENTS]) {
+		guint8 *ssid;
+		guint32 ssid_len;
+
+		find_ssid(nla_data (bss[NL80211_BSS_INFORMATION_ELEMENTS]),
+			  nla_len (bss[NL80211_BSS_INFORMATION_ELEMENTS]),
+			  &ssid, &ssid_len);
+		if (ssid && ssid_len && ssid_len <= sizeof(info->ssid)) {
+			memcpy (info->ssid, ssid, ssid_len);
+			info->ssid_len = ssid_len;
+		}
+	}
+
+	info->valid = TRUE;
+
+	return NL_SKIP;
+}
+
+static void nl80211_get_bss_info (WifiDataNl80211 *nl80211,
+				  struct nl80211_bss_info *bss_info)
+{
+	struct nl_msg *msg;
+
+	memset(bss_info, 0, sizeof(*bss_info));
+
+	msg = nl80211_alloc_msg (nl80211, NL80211_CMD_GET_SCAN, NLM_F_DUMP);
+
+	nl80211_send_and_recv (nl80211, msg, nl80211_bss_dump_handler, bss_info);
+}
+
+static guint32
+wifi_nl80211_get_freq (WifiData *data)
+{
+	WifiDataNl80211 *nl80211 = (WifiDataNl80211 *) data;
+	struct nl80211_bss_info bss_info;
+
+	nl80211_get_bss_info (nl80211, &bss_info);
+
+	return bss_info.freq;
+}
+
+static guint32
+wifi_nl80211_find_freq (WifiData *data, const guint32 *freqs)
+{
+	WifiDataNl80211 *nl80211 = (WifiDataNl80211 *) data;
+	int i;
+
+	for (i = 0; i < nl80211->num_freqs; i++) {
+		while (*freqs) {
+			if (nl80211->freqs[i] == *freqs)
+				return *freqs;
+			freqs++;
+		}
+	}
+	return 0;
+}
+
+static GByteArray *
+wifi_nl80211_get_ssid (WifiData *data)
+{
+	WifiDataNl80211 *nl80211 = (WifiDataNl80211 *) data;
+	GByteArray *array = NULL;
+	struct nl80211_bss_info bss_info;
+
+	nl80211_get_bss_info (nl80211, &bss_info);
+
+	if (bss_info.valid) {
+		array = g_byte_array_sized_new (bss_info.ssid_len);
+		g_byte_array_append (array, (const guint8 *) bss_info.ssid,
+				     bss_info.ssid_len);
+	}
+
+	return array;
+}
+
+static gboolean
+wifi_nl80211_get_bssid (WifiData *data, struct ether_addr *out_bssid)
+{
+	WifiDataNl80211 *nl80211 = (WifiDataNl80211 *) data;
+	struct nl80211_bss_info bss_info;
+
+	nl80211_get_bss_info (nl80211, &bss_info);
+
+	if (bss_info.valid)
+		memcpy(out_bssid, bss_info.bssid, ETH_ALEN);
+
+	return bss_info.valid;
+}
+
+struct nl80211_station_info {
+	guint32 txrate;
+	gboolean txrate_valid;
+	guint8 signal;
+	gboolean signal_valid;
+};
+
+static int nl80211_station_handler (struct nl_msg *msg, void *arg)
+{
+	struct nl80211_station_info *info = arg;
+	struct nlattr *tb[NL80211_ATTR_MAX + 1];
+	struct genlmsghdr *gnlh = nlmsg_data (nlmsg_hdr (msg));
+	struct nlattr *sinfo[NL80211_STA_INFO_MAX + 1];
+	struct nlattr *rinfo[NL80211_RATE_INFO_MAX + 1];
+	static struct nla_policy stats_policy[NL80211_STA_INFO_MAX + 1] = {
+		[NL80211_STA_INFO_INACTIVE_TIME] = { .type = NLA_U32 },
+		[NL80211_STA_INFO_RX_BYTES] = { .type = NLA_U32 },
+		[NL80211_STA_INFO_TX_BYTES] = { .type = NLA_U32 },
+		[NL80211_STA_INFO_RX_PACKETS] = { .type = NLA_U32 },
+		[NL80211_STA_INFO_TX_PACKETS] = { .type = NLA_U32 },
+		[NL80211_STA_INFO_SIGNAL] = { .type = NLA_U8 },
+		[NL80211_STA_INFO_TX_BITRATE] = { .type = NLA_NESTED },
+		[NL80211_STA_INFO_LLID] = { .type = NLA_U16 },
+		[NL80211_STA_INFO_PLID] = { .type = NLA_U16 },
+		[NL80211_STA_INFO_PLINK_STATE] = { .type = NLA_U8 },
+	};
+
+	static struct nla_policy rate_policy[NL80211_RATE_INFO_MAX + 1] = {
+		[NL80211_RATE_INFO_BITRATE] = { .type = NLA_U16 },
+		[NL80211_RATE_INFO_MCS] = { .type = NLA_U8 },
+		[NL80211_RATE_INFO_40_MHZ_WIDTH] = { .type = NLA_FLAG },
+		[NL80211_RATE_INFO_SHORT_GI] = { .type = NLA_FLAG },
+	};
+
+	if (nla_parse (tb, NL80211_ATTR_MAX, genlmsg_attrdata (gnlh, 0),
+		       genlmsg_attrlen (gnlh, 0), NULL) < 0)
+		return NL_SKIP;
+
+	if (tb[NL80211_ATTR_STA_INFO] == NULL)
+		return NL_SKIP;
+
+	if (nla_parse_nested (sinfo, NL80211_STA_INFO_MAX,
+			      tb[NL80211_ATTR_STA_INFO],
+			      stats_policy))
+		return NL_SKIP;
+
+	if (sinfo[NL80211_STA_INFO_TX_BITRATE] == NULL)
+		return NL_SKIP;
+
+	if (nla_parse_nested (rinfo, NL80211_RATE_INFO_MAX,
+			      sinfo[NL80211_STA_INFO_TX_BITRATE],
+			      rate_policy))
+		return NL_SKIP;
+
+	if (rinfo[NL80211_RATE_INFO_BITRATE] == NULL)
+		return NL_SKIP;
+
+	/* convert from nl80211's units of 100kbps to NM's kbps */
+	info->txrate = nla_get_u16 (rinfo[NL80211_RATE_INFO_BITRATE]) * 100;
+	info->txrate_valid = TRUE;
+
+	if (sinfo[NL80211_STA_INFO_SIGNAL] != NULL) {
+		info->signal = nl80211_xbm_to_percent ((gint8) nla_get_u8 (sinfo[NL80211_STA_INFO_SIGNAL]), 1);
+		info->signal_valid = TRUE;
+	}
+
+	return NL_SKIP;
+}
+
+static void nl80211_get_ap_info (WifiDataNl80211 *nl80211,
+				 struct nl80211_station_info *sta_info)
+{
+	struct nl_msg *msg;
+	struct nl80211_bss_info bss_info;
+
+	memset(sta_info, 0, sizeof(*sta_info));
+
+	nl80211_get_bss_info (nl80211, &bss_info);
+	if (!bss_info.valid)
+		return;
+
+	msg = nl80211_alloc_msg (nl80211, NL80211_CMD_GET_STATION, 0);
+	if (msg) {
+		NLA_PUT (msg, NL80211_ATTR_MAC, ETH_ALEN, bss_info.bssid);
+
+		nl80211_send_and_recv (nl80211, msg, nl80211_station_handler, sta_info);
+		if (!sta_info->signal_valid) {
+			/* Fall back to bss_info signal quality (both are in percent) */
+			sta_info->signal = bss_info.beacon_signal;
+		}
+	}
+
+	return;
+
+ nla_put_failure:
+	nlmsg_free (msg);
+	return;
+}
+
+static guint32
+wifi_nl80211_get_rate (WifiData *data)
+{
+	WifiDataNl80211 *nl80211 = (WifiDataNl80211 *) data;
+	struct nl80211_station_info sta_info;
+
+	nl80211_get_ap_info (nl80211, &sta_info);
+
+	return sta_info.txrate;
+}
+
+static int
+wifi_nl80211_get_qual (WifiData *data)
+{
+	WifiDataNl80211 *nl80211 = (WifiDataNl80211 *) data;
+	struct nl80211_station_info sta_info;
+
+	nl80211_get_ap_info (nl80211, &sta_info);
+	return sta_info.signal;
+}
+
+struct nl80211_device_info {
+	guint32 *freqs;
+	int num_freqs;
+	guint32 caps;
+	gboolean can_scan, can_scan_ssid;
+	gboolean success;
+};
+
+static int nl80211_wiphy_info_handler (struct nl_msg *msg, void *arg)
+{
+	struct nlattr *tb[NL80211_ATTR_MAX + 1];
+	struct genlmsghdr *gnlh = nlmsg_data (nlmsg_hdr (msg));
+	struct nl80211_device_info *info = arg;
+	struct nlattr *tb_band[NL80211_BAND_ATTR_MAX + 1];
+	struct nlattr *tb_freq[NL80211_FREQUENCY_ATTR_MAX + 1];
+	struct nlattr *nl_band;
+	struct nlattr *nl_freq;
+	int rem_freq;
+	int rem_band;
+	int freq_idx;
+	static struct nla_policy freq_policy[NL80211_FREQUENCY_ATTR_MAX + 1] = {
+		[NL80211_FREQUENCY_ATTR_FREQ] = { .type = NLA_U32 },
+		[NL80211_FREQUENCY_ATTR_DISABLED] = { .type = NLA_FLAG },
+		[NL80211_FREQUENCY_ATTR_PASSIVE_SCAN] = { .type = NLA_FLAG },
+		[NL80211_FREQUENCY_ATTR_NO_IBSS] = { .type = NLA_FLAG },
+		[NL80211_FREQUENCY_ATTR_RADAR] = { .type = NLA_FLAG },
+		[NL80211_FREQUENCY_ATTR_MAX_TX_POWER] = { .type = NLA_U32 },
+	};
+
+	if (nla_parse (tb, NL80211_ATTR_MAX, genlmsg_attrdata(gnlh, 0),
+		       genlmsg_attrlen (gnlh, 0), NULL) < 0)
+		return NL_SKIP;
+
+	if (tb[NL80211_ATTR_WIPHY_BANDS] == NULL)
+		return NL_SKIP;
+
+	if (tb[NL80211_ATTR_MAX_NUM_SCAN_SSIDS]) {
+		info->can_scan_ssid =
+			nla_get_u8 (tb[NL80211_ATTR_MAX_NUM_SCAN_SSIDS]) > 0;
+	} else {
+		/* old kernel that only had mac80211, so assume it can */
+		info->can_scan_ssid = TRUE;
+	}
+
+	if (tb[NL80211_ATTR_SUPPORTED_COMMANDS]) {
+		struct nlattr *nl_cmd;
+		int i;
+
+		nla_for_each_nested (nl_cmd,
+				     tb[NL80211_ATTR_SUPPORTED_COMMANDS], i) {
+			guint32 cmd = nla_get_u32 (nl_cmd);
+			if (cmd == NL80211_CMD_TRIGGER_SCAN)
+				info->can_scan = TRUE;
+		}
+	}
+
+	info->num_freqs = 0;
+
+	nla_for_each_nested (nl_band, tb[NL80211_ATTR_WIPHY_BANDS], rem_band) {
+		if (nla_parse_nested (tb_band, NL80211_BAND_ATTR_MAX, nl_band,
+				      NULL) < 0)
+			return NL_SKIP;
+
+		nla_for_each_nested(nl_freq, tb_band[NL80211_BAND_ATTR_FREQS],
+				    rem_freq) {
+			nla_parse_nested (tb_freq, NL80211_FREQUENCY_ATTR_MAX,
+					  nl_freq, freq_policy);
+
+			if (!tb_freq[NL80211_FREQUENCY_ATTR_FREQ])
+				continue;
+
+			info->num_freqs++;
+		}
+	}
+
+	info->freqs = g_malloc0 (sizeof(guint32) * info->num_freqs);
+
+	freq_idx = 0;
+	nla_for_each_nested (nl_band, tb[NL80211_ATTR_WIPHY_BANDS], rem_band) {
+		if (nla_parse_nested (tb_band, NL80211_BAND_ATTR_MAX, nl_band,
+				      NULL) < 0)
+			return NL_SKIP;
+
+		nla_for_each_nested(nl_freq, tb_band[NL80211_BAND_ATTR_FREQS],
+				    rem_freq) {
+			nla_parse_nested (tb_freq, NL80211_FREQUENCY_ATTR_MAX,
+					  nl_freq, freq_policy);
+
+			if (!tb_freq[NL80211_FREQUENCY_ATTR_FREQ])
+				continue;
+
+			info->freqs[freq_idx] =
+				nla_get_u32 (tb_freq[NL80211_FREQUENCY_ATTR_FREQ]);
+			freq_idx++;
+		}
+	}
+
+	if (tb[NL80211_ATTR_CIPHER_SUITES]) {
+		int num;
+		int i;
+		__u32 *ciphers = nla_data (tb[NL80211_ATTR_CIPHER_SUITES]);
+
+		num = nla_len (tb[NL80211_ATTR_CIPHER_SUITES]) / sizeof(__u32);
+		for (i = 0; i < num; i++) {
+			switch (ciphers[i]) {
+			case 0x000fac01:
+				info->caps |= NM_WIFI_DEVICE_CAP_CIPHER_WEP40;
+				break;
+			case 0x000fac05:
+				info->caps |= NM_WIFI_DEVICE_CAP_CIPHER_WEP104;
+				break;
+			case 0x000fac02:
+				info->caps |= NM_WIFI_DEVICE_CAP_CIPHER_TKIP |
+					      NM_WIFI_DEVICE_CAP_WPA;
+				break;
+			case 0x000fac04:
+				info->caps |= NM_WIFI_DEVICE_CAP_CIPHER_CCMP |
+					      NM_WIFI_DEVICE_CAP_RSN;
+				break;
+			}
+		}
+	}
+
+	if (tb[NL80211_ATTR_SUPPORTED_IFTYPES]) {
+		struct nlattr *nl_mode;
+		int i;
+
+		nla_for_each_nested (nl_mode, tb[NL80211_ATTR_SUPPORTED_IFTYPES], i) {
+			if (nla_type (nl_mode) == NL80211_IFTYPE_AP) {
+				info->caps |= NM_WIFI_DEVICE_CAP_AP;
+				break;
+			}
+		}
+	}
+
+	info->success = TRUE;
+
+	return NL_SKIP;
+}
+
+WifiData *
+wifi_nl80211_init (const char *iface, int ifindex)
+{
+	WifiDataNl80211 *nl80211;
+	struct nl_msg *msg;
+	struct nl80211_device_info device_info = {};
+
+	nl80211 = wifi_data_new (iface, ifindex, sizeof (*nl80211));
+	nl80211->parent.get_mode = wifi_nl80211_get_mode;
+	nl80211->parent.set_mode = wifi_nl80211_set_mode;
+	nl80211->parent.get_freq = wifi_nl80211_get_freq;
+	nl80211->parent.find_freq = wifi_nl80211_find_freq;
+	nl80211->parent.get_ssid = wifi_nl80211_get_ssid;
+	nl80211->parent.get_bssid = wifi_nl80211_get_bssid;
+	nl80211->parent.get_rate = wifi_nl80211_get_rate;
+	nl80211->parent.get_qual = wifi_nl80211_get_qual;
+	nl80211->parent.deinit = wifi_nl80211_deinit;
+
+	nl80211->nl_sock = nl_socket_alloc ();
+	if (nl80211->nl_sock == NULL)
+		goto error;
+
+	if (genl_connect (nl80211->nl_sock))
+		goto error;
+
+	nl80211->id = genl_ctrl_resolve (nl80211->nl_sock, "nl80211");
+	if (nl80211->id < 0)
+		goto error;
+
+	nl80211->nl_cb = nl_cb_alloc (NL_CB_DEFAULT);
+	if (nl80211->nl_cb == NULL)
+		goto error;
+
+	msg = nl80211_alloc_msg (nl80211, NL80211_CMD_GET_WIPHY, 0);
+
+	if (nl80211_send_and_recv (nl80211, msg, nl80211_wiphy_info_handler,
+				   &device_info) < 0) {
+		nm_log_dbg (LOGD_HW | LOGD_WIFI,
+				    "(%s): NL80211_CMD_GET_WIPHY request failed",
+				    nl80211->parent.iface);
+		goto error;
+	}
+
+	if (!device_info.success) {
+		nm_log_dbg (LOGD_HW | LOGD_WIFI,
+				    "(%s): NL80211_CMD_GET_WIPHY request indicated failure",
+				    nl80211->parent.iface);
+		goto error;
+	}
+
+	if (!device_info.can_scan_ssid) {
+		nm_log_err (LOGD_HW | LOGD_WIFI,
+		            "(%s): driver does not support SSID scans",
+		            nl80211->parent.iface);
+		goto error;
+	}
+
+	if (device_info.num_freqs == 0 || device_info.freqs == NULL) {
+		nm_log_err (LOGD_HW | LOGD_WIFI,
+				    "(%s): driver reports no supported frequencies",
+				    nl80211->parent.iface);
+		goto error;
+	}
+
+	nl80211->freqs = device_info.freqs;
+	nl80211->num_freqs = device_info.num_freqs;
+	nl80211->parent.can_scan_ssid = device_info.can_scan_ssid;
+	nl80211->parent.caps = device_info.caps;
+
+	nm_log_info (LOGD_HW | LOGD_WIFI,
+	             "(%s): using nl80211 for WiFi device control",
+	             nl80211->parent.iface);
+
+	return (WifiData *) nl80211;
+
+error:
+	wifi_utils_deinit ((WifiData *) nl80211);
+	return NULL;
+}
+
+static int
+iface_to_index (struct nl_sock *nl_sock, const char *iface)
+{
+	struct nl_cache *link_cache = NULL;
+	int err, ifindex;
+
+	/* name to index */
+	err = rtnl_link_alloc_cache (nl_sock, &link_cache);
+	if (err < 0) {
+		nm_log_warn (LOGD_HW, "failed to allocate link cache: (%d) %s",
+		             err, nl_geterror (err));
+		return -1;
+	}
+	nl_cache_mngt_provide (link_cache);
+	nl_cache_refill (nl_sock, link_cache);
+	ifindex = rtnl_link_name2i (link_cache, iface);
+	nl_cache_free (link_cache);
+
+	return ifindex;
+}
+
+gboolean
+wifi_nl80211_is_wifi (const char *iface)
+{
+	struct nl_sock *nl_sock;
+	struct nl_cb *nl_cb = NULL;
+	struct nl_msg *msg = NULL;
+	int id, ifindex;
+	struct nl80211_iface_info iface_info = {
+		.mode = NM_802_11_MODE_UNKNOWN,
+	};
+	gboolean is_wifi = FALSE;
+
+	nl_sock = nl_socket_alloc ();
+	if (nl_sock == NULL)
+		return FALSE;
+
+	if (genl_connect (nl_sock))
+		goto error;
+
+	ifindex = iface_to_index (nl_sock, iface);
+	if (ifindex < 0)
+		goto error;
+
+	id = genl_ctrl_resolve (nl_sock, "nl80211");
+	if (id < 0)
+		goto error;
+
+	nl_cb = nl_cb_alloc (NL_CB_DEFAULT);
+	if (nl_cb) {
+		msg = _nl80211_alloc_msg (id, ifindex, NL80211_CMD_GET_INTERFACE, 0);
+		if (_nl80211_send_and_recv (nl_sock,
+			                        nl_cb,
+			                        msg,
+			                        nl80211_iface_info_handler,
+			                        &iface_info) >= 0)
+			is_wifi = (iface_info.mode != NM_802_11_MODE_UNKNOWN);
+	}
+
+ error:
+	if (nl_cb)
+		nl_cb_put (nl_cb);
+	nl_socket_free (nl_sock);
+	return is_wifi;
+}
+
diff --git a/src/wifi/wifi-utils-nl80211.h b/src/wifi/wifi-utils-nl80211.h
new file mode 100644
index 00000000..2a7fe874
--- /dev/null
+++ b/src/wifi/wifi-utils-nl80211.h
@@ -0,0 +1,30 @@
+/* -*- 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 Intel Corporation. All rights reserved.
+ */
+
+#ifndef WIFI_UTILS_NL80211_H
+#define WIFI_UTILS_NL80211_H
+
+#include "wifi-utils.h"
+
+WifiData *wifi_nl80211_init (const char *iface, int ifindex);
+
+gboolean wifi_nl80211_is_wifi (const char *iface);
+
+#endif  /* WIFI_UTILS_NL80211_H */
diff --git a/src/wifi/wifi-utils-private.h b/src/wifi/wifi-utils-private.h
new file mode 100644
index 00000000..83075090
--- /dev/null
+++ b/src/wifi/wifi-utils-private.h
@@ -0,0 +1,74 @@
+/* -*- 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 WIFI_UTILS_PRIVATE_H
+#define WIFI_UTILS_PRIVATE_H
+
+#include <glib.h>
+
+#include "NetworkManager.h"
+#include "wifi-utils.h"
+
+struct WifiData {
+	char *iface;
+	int ifindex;
+	NMDeviceWifiCapabilities caps;
+	gboolean can_scan_ssid;
+
+	NM80211Mode (*get_mode) (WifiData *data);
+
+	gboolean (*set_mode) (WifiData *data, const NM80211Mode mode);
+
+	/* Return current frequency in MHz (really associated BSS frequency) */
+	guint32 (*get_freq) (WifiData *data);
+
+	/* Return first supported frequency in the zero-terminated list */
+	guint32 (*find_freq) (WifiData *data, const guint32 *freqs);
+
+	/* If SSID is empty/blank (zero-length or all \0s) return NULL */
+	GByteArray * (*get_ssid) (WifiData *data);
+
+	/* Return current bitrate in Kbps */
+	guint32 (*get_rate) (WifiData *data);
+
+	gboolean (*get_bssid) (WifiData *data, struct ether_addr *out_bssid);
+
+	/* Return a signal strength percentage 0 - 100% for the current BSSID;
+	 * return -1 on errors or if not associated.
+	 */
+	int (*get_qual) (WifiData *data);
+
+	void (*deinit) (WifiData *data);
+
+	/* OLPC Mesh-only functions */
+
+	guint32 (*get_mesh_channel) (WifiData *data);
+
+	/* channel == 0 means "auto channel" */
+	gboolean (*set_mesh_channel) (WifiData *data, guint32 channel);
+
+	/* ssid == NULL means "auto SSID" */
+	gboolean (*set_mesh_ssid) (WifiData *data, const GByteArray *ssid);
+};
+
+gpointer wifi_data_new (const char *iface, int ifindex, gsize len);
+void wifi_data_free (WifiData *data);
+
+#endif  /* WIFI_UTILS_PRIVATE_H */
diff --git a/src/wifi/wifi-utils-wext.c b/src/wifi/wifi-utils-wext.c
new file mode 100644
index 00000000..75d00f41
--- /dev/null
+++ b/src/wifi/wifi-utils-wext.c
@@ -0,0 +1,663 @@
+/* -*- 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) 2005 - 2011 Red Hat, Inc.
+ * Copyright (C) 2006 - 2008 Novell, Inc.
+ */
+
+#include <config.h>
+#include <errno.h>
+#include <string.h>
+#include <sys/ioctl.h>
+#include <net/ethernet.h>
+#include <unistd.h>
+#include <math.h>
+
+#include <glib.h>
+
+#include "wifi-utils-private.h"
+#include "wifi-utils-wext.h"
+#include "nm-logging.h"
+#include "nm-utils.h"
+
+/* Hacks necessary to #include wireless.h; yay for WEXT */
+#ifndef __user
+#define __user
+#endif
+#include <sys/types.h>
+#include <linux/types.h>
+#include <sys/socket.h>
+#include <linux/if.h>
+#include <linux/wireless.h>
+
+
+typedef struct {
+	WifiData parent;
+	int fd;
+	struct iw_quality max_qual;
+	gint8 num_freqs;
+	guint32 freqs[IW_MAX_FREQUENCIES];
+} WifiDataWext;
+
+/* Until a new wireless-tools comes out that has the defs and the structure,
+ * need to copy them here.
+ */
+/* Scan capability flags - in (struct iw_range *)->scan_capa */
+#define NM_IW_SCAN_CAPA_NONE    0x00
+#define NM_IW_SCAN_CAPA_ESSID   0x01
+
+struct iw_range_with_scan_capa
+{
+	guint32 throughput;
+	guint32 min_nwid;
+	guint32 max_nwid;
+	guint16 old_num_channels;
+	guint8  old_num_frequency;
+
+	guint8  scan_capa;
+/* don't need the rest... */
+};
+
+static guint32
+iw_freq_to_uint32 (struct iw_freq *freq)
+{
+	if (freq->e == 0) {
+		/* Some drivers report channel not frequency.  Convert to a
+		 * frequency; but this assumes that the device is in b/g mode.
+		 */
+		if ((freq->m >= 1) && (freq->m <= 13))
+			return 2407 + (5 * freq->m);
+		else if (freq->m == 14)
+			return 2484;
+	}
+
+	return (guint32) (((double) freq->m) * pow (10, freq->e) / 1000000);
+}
+
+static void
+wifi_wext_deinit (WifiData *parent)
+{
+	WifiDataWext *wext = (WifiDataWext *) parent;
+
+	if (wext->fd >= 0)
+		close (wext->fd);
+}
+
+static NM80211Mode
+wifi_wext_get_mode (WifiData *data)
+{
+	WifiDataWext *wext = (WifiDataWext *) data;
+	struct iwreq wrq;
+
+	memset (&wrq, 0, sizeof (struct iwreq));
+	strncpy (wrq.ifr_name, wext->parent.iface, IFNAMSIZ);
+
+	if (ioctl (wext->fd, SIOCGIWMODE, &wrq) < 0) {
+		if (errno != ENODEV) {
+			nm_log_warn (LOGD_HW | LOGD_WIFI,
+			             "(%s): error %d getting card mode",
+			             wext->parent.iface, errno);
+		}
+		return NM_802_11_MODE_UNKNOWN;
+	}
+
+	switch (wrq.u.mode) {
+	case IW_MODE_ADHOC:
+		return NM_802_11_MODE_ADHOC;
+	case IW_MODE_INFRA:
+		return NM_802_11_MODE_INFRA;
+	default:
+		break;
+	}
+	return NM_802_11_MODE_UNKNOWN;
+}
+
+static gboolean
+wifi_wext_set_mode (WifiData *data, const NM80211Mode mode)
+{
+	WifiDataWext *wext = (WifiDataWext *) data;
+	struct iwreq wrq;
+
+	if (wifi_wext_get_mode (data) == mode)
+		return TRUE;
+
+	memset (&wrq, 0, sizeof (struct iwreq));
+	switch (mode) {
+	case NM_802_11_MODE_ADHOC:
+		wrq.u.mode = IW_MODE_ADHOC;
+		break;
+	case NM_802_11_MODE_INFRA:
+		wrq.u.mode = IW_MODE_INFRA;
+		break;
+	default:
+		g_warn_if_reached ();
+		return FALSE;
+	}
+
+	strncpy (wrq.ifr_name, wext->parent.iface, IFNAMSIZ);
+	if (ioctl (wext->fd, SIOCSIWMODE, &wrq) < 0) {
+		if (errno != ENODEV) {
+			nm_log_err (LOGD_HW | LOGD_WIFI, "(%s): error setting mode %d",
+			            wext->parent.iface, mode);
+		}
+		return FALSE;
+	}
+
+	return TRUE;
+}
+
+static guint32
+wifi_wext_get_freq (WifiData *data)
+{
+	WifiDataWext *wext = (WifiDataWext *) data;
+	struct iwreq wrq;
+
+	memset (&wrq, 0, sizeof (struct iwreq));
+	strncpy (wrq.ifr_name, wext->parent.iface, IFNAMSIZ);
+	if (ioctl (wext->fd, SIOCGIWFREQ, &wrq) < 0) {
+		nm_log_warn (LOGD_HW | LOGD_WIFI,
+		             "(%s): error getting frequency: %s",
+		             wext->parent.iface, strerror (errno));
+		return 0;
+	}
+
+	return iw_freq_to_uint32 (&wrq.u.freq);
+}
+
+static guint32
+wifi_wext_find_freq (WifiData *data, const guint32 *freqs)
+{
+	WifiDataWext *wext = (WifiDataWext *) data;
+	int i;
+
+	for (i = 0; i < wext->num_freqs; i++) {
+		while (*freqs) {
+			if (wext->freqs[i] == *freqs)
+				return *freqs;
+			freqs++;
+		}
+	}
+	return 0;
+}
+
+static GByteArray *
+wifi_wext_get_ssid (WifiData *data)
+{
+	WifiDataWext *wext = (WifiDataWext *) data;
+	struct iwreq wrq;
+	char ssid[IW_ESSID_MAX_SIZE + 2];
+	guint32 len;
+	GByteArray *array = NULL;
+
+	memset (ssid, 0, sizeof (ssid));
+	wrq.u.essid.pointer = (caddr_t) &ssid;
+	wrq.u.essid.length = sizeof (ssid);
+	wrq.u.essid.flags = 0;
+	strncpy (wrq.ifr_name, wext->parent.iface, IFNAMSIZ);
+
+	if (ioctl (wext->fd, SIOCGIWESSID, &wrq) < 0) {
+		nm_log_err (LOGD_HW | LOGD_WIFI, "(%s): couldn't get SSID: %d",
+		            wext->parent.iface, errno);
+		return NULL;
+	}
+
+	len = wrq.u.essid.length;
+	if (nm_utils_is_empty_ssid ((guint8 *) ssid, len) == FALSE) {
+		array = g_byte_array_sized_new (len);
+		g_byte_array_append (array, (const guint8 *) ssid, len);
+	}
+
+	return array;
+}
+
+static gboolean
+wifi_wext_get_bssid (WifiData *data, struct ether_addr *out_bssid)
+{
+	WifiDataWext *wext = (WifiDataWext *) data;
+	struct iwreq wrq;
+
+	memset (&wrq, 0, sizeof (wrq));
+	strncpy (wrq.ifr_name, wext->parent.iface, IFNAMSIZ);
+	if (ioctl (wext->fd, SIOCGIWAP, &wrq) < 0) {
+		nm_log_warn (LOGD_HW | LOGD_WIFI,
+		             "(%s): error getting associated BSSID: %s",
+		             wext->parent.iface, strerror (errno));
+		return FALSE;
+	}
+	memcpy (out_bssid->ether_addr_octet, &(wrq.u.ap_addr.sa_data), ETH_ALEN);
+	return TRUE;
+}
+
+static guint32
+wifi_wext_get_rate (WifiData *data)
+{
+	WifiDataWext *wext = (WifiDataWext *) data;
+	struct iwreq wrq;
+	int err;
+
+	memset (&wrq, 0, sizeof (wrq));
+	strncpy (wrq.ifr_name, wext->parent.iface, IFNAMSIZ);
+	err = ioctl (wext->fd, SIOCGIWRATE, &wrq);
+	return ((err == 0) ? wrq.u.bitrate.value / 1000 : 0);
+}
+
+static int
+wext_qual_to_percent (const struct iw_quality *qual,
+                      const struct iw_quality *max_qual)
+{
+	int percent = -1;
+	int level_percent = -1;
+
+	g_return_val_if_fail (qual != NULL, -1);
+	g_return_val_if_fail (max_qual != NULL, -1);
+
+	/* Magically convert the many different WEXT quality representations to a percentage */
+
+	nm_log_dbg (LOGD_WIFI,
+	            "QL: qual %d/%u/0x%X, level %d/%u/0x%X, noise %d/%u/0x%X, updated: 0x%X  ** MAX: qual %d/%u/0x%X, level %d/%u/0x%X, noise %d/%u/0x%X, updated: 0x%X",
+	            (__s8) qual->qual, qual->qual, qual->qual,
+	            (__s8) qual->level, qual->level, qual->level,
+	            (__s8) qual->noise, qual->noise, qual->noise,
+	            qual->updated,
+	            (__s8) max_qual->qual, max_qual->qual, max_qual->qual,
+	            (__s8) max_qual->level, max_qual->level, max_qual->level,
+	            (__s8) max_qual->noise, max_qual->noise, max_qual->noise,
+	            max_qual->updated);
+
+	/* Try using the card's idea of the signal quality first as long as it tells us what the max quality is.
+	 * Drivers that fill in quality values MUST treat them as percentages, ie the "Link Quality" MUST be 
+	 * bounded by 0 and max_qual->qual, and MUST change in a linear fashion.  Within those bounds, drivers
+	 * are free to use whatever they want to calculate "Link Quality".
+	 */
+	if ((max_qual->qual != 0) && !(max_qual->updated & IW_QUAL_QUAL_INVALID) && !(qual->updated & IW_QUAL_QUAL_INVALID))
+		percent = (int)(100 * ((double)qual->qual / (double)max_qual->qual));
+
+	/* If the driver doesn't specify a complete and valid quality, we have two options:
+	 *
+	 * 1) dBm: driver must specify max_qual->level = 0, and have valid values for
+	 *        qual->level and (qual->noise OR max_qual->noise)
+	 * 2) raw RSSI: driver must specify max_qual->level > 0, and have valid values for
+	 *        qual->level and max_qual->level
+	 *
+	 * This is the WEXT spec.  If this interpretation is wrong, I'll fix it.  Otherwise,
+	 * If drivers don't conform to it, they are wrong and need to be fixed.
+	 */
+
+	if (    (max_qual->level == 0) && !(max_qual->updated & IW_QUAL_LEVEL_INVALID)          /* Valid max_qual->level == 0 */
+		&& !(qual->updated & IW_QUAL_LEVEL_INVALID)                                     /* Must have valid qual->level */
+		&& (    ((max_qual->noise > 0) && !(max_qual->updated & IW_QUAL_NOISE_INVALID)) /* Must have valid max_qual->noise */
+			|| ((qual->noise > 0) && !(qual->updated & IW_QUAL_NOISE_INVALID)))     /*    OR valid qual->noise */
+	   ) {
+		/* Absolute power values (dBm) */
+
+		/* Reasonable fallbacks for dumb drivers that don't specify either level. */
+		#define FALLBACK_NOISE_FLOOR_DBM  -90
+		#define FALLBACK_SIGNAL_MAX_DBM   -20
+		int max_level = FALLBACK_SIGNAL_MAX_DBM;
+		int noise = FALLBACK_NOISE_FLOOR_DBM;
+		int level = qual->level - 0x100;
+
+		level = CLAMP (level, FALLBACK_NOISE_FLOOR_DBM, FALLBACK_SIGNAL_MAX_DBM);
+
+		if ((qual->noise > 0) && !(qual->updated & IW_QUAL_NOISE_INVALID))
+			noise = qual->noise - 0x100;
+		else if ((max_qual->noise > 0) && !(max_qual->updated & IW_QUAL_NOISE_INVALID))
+			noise = max_qual->noise - 0x100;
+		noise = CLAMP (noise, FALLBACK_NOISE_FLOOR_DBM, FALLBACK_SIGNAL_MAX_DBM);
+
+		/* A sort of signal-to-noise ratio calculation */
+		level_percent = (int)(100 - 70 *(
+		                                ((double)max_level - (double)level) /
+		                                ((double)max_level - (double)noise)));
+		nm_log_dbg (LOGD_WIFI, "QL1: level_percent is %d.  max_level %d, level %d, noise_floor %d.",
+		            level_percent, max_level, level, noise);
+	} else if (   (max_qual->level != 0)
+	           && !(max_qual->updated & IW_QUAL_LEVEL_INVALID) /* Valid max_qual->level as upper bound */
+	           && !(qual->updated & IW_QUAL_LEVEL_INVALID)) {
+		/* Relative power values (RSSI) */
+
+		int level = qual->level;
+
+		/* Signal level is relavtive (0 -> max_qual->level) */
+		level = CLAMP (level, 0, max_qual->level);
+		level_percent = (int)(100 * ((double)level / (double)max_qual->level));
+		nm_log_dbg (LOGD_WIFI, "QL2: level_percent is %d.  max_level %d, level %d.",
+		            level_percent, max_qual->level, level);
+	} else if (percent == -1) {
+		nm_log_dbg (LOGD_WIFI, "QL: Could not get quality %% value from driver.  Driver is probably buggy.");
+	}
+
+	/* If the quality percent was 0 or doesn't exist, then try to use signal levels instead */
+	if ((percent < 1) && (level_percent >= 0))
+		percent = level_percent;
+
+	nm_log_dbg (LOGD_WIFI, "QL: Final quality percent is %d (%d).",
+	            percent, CLAMP (percent, 0, 100));
+	return (CLAMP (percent, 0, 100));
+}
+
+static int
+wifi_wext_get_qual (WifiData *data)
+{
+	WifiDataWext *wext = (WifiDataWext *) data;
+	struct iwreq wrq;
+	struct iw_statistics stats;
+
+	memset (&stats, 0, sizeof (stats));
+	wrq.u.data.pointer = &stats;
+	wrq.u.data.length = sizeof (stats);
+	wrq.u.data.flags = 1;  /* Clear updated flag */
+	strncpy (wrq.ifr_name, wext->parent.iface, IFNAMSIZ);
+
+	if (ioctl (wext->fd, SIOCGIWSTATS, &wrq) < 0) {
+		nm_log_warn (LOGD_HW | LOGD_WIFI,
+		             "(%s): error getting signal strength: %s",
+		             wext->parent.iface, strerror (errno));
+		return -1;
+	}
+
+	return wext_qual_to_percent (&stats.qual, &wext->max_qual);
+}
+
+/*********************/
+/* OLPC Mesh-only functions */
+
+static guint32
+wifi_wext_get_mesh_channel (WifiData *data)
+{
+	WifiDataWext *wext = (WifiDataWext *) data;
+	guint32 freq;
+	int i;
+
+	freq = wifi_utils_get_freq (data);
+	for (i = 0; i < wext->num_freqs; i++) {
+		if (freq == wext->freqs[i])
+			return i + 1;
+	}
+	return 0;
+}
+
+static gboolean
+wifi_wext_set_mesh_channel (WifiData *data, guint32 channel)
+{
+	WifiDataWext *wext = (WifiDataWext *) data;
+	struct iwreq wrq;
+
+	memset (&wrq, 0, sizeof (struct iwreq));
+	strncpy (wrq.ifr_name, wext->parent.iface, IFNAMSIZ);
+
+	if (channel > 0) {
+		wrq.u.freq.flags = IW_FREQ_FIXED;
+		wrq.u.freq.e = 0;
+		wrq.u.freq.m = channel;
+	}
+
+	if (ioctl (wext->fd, SIOCSIWFREQ, &wrq) < 0) {
+		nm_log_err (LOGD_HW | LOGD_WIFI | LOGD_OLPC_MESH,
+		            "(%s): error setting channel to %d: %s",
+		            wext->parent.iface, channel, strerror (errno));
+		return FALSE;
+	}
+
+	return TRUE;
+}
+
+static gboolean
+wifi_wext_set_mesh_ssid (WifiData *data, const GByteArray *ssid)
+{
+	WifiDataWext *wext = (WifiDataWext *) data;
+	struct iwreq wrq;
+	guint32 len = 0;
+	char buf[IW_ESSID_MAX_SIZE + 1];
+
+	memset (buf, 0, sizeof (buf));
+	if (ssid) {
+		len = ssid->len;
+		memcpy (buf, ssid->data, MIN (sizeof (buf) - 1, len));
+	}
+	wrq.u.essid.pointer = (caddr_t) buf;
+	wrq.u.essid.length = len;
+	wrq.u.essid.flags = (len > 0) ? 1 : 0; /* 1=enable SSID, 0=disable/any */
+
+	strncpy (wrq.ifr_name, wext->parent.iface, IFNAMSIZ);
+	if (ioctl (wext->fd, SIOCSIWESSID, &wrq) == 0)
+		return TRUE;
+
+	if (errno != ENODEV) {
+		nm_log_err (LOGD_HW | LOGD_WIFI | LOGD_OLPC_MESH,
+		            "(%s): error setting SSID to '%s': %s",
+		            wext->parent.iface,
+		            ssid ? nm_utils_escape_ssid (ssid->data, ssid->len) : "(null)",
+		            strerror (errno));
+	}
+
+	return FALSE;
+}
+
+/*********************/
+
+static gboolean
+wext_can_scan (WifiDataWext *wext)
+{
+	struct iwreq wrq;
+
+	memset (&wrq, 0, sizeof (struct iwreq));
+	strncpy (wrq.ifr_name, wext->parent.iface, IFNAMSIZ);
+	if (ioctl (wext->fd, SIOCSIWSCAN, &wrq) < 0) {
+		if (errno == EOPNOTSUPP)
+			return FALSE;
+	}
+	return TRUE;
+}
+
+static gboolean
+wext_get_range (WifiDataWext *wext,
+                struct iw_range *range,
+                guint32 *response_len)
+{
+	int i = 26;
+	gboolean success = FALSE;
+	struct iwreq wrq;
+
+	memset (&wrq, 0, sizeof (struct iwreq));
+	strncpy (wrq.ifr_name, wext->parent.iface, IFNAMSIZ);
+	wrq.u.data.pointer = (caddr_t) range;
+	wrq.u.data.length = sizeof (struct iw_range);
+
+	/* Need to give some drivers time to recover after suspend/resume
+	 * (ex ipw3945 takes a few seconds to talk to its regulatory daemon;
+	 * see rh bz#362421)
+	 */
+	while (i-- > 0) {
+		if (ioctl (wext->fd, SIOCGIWRANGE, &wrq) == 0) {
+			if (response_len)
+				*response_len = wrq.u.data.length;
+			success = TRUE;
+			break;
+		} else if (errno != EAGAIN) {
+			nm_log_err (LOGD_HW | LOGD_WIFI,
+			            "(%s): couldn't get driver range information (%d).",
+			            wext->parent.iface, errno);
+			break;
+		}
+
+		g_usleep (G_USEC_PER_SEC / 4);
+	}
+
+	if (i <= 0) {
+		nm_log_warn (LOGD_HW | LOGD_WIFI,
+		             "(%s): driver took too long to respond to IWRANGE query.",
+		             wext->parent.iface);
+	}
+
+	return success;
+}
+
+#define WPA_CAPS (NM_WIFI_DEVICE_CAP_CIPHER_TKIP | \
+                  NM_WIFI_DEVICE_CAP_CIPHER_CCMP | \
+                  NM_WIFI_DEVICE_CAP_WPA | \
+                  NM_WIFI_DEVICE_CAP_RSN)
+
+static guint32
+wext_get_caps (WifiDataWext *wext, struct iw_range *range)
+{
+	guint32 caps = NM_WIFI_DEVICE_CAP_NONE;
+
+	g_return_val_if_fail (wext != NULL, NM_WIFI_DEVICE_CAP_NONE);
+	g_return_val_if_fail (range != NULL, NM_WIFI_DEVICE_CAP_NONE);
+
+	/* All drivers should support WEP by default */
+	caps |= NM_WIFI_DEVICE_CAP_CIPHER_WEP40 | NM_WIFI_DEVICE_CAP_CIPHER_WEP104;
+
+	if (range->enc_capa & IW_ENC_CAPA_CIPHER_TKIP)
+		caps |= NM_WIFI_DEVICE_CAP_CIPHER_TKIP;
+
+	if (range->enc_capa & IW_ENC_CAPA_CIPHER_CCMP)
+		caps |= NM_WIFI_DEVICE_CAP_CIPHER_CCMP;
+
+	if (range->enc_capa & IW_ENC_CAPA_WPA)
+		caps |= NM_WIFI_DEVICE_CAP_WPA;
+
+	if (range->enc_capa & IW_ENC_CAPA_WPA2)
+		caps |= NM_WIFI_DEVICE_CAP_RSN;
+
+	/* Check for cipher support but not WPA support */
+	if (    (caps & (NM_WIFI_DEVICE_CAP_CIPHER_TKIP | NM_WIFI_DEVICE_CAP_CIPHER_CCMP))
+	    && !(caps & (NM_WIFI_DEVICE_CAP_WPA | NM_WIFI_DEVICE_CAP_RSN))) {
+		nm_log_warn (LOGD_WIFI, "%s: device supports WPA ciphers but not WPA protocol; "
+		             "WPA unavailable.", wext->parent.iface);
+		caps &= ~WPA_CAPS;
+	}
+
+	/* Check for WPA support but not cipher support */
+	if (    (caps & (NM_WIFI_DEVICE_CAP_WPA | NM_WIFI_DEVICE_CAP_RSN))
+	    && !(caps & (NM_WIFI_DEVICE_CAP_CIPHER_TKIP | NM_WIFI_DEVICE_CAP_CIPHER_CCMP))) {
+		nm_log_warn (LOGD_WIFI, "%s: device supports WPA protocol but not WPA ciphers; "
+		             "WPA unavailable.", wext->parent.iface);
+		caps &= ~WPA_CAPS;
+	}
+
+	return caps;
+}
+
+WifiData *
+wifi_wext_init (const char *iface, int ifindex, gboolean check_scan)
+{
+	WifiDataWext *wext;
+	struct iw_range range;
+	guint32 response_len = 0;
+	struct iw_range_with_scan_capa *scan_capa_range;
+	int i;
+
+	wext = wifi_data_new (iface, ifindex, sizeof (*wext));
+	wext->parent.get_mode = wifi_wext_get_mode;
+	wext->parent.set_mode = wifi_wext_set_mode;
+	wext->parent.get_freq = wifi_wext_get_freq;
+	wext->parent.find_freq = wifi_wext_find_freq;
+	wext->parent.get_ssid = wifi_wext_get_ssid;
+	wext->parent.get_bssid = wifi_wext_get_bssid;
+	wext->parent.get_rate = wifi_wext_get_rate;
+	wext->parent.get_qual = wifi_wext_get_qual;
+	wext->parent.deinit = wifi_wext_deinit;
+	wext->parent.get_mesh_channel = wifi_wext_get_mesh_channel;
+	wext->parent.set_mesh_channel = wifi_wext_set_mesh_channel;
+	wext->parent.set_mesh_ssid = wifi_wext_set_mesh_ssid;
+
+	wext->fd = socket (PF_INET, SOCK_DGRAM, 0);
+	if (wext->fd < 0)
+		goto error;
+
+	memset (&range, 0, sizeof (struct iw_range));
+	if (wext_get_range (wext, &range, &response_len) == FALSE) {
+		nm_log_info (LOGD_HW | LOGD_WIFI, "(%s): driver WEXT range request failed",
+		             wext->parent.iface);
+		goto error;
+	}
+
+	if ((response_len < 300) || (range.we_version_compiled < 21)) {
+		nm_log_info (LOGD_HW | LOGD_WIFI,
+		             "(%s): driver WEXT version too old (got %d, expected >= 21)",
+		             wext->parent.iface,
+		             range.we_version_compiled);
+		goto error;
+	}
+
+	wext->max_qual.qual = range.max_qual.qual;
+	wext->max_qual.level = range.max_qual.level;
+	wext->max_qual.noise = range.max_qual.noise;
+	wext->max_qual.updated = range.max_qual.updated;
+
+	wext->num_freqs = MIN (range.num_frequency, IW_MAX_FREQUENCIES);
+	for (i = 0; i < wext->num_freqs; i++)
+		wext->freqs[i] = iw_freq_to_uint32 (&range.freq[i]);
+
+	/* Check for scanning capability; cards that can't scan are not supported */
+	if (check_scan && (wext_can_scan (wext) == FALSE)) {
+		nm_log_info (LOGD_HW | LOGD_WIFI,
+		             "(%s): drivers that cannot scan are unsupported",
+		             wext->parent.iface);
+		goto error;
+	}
+
+	/* Check for the ability to scan specific SSIDs.  Until the scan_capa
+	 * field gets added to wireless-tools, need to work around that by casting
+	 * to the custom structure.
+	 */
+	scan_capa_range = (struct iw_range_with_scan_capa *) &range;
+	if (scan_capa_range->scan_capa & NM_IW_SCAN_CAPA_ESSID) {
+		wext->parent.can_scan_ssid = TRUE;
+		nm_log_info (LOGD_HW | LOGD_WIFI,
+		             "(%s): driver supports SSID scans (scan_capa 0x%02X).",
+		             wext->parent.iface,
+		             scan_capa_range->scan_capa);
+	} else {
+		nm_log_info (LOGD_HW | LOGD_WIFI,
+		             "(%s): driver does not support SSID scans (scan_capa 0x%02X).",
+		             wext->parent.iface,
+		             scan_capa_range->scan_capa);
+	}
+
+	wext->parent.caps = wext_get_caps (wext, &range);
+
+	nm_log_info (LOGD_HW | LOGD_WIFI,
+	             "(%s): using WEXT for WiFi device control",
+	             wext->parent.iface);
+
+	return (WifiData *) wext;
+
+error:
+	wifi_utils_deinit ((WifiData *) wext);
+	return NULL;
+}
+
+gboolean
+wifi_wext_is_wifi (const char *iface)
+{
+	int fd;
+	struct iwreq iwr;
+	gboolean is_wifi = FALSE;
+
+	fd = socket (PF_INET, SOCK_DGRAM, 0);
+	if (fd >= 0) {
+		strncpy (iwr.ifr_ifrn.ifrn_name, iface, IFNAMSIZ);
+		if (ioctl (fd, SIOCGIWNAME, &iwr) == 0)
+			is_wifi = TRUE;
+		close (fd);
+	}
+	return is_wifi;
+}
+
diff --git a/src/wifi/wifi-utils-wext.h b/src/wifi/wifi-utils-wext.h
new file mode 100644
index 00000000..96ad74eb
--- /dev/null
+++ b/src/wifi/wifi-utils-wext.h
@@ -0,0 +1,30 @@
+/* -*- 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 WIFI_UTILS_WEXT_H
+#define WIFI_UTILS_WEXT_H
+
+#include "wifi-utils.h"
+
+WifiData *wifi_wext_init (const char *iface, int ifindex, gboolean check_scan);
+
+gboolean wifi_wext_is_wifi (const char *iface);
+
+#endif  /* WIFI_UTILS_WEXT_H */
diff --git a/src/wifi/wifi-utils.c b/src/wifi/wifi-utils.c
new file mode 100644
index 00000000..a99a4b7b
--- /dev/null
+++ b/src/wifi/wifi-utils.c
@@ -0,0 +1,213 @@
+/* -*- 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) 2005 - 2011 Red Hat, Inc.
+ * Copyright (C) 2006 - 2008 Novell, Inc.
+ */
+
+#include <config.h>
+#include <sys/stat.h>
+#include <stdio.h>
+#include <string.h>
+#include <glib.h>
+
+#include "wifi-utils.h"
+#include "wifi-utils-private.h"
+#include "wifi-utils-nl80211.h"
+#if HAVE_WEXT
+#include "wifi-utils-wext.h"
+#endif
+
+gpointer
+wifi_data_new (const char *iface, int ifindex, gsize len)
+{
+	WifiData *data;
+
+	data = g_malloc0 (len);
+	data->iface = g_strdup (iface);
+	data->ifindex = ifindex;
+	return data;
+}
+
+void
+wifi_data_free (WifiData *data)
+{
+	g_free (data->iface);
+	memset (data, 0, sizeof (*data));
+	g_free (data);
+}
+
+/***************************************************************/
+
+WifiData *
+wifi_utils_init (const char *iface, int ifindex, gboolean check_scan)
+{
+	WifiData *ret;
+
+	g_return_val_if_fail (iface != NULL, NULL);
+	g_return_val_if_fail (ifindex > 0, NULL);
+
+	ret = wifi_nl80211_init (iface, ifindex);
+	if (ret == NULL) {
+#if HAVE_WEXT
+		ret = wifi_wext_init (iface, ifindex, check_scan);
+#endif
+	}
+	return ret;
+}
+
+NMDeviceWifiCapabilities
+wifi_utils_get_caps (WifiData *data)
+{
+	g_return_val_if_fail (data != NULL, NM_WIFI_DEVICE_CAP_NONE);
+
+	return data->caps;	
+}
+
+gboolean
+wifi_utils_can_scan_ssid (WifiData *data)
+{
+	g_return_val_if_fail (data != NULL, FALSE);
+	return data->can_scan_ssid;
+}
+
+NM80211Mode
+wifi_utils_get_mode (WifiData *data)
+{
+	g_return_val_if_fail (data != NULL, NM_802_11_MODE_UNKNOWN);
+	return data->get_mode (data);
+}
+
+gboolean
+wifi_utils_set_mode (WifiData *data, const NM80211Mode mode)
+{
+	g_return_val_if_fail (data != NULL, FALSE);
+	g_return_val_if_fail ((mode == NM_802_11_MODE_INFRA) || (mode == NM_802_11_MODE_ADHOC), FALSE);
+
+	/* nl80211 probably doesn't need this */
+	return data->set_mode ? data->set_mode (data, mode) : TRUE;
+}
+
+guint32
+wifi_utils_get_freq (WifiData *data)
+{
+	g_return_val_if_fail (data != NULL, 0);
+	return data->get_freq (data);
+}
+
+guint32
+wifi_utils_find_freq (WifiData *data, const guint32 *freqs)
+{
+	g_return_val_if_fail (data != NULL, 0);
+	g_return_val_if_fail (freqs != NULL, 0);
+	return data->find_freq (data, freqs);
+}
+
+GByteArray *
+wifi_utils_get_ssid (WifiData *data)
+{
+	g_return_val_if_fail (data != NULL, NULL);
+	return data->get_ssid (data);
+}
+
+gboolean
+wifi_utils_get_bssid (WifiData *data, struct ether_addr *out_bssid)
+{
+	g_return_val_if_fail (data != NULL, FALSE);
+	g_return_val_if_fail (out_bssid != NULL, FALSE);
+
+	memset (out_bssid, 0, sizeof (*out_bssid));
+	return data->get_bssid (data, out_bssid);
+}
+
+guint32
+wifi_utils_get_rate (WifiData *data)
+{
+	g_return_val_if_fail (data != NULL, 0);
+	return data->get_rate (data);
+}
+
+int
+wifi_utils_get_qual (WifiData *data)
+{
+	g_return_val_if_fail (data != NULL, 0);
+	return data->get_qual (data);
+}
+
+void
+wifi_utils_deinit (WifiData *data)
+{
+	g_return_if_fail (data != NULL);
+	data->deinit (data);
+	wifi_data_free (data);
+}
+
+gboolean
+wifi_utils_is_wifi (const char *iface, const char *sysfs_path)
+{
+	char phy80211_path[255];
+	struct stat s;
+
+	g_return_val_if_fail (iface != NULL, FALSE);
+
+	if (sysfs_path) {
+		/* Check for nl80211 sysfs paths */
+		snprintf (phy80211_path, sizeof (phy80211_path), "%s/phy80211", sysfs_path);
+		if ((stat (phy80211_path, &s) == 0 && (s.st_mode & S_IFDIR)))
+			return TRUE;
+	}
+
+	if (wifi_nl80211_is_wifi (iface))
+		return TRUE;
+
+#if HAVE_WEXT
+	if (wifi_wext_is_wifi (iface))
+		return TRUE;
+#endif
+
+	return FALSE;
+}
+
+
+/* OLPC Mesh-only functions */
+
+guint32
+wifi_utils_get_mesh_channel (WifiData *data)
+{
+	g_return_val_if_fail (data != NULL, FALSE);
+	g_return_val_if_fail (data->get_mesh_channel != NULL, FALSE);
+	return data->get_mesh_channel (data);
+}
+
+gboolean
+wifi_utils_set_mesh_channel (WifiData *data, guint32 channel)
+{
+	g_return_val_if_fail (data != NULL, FALSE);
+	g_return_val_if_fail (channel >= 0, FALSE);
+	g_return_val_if_fail (channel <= 13, FALSE);
+	g_return_val_if_fail (data->set_mesh_channel != NULL, FALSE);
+	return data->set_mesh_channel (data, channel);
+}
+
+gboolean
+wifi_utils_set_mesh_ssid (WifiData *data, const GByteArray *ssid)
+{
+	g_return_val_if_fail (data != NULL, FALSE);
+	g_return_val_if_fail (data->set_mesh_ssid != NULL, FALSE);
+	return data->set_mesh_ssid (data, ssid);
+}
+
diff --git a/src/wifi/wifi-utils.h b/src/wifi/wifi-utils.h
new file mode 100644
index 00000000..09583e7b
--- /dev/null
+++ b/src/wifi/wifi-utils.h
@@ -0,0 +1,72 @@
+/* -*- 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) 2005 - 2011 Red Hat, Inc.
+ * Copyright (C) 2006 - 2008 Novell, Inc.
+ */
+
+#ifndef WIFI_UTILS_H
+#define WIFI_UTILS_H
+
+#include <net/ethernet.h>
+#include <glib.h>
+
+#include "NetworkManager.h"
+
+typedef struct WifiData WifiData;
+
+gboolean wifi_utils_is_wifi (const char *iface, const char *sysfs_path);
+
+WifiData *wifi_utils_init (const char *iface, int ifindex, gboolean check_scan);
+
+void wifi_utils_deinit (WifiData *data);
+
+NMDeviceWifiCapabilities wifi_utils_get_caps (WifiData *data);
+
+gboolean wifi_utils_can_scan_ssid (WifiData *data);
+
+NM80211Mode wifi_utils_get_mode (WifiData *data);
+
+gboolean wifi_utils_set_mode (WifiData *data, const NM80211Mode mode);
+
+/* Returns frequency in MHz */
+guint32 wifi_utils_get_freq (WifiData *data);
+
+/* Return the first supported frequency in the zero-terminated list */
+guint32 wifi_utils_find_freq (WifiData *data, const guint32 *freqs);
+
+/* Caller must free returned byte array */
+GByteArray *wifi_utils_get_ssid (WifiData *data);
+
+/* Caller must free returned byte array */
+gboolean wifi_utils_get_bssid (WifiData *data, struct ether_addr *out_bssid);
+
+/* Returns current bitrate in Kbps */
+guint32 wifi_utils_get_rate (WifiData *data);
+
+/* Returns quality 0 - 100% on succes, or -1 on error */
+int wifi_utils_get_qual (WifiData *data);
+
+
+/* OLPC Mesh-only functions */
+guint32 wifi_utils_get_mesh_channel (WifiData *data);
+
+gboolean wifi_utils_set_mesh_channel (WifiData *data, guint32 channel);
+
+gboolean wifi_utils_set_mesh_ssid (WifiData *data, const GByteArray *ssid);
+
+#endif  /* WIFI_UTILS_H */
diff --git a/src/wimax/Makefile.am b/src/wimax/Makefile.am
index 91f1dc4e..63c95dc7 100644
--- a/src/wimax/Makefile.am
+++ b/src/wimax/Makefile.am
@@ -1,13 +1,14 @@
 INCLUDES = \
 	-I${top_srcdir}/src \
+	-I${top_srcdir}/src/generated \
 	-I${top_srcdir}/src/logging \
 	-I${top_srcdir}/include \
-	-I${top_srcdir}/libnm-util \
-	-I${top_builddir}/marshallers
+	-I${top_srcdir}/libnm-util
 
-noinst_LTLIBRARIES = libwimax.la
+pkglib_LTLIBRARIES = libnm-device-plugin-wimax.la
 
-libwimax_la_SOURCES = \
+libnm_device_plugin_wimax_la_SOURCES = \
+	nm-wimax-factory.c \
 	nm-device-wimax.c \
 	nm-device-wimax.h \
 	nm-wimax-nsp.c \
@@ -18,14 +19,18 @@ libwimax_la_SOURCES = \
 	iwmxsdk.c \
 	iwmxsdk.h
 
-libwimax_la_CPPFLAGS = \
+libnm_device_plugin_wimax_la_CPPFLAGS = \
 	$(DBUS_CFLAGS) \
-	$(IWMX_SDK_CFLAGS)
+	$(IWMX_SDK_CFLAGS) \
+	$(LIBNL_CFLAGS) \
+	$(GUDEV_CFLAGS)
 
-libwimax_la_LIBADD = \
+libnm_device_plugin_wimax_la_LDFLAGS = -module -avoid-version
+libnm_device_plugin_wimax_la_LIBADD = \
 	$(DBUS_LIBS) \
 	$(IWMX_SDK_LIBS) \
-	$(top_builddir)/marshallers/libmarshallers.la
+	$(GUDEV_LIBS) \
+	$(top_builddir)/src/generated/libnm-generated.la
 
 nm-wimax-nsp-glue.h: $(top_srcdir)/introspection/nm-wimax-nsp.xml
 	dbus-binding-tool --prefix=nm_wimax_nsp --mode=glib-server --output=$@ $<
diff --git a/src/wimax/Makefile.in b/src/wimax/Makefile.in
index e9b51e9f..2de52180 100644
--- a/src/wimax/Makefile.in
+++ b/src/wimax/Makefile.in
@@ -54,17 +54,48 @@ mkinstalldirs = $(install_sh) -d
 CONFIG_HEADER = $(top_builddir)/config.h
 CONFIG_CLEAN_FILES =
 CONFIG_CLEAN_VPATH_FILES =
-LTLIBRARIES = $(noinst_LTLIBRARIES)
+am__vpath_adj_setup = srcdirstrip=`echo "$(srcdir)" | sed 's|.|.|g'`;
+am__vpath_adj = case $$p in \
+    $(srcdir)/*) f=`echo "$$p" | sed "s|^$$srcdirstrip/||"`;; \
+    *) f=$$p;; \
+  esac;
+am__strip_dir = f=`echo $$p | sed -e 's|^.*/||'`;
+am__install_max = 40
+am__nobase_strip_setup = \
+  srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*|]/\\\\&/g'`
+am__nobase_strip = \
+  for p in $$list; do echo "$$p"; done | sed -e "s|$$srcdirstrip/||"
+am__nobase_list = $(am__nobase_strip_setup); \
+  for p in $$list; do echo "$$p $$p"; done | \
+  sed "s| $$srcdirstrip/| |;"' / .*\//!s/ .*/ ./; s,\( .*\)/[^/]*$$,\1,' | \
+  $(AWK) 'BEGIN { files["."] = "" } { files[$$2] = files[$$2] " " $$1; \
+    if (++n[$$2] == $(am__install_max)) \
+      { print $$2, files[$$2]; n[$$2] = 0; files[$$2] = "" } } \
+    END { for (dir in files) print dir, files[dir] }'
+am__base_list = \
+  sed '$$!N;$$!N;$$!N;$$!N;$$!N;$$!N;$$!N;s/\n/ /g' | \
+  sed '$$!N;$$!N;$$!N;$$!N;s/\n/ /g'
+am__installdirs = "$(DESTDIR)$(pkglibdir)"
+LTLIBRARIES = $(pkglib_LTLIBRARIES)
 am__DEPENDENCIES_1 =
-libwimax_la_DEPENDENCIES = $(am__DEPENDENCIES_1) $(am__DEPENDENCIES_1) \
-	$(top_builddir)/marshallers/libmarshallers.la
-am_libwimax_la_OBJECTS = libwimax_la-nm-device-wimax.lo \
-	libwimax_la-nm-wimax-nsp.lo libwimax_la-nm-wimax-util.lo \
-	libwimax_la-iwmxsdk.lo
-libwimax_la_OBJECTS = $(am_libwimax_la_OBJECTS)
+libnm_device_plugin_wimax_la_DEPENDENCIES = $(am__DEPENDENCIES_1) \
+	$(am__DEPENDENCIES_1) $(am__DEPENDENCIES_1) \
+	$(top_builddir)/src/generated/libnm-generated.la
+am_libnm_device_plugin_wimax_la_OBJECTS =  \
+	libnm_device_plugin_wimax_la-nm-wimax-factory.lo \
+	libnm_device_plugin_wimax_la-nm-device-wimax.lo \
+	libnm_device_plugin_wimax_la-nm-wimax-nsp.lo \
+	libnm_device_plugin_wimax_la-nm-wimax-util.lo \
+	libnm_device_plugin_wimax_la-iwmxsdk.lo
+libnm_device_plugin_wimax_la_OBJECTS =  \
+	$(am_libnm_device_plugin_wimax_la_OBJECTS)
 AM_V_lt = $(am__v_lt_$(V))
 am__v_lt_ = $(am__v_lt_$(AM_DEFAULT_VERBOSITY))
 am__v_lt_0 = --silent
+libnm_device_plugin_wimax_la_LINK = $(LIBTOOL) $(AM_V_lt) --tag=CC \
+	$(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=link $(CCLD) \
+	$(AM_CFLAGS) $(CFLAGS) $(libnm_device_plugin_wimax_la_LDFLAGS) \
+	$(LDFLAGS) -o $@
 DEFAULT_INCLUDES = -I.@am__isrc@ -I$(top_builddir)
 depcomp = $(SHELL) $(top_srcdir)/build-aux/depcomp
 am__depfiles_maybe = depfiles
@@ -91,8 +122,8 @@ am__v_CCLD_0 = @echo "  CCLD  " $@;
 AM_V_GEN = $(am__v_GEN_$(V))
 am__v_GEN_ = $(am__v_GEN_$(AM_DEFAULT_VERBOSITY))
 am__v_GEN_0 = @echo "  GEN   " $@;
-SOURCES = $(libwimax_la_SOURCES)
-DIST_SOURCES = $(libwimax_la_SOURCES)
+SOURCES = $(libnm_device_plugin_wimax_la_SOURCES)
+DIST_SOURCES = $(libnm_device_plugin_wimax_la_SOURCES)
 ETAGS = etags
 CTAGS = ctags
 DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST)
@@ -141,6 +172,8 @@ GIO_LIBS = @GIO_LIBS@
 GLIB_CFLAGS = @GLIB_CFLAGS@
 GLIB_GENMARSHAL = @GLIB_GENMARSHAL@
 GLIB_LIBS = @GLIB_LIBS@
+GLIB_MAKEFILE = @GLIB_MAKEFILE@
+GLIB_MKENUMS = @GLIB_MKENUMS@
 GMODULE_CFLAGS = @GMODULE_CFLAGS@
 GMODULE_LIBS = @GMODULE_LIBS@
 GMSGFMT = @GMSGFMT@
@@ -195,11 +228,15 @@ LIBNL2_LIBS = @LIBNL2_LIBS@
 LIBNL3_CFLAGS = @LIBNL3_CFLAGS@
 LIBNL3_LIBS = @LIBNL3_LIBS@
 LIBNL_CFLAGS = @LIBNL_CFLAGS@
+LIBNL_GENL3_CFLAGS = @LIBNL_GENL3_CFLAGS@
+LIBNL_GENL3_LIBS = @LIBNL_GENL3_LIBS@
 LIBNL_LIBS = @LIBNL_LIBS@
 LIBNL_ROUTE3_CFLAGS = @LIBNL_ROUTE3_CFLAGS@
 LIBNL_ROUTE3_LIBS = @LIBNL_ROUTE3_LIBS@
 LIBOBJS = @LIBOBJS@
 LIBS = @LIBS@
+LIBSOUP_CFLAGS = @LIBSOUP_CFLAGS@
+LIBSOUP_LIBS = @LIBSOUP_LIBS@
 LIBTOOL = @LIBTOOL@
 LIPO = @LIPO@
 LN_S = @LN_S@
@@ -210,6 +247,7 @@ MAINT = @MAINT@
 MAKEINFO = @MAKEINFO@
 MANIFEST_TOOL = @MANIFEST_TOOL@
 MKDIR_P = @MKDIR_P@
+MOC = @MOC@
 MSGFMT = @MSGFMT@
 MSGFMT_015 = @MSGFMT_015@
 MSGMERGE = @MSGMERGE@
@@ -249,6 +287,8 @@ SED = @SED@
 SET_MAKE = @SET_MAKE@
 SHELL = @SHELL@
 STRIP = @STRIP@
+SYSTEMD_CFLAGS = @SYSTEMD_CFLAGS@
+SYSTEMD_LIBS = @SYSTEMD_LIBS@
 SYSTEM_CA_PATH = @SYSTEM_CA_PATH@
 UDEV_BASE_DIR = @UDEV_BASE_DIR@
 USE_NLS = @USE_NLS@
@@ -314,13 +354,14 @@ top_builddir = @top_builddir@
 top_srcdir = @top_srcdir@
 INCLUDES = \
 	-I${top_srcdir}/src \
+	-I${top_srcdir}/src/generated \
 	-I${top_srcdir}/src/logging \
 	-I${top_srcdir}/include \
-	-I${top_srcdir}/libnm-util \
-	-I${top_builddir}/marshallers
+	-I${top_srcdir}/libnm-util
 
-noinst_LTLIBRARIES = libwimax.la
-libwimax_la_SOURCES = \
+pkglib_LTLIBRARIES = libnm-device-plugin-wimax.la
+libnm_device_plugin_wimax_la_SOURCES = \
+	nm-wimax-factory.c \
 	nm-device-wimax.c \
 	nm-device-wimax.h \
 	nm-wimax-nsp.c \
@@ -331,14 +372,18 @@ libwimax_la_SOURCES = \
 	iwmxsdk.c \
 	iwmxsdk.h
 
-libwimax_la_CPPFLAGS = \
+libnm_device_plugin_wimax_la_CPPFLAGS = \
 	$(DBUS_CFLAGS) \
-	$(IWMX_SDK_CFLAGS)
+	$(IWMX_SDK_CFLAGS) \
+	$(LIBNL_CFLAGS) \
+	$(GUDEV_CFLAGS)
 
-libwimax_la_LIBADD = \
+libnm_device_plugin_wimax_la_LDFLAGS = -module -avoid-version
+libnm_device_plugin_wimax_la_LIBADD = \
 	$(DBUS_LIBS) \
 	$(IWMX_SDK_LIBS) \
-	$(top_builddir)/marshallers/libmarshallers.la
+	$(GUDEV_LIBS) \
+	$(top_builddir)/src/generated/libnm-generated.la
 
 BUILT_SOURCES = \
 	nm-wimax-nsp-glue.h \
@@ -380,17 +425,39 @@ $(top_srcdir)/configure: @MAINTAINER_MODE_TRUE@ $(am__configure_deps)
 $(ACLOCAL_M4): @MAINTAINER_MODE_TRUE@ $(am__aclocal_m4_deps)
 	cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
 $(am__aclocal_m4_deps):
+install-pkglibLTLIBRARIES: $(pkglib_LTLIBRARIES)
+	@$(NORMAL_INSTALL)
+	test -z "$(pkglibdir)" || $(MKDIR_P) "$(DESTDIR)$(pkglibdir)"
+	@list='$(pkglib_LTLIBRARIES)'; test -n "$(pkglibdir)" || list=; \
+	list2=; for p in $$list; do \
+	  if test -f $$p; then \
+	    list2="$$list2 $$p"; \
+	  else :; fi; \
+	done; \
+	test -z "$$list2" || { \
+	  echo " $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=install $(INSTALL) $(INSTALL_STRIP_FLAG) $$list2 '$(DESTDIR)$(pkglibdir)'"; \
+	  $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=install $(INSTALL) $(INSTALL_STRIP_FLAG) $$list2 "$(DESTDIR)$(pkglibdir)"; \
+	}
+
+uninstall-pkglibLTLIBRARIES:
+	@$(NORMAL_UNINSTALL)
+	@list='$(pkglib_LTLIBRARIES)'; test -n "$(pkglibdir)" || list=; \
+	for p in $$list; do \
+	  $(am__strip_dir) \
+	  echo " $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=uninstall rm -f '$(DESTDIR)$(pkglibdir)/$$f'"; \
+	  $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=uninstall rm -f "$(DESTDIR)$(pkglibdir)/$$f"; \
+	done
 
-clean-noinstLTLIBRARIES:
-	-test -z "$(noinst_LTLIBRARIES)" || rm -f $(noinst_LTLIBRARIES)
-	@list='$(noinst_LTLIBRARIES)'; for p in $$list; do \
+clean-pkglibLTLIBRARIES:
+	-test -z "$(pkglib_LTLIBRARIES)" || rm -f $(pkglib_LTLIBRARIES)
+	@list='$(pkglib_LTLIBRARIES)'; for p in $$list; do \
 	  dir="`echo $$p | sed -e 's|/[^/]*$$||'`"; \
 	  test "$$dir" != "$$p" || dir=.; \
 	  echo "rm -f \"$${dir}/so_locations\""; \
 	  rm -f "$${dir}/so_locations"; \
 	done
-libwimax.la: $(libwimax_la_OBJECTS) $(libwimax_la_DEPENDENCIES) 
-	$(AM_V_CCLD)$(LINK)  $(libwimax_la_OBJECTS) $(libwimax_la_LIBADD) $(LIBS)
+libnm-device-plugin-wimax.la: $(libnm_device_plugin_wimax_la_OBJECTS) $(libnm_device_plugin_wimax_la_DEPENDENCIES) 
+	$(AM_V_CCLD)$(libnm_device_plugin_wimax_la_LINK) -rpath $(pkglibdir) $(libnm_device_plugin_wimax_la_OBJECTS) $(libnm_device_plugin_wimax_la_LIBADD) $(LIBS)
 
 mostlyclean-compile:
 	-rm -f *.$(OBJEXT)
@@ -398,10 +465,11 @@ mostlyclean-compile:
 distclean-compile:
 	-rm -f *.tab.c
 
-@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libwimax_la-iwmxsdk.Plo@am__quote@
-@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libwimax_la-nm-device-wimax.Plo@am__quote@
-@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libwimax_la-nm-wimax-nsp.Plo@am__quote@
-@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libwimax_la-nm-wimax-util.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libnm_device_plugin_wimax_la-iwmxsdk.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libnm_device_plugin_wimax_la-nm-device-wimax.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libnm_device_plugin_wimax_la-nm-wimax-factory.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libnm_device_plugin_wimax_la-nm-wimax-nsp.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libnm_device_plugin_wimax_la-nm-wimax-util.Plo@am__quote@
 
 .c.o:
 @am__fastdepCC_TRUE@	$(AM_V_CC)depbase=`echo $@ | sed 's|[^/]*$$|$(DEPDIR)/&|;s|\.o$$||'`;\
@@ -430,37 +498,45 @@ distclean-compile:
 @AMDEP_TRUE@@am__fastdepCC_FALSE@	DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
 @am__fastdepCC_FALSE@	$(LTCOMPILE) -c -o $@ $<
 
-libwimax_la-nm-device-wimax.lo: nm-device-wimax.c
-@am__fastdepCC_TRUE@	$(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libwimax_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT libwimax_la-nm-device-wimax.lo -MD -MP -MF $(DEPDIR)/libwimax_la-nm-device-wimax.Tpo -c -o libwimax_la-nm-device-wimax.lo `test -f 'nm-device-wimax.c' || echo '$(srcdir)/'`nm-device-wimax.c
-@am__fastdepCC_TRUE@	$(AM_V_at)$(am__mv) $(DEPDIR)/libwimax_la-nm-device-wimax.Tpo $(DEPDIR)/libwimax_la-nm-device-wimax.Plo
+libnm_device_plugin_wimax_la-nm-wimax-factory.lo: nm-wimax-factory.c
+@am__fastdepCC_TRUE@	$(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libnm_device_plugin_wimax_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT libnm_device_plugin_wimax_la-nm-wimax-factory.lo -MD -MP -MF $(DEPDIR)/libnm_device_plugin_wimax_la-nm-wimax-factory.Tpo -c -o libnm_device_plugin_wimax_la-nm-wimax-factory.lo `test -f 'nm-wimax-factory.c' || echo '$(srcdir)/'`nm-wimax-factory.c
+@am__fastdepCC_TRUE@	$(AM_V_at)$(am__mv) $(DEPDIR)/libnm_device_plugin_wimax_la-nm-wimax-factory.Tpo $(DEPDIR)/libnm_device_plugin_wimax_la-nm-wimax-factory.Plo
+@am__fastdepCC_FALSE@	$(AM_V_CC) @AM_BACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@	source='nm-wimax-factory.c' object='libnm_device_plugin_wimax_la-nm-wimax-factory.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@	DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@	$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libnm_device_plugin_wimax_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o libnm_device_plugin_wimax_la-nm-wimax-factory.lo `test -f 'nm-wimax-factory.c' || echo '$(srcdir)/'`nm-wimax-factory.c
+
+libnm_device_plugin_wimax_la-nm-device-wimax.lo: nm-device-wimax.c
+@am__fastdepCC_TRUE@	$(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libnm_device_plugin_wimax_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT libnm_device_plugin_wimax_la-nm-device-wimax.lo -MD -MP -MF $(DEPDIR)/libnm_device_plugin_wimax_la-nm-device-wimax.Tpo -c -o libnm_device_plugin_wimax_la-nm-device-wimax.lo `test -f 'nm-device-wimax.c' || echo '$(srcdir)/'`nm-device-wimax.c
+@am__fastdepCC_TRUE@	$(AM_V_at)$(am__mv) $(DEPDIR)/libnm_device_plugin_wimax_la-nm-device-wimax.Tpo $(DEPDIR)/libnm_device_plugin_wimax_la-nm-device-wimax.Plo
 @am__fastdepCC_FALSE@	$(AM_V_CC) @AM_BACKSLASH@
-@AMDEP_TRUE@@am__fastdepCC_FALSE@	source='nm-device-wimax.c' object='libwimax_la-nm-device-wimax.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@	source='nm-device-wimax.c' object='libnm_device_plugin_wimax_la-nm-device-wimax.lo' libtool=yes @AMDEPBACKSLASH@
 @AMDEP_TRUE@@am__fastdepCC_FALSE@	DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
-@am__fastdepCC_FALSE@	$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libwimax_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o libwimax_la-nm-device-wimax.lo `test -f 'nm-device-wimax.c' || echo '$(srcdir)/'`nm-device-wimax.c
+@am__fastdepCC_FALSE@	$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libnm_device_plugin_wimax_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o libnm_device_plugin_wimax_la-nm-device-wimax.lo `test -f 'nm-device-wimax.c' || echo '$(srcdir)/'`nm-device-wimax.c
 
-libwimax_la-nm-wimax-nsp.lo: nm-wimax-nsp.c
-@am__fastdepCC_TRUE@	$(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libwimax_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT libwimax_la-nm-wimax-nsp.lo -MD -MP -MF $(DEPDIR)/libwimax_la-nm-wimax-nsp.Tpo -c -o libwimax_la-nm-wimax-nsp.lo `test -f 'nm-wimax-nsp.c' || echo '$(srcdir)/'`nm-wimax-nsp.c
-@am__fastdepCC_TRUE@	$(AM_V_at)$(am__mv) $(DEPDIR)/libwimax_la-nm-wimax-nsp.Tpo $(DEPDIR)/libwimax_la-nm-wimax-nsp.Plo
+libnm_device_plugin_wimax_la-nm-wimax-nsp.lo: nm-wimax-nsp.c
+@am__fastdepCC_TRUE@	$(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libnm_device_plugin_wimax_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT libnm_device_plugin_wimax_la-nm-wimax-nsp.lo -MD -MP -MF $(DEPDIR)/libnm_device_plugin_wimax_la-nm-wimax-nsp.Tpo -c -o libnm_device_plugin_wimax_la-nm-wimax-nsp.lo `test -f 'nm-wimax-nsp.c' || echo '$(srcdir)/'`nm-wimax-nsp.c
+@am__fastdepCC_TRUE@	$(AM_V_at)$(am__mv) $(DEPDIR)/libnm_device_plugin_wimax_la-nm-wimax-nsp.Tpo $(DEPDIR)/libnm_device_plugin_wimax_la-nm-wimax-nsp.Plo
 @am__fastdepCC_FALSE@	$(AM_V_CC) @AM_BACKSLASH@
-@AMDEP_TRUE@@am__fastdepCC_FALSE@	source='nm-wimax-nsp.c' object='libwimax_la-nm-wimax-nsp.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@	source='nm-wimax-nsp.c' object='libnm_device_plugin_wimax_la-nm-wimax-nsp.lo' libtool=yes @AMDEPBACKSLASH@
 @AMDEP_TRUE@@am__fastdepCC_FALSE@	DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
-@am__fastdepCC_FALSE@	$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libwimax_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o libwimax_la-nm-wimax-nsp.lo `test -f 'nm-wimax-nsp.c' || echo '$(srcdir)/'`nm-wimax-nsp.c
+@am__fastdepCC_FALSE@	$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libnm_device_plugin_wimax_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o libnm_device_plugin_wimax_la-nm-wimax-nsp.lo `test -f 'nm-wimax-nsp.c' || echo '$(srcdir)/'`nm-wimax-nsp.c
 
-libwimax_la-nm-wimax-util.lo: nm-wimax-util.c
-@am__fastdepCC_TRUE@	$(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libwimax_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT libwimax_la-nm-wimax-util.lo -MD -MP -MF $(DEPDIR)/libwimax_la-nm-wimax-util.Tpo -c -o libwimax_la-nm-wimax-util.lo `test -f 'nm-wimax-util.c' || echo '$(srcdir)/'`nm-wimax-util.c
-@am__fastdepCC_TRUE@	$(AM_V_at)$(am__mv) $(DEPDIR)/libwimax_la-nm-wimax-util.Tpo $(DEPDIR)/libwimax_la-nm-wimax-util.Plo
+libnm_device_plugin_wimax_la-nm-wimax-util.lo: nm-wimax-util.c
+@am__fastdepCC_TRUE@	$(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libnm_device_plugin_wimax_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT libnm_device_plugin_wimax_la-nm-wimax-util.lo -MD -MP -MF $(DEPDIR)/libnm_device_plugin_wimax_la-nm-wimax-util.Tpo -c -o libnm_device_plugin_wimax_la-nm-wimax-util.lo `test -f 'nm-wimax-util.c' || echo '$(srcdir)/'`nm-wimax-util.c
+@am__fastdepCC_TRUE@	$(AM_V_at)$(am__mv) $(DEPDIR)/libnm_device_plugin_wimax_la-nm-wimax-util.Tpo $(DEPDIR)/libnm_device_plugin_wimax_la-nm-wimax-util.Plo
 @am__fastdepCC_FALSE@	$(AM_V_CC) @AM_BACKSLASH@
-@AMDEP_TRUE@@am__fastdepCC_FALSE@	source='nm-wimax-util.c' object='libwimax_la-nm-wimax-util.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@	source='nm-wimax-util.c' object='libnm_device_plugin_wimax_la-nm-wimax-util.lo' libtool=yes @AMDEPBACKSLASH@
 @AMDEP_TRUE@@am__fastdepCC_FALSE@	DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
-@am__fastdepCC_FALSE@	$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libwimax_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o libwimax_la-nm-wimax-util.lo `test -f 'nm-wimax-util.c' || echo '$(srcdir)/'`nm-wimax-util.c
+@am__fastdepCC_FALSE@	$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libnm_device_plugin_wimax_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o libnm_device_plugin_wimax_la-nm-wimax-util.lo `test -f 'nm-wimax-util.c' || echo '$(srcdir)/'`nm-wimax-util.c
 
-libwimax_la-iwmxsdk.lo: iwmxsdk.c
-@am__fastdepCC_TRUE@	$(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libwimax_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT libwimax_la-iwmxsdk.lo -MD -MP -MF $(DEPDIR)/libwimax_la-iwmxsdk.Tpo -c -o libwimax_la-iwmxsdk.lo `test -f 'iwmxsdk.c' || echo '$(srcdir)/'`iwmxsdk.c
-@am__fastdepCC_TRUE@	$(AM_V_at)$(am__mv) $(DEPDIR)/libwimax_la-iwmxsdk.Tpo $(DEPDIR)/libwimax_la-iwmxsdk.Plo
+libnm_device_plugin_wimax_la-iwmxsdk.lo: iwmxsdk.c
+@am__fastdepCC_TRUE@	$(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libnm_device_plugin_wimax_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT libnm_device_plugin_wimax_la-iwmxsdk.lo -MD -MP -MF $(DEPDIR)/libnm_device_plugin_wimax_la-iwmxsdk.Tpo -c -o libnm_device_plugin_wimax_la-iwmxsdk.lo `test -f 'iwmxsdk.c' || echo '$(srcdir)/'`iwmxsdk.c
+@am__fastdepCC_TRUE@	$(AM_V_at)$(am__mv) $(DEPDIR)/libnm_device_plugin_wimax_la-iwmxsdk.Tpo $(DEPDIR)/libnm_device_plugin_wimax_la-iwmxsdk.Plo
 @am__fastdepCC_FALSE@	$(AM_V_CC) @AM_BACKSLASH@
-@AMDEP_TRUE@@am__fastdepCC_FALSE@	source='iwmxsdk.c' object='libwimax_la-iwmxsdk.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@	source='iwmxsdk.c' object='libnm_device_plugin_wimax_la-iwmxsdk.lo' libtool=yes @AMDEPBACKSLASH@
 @AMDEP_TRUE@@am__fastdepCC_FALSE@	DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
-@am__fastdepCC_FALSE@	$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libwimax_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o libwimax_la-iwmxsdk.lo `test -f 'iwmxsdk.c' || echo '$(srcdir)/'`iwmxsdk.c
+@am__fastdepCC_FALSE@	$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libnm_device_plugin_wimax_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o libnm_device_plugin_wimax_la-iwmxsdk.lo `test -f 'iwmxsdk.c' || echo '$(srcdir)/'`iwmxsdk.c
 
 mostlyclean-libtool:
 	-rm -f *.lo
@@ -555,6 +631,9 @@ check: $(BUILT_SOURCES)
 	$(MAKE) $(AM_MAKEFLAGS) check-am
 all-am: Makefile $(LTLIBRARIES)
 installdirs:
+	for dir in "$(DESTDIR)$(pkglibdir)"; do \
+	  test -z "$$dir" || $(MKDIR_P) "$$dir"; \
+	done
 install: $(BUILT_SOURCES)
 	$(MAKE) $(AM_MAKEFLAGS) install-am
 install-exec: install-exec-am
@@ -585,7 +664,7 @@ maintainer-clean-generic:
 	-test -z "$(BUILT_SOURCES)" || rm -f $(BUILT_SOURCES)
 clean: clean-am
 
-clean-am: clean-generic clean-libtool clean-noinstLTLIBRARIES \
+clean-am: clean-generic clean-libtool clean-pkglibLTLIBRARIES \
 	mostlyclean-am
 
 distclean: distclean-am
@@ -612,7 +691,7 @@ install-dvi: install-dvi-am
 
 install-dvi-am:
 
-install-exec-am:
+install-exec-am: install-pkglibLTLIBRARIES
 
 install-html: install-html-am
 
@@ -652,22 +731,23 @@ ps: ps-am
 
 ps-am:
 
-uninstall-am:
+uninstall-am: uninstall-pkglibLTLIBRARIES
 
 .MAKE: all check install install-am install-strip
 
 .PHONY: CTAGS GTAGS all all-am check check-am clean clean-generic \
-	clean-libtool clean-noinstLTLIBRARIES ctags distclean \
+	clean-libtool clean-pkglibLTLIBRARIES ctags distclean \
 	distclean-compile distclean-generic distclean-libtool \
 	distclean-tags distdir dvi dvi-am html html-am info info-am \
 	install install-am install-data install-data-am install-dvi \
 	install-dvi-am install-exec install-exec-am install-html \
 	install-html-am install-info install-info-am install-man \
-	install-pdf install-pdf-am install-ps install-ps-am \
-	install-strip installcheck installcheck-am installdirs \
-	maintainer-clean maintainer-clean-generic mostlyclean \
-	mostlyclean-compile mostlyclean-generic mostlyclean-libtool \
-	pdf pdf-am ps ps-am tags uninstall uninstall-am
+	install-pdf install-pdf-am install-pkglibLTLIBRARIES \
+	install-ps install-ps-am install-strip installcheck \
+	installcheck-am installdirs maintainer-clean \
+	maintainer-clean-generic mostlyclean mostlyclean-compile \
+	mostlyclean-generic mostlyclean-libtool pdf pdf-am ps ps-am \
+	tags uninstall uninstall-am uninstall-pkglibLTLIBRARIES
 
 
 nm-wimax-nsp-glue.h: $(top_srcdir)/introspection/nm-wimax-nsp.xml
diff --git a/src/wimax/nm-device-wimax.c b/src/wimax/nm-device-wimax.c
index 2d8553a0..1f1a622c 100644
--- a/src/wimax/nm-device-wimax.c
+++ b/src/wimax/nm-device-wimax.c
@@ -25,6 +25,7 @@
 #include <net/ethernet.h>
 #include <sys/socket.h>
 #include <linux/if.h>
+#include <netinet/ether.h>
 
 #include <WiMaxAPI.h>
 #include <WiMaxAPIEx.h>
@@ -32,7 +33,6 @@
 #include "nm-device-wimax.h"
 #include "nm-wimax-util.h"
 #include "nm-logging.h"
-#include "nm-device-interface.h"
 #include "nm-device-private.h"
 #include "nm-system.h"
 #include "NetworkManagerUtils.h"
@@ -43,15 +43,13 @@
 #include "nm-utils.h"
 #include "nm-rfkill.h"
 #include "iwmxsdk.h"
+#include "nm-enum-types.h"
 
 static gboolean impl_device_get_nsp_list (NMDeviceWimax *device, GPtrArray **list, GError **error);
 
 #include "nm-device-wimax-glue.h"
 
-static void device_interface_init (NMDeviceInterface *iface_class);
-
-G_DEFINE_TYPE_EXTENDED (NMDeviceWimax, nm_device_wimax, NM_TYPE_DEVICE, 0,
-						G_IMPLEMENT_INTERFACE (NM_TYPE_DEVICE_INTERFACE, device_interface_init))
+G_DEFINE_TYPE (NMDeviceWimax, nm_device_wimax, NM_TYPE_DEVICE)
 
 enum {
 	PROP_0,
@@ -113,16 +111,7 @@ typedef struct {
 
 /***********************************************************/
 
-typedef enum
-{
-	NM_WIMAX_ERROR_CONNECTION_NOT_WIMAX = 0,
-	NM_WIMAX_ERROR_CONNECTION_INVALID,
-	NM_WIMAX_ERROR_CONNECTION_INCOMPATIBLE,
-	NM_WIMAX_ERROR_NSP_NOT_FOUND,
-} NMWimaxError;
-
 #define NM_WIMAX_ERROR (nm_wimax_error_quark ())
-#define NM_TYPE_WIMAX_ERROR (nm_wimax_error_get_type ()) 
 
 static GQuark
 nm_wimax_error_quark (void)
@@ -133,31 +122,6 @@ nm_wimax_error_quark (void)
 	return quark;
 }
 
-/* This should really be standard. */
-#define ENUM_ENTRY(NAME, DESC) { NAME, "" #NAME "", DESC }
-
-static GType
-nm_wimax_error_get_type (void)
-{
-	static GType etype = 0;
-
-	if (etype == 0) {
-		static const GEnumValue values[] = {
-			/* Connection was not a wired connection. */
-			ENUM_ENTRY (NM_WIMAX_ERROR_CONNECTION_NOT_WIMAX, "ConnectionNotWimax"),
-			/* Connection was not a valid wired connection. */
-			ENUM_ENTRY (NM_WIMAX_ERROR_CONNECTION_INVALID, "ConnectionInvalid"),
-			/* Connection does not apply to this device. */
-			ENUM_ENTRY (NM_WIMAX_ERROR_CONNECTION_INCOMPATIBLE, "ConnectionIncompatible"),
-			/* NSP not found in the scan list. */
-			ENUM_ENTRY (NM_WIMAX_ERROR_NSP_NOT_FOUND, "NspNotFound"),
-			{ 0, 0, 0 }
-		};
-		etype = g_enum_register_static ("NMWimaxError", values);
-	}
-	return etype;
-}
-
 /***********************************************************/
 
 void
@@ -321,7 +285,7 @@ update_availability (NMDeviceWimax *self, gboolean old_available)
 	if (new_available == old_available)
 		return FALSE;
 
-	state = nm_device_interface_get_state (NM_DEVICE_INTERFACE (self));
+	state = nm_device_get_state (device);
 	if (state == NM_DEVICE_STATE_UNAVAILABLE) {
 		if (new_available == TRUE) {
 			nm_device_state_changed (device,
@@ -344,7 +308,7 @@ update_availability (NMDeviceWimax *self, gboolean old_available)
 /* NMDeviceInterface interface */
 
 static void
-real_set_enabled (NMDeviceInterface *device, gboolean enabled)
+real_set_enabled (NMDevice *device, gboolean enabled)
 {
 	NMDeviceWimax *self = NM_DEVICE_WIMAX (device);
 	NMDeviceWimaxPrivate *priv = NM_DEVICE_WIMAX_GET_PRIVATE (self);
@@ -446,6 +410,35 @@ real_update_hw_address (NMDevice *dev)
 }
 
 static gboolean
+hwaddr_matches (NMDevice *device,
+                NMConnection *connection,
+                const guint8 *other_hwaddr,
+                guint other_hwaddr_len,
+                gboolean fail_if_no_hwaddr)
+{
+	NMDeviceWimaxPrivate *priv = NM_DEVICE_WIMAX_GET_PRIVATE (device);
+	NMSettingWimax *s_wimax;
+	const GByteArray *mac = NULL;
+
+	s_wimax = nm_connection_get_setting_wimax (connection);
+	if (s_wimax)
+		mac = nm_setting_wimax_get_mac_address (s_wimax);
+
+	if (mac) {
+		g_return_val_if_fail (mac->len == ETH_ALEN, FALSE);
+		if (other_hwaddr) {
+			g_return_val_if_fail (other_hwaddr_len == ETH_ALEN, FALSE);
+			if (memcmp (mac->data, other_hwaddr, mac->len) == 0)
+				return TRUE;
+		} else if (memcmp (mac->data, priv->hw_addr.ether_addr_octet, mac->len) == 0)
+			return TRUE;
+	} else if (fail_if_no_hwaddr == FALSE)
+		return TRUE;
+
+	return FALSE;
+}
+
+static gboolean
 real_check_connection_compatible (NMDevice *device,
                                   NMConnection *connection,
                                   GError **error)
@@ -731,7 +724,7 @@ real_act_stage1_prepare (NMDevice *device, NMDeviceStateReason *reason)
 	if (!req)
 		return NM_ACT_STAGE_RETURN_FAILURE;
 
-	path = nm_act_request_get_specific_object (req);
+	path = nm_active_connection_get_specific_object (NM_ACTIVE_CONNECTION (req));
 	if (!path)
 		return NM_ACT_STAGE_RETURN_FAILURE;
 
@@ -774,7 +767,7 @@ real_act_stage2_config (NMDevice *device, NMDeviceStateReason *reason)
 	iface = nm_device_get_iface (device);
 	g_assert (iface);
 
-	connection = nm_act_request_get_connection (nm_device_get_act_request (device));
+	connection = nm_device_get_connection (device);
 	g_assert (connection);
 
 	s_wimax = nm_connection_get_setting_wimax (connection);
@@ -878,7 +871,7 @@ wmx_state_change_cb (struct wmxsdk *wmxsdk,
 	if (new_status == old_status)
 		return;
 
-	state = nm_device_interface_get_state (NM_DEVICE_INTERFACE (self));
+	state = nm_device_get_state (NM_DEVICE (self));
 	old_available = nm_device_is_available (NM_DEVICE (self));
 
 	priv->status = new_status;
@@ -917,7 +910,7 @@ wmx_state_change_cb (struct wmxsdk *wmxsdk,
 	}
 
 	/* Handle activation success and failure */
-	if (IS_ACTIVATING_STATE (state)) {
+	if (nm_device_is_activating (NM_DEVICE (self))) {
 	    if (new_status == WIMAX_API_DEVICE_STATUS_Data_Connected) {
 			/* Success */
 			clear_activation_timeout (self);
@@ -993,7 +986,7 @@ wmx_media_status_cb (struct wmxsdk *wmxsdk,
 	const char *iface;
 
 	iface = nm_device_get_iface (NM_DEVICE (self));
-	state = nm_device_interface_get_state (NM_DEVICE_INTERFACE (self));
+	state = nm_device_get_state (NM_DEVICE (self));
 
 	nm_log_dbg (LOGD_WIMAX, "(%s): media status change to %s",
 	            iface, iwmx_sdk_media_status_to_str (new_status));
@@ -1032,10 +1025,8 @@ wmx_connect_result_cb (struct wmxsdk *wmxsdk,
 {
 	NMDeviceWimax *self = NM_DEVICE_WIMAX (user_data);
 	NMDeviceWimaxPrivate *priv = NM_DEVICE_WIMAX_GET_PRIVATE (self);
-	NMDeviceState state;
 
-	state = nm_device_interface_get_state (NM_DEVICE_INTERFACE (self));
-	if (IS_ACTIVATING_STATE (state)) {
+	if (nm_device_is_activating (NM_DEVICE (self))) {
 		priv->connect_failed = (result == WIMAX_API_CONNECTION_SUCCESS);
 		/* Wait for the state change so we can get the reason code; we
 		 * cache the connect failure so we don't have to wait for the
@@ -1373,12 +1364,12 @@ nm_device_wimax_new (const char *udi,
 	g_return_val_if_fail (driver != NULL, NULL);
 
 	device = (NMDevice *) g_object_new (NM_TYPE_DEVICE_WIMAX,
-	                                    NM_DEVICE_INTERFACE_UDI, udi,
-	                                    NM_DEVICE_INTERFACE_IFACE, iface,
-	                                    NM_DEVICE_INTERFACE_DRIVER, driver,
-	                                    NM_DEVICE_INTERFACE_TYPE_DESC, "WiMAX",
-	                                    NM_DEVICE_INTERFACE_DEVICE_TYPE, NM_DEVICE_TYPE_WIMAX,
-	                                    NM_DEVICE_INTERFACE_RFKILL_TYPE, RFKILL_TYPE_WIMAX,
+	                                    NM_DEVICE_UDI, udi,
+	                                    NM_DEVICE_IFACE, iface,
+	                                    NM_DEVICE_DRIVER, driver,
+	                                    NM_DEVICE_TYPE_DESC, "WiMAX",
+	                                    NM_DEVICE_DEVICE_TYPE, NM_DEVICE_TYPE_WIMAX,
+	                                    NM_DEVICE_RFKILL_TYPE, RFKILL_TYPE_WIMAX,
 	                                    NULL);
 	if (device) {
 		struct wmxsdk *sdk;
@@ -1399,12 +1390,6 @@ nm_device_wimax_new (const char *udi,
 }
 
 static void
-device_interface_init (NMDeviceInterface *iface_class)
-{
-    iface_class->set_enabled = real_set_enabled;
-}
-
-static void
 nm_device_wimax_init (NMDeviceWimax *self)
 {
 	NMDeviceWimaxPrivate *priv = NM_DEVICE_WIMAX_GET_PRIVATE (self);
@@ -1434,7 +1419,7 @@ get_property (GObject *object, guint prop_id,
 	switch (prop_id) {
 	case PROP_HW_ADDRESS:
 		nm_device_wimax_get_hw_address (self, &hw_addr);
-		g_value_take_string (value, nm_ether_ntop (&hw_addr));
+		g_value_take_string (value, nm_utils_hwaddr_ntoa (&hw_addr, ARPHRD_ETHER));
 		break;
 	case PROP_ACTIVE_NSP:
 		if (priv->current_nsp)
@@ -1526,6 +1511,8 @@ nm_device_wimax_class_init (NMDeviceWimaxClass *klass)
 	device_class->act_stage1_prepare = real_act_stage1_prepare;
 	device_class->act_stage2_config = real_act_stage2_config;
 	device_class->deactivate = real_deactivate;
+    device_class->set_enabled = real_set_enabled;
+    device_class->hwaddr_matches = hwaddr_matches;
 
 	/* Properties */
 	g_object_class_install_property
diff --git a/src/wimax/nm-device-wimax.h b/src/wimax/nm-device-wimax.h
index d70380ac..a67ff17d 100644
--- a/src/wimax/nm-device-wimax.h
+++ b/src/wimax/nm-device-wimax.h
@@ -35,6 +35,14 @@ G_BEGIN_DECLS
 #define NM_IS_DEVICE_WIMAX_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass),  NM_TYPE_DEVICE_WIMAX))
 #define NM_DEVICE_WIMAX_GET_CLASS(obj)  (G_TYPE_INSTANCE_GET_CLASS ((obj),  NM_TYPE_DEVICE_WIMAX, NMDeviceWimaxClass))
 
+typedef enum
+{
+	NM_WIMAX_ERROR_CONNECTION_NOT_WIMAX = 0, /*< nick=ConnectionNotWimax >*/
+	NM_WIMAX_ERROR_CONNECTION_INVALID,       /*< nick=ConnectionInvalid >*/
+	NM_WIMAX_ERROR_CONNECTION_INCOMPATIBLE,  /*< nick=ConnectionIncompatible >*/
+	NM_WIMAX_ERROR_NSP_NOT_FOUND,            /*< nick=NspNotFound >*/
+} NMWimaxError;
+
 #define NM_DEVICE_WIMAX_HW_ADDRESS       "hw-address"
 #define NM_DEVICE_WIMAX_ACTIVE_NSP       "active-nsp"
 #define NM_DEVICE_WIMAX_CENTER_FREQUENCY "center-frequency"
diff --git a/src/wimax/nm-wimax-factory.c b/src/wimax/nm-wimax-factory.c
new file mode 100644
index 00000000..95cb4bf7
--- /dev/null
+++ b/src/wimax/nm-wimax-factory.c
@@ -0,0 +1,58 @@
+/* -*- 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 <gmodule.h>
+
+#include "nm-device-factory.h"
+#include "nm-device-wimax.h"
+
+G_MODULE_EXPORT GObject *
+nm_device_factory_create_device (GUdevDevice *device,
+                                 const char *devpath,
+                                 const char *ifname,
+                                 const char *driver,
+                                 GError **error)
+{
+	GObject *dev;
+
+	/* FIXME: check 'DEVTYPE' instead; but since we only support Intel
+	 * WiMAX devices for now this is appropriate.
+	 */
+	if (g_strcmp0 (driver, "i2400m_usb") != 0)
+		return NULL;  /* unsupported */
+
+	dev = (GObject *) nm_device_wimax_new (devpath, ifname, driver);
+	if (dev == NULL)
+		g_set_error_literal (error, 0, 0, "Failed to create WiMAX device.");
+	return dev;
+}
+
+G_MODULE_EXPORT guint32
+nm_device_factory_get_priority (void)
+{
+	return 0;
+}
+
+G_MODULE_EXPORT NMDeviceType
+nm_device_factory_get_type (void)
+{
+	return NM_DEVICE_TYPE_WIMAX;
+}
+
diff --git a/src/wimax/nm-wimax-nsp.c b/src/wimax/nm-wimax-nsp.c
index b10cee39..491cb5da 100644
--- a/src/wimax/nm-wimax-nsp.c
+++ b/src/wimax/nm-wimax-nsp.c
@@ -118,7 +118,7 @@ nm_wimax_nsp_check_compatible (NMWimaxNsp *self,
 
 	priv = GET_PRIVATE (self);
 
-	s_wimax = NM_SETTING_WIMAX (nm_connection_get_setting (connection, NM_TYPE_SETTING_WIMAX));
+	s_wimax = nm_connection_get_setting_wimax (connection);
 	if (!s_wimax)
 		return FALSE;
 
diff --git a/src/wpa.c b/src/wpa.c
deleted file mode 100644
index 7d0e2261..00000000
--- a/src/wpa.c
+++ /dev/null
@@ -1,455 +0,0 @@
-/* -*- Mode: C; tab-width: 4; indent-tabs-mode: t; c-basic-offset: 4 -*- */
-/*
- * WPA Supplicant - WPA state machine and EAPOL-Key processing
- * Copyright (c) 2003-2005, Jouni Malinen <jkmaline@cc.hut.fi>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
- *
- * Alternatively, this file may be distributed under the terms of BSD
- * license.
- *
- * See README and COPYING for more details.
- */
-
-#include "wireless-helper.h"
-
-#include <stdint.h>
-#include <string.h>
-#include <glib.h>
-
-#include "wpa.h"
-#include "nm-logging.h"
-
-typedef guint16 u16;
-typedef guint8 u8;
-
-#define WPA_GET_LE16(a) ((u16) (((a)[1] << 8) | (a)[0]))
-
-#define BIT(n) (1 << (n))
-#define WPA_CAPABILITY_PREAUTH BIT(0)
-
-#define WPA_REPLAY_COUNTER_LEN 8
-#define WPA_NONCE_LEN 32
-
-#define PMKID_LEN 16
-
-static const int WPA_SELECTOR_LEN = 4;
-static const u8 WPA_OUI_TYPE[] = { 0x00, 0x50, 0xf2, 1 };
-static const u16 WPA_VERSION = 1;
-static const u8 WPA_AUTH_KEY_MGMT_NONE[] = { 0x00, 0x50, 0xf2, 0 };
-static const u8 WPA_AUTH_KEY_MGMT_UNSPEC_802_1X[] = { 0x00, 0x50, 0xf2, 1 };
-static const u8 WPA_AUTH_KEY_MGMT_PSK_OVER_802_1X[] = { 0x00, 0x50, 0xf2, 2 };
-static const u8 WPA_CIPHER_SUITE_NONE[] = { 0x00, 0x50, 0xf2, 0 };
-static const u8 WPA_CIPHER_SUITE_WEP40[] = { 0x00, 0x50, 0xf2, 1 };
-static const u8 WPA_CIPHER_SUITE_TKIP[] = { 0x00, 0x50, 0xf2, 2 };
-static const u8 WPA_CIPHER_SUITE_WRAP[] = { 0x00, 0x50, 0xf2, 3 };
-static const u8 WPA_CIPHER_SUITE_CCMP[] = { 0x00, 0x50, 0xf2, 4 };
-static const u8 WPA_CIPHER_SUITE_WEP104[] = { 0x00, 0x50, 0xf2, 5 };
-
-/* WPA IE version 1
- * 00-50-f2:1 (OUI:OUI type)
- * 0x01 0x00 (version; little endian)
- * (all following fields are optional:)
- * Group Suite Selector (4 octets) (default: TKIP)
- * Pairwise Suite Count (2 octets, little endian) (default: 1)
- * Pairwise Suite List (4 * n octets) (default: TKIP)
- * Authenticated Key Management Suite Count (2 octets, little endian)
- *    (default: 1)
- * Authenticated Key Management Suite List (4 * n octets)
- *    (default: unspec 802.1X)
- * WPA Capabilities (2 octets, little endian) (default: 0)
- */
-
-struct wpa_ie_hdr {
-	u8 elem_id;
-	u8 len;
-	u8 oui[3];
-	u8 oui_type;
-	u8 version[2];
-} __attribute__ ((packed));
-
-
-static const int RSN_SELECTOR_LEN = 4;
-static const u16 RSN_VERSION = 1;
-static const u8 RSN_AUTH_KEY_MGMT_UNSPEC_802_1X[] = { 0x00, 0x0f, 0xac, 1 };
-static const u8 RSN_AUTH_KEY_MGMT_PSK_OVER_802_1X[] = { 0x00, 0x0f, 0xac, 2 };
-static const u8 RSN_CIPHER_SUITE_NONE[] = { 0x00, 0x0f, 0xac, 0 };
-static const u8 RSN_CIPHER_SUITE_WEP40[] = { 0x00, 0x0f, 0xac, 1 };
-static const u8 RSN_CIPHER_SUITE_TKIP[] = { 0x00, 0x0f, 0xac, 2 };
-static const u8 RSN_CIPHER_SUITE_WRAP[] = { 0x00, 0x0f, 0xac, 3 };
-static const u8 RSN_CIPHER_SUITE_CCMP[] = { 0x00, 0x0f, 0xac, 4 };
-static const u8 RSN_CIPHER_SUITE_WEP104[] = { 0x00, 0x0f, 0xac, 5 };
-
-/* EAPOL-Key Key Data Encapsulation
- * GroupKey and STAKey require encryption, otherwise, encryption is optional.
- */
-static const u8 RSN_KEY_DATA_GROUPKEY[] = { 0x00, 0x0f, 0xac, 1 };
-static const u8 RSN_KEY_DATA_STAKEY[] = { 0x00, 0x0f, 0xac, 2 };
-static const u8 RSN_KEY_DATA_MAC_ADDR[] = { 0x00, 0x0f, 0xac, 3 };
-static const u8 RSN_KEY_DATA_PMKID[] = { 0x00, 0x0f, 0xac, 4 };
-
-/* RSN IE version 1
- * 0x01 0x00 (version; little endian)
- * (all following fields are optional:)
- * Group Suite Selector (4 octets) (default: CCMP)
- * Pairwise Suite Count (2 octets, little endian) (default: 1)
- * Pairwise Suite List (4 * n octets) (default: CCMP)
- * Authenticated Key Management Suite Count (2 octets, little endian)
- *    (default: 1)
- * Authenticated Key Management Suite List (4 * n octets)
- *    (default: unspec 802.1X)
- * RSN Capabilities (2 octets, little endian) (default: 0)
- * PMKID Count (2 octets) (default: 0)
- * PMKID List (16 * n octets)
- */
-
-struct rsn_ie_hdr {
-	u8 elem_id; /* WLAN_EID_RSN */
-	u8 len;
-	u8 version[2];
-} __attribute__ ((packed));
-
-
-#define WPA_KEY_INFO_TYPE_MASK (BIT(0) | BIT(1) | BIT(2))
-#define WPA_KEY_INFO_TYPE_HMAC_MD5_RC4 BIT(0)
-#define WPA_KEY_INFO_TYPE_HMAC_SHA1_AES BIT(1)
-#define WPA_KEY_INFO_KEY_TYPE BIT(3) /* 1 = Pairwise, 0 = Group key */
-/* bit4..5 is used in WPA, but is reserved in IEEE 802.11i/RSN */
-#define WPA_KEY_INFO_KEY_INDEX_MASK (BIT(4) | BIT(5))
-#define WPA_KEY_INFO_KEY_INDEX_SHIFT 4
-#define WPA_KEY_INFO_INSTALL BIT(6) /* pairwise */
-#define WPA_KEY_INFO_TXRX BIT(6) /* group */
-#define WPA_KEY_INFO_ACK BIT(7)
-#define WPA_KEY_INFO_MIC BIT(8)
-#define WPA_KEY_INFO_SECURE BIT(9)
-#define WPA_KEY_INFO_ERROR BIT(10)
-#define WPA_KEY_INFO_REQUEST BIT(11)
-#define WPA_KEY_INFO_ENCR_KEY_DATA BIT(12) /* IEEE 802.11i/RSN only */
-
-
-
-static int wpa_selector_to_bitfield(const u8 *s)
-{
-	if (memcmp(s, WPA_CIPHER_SUITE_NONE, WPA_SELECTOR_LEN) == 0)
-		return IW_AUTH_CIPHER_NONE;
-	if (memcmp(s, WPA_CIPHER_SUITE_WEP40, WPA_SELECTOR_LEN) == 0)
-		return IW_AUTH_CIPHER_WEP40;
-	if (memcmp(s, WPA_CIPHER_SUITE_TKIP, WPA_SELECTOR_LEN) == 0)
-		return IW_AUTH_CIPHER_TKIP;
-	if (memcmp(s, WPA_CIPHER_SUITE_CCMP, WPA_SELECTOR_LEN) == 0)
-		return IW_AUTH_CIPHER_CCMP;
-	if (memcmp(s, WPA_CIPHER_SUITE_WEP104, WPA_SELECTOR_LEN) == 0)
-		return IW_AUTH_CIPHER_WEP104;
-	return 0;
-}
-
-
-static int wpa_key_mgmt_to_bitfield(const u8 *s)
-{
-	if (memcmp(s, WPA_AUTH_KEY_MGMT_UNSPEC_802_1X, WPA_SELECTOR_LEN) == 0)
-		return IW_AUTH_KEY_MGMT_802_1X;
-	if (memcmp(s, WPA_AUTH_KEY_MGMT_PSK_OVER_802_1X, WPA_SELECTOR_LEN) ==
-	    0)
-		return IW_AUTH_KEY_MGMT_PSK;
-	if (memcmp(s, WPA_AUTH_KEY_MGMT_NONE, WPA_SELECTOR_LEN) == 0)
-		return 0;
-	return 0;
-}
-
-
-static int rsn_selector_to_bitfield(const u8 *s)
-{
-	if (memcmp(s, RSN_CIPHER_SUITE_NONE, RSN_SELECTOR_LEN) == 0)
-		return IW_AUTH_CIPHER_NONE;
-	if (memcmp(s, RSN_CIPHER_SUITE_WEP40, RSN_SELECTOR_LEN) == 0)
-		return IW_AUTH_CIPHER_WEP40;
-	if (memcmp(s, RSN_CIPHER_SUITE_TKIP, RSN_SELECTOR_LEN) == 0)
-		return IW_AUTH_CIPHER_TKIP;
-	if (memcmp(s, RSN_CIPHER_SUITE_CCMP, RSN_SELECTOR_LEN) == 0)
-		return IW_AUTH_CIPHER_CCMP;
-	if (memcmp(s, RSN_CIPHER_SUITE_WEP104, RSN_SELECTOR_LEN) == 0)
-		return IW_AUTH_CIPHER_WEP104;
-	return 0;
-}
-
-
-static int rsn_key_mgmt_to_bitfield(const u8 *s)
-{
-	if (memcmp(s, RSN_AUTH_KEY_MGMT_UNSPEC_802_1X, RSN_SELECTOR_LEN) == 0)
-		return IW_AUTH_KEY_MGMT_802_1X;
-	if (memcmp(s, RSN_AUTH_KEY_MGMT_PSK_OVER_802_1X, RSN_SELECTOR_LEN) ==
-	    0)
-		return IW_AUTH_KEY_MGMT_PSK;
-	return 0;
-}
-
-
-static int wpa_parse_wpa_ie_wpa(const u8 *wpa_ie, size_t wpa_ie_len,
-				struct wpa_ie_data *data)
-{
-	const struct wpa_ie_hdr *hdr;
-	const u8 *pos;
-	int left;
-	int i, count;
-
-	data->proto = IW_AUTH_WPA_VERSION_WPA;
-	data->pairwise_cipher = IW_AUTH_CIPHER_TKIP;
-	data->group_cipher = IW_AUTH_CIPHER_TKIP;
-	data->key_mgmt = IW_AUTH_KEY_MGMT_802_1X;
-	data->capabilities = 0;
-	data->pmkid = NULL;
-	data->num_pmkid = 0;
-
-	if (wpa_ie_len == 0) {
-		/* No WPA IE - fail silently */
-		return -1;
-	}
-
-	if (wpa_ie_len < sizeof(struct wpa_ie_hdr)) {
-		nm_log_dbg (LOGD_WIFI, "IE len too short %lu",
-			    (unsigned long) wpa_ie_len);
-		return -1;
-	}
-
-	hdr = (const struct wpa_ie_hdr *) wpa_ie;
-
-	if (hdr->elem_id != WPA_GENERIC_INFO_ELEM ||
-	    hdr->len != wpa_ie_len - 2 ||
-	    memcmp(hdr->oui, WPA_OUI_TYPE, WPA_SELECTOR_LEN) != 0 ||
-	    WPA_GET_LE16(hdr->version) != WPA_VERSION) {
-		nm_log_dbg (LOGD_WIFI, "malformed IE or unknown version");
-		return -1;
-	}
-
-	pos = (const u8 *) (hdr + 1);
-	left = wpa_ie_len - sizeof(*hdr);
-
-	if (left >= WPA_SELECTOR_LEN) {
-		data->group_cipher = wpa_selector_to_bitfield(pos);
-		pos += WPA_SELECTOR_LEN;
-		left -= WPA_SELECTOR_LEN;
-	} else if (left > 0) {
-		nm_log_dbg (LOGD_WIFI, "IE length mismatch, %u too much", left);
-		return -1;
-	}
-
-	if (left >= 2) {
-		data->pairwise_cipher = 0;
-		count = WPA_GET_LE16(pos);
-		pos += 2;
-		left -= 2;
-		if (count == 0 || left < count * WPA_SELECTOR_LEN) {
-			nm_log_dbg (LOGD_WIFI, "IE count botch (pairwise), "
-			            "count %u left %u", count, left);
-			return -1;
-		}
-		for (i = 0; i < count; i++) {
-			data->pairwise_cipher |= wpa_selector_to_bitfield(pos);
-			pos += WPA_SELECTOR_LEN;
-			left -= WPA_SELECTOR_LEN;
-		}
-	} else if (left == 1) {
-		nm_log_dbg (LOGD_WIFI, "IE too short (for key mgmt)");
-		return -1;
-	}
-
-	if (left >= 2) {
-		data->key_mgmt = 0;
-		count = WPA_GET_LE16(pos);
-		pos += 2;
-		left -= 2;
-		if (count == 0 || left < count * WPA_SELECTOR_LEN) {
-			nm_log_dbg (LOGD_WIFI, "IE count botch (key mgmt), "
-				   "count %u left %u", count, left);
-			return -1;
-		}
-		for (i = 0; i < count; i++) {
-			data->key_mgmt |= wpa_key_mgmt_to_bitfield(pos);
-			pos += WPA_SELECTOR_LEN;
-			left -= WPA_SELECTOR_LEN;
-		}
-	} else if (left == 1) {
-		nm_log_dbg (LOGD_WIFI, "IE too short (for capabilities)");
-		return -1;
-	}
-
-	if (left >= 2) {
-		if (WPA_GET_LE16 (pos) & WPA_CAPABILITY_PREAUTH)
-			data->capabilities |= IW_PMKID_CAND_PREAUTH;
-		pos += 2;
-		left -= 2;
-	}
-
-	if (left > 0) {
-		nm_log_dbg (LOGD_WIFI, "IE has %u trailing bytes", left);
-		return -1;
-	}
-
-	return 0;
-}
-
-
-static int wpa_parse_wpa_ie_rsn(const u8 *rsn_ie, size_t rsn_ie_len,
-				struct wpa_ie_data *data)
-{
-	const struct rsn_ie_hdr *hdr;
-	const u8 *pos;
-	int left;
-	int i, count;
-
-	data->proto = IW_AUTH_WPA_VERSION_WPA2;
-	data->pairwise_cipher = IW_AUTH_CIPHER_CCMP;
-	data->group_cipher = IW_AUTH_CIPHER_CCMP;
-	data->key_mgmt = IW_AUTH_KEY_MGMT_802_1X;
-	data->capabilities = 0;
-	data->pmkid = NULL;
-	data->num_pmkid = 0;
-
-	if (rsn_ie_len == 0) {
-		/* No RSN IE - fail silently */
-		return -1;
-	}
-
-	if (rsn_ie_len < sizeof(struct rsn_ie_hdr)) {
-		nm_log_dbg (LOGD_WIFI, "IE len too short %lu",
-			    (unsigned long) rsn_ie_len);
-		return -1;
-	}
-
-	hdr = (const struct rsn_ie_hdr *) rsn_ie;
-
-	if (hdr->elem_id != WPA_RSN_INFO_ELEM ||
-	    hdr->len != rsn_ie_len - 2 ||
-	    WPA_GET_LE16(hdr->version) != RSN_VERSION) {
-		nm_log_dbg (LOGD_WIFI, "malformed IE or unknown version");
-		return -1;
-	}
-
-	pos = (const u8 *) (hdr + 1);
-	left = rsn_ie_len - sizeof(*hdr);
-
-	if (left >= RSN_SELECTOR_LEN) {
-		data->group_cipher = rsn_selector_to_bitfield(pos);
-		pos += RSN_SELECTOR_LEN;
-		left -= RSN_SELECTOR_LEN;
-	} else if (left > 0) {
-		nm_log_dbg (LOGD_WIFI, "IE length mismatch, %u too much", left);
-		return -1;
-	}
-
-	if (left >= 2) {
-		data->pairwise_cipher = 0;
-		count = WPA_GET_LE16(pos);
-		pos += 2;
-		left -= 2;
-		if (count == 0 || left < count * RSN_SELECTOR_LEN) {
-			nm_log_dbg (LOGD_WIFI, "IE count botch (pairwise), "
-				    "count %u left %u", count, left);
-			return -1;
-		}
-		for (i = 0; i < count; i++) {
-			data->pairwise_cipher |= rsn_selector_to_bitfield(pos);
-			pos += RSN_SELECTOR_LEN;
-			left -= RSN_SELECTOR_LEN;
-		}
-	} else if (left == 1) {
-		nm_log_dbg (LOGD_WIFI, "IE too short (for key mgmt)");
-		return -1;
-	}
-
-	if (left >= 2) {
-		data->key_mgmt = 0;
-		count = WPA_GET_LE16(pos);
-		pos += 2;
-		left -= 2;
-		if (count == 0 || left < count * RSN_SELECTOR_LEN) {
-			nm_log_dbg (LOGD_WIFI, "IE count botch (key mgmt), "
-				   "count %u left %u", count, left);
-			return -1;
-		}
-		for (i = 0; i < count; i++) {
-			data->key_mgmt |= rsn_key_mgmt_to_bitfield(pos);
-			pos += RSN_SELECTOR_LEN;
-			left -= RSN_SELECTOR_LEN;
-		}
-	} else if (left == 1) {
-		nm_log_dbg (LOGD_WIFI, "IE too short (for capabilities)");
-		return -1;
-	}
-
-	if (left >= 2) {
-		if (WPA_GET_LE16 (pos) & WPA_CAPABILITY_PREAUTH)
-			data->capabilities |= IW_PMKID_CAND_PREAUTH;
-		pos += 2;
-		left -= 2;
-	}
-
-	if (left >= 2) {
-		data->num_pmkid = WPA_GET_LE16(pos);
-		pos += 2;
-		left -= 2;
-		if (left < data->num_pmkid * PMKID_LEN) {
-			nm_log_dbg (LOGD_WIFI, "PMKID underflow "
-				    "(num_pmkid=%d left=%d)",
-				    data->num_pmkid, left);
-			data->num_pmkid = 0;
-		} else {
-			data->pmkid = pos;
-			pos += data->num_pmkid * PMKID_LEN;
-			left -= data->num_pmkid * PMKID_LEN;
-		}
-	}
-
-	if (left > 0) {
-		nm_log_dbg (LOGD_WIFI, "IE has %u trailing bytes - ignored", left);
-	}
-
-	return 0;
-}
-
-
-/**
- * wpa_parse_wpa_ie - Parse WPA/RSN IE
- * @wpa_ie: Pointer to WPA or RSN IE
- * @wpa_ie_len: Length of the WPA/RSN IE
- * @data: Pointer to data area for parsing results
- * Returns: parsed results on success, NULL on failure
- *
- * Parse the contents of WPA or RSN IE and write the parsed data into data.
- */
-wpa_ie_data * wpa_parse_wpa_ie(const u8 *wpa_ie, size_t wpa_ie_len)
-{
-	wpa_ie_data *data = NULL;
-	int err = -1;
-
-	if (!wpa_ie || wpa_ie_len <= 0)
-		return NULL;
-
-	data = g_slice_new0 (wpa_ie_data);
-
-	if (wpa_ie_len >= 1 && wpa_ie[0] == WPA_RSN_INFO_ELEM)
-		err = wpa_parse_wpa_ie_rsn(wpa_ie, wpa_ie_len, data);
-	else
-		err = wpa_parse_wpa_ie_wpa(wpa_ie, wpa_ie_len, data);
-
-	if (err != 0) {
-		g_slice_free (wpa_ie_data, data);
-		data = NULL;
-	}
-
-	if (data) {
-		nm_log_dbg (LOGD_WIFI, "WPA IE: -------------------");
-		nm_log_dbg (LOGD_WIFI, "   proto        0x%X", data->proto);
-		nm_log_dbg (LOGD_WIFI, "   pw cipher    0x%X", data->pairwise_cipher);
-		nm_log_dbg (LOGD_WIFI, "   gr cipher    0x%X", data->group_cipher);
-		nm_log_dbg (LOGD_WIFI, "   key mgmt     0x%X", data->key_mgmt);
-		nm_log_dbg (LOGD_WIFI, "   capabilities 0x%X", data->capabilities);
-		nm_log_dbg (LOGD_WIFI, "   # pmkid      0x%X", data->num_pmkid);
-		nm_log_dbg (LOGD_WIFI, " ");
-	}
-
-	return data;
-}
-
diff --git a/src/wpa.h b/src/wpa.h
deleted file mode 100644
index 18d1dbee..00000000
--- a/src/wpa.h
+++ /dev/null
@@ -1,38 +0,0 @@
-/*
- * wpa_supplicant - WPA definitions
- * Copyright (c) 2003-2005, Jouni Malinen <jkmaline@cc.hut.fi>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
- *
- * Alternatively, this file may be distributed under the terms of BSD
- * license.
- *
- * See README and COPYING for more details.
- */
-
-#ifndef WPA_H
-#define WPA_H
-
-#include <stdint.h>
-
-#define WPA_GENERIC_INFO_ELEM 0xdd
-#define WPA_RSN_INFO_ELEM 0x30
-
-#define WPA_MAX_IE_LEN 40
-
-typedef struct wpa_ie_data {
-	int proto;
-	int pairwise_cipher;
-	int group_cipher;
-	int key_mgmt;
-	int capabilities;
-	int num_pmkid;
-	const uint8_t *pmkid;
-} wpa_ie_data;
-
-
-wpa_ie_data * wpa_parse_wpa_ie (const uint8_t *wpa_ie, size_t wpa_ie_len);
-
-#endif /* WPA_H */