about summary refs log tree commit diff
path: root/libnm-glib
diff options
context:
space:
mode:
Diffstat (limited to 'libnm-glib')
-rw-r--r--libnm-glib/Makefile.am33
-rw-r--r--libnm-glib/Makefile.in143
-rw-r--r--libnm-glib/libnm-glib-test.c10
-rw-r--r--libnm-glib/libnm-glib-vpn.ver1
-rw-r--r--libnm-glib/libnm-glib.pc.in2
-rw-r--r--libnm-glib/libnm-glib.ver47
-rw-r--r--libnm-glib/libnm_glib.c6
-rw-r--r--libnm-glib/nm-access-point.c29
-rw-r--r--libnm-glib/nm-access-point.h1
-rw-r--r--libnm-glib/nm-active-connection.c351
-rw-r--r--libnm-glib/nm-active-connection.h31
-rw-r--r--libnm-glib/nm-client.c467
-rw-r--r--libnm-glib/nm-client.h26
-rw-r--r--libnm-glib/nm-dbus-helpers-private.h38
-rw-r--r--libnm-glib/nm-dbus-helpers.c107
-rw-r--r--libnm-glib/nm-device-adsl.c20
-rw-r--r--libnm-glib/nm-device-bond.c36
-rw-r--r--libnm-glib/nm-device-bridge.c36
-rw-r--r--libnm-glib/nm-device-bt.c28
-rw-r--r--libnm-glib/nm-device-ethernet.c35
-rw-r--r--libnm-glib/nm-device-ethernet.h4
-rw-r--r--libnm-glib/nm-device-generic.c289
-rw-r--r--libnm-glib/nm-device-generic.h81
-rw-r--r--libnm-glib/nm-device-infiniband.c35
-rw-r--r--libnm-glib/nm-device-modem.c59
-rw-r--r--libnm-glib/nm-device-olpc-mesh.c32
-rw-r--r--libnm-glib/nm-device-team.c356
-rw-r--r--libnm-glib/nm-device-team.h85
-rw-r--r--libnm-glib/nm-device-vlan.c49
-rw-r--r--libnm-glib/nm-device-vlan.h2
-rw-r--r--libnm-glib/nm-device-wifi.c123
-rw-r--r--libnm-glib/nm-device-wifi.h1
-rw-r--r--libnm-glib/nm-device-wimax.c112
-rw-r--r--libnm-glib/nm-device-wimax.h1
-rw-r--r--libnm-glib/nm-device.c786
-rw-r--r--libnm-glib/nm-device.h48
-rw-r--r--libnm-glib/nm-dhcp4-config.c31
-rw-r--r--libnm-glib/nm-dhcp6-config.c31
-rw-r--r--libnm-glib/nm-glib-enum-types.c122
-rw-r--r--libnm-glib/nm-glib-enum-types.h12
-rw-r--r--libnm-glib/nm-glib-marshal.c204
-rw-r--r--libnm-glib/nm-glib-marshal.h44
-rw-r--r--libnm-glib/nm-ip4-config.c213
-rw-r--r--libnm-glib/nm-ip4-config.h10
-rw-r--r--libnm-glib/nm-ip6-config.c248
-rw-r--r--libnm-glib/nm-ip6-config.h22
-rw-r--r--libnm-glib/nm-object-private.h17
-rw-r--r--libnm-glib/nm-object.c526
-rw-r--r--libnm-glib/nm-object.h2
-rw-r--r--libnm-glib/nm-remote-connection.c509
-rw-r--r--libnm-glib/nm-remote-connection.h63
-rw-r--r--libnm-glib/nm-remote-settings.c550
-rw-r--r--libnm-glib/nm-remote-settings.h27
-rw-r--r--libnm-glib/nm-secret-agent.c167
-rw-r--r--libnm-glib/nm-secret-agent.h23
-rw-r--r--libnm-glib/nm-types.c3
-rw-r--r--libnm-glib/nm-vpn-connection.c19
-rw-r--r--libnm-glib/nm-vpn-enum-types.c1
-rw-r--r--libnm-glib/nm-vpn-plugin-ui-interface.h8
-rw-r--r--libnm-glib/nm-vpn-plugin.c311
-rw-r--r--libnm-glib/nm-vpn-plugin.h41
-rw-r--r--libnm-glib/nm-wimax-nsp.c14
-rw-r--r--libnm-glib/tests/Makefile.am36
-rw-r--r--libnm-glib/tests/Makefile.in105
-rwxr-xr-xlibnm-glib/tests/test-fake-nm.py776
-rw-r--r--libnm-glib/tests/test-nm-client.c953
-rw-r--r--libnm-glib/tests/test-remote-settings-client.c24
-rwxr-xr-xlibnm-glib/tests/test-remote-settings-service.py37
68 files changed, 6807 insertions, 1852 deletions
diff --git a/libnm-glib/Makefile.am b/libnm-glib/Makefile.am
index 410848af..623bf45d 100644
--- a/libnm-glib/Makefile.am
+++ b/libnm-glib/Makefile.am
@@ -6,7 +6,11 @@ AM_CPPFLAGS = \
 	-I$(top_srcdir)/include \
 	-I$(top_builddir)/include \
 	-I$(top_srcdir)/libnm-util \
-	-I$(top_builddir)/libnm-util
+	-I$(top_builddir)/libnm-util \
+	-DG_LOG_DOMAIN=\""libnm-glib"\" \
+	-DNM_VERSION_MAX_ALLOWED=NM_VERSION_NEXT_STABLE \
+	$(DBUS_CFLAGS) \
+	$(GLIB_CFLAGS)
 
 BUILT_SOURCES = \
 	nm-vpn-plugin-glue.h \
@@ -26,8 +30,6 @@ libdeprecated_nm_glib_la_SOURCES = \
 	libnm_glib.c
 
 libdeprecated_nm_glib_la_CPPFLAGS = \
-	$(DBUS_CFLAGS) \
-	$(GLIB_CFLAGS) \
 	$(AM_CPPFLAGS) \
 	-Wno-deprecated-declarations \
 	-Wno-deprecated
@@ -48,7 +50,8 @@ lib_LTLIBRARIES = libnm-glib.la libnm-glib-vpn.la
 libnm_glib_la_CFLAGS = \
 	$(GLIB_CFLAGS) \
 	$(DBUS_CFLAGS) \
-	$(GUDEV_CFLAGS)
+	$(GUDEV_CFLAGS) \
+	-DNMRUNDIR=\"$(nmrundir)\"
 
 libnmincludedir = $(includedir)/libnm-glib
 libnmvpndir = $(includedir)/libnm-glib
@@ -64,8 +67,10 @@ libnminclude_HEADERS = \
 	nm-device-bt.h \
 	nm-device-olpc-mesh.h \
 	nm-device-bond.h \
+	nm-device-team.h \
 	nm-device-bridge.h \
 	nm-device-vlan.h \
+	nm-device-generic.h \
 	nm-access-point.h \
 	nm-ip4-config.h \
 	nm-device-modem.h \
@@ -90,6 +95,7 @@ libnmvpn_HEADERS = \
 
 libnm_glib_la_csources = \
 	nm-object.c \
+	nm-dbus-helpers.c \
 	nm-client.c \
 	nm-device.c \
 	nm-device-ethernet.c \
@@ -99,8 +105,10 @@ libnm_glib_la_csources = \
 	nm-device-bt.c \
 	nm-device-olpc-mesh.c \
 	nm-device-bond.c \
+	nm-device-team.c \
 	nm-device-bridge.c \
 	nm-device-vlan.c \
+	nm-device-generic.c \
 	nm-access-point.c \
 	nm-ip4-config.c \
 	nm-device-modem.c \
@@ -116,8 +124,7 @@ libnm_glib_la_csources = \
 	nm-secret-agent.c \
 	nm-device-wimax.c \
 	nm-wimax-nsp.c \
-	nm-glib-enum-types.c \
-	nm-glib-marshal.c
+	nm-glib-enum-types.c
 
 libnm_glib_la_private_headers = \
 	nm-object-private.h \
@@ -125,7 +132,7 @@ libnm_glib_la_private_headers = \
 	nm-types-private.h \
 	nm-object-cache.h \
 	nm-remote-connection-private.h \
-	nm-glib-marshal.h
+	nm-dbus-helpers-private.h
 
 libnm_glib_la_SOURCES = \
 	$(libnm_glib_la_csources) \
@@ -136,9 +143,6 @@ nm_glib_enum_types_sources = $(libnminclude_HEADERS)
 GLIB_MKENUMS_H_FLAGS = --identifier-prefix NM
 GLIB_MKENUMS_C_FLAGS = --identifier-prefix NM
 
-GLIB_GENERATED += nm-glib-marshal.h nm-glib-marshal.c
-nm_glib_marshal_sources = $(libnm_glib_la_SOURCES)
-
 libnm_glib_la_LIBADD = \
 	$(top_builddir)/libnm-util/libnm-util.la \
 	$(builddir)/libdeprecated-nm-glib.la \
@@ -149,7 +153,7 @@ libnm_glib_la_LIBADD = \
 SYMBOL_VIS_FILE=$(srcdir)/libnm-glib.ver
 
 libnm_glib_la_LDFLAGS = -Wl,--version-script=$(SYMBOL_VIS_FILE) \
-	-version-info "10:0:6"
+	-version-info "12:0:8"
 
 noinst_PROGRAMS = libnm-glib-test
 
@@ -168,7 +172,7 @@ nm_vpn_enum_types_sources = $(libnmvpn_HEADERS)
 libnm_glib_vpn_la_CFLAGS = $(GLIB_CFLAGS) $(DBUS_CFLAGS)
 libnm_glib_vpn_la_LIBADD = $(top_builddir)/libnm-util/libnm-util.la $(GLIB_LIBS) $(DBUS_LIBS)
 libnm_glib_vpn_la_LDFLAGS = -Wl,--version-script=$(srcdir)/libnm-glib-vpn.ver \
-	-version-info "2:0:1"
+	-version-info "3:0:2"
 
 BUILT_SOURCES += $(GLIB_GENERATED)
 
@@ -180,10 +184,11 @@ libnm_glib_test_la_CFLAGS = \
 	$(GLIB_CFLAGS) \
 	$(DBUS_CFLAGS) \
 	$(GUDEV_CFLAGS) \
-	-DLIBNM_GLIB_TEST
+	-DLIBNM_GLIB_TEST \
+	-DNMRUNDIR=\"$(nmrundir)\"
 
 libnm_glib_test_la_SOURCES = \
-	$(li0bnminclude_HEADERS) \
+	$(libnminclude_HEADERS) \
 	$(libnm_glib_la_SOURCES)
 
 libnm_glib_test_la_LIBADD = \
diff --git a/libnm-glib/Makefile.in b/libnm-glib/Makefile.in
index e726df56..4b169f40 100644
--- a/libnm-glib/Makefile.in
+++ b/libnm-glib/Makefile.in
@@ -90,7 +90,8 @@ DIST_COMMON = $(srcdir)/Makefile.in $(srcdir)/Makefile.am \
 	$(top_srcdir)/build-aux/depcomp $(libdeprecated_HEADERS) \
 	$(libnminclude_HEADERS) $(libnmvpn_HEADERS)
 ACLOCAL_M4 = $(top_srcdir)/aclocal.m4
-am__aclocal_m4_deps = $(top_srcdir)/m4/compiler_warnings.m4 \
+am__aclocal_m4_deps = $(top_srcdir)/m4/ax_lib_readline.m4 \
+	$(top_srcdir)/m4/compiler_warnings.m4 \
 	$(top_srcdir)/m4/gettext.m4 \
 	$(top_srcdir)/m4/gnome-code-coverage.m4 \
 	$(top_srcdir)/m4/gtk-doc.m4 $(top_srcdir)/m4/iconv.m4 \
@@ -154,7 +155,9 @@ am__v_lt_1 =
 libnm_glib_test_la_DEPENDENCIES =  \
 	$(top_builddir)/libnm-util/libnm-util.la $(am__DEPENDENCIES_1) \
 	$(am__DEPENDENCIES_1) $(am__DEPENDENCIES_1)
-am__objects_1 = libnm_glib_test_la-nm-object.lo \
+am__objects_1 =
+am__objects_2 = libnm_glib_test_la-nm-object.lo \
+	libnm_glib_test_la-nm-dbus-helpers.lo \
 	libnm_glib_test_la-nm-client.lo \
 	libnm_glib_test_la-nm-device.lo \
 	libnm_glib_test_la-nm-device-ethernet.lo \
@@ -164,8 +167,10 @@ am__objects_1 = libnm_glib_test_la-nm-object.lo \
 	libnm_glib_test_la-nm-device-bt.lo \
 	libnm_glib_test_la-nm-device-olpc-mesh.lo \
 	libnm_glib_test_la-nm-device-bond.lo \
+	libnm_glib_test_la-nm-device-team.lo \
 	libnm_glib_test_la-nm-device-bridge.lo \
 	libnm_glib_test_la-nm-device-vlan.lo \
+	libnm_glib_test_la-nm-device-generic.lo \
 	libnm_glib_test_la-nm-access-point.lo \
 	libnm_glib_test_la-nm-ip4-config.lo \
 	libnm_glib_test_la-nm-device-modem.lo \
@@ -181,11 +186,9 @@ am__objects_1 = libnm_glib_test_la-nm-object.lo \
 	libnm_glib_test_la-nm-secret-agent.lo \
 	libnm_glib_test_la-nm-device-wimax.lo \
 	libnm_glib_test_la-nm-wimax-nsp.lo \
-	libnm_glib_test_la-nm-glib-enum-types.lo \
-	libnm_glib_test_la-nm-glib-marshal.lo
-am__objects_2 =
-am__objects_3 = $(am__objects_1) $(am__objects_2)
-am_libnm_glib_test_la_OBJECTS = $(am__objects_3)
+	libnm_glib_test_la-nm-glib-enum-types.lo
+am__objects_3 = $(am__objects_2) $(am__objects_1)
+am_libnm_glib_test_la_OBJECTS = $(am__objects_1) $(am__objects_3)
 libnm_glib_test_la_OBJECTS = $(am_libnm_glib_test_la_OBJECTS)
 libnm_glib_test_la_LINK = $(LIBTOOL) $(AM_V_lt) --tag=CC \
 	$(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=link $(CCLD) \
@@ -206,15 +209,18 @@ libnm_glib_vpn_la_LINK = $(LIBTOOL) $(AM_V_lt) --tag=CC \
 libnm_glib_la_DEPENDENCIES = $(top_builddir)/libnm-util/libnm-util.la \
 	$(builddir)/libdeprecated-nm-glib.la $(am__DEPENDENCIES_1) \
 	$(am__DEPENDENCIES_1) $(am__DEPENDENCIES_1)
-am__objects_4 = libnm_glib_la-nm-object.lo libnm_glib_la-nm-client.lo \
+am__objects_4 = libnm_glib_la-nm-object.lo \
+	libnm_glib_la-nm-dbus-helpers.lo libnm_glib_la-nm-client.lo \
 	libnm_glib_la-nm-device.lo libnm_glib_la-nm-device-ethernet.lo \
 	libnm_glib_la-nm-device-infiniband.lo \
 	libnm_glib_la-nm-device-adsl.lo \
 	libnm_glib_la-nm-device-wifi.lo libnm_glib_la-nm-device-bt.lo \
 	libnm_glib_la-nm-device-olpc-mesh.lo \
 	libnm_glib_la-nm-device-bond.lo \
+	libnm_glib_la-nm-device-team.lo \
 	libnm_glib_la-nm-device-bridge.lo \
 	libnm_glib_la-nm-device-vlan.lo \
+	libnm_glib_la-nm-device-generic.lo \
 	libnm_glib_la-nm-access-point.lo \
 	libnm_glib_la-nm-ip4-config.lo \
 	libnm_glib_la-nm-device-modem.lo \
@@ -228,9 +234,8 @@ am__objects_4 = libnm_glib_la-nm-object.lo libnm_glib_la-nm-client.lo \
 	libnm_glib_la-nm-remote-settings.lo \
 	libnm_glib_la-nm-secret-agent.lo \
 	libnm_glib_la-nm-device-wimax.lo libnm_glib_la-nm-wimax-nsp.lo \
-	libnm_glib_la-nm-glib-enum-types.lo \
-	libnm_glib_la-nm-glib-marshal.lo
-am_libnm_glib_la_OBJECTS = $(am__objects_4) $(am__objects_2)
+	libnm_glib_la-nm-glib-enum-types.lo
+am_libnm_glib_la_OBJECTS = $(am__objects_4) $(am__objects_1)
 libnm_glib_la_OBJECTS = $(am_libnm_glib_la_OBJECTS)
 libnm_glib_la_LINK = $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) \
 	$(LIBTOOLFLAGS) --mode=link $(CCLD) $(libnm_glib_la_CFLAGS) \
@@ -381,12 +386,15 @@ CXXFLAGS = @CXXFLAGS@
 CYGPATH_W = @CYGPATH_W@
 DATADIRNAME = @DATADIRNAME@
 DBUS_CFLAGS = @DBUS_CFLAGS@
+DBUS_GLIB_100_CFLAGS = @DBUS_GLIB_100_CFLAGS@
+DBUS_GLIB_100_LIBS = @DBUS_GLIB_100_LIBS@
 DBUS_LIBS = @DBUS_LIBS@
 DBUS_SYS_DIR = @DBUS_SYS_DIR@
 DEFS = @DEFS@
 DEPDIR = @DEPDIR@
 DHCLIENT_PATH = @DHCLIENT_PATH@
 DHCPCD_PATH = @DHCPCD_PATH@
+DISTRO_NETWORK_SERVICE = @DISTRO_NETWORK_SERVICE@
 DLLTOOL = @DLLTOOL@
 DNSMASQ_PATH = @DNSMASQ_PATH@
 DSYMUTIL = @DSYMUTIL@
@@ -411,7 +419,6 @@ GNUTLS_CFLAGS = @GNUTLS_CFLAGS@
 GNUTLS_LIBS = @GNUTLS_LIBS@
 GREP = @GREP@
 GTKDOC_CHECK = @GTKDOC_CHECK@
-GTKDOC_CHECK_PATH = @GTKDOC_CHECK_PATH@
 GTKDOC_DEPS_CFLAGS = @GTKDOC_DEPS_CFLAGS@
 GTKDOC_DEPS_LIBS = @GTKDOC_DEPS_LIBS@
 GTKDOC_MKPDF = @GTKDOC_MKPDF@
@@ -456,12 +463,16 @@ LIBGCRYPT_LIBS = @LIBGCRYPT_LIBS@
 LIBICONV = @LIBICONV@
 LIBINTL = @LIBINTL@
 LIBM = @LIBM@
+LIBNDP_CFLAGS = @LIBNDP_CFLAGS@
+LIBNDP_LIBS = @LIBNDP_LIBS@
 LIBNL_CFLAGS = @LIBNL_CFLAGS@
 LIBNL_LIBS = @LIBNL_LIBS@
 LIBOBJS = @LIBOBJS@
 LIBS = @LIBS@
 LIBSOUP_CFLAGS = @LIBSOUP_CFLAGS@
 LIBSOUP_LIBS = @LIBSOUP_LIBS@
+LIBTEAMDCTL_CFLAGS = @LIBTEAMDCTL_CFLAGS@
+LIBTEAMDCTL_LIBS = @LIBTEAMDCTL_LIBS@
 LIBTOOL = @LIBTOOL@
 LIPO = @LIPO@
 LN_S = @LN_S@
@@ -478,6 +489,8 @@ MOC = @MOC@
 MSGFMT = @MSGFMT@
 MSGFMT_015 = @MSGFMT_015@
 MSGMERGE = @MSGMERGE@
+NEWT_CFLAGS = @NEWT_CFLAGS@
+NEWT_LIBS = @NEWT_LIBS@
 NM = @NM@
 NMEDIT = @NMEDIT@
 NM_MAJOR_VERSION = @NM_MAJOR_VERSION@
@@ -505,11 +518,16 @@ PKG_CONFIG_PATH = @PKG_CONFIG_PATH@
 POLKIT_CFLAGS = @POLKIT_CFLAGS@
 POLKIT_LIBS = @POLKIT_LIBS@
 POSUB = @POSUB@
+PPPD_PATH = @PPPD_PATH@
 PPPD_PLUGIN_DIR = @PPPD_PLUGIN_DIR@
+PPPOE_PATH = @PPPOE_PATH@
 QT_CFLAGS = @QT_CFLAGS@
 QT_LIBS = @QT_LIBS@
 RANLIB = @RANLIB@
+READLINE_LIBS = @READLINE_LIBS@
 SED = @SED@
+SELINUX_CFLAGS = @SELINUX_CFLAGS@
+SELINUX_LIBS = @SELINUX_LIBS@
 SET_MAKE = @SET_MAKE@
 SHELL = @SHELL@
 STRIP = @STRIP@
@@ -524,6 +542,7 @@ UDEV_BASE_DIR = @UDEV_BASE_DIR@
 USE_NLS = @USE_NLS@
 UUID_CFLAGS = @UUID_CFLAGS@
 UUID_LIBS = @UUID_LIBS@
+VALGRIND_RULES = @VALGRIND_RULES@
 VAPIGEN = @VAPIGEN@
 VAPIGEN_MAKEFILE = @VAPIGEN_MAKEFILE@
 VAPIGEN_VAPIDIR = @VAPIGEN_VAPIDIR@
@@ -586,6 +605,7 @@ psdir = @psdir@
 sbindir = @sbindir@
 sharedstatedir = @sharedstatedir@
 srcdir = @srcdir@
+subdirs = @subdirs@
 sysconfdir = @sysconfdir@
 systemdsystemunitdir = @systemdsystemunitdir@
 target_alias = @target_alias@
@@ -596,12 +616,17 @@ with_dhclient = @with_dhclient@
 with_dhcpcd = @with_dhcpcd@
 with_netconfig = @with_netconfig@
 with_resolvconf = @with_resolvconf@
+with_valgrind = @with_valgrind@
 SUBDIRS = . tests
 AM_CPPFLAGS = \
 	-I$(top_srcdir)/include \
 	-I$(top_builddir)/include \
 	-I$(top_srcdir)/libnm-util \
-	-I$(top_builddir)/libnm-util
+	-I$(top_builddir)/libnm-util \
+	-DG_LOG_DOMAIN=\""libnm-glib"\" \
+	-DNM_VERSION_MAX_ALLOWED=NM_VERSION_NEXT_STABLE \
+	$(DBUS_CFLAGS) \
+	$(GLIB_CFLAGS)
 
 BUILT_SOURCES = nm-vpn-plugin-glue.h nm-secret-agent-glue.h \
 	$(GLIB_GENERATED)
@@ -618,8 +643,6 @@ libdeprecated_nm_glib_la_SOURCES = \
 	libnm_glib.c
 
 libdeprecated_nm_glib_la_CPPFLAGS = \
-	$(DBUS_CFLAGS) \
-	$(GLIB_CFLAGS) \
 	$(AM_CPPFLAGS) \
 	-Wno-deprecated-declarations \
 	-Wno-deprecated
@@ -638,7 +661,8 @@ lib_LTLIBRARIES = libnm-glib.la libnm-glib-vpn.la
 libnm_glib_la_CFLAGS = \
 	$(GLIB_CFLAGS) \
 	$(DBUS_CFLAGS) \
-	$(GUDEV_CFLAGS)
+	$(GUDEV_CFLAGS) \
+	-DNMRUNDIR=\"$(nmrundir)\"
 
 libnmincludedir = $(includedir)/libnm-glib
 libnmvpndir = $(includedir)/libnm-glib
@@ -653,8 +677,10 @@ libnminclude_HEADERS = \
 	nm-device-bt.h \
 	nm-device-olpc-mesh.h \
 	nm-device-bond.h \
+	nm-device-team.h \
 	nm-device-bridge.h \
 	nm-device-vlan.h \
+	nm-device-generic.h \
 	nm-access-point.h \
 	nm-ip4-config.h \
 	nm-device-modem.h \
@@ -679,6 +705,7 @@ libnmvpn_HEADERS = \
 
 libnm_glib_la_csources = \
 	nm-object.c \
+	nm-dbus-helpers.c \
 	nm-client.c \
 	nm-device.c \
 	nm-device-ethernet.c \
@@ -688,8 +715,10 @@ libnm_glib_la_csources = \
 	nm-device-bt.c \
 	nm-device-olpc-mesh.c \
 	nm-device-bond.c \
+	nm-device-team.c \
 	nm-device-bridge.c \
 	nm-device-vlan.c \
+	nm-device-generic.c \
 	nm-access-point.c \
 	nm-ip4-config.c \
 	nm-device-modem.c \
@@ -705,8 +734,7 @@ libnm_glib_la_csources = \
 	nm-secret-agent.c \
 	nm-device-wimax.c \
 	nm-wimax-nsp.c \
-	nm-glib-enum-types.c \
-	nm-glib-marshal.c
+	nm-glib-enum-types.c
 
 libnm_glib_la_private_headers = \
 	nm-object-private.h \
@@ -714,19 +742,17 @@ libnm_glib_la_private_headers = \
 	nm-types-private.h \
 	nm-object-cache.h \
 	nm-remote-connection-private.h \
-	nm-glib-marshal.h
+	nm-dbus-helpers-private.h
 
 libnm_glib_la_SOURCES = \
 	$(libnm_glib_la_csources) \
 	$(libnm_glib_la_private_headers)
 
 GLIB_GENERATED = nm-glib-enum-types.h nm-glib-enum-types.c \
-	nm-glib-marshal.h nm-glib-marshal.c nm-vpn-enum-types.h \
-	nm-vpn-enum-types.c
+	nm-vpn-enum-types.h nm-vpn-enum-types.c
 nm_glib_enum_types_sources = $(libnminclude_HEADERS)
 GLIB_MKENUMS_H_FLAGS = --identifier-prefix NM
 GLIB_MKENUMS_C_FLAGS = --identifier-prefix NM
-nm_glib_marshal_sources = $(libnm_glib_la_SOURCES)
 libnm_glib_la_LIBADD = \
 	$(top_builddir)/libnm-util/libnm-util.la \
 	$(builddir)/libdeprecated-nm-glib.la \
@@ -736,7 +762,7 @@ libnm_glib_la_LIBADD = \
 
 SYMBOL_VIS_FILE = $(srcdir)/libnm-glib.ver
 libnm_glib_la_LDFLAGS = -Wl,--version-script=$(SYMBOL_VIS_FILE) \
-	-version-info "10:0:6"
+	-version-info "12:0:8"
 
 libnm_glib_test_SOURCES = libnm-glib-test.c
 libnm_glib_test_CFLAGS = $(GLIB_CFLAGS) $(DBUS_CFLAGS)
@@ -751,7 +777,7 @@ nm_vpn_enum_types_sources = $(libnmvpn_HEADERS)
 libnm_glib_vpn_la_CFLAGS = $(GLIB_CFLAGS) $(DBUS_CFLAGS)
 libnm_glib_vpn_la_LIBADD = $(top_builddir)/libnm-util/libnm-util.la $(GLIB_LIBS) $(DBUS_LIBS)
 libnm_glib_vpn_la_LDFLAGS = -Wl,--version-script=$(srcdir)/libnm-glib-vpn.ver \
-	-version-info "2:0:1"
+	-version-info "3:0:2"
 
 
 #####################################################
@@ -761,10 +787,11 @@ libnm_glib_test_la_CFLAGS = \
 	$(GLIB_CFLAGS) \
 	$(DBUS_CFLAGS) \
 	$(GUDEV_CFLAGS) \
-	-DLIBNM_GLIB_TEST
+	-DLIBNM_GLIB_TEST \
+	-DNMRUNDIR=\"$(nmrundir)\"
 
 libnm_glib_test_la_SOURCES = \
-	$(li0bnminclude_HEADERS) \
+	$(libnminclude_HEADERS) \
 	$(libnm_glib_la_SOURCES)
 
 libnm_glib_test_la_LIBADD = \
@@ -913,14 +940,17 @@ distclean-compile:
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libnm_glib_la-nm-access-point.Plo@am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libnm_glib_la-nm-active-connection.Plo@am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libnm_glib_la-nm-client.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libnm_glib_la-nm-dbus-helpers.Plo@am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libnm_glib_la-nm-device-adsl.Plo@am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libnm_glib_la-nm-device-bond.Plo@am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libnm_glib_la-nm-device-bridge.Plo@am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libnm_glib_la-nm-device-bt.Plo@am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libnm_glib_la-nm-device-ethernet.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libnm_glib_la-nm-device-generic.Plo@am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libnm_glib_la-nm-device-infiniband.Plo@am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libnm_glib_la-nm-device-modem.Plo@am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libnm_glib_la-nm-device-olpc-mesh.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libnm_glib_la-nm-device-team.Plo@am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libnm_glib_la-nm-device-vlan.Plo@am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libnm_glib_la-nm-device-wifi.Plo@am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libnm_glib_la-nm-device-wimax.Plo@am__quote@
@@ -928,7 +958,6 @@ distclean-compile:
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libnm_glib_la-nm-dhcp4-config.Plo@am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libnm_glib_la-nm-dhcp6-config.Plo@am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libnm_glib_la-nm-glib-enum-types.Plo@am__quote@
-@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libnm_glib_la-nm-glib-marshal.Plo@am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libnm_glib_la-nm-ip4-config.Plo@am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libnm_glib_la-nm-ip6-config.Plo@am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libnm_glib_la-nm-object-cache.Plo@am__quote@
@@ -943,14 +972,17 @@ distclean-compile:
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libnm_glib_test_la-nm-access-point.Plo@am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libnm_glib_test_la-nm-active-connection.Plo@am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libnm_glib_test_la-nm-client.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libnm_glib_test_la-nm-dbus-helpers.Plo@am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libnm_glib_test_la-nm-device-adsl.Plo@am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libnm_glib_test_la-nm-device-bond.Plo@am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libnm_glib_test_la-nm-device-bridge.Plo@am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libnm_glib_test_la-nm-device-bt.Plo@am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libnm_glib_test_la-nm-device-ethernet.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libnm_glib_test_la-nm-device-generic.Plo@am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libnm_glib_test_la-nm-device-infiniband.Plo@am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libnm_glib_test_la-nm-device-modem.Plo@am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libnm_glib_test_la-nm-device-olpc-mesh.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libnm_glib_test_la-nm-device-team.Plo@am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libnm_glib_test_la-nm-device-vlan.Plo@am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libnm_glib_test_la-nm-device-wifi.Plo@am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libnm_glib_test_la-nm-device-wimax.Plo@am__quote@
@@ -958,7 +990,6 @@ distclean-compile:
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libnm_glib_test_la-nm-dhcp4-config.Plo@am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libnm_glib_test_la-nm-dhcp6-config.Plo@am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libnm_glib_test_la-nm-glib-enum-types.Plo@am__quote@
-@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libnm_glib_test_la-nm-glib-marshal.Plo@am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libnm_glib_test_la-nm-ip4-config.Plo@am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libnm_glib_test_la-nm-ip6-config.Plo@am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libnm_glib_test_la-nm-object-cache.Plo@am__quote@
@@ -1009,6 +1040,13 @@ libnm_glib_test_la-nm-object.lo: nm-object.c
 @AMDEP_TRUE@@am__fastdepCC_FALSE@	DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
 @am__fastdepCC_FALSE@	$(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libnm_glib_test_la_CFLAGS) $(CFLAGS) -c -o libnm_glib_test_la-nm-object.lo `test -f 'nm-object.c' || echo '$(srcdir)/'`nm-object.c
 
+libnm_glib_test_la-nm-dbus-helpers.lo: nm-dbus-helpers.c
+@am__fastdepCC_TRUE@	$(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libnm_glib_test_la_CFLAGS) $(CFLAGS) -MT libnm_glib_test_la-nm-dbus-helpers.lo -MD -MP -MF $(DEPDIR)/libnm_glib_test_la-nm-dbus-helpers.Tpo -c -o libnm_glib_test_la-nm-dbus-helpers.lo `test -f 'nm-dbus-helpers.c' || echo '$(srcdir)/'`nm-dbus-helpers.c
+@am__fastdepCC_TRUE@	$(AM_V_at)$(am__mv) $(DEPDIR)/libnm_glib_test_la-nm-dbus-helpers.Tpo $(DEPDIR)/libnm_glib_test_la-nm-dbus-helpers.Plo
+@AMDEP_TRUE@@am__fastdepCC_FALSE@	$(AM_V_CC)source='nm-dbus-helpers.c' object='libnm_glib_test_la-nm-dbus-helpers.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@	DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@	$(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libnm_glib_test_la_CFLAGS) $(CFLAGS) -c -o libnm_glib_test_la-nm-dbus-helpers.lo `test -f 'nm-dbus-helpers.c' || echo '$(srcdir)/'`nm-dbus-helpers.c
+
 libnm_glib_test_la-nm-client.lo: nm-client.c
 @am__fastdepCC_TRUE@	$(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libnm_glib_test_la_CFLAGS) $(CFLAGS) -MT libnm_glib_test_la-nm-client.lo -MD -MP -MF $(DEPDIR)/libnm_glib_test_la-nm-client.Tpo -c -o libnm_glib_test_la-nm-client.lo `test -f 'nm-client.c' || echo '$(srcdir)/'`nm-client.c
 @am__fastdepCC_TRUE@	$(AM_V_at)$(am__mv) $(DEPDIR)/libnm_glib_test_la-nm-client.Tpo $(DEPDIR)/libnm_glib_test_la-nm-client.Plo
@@ -1072,6 +1110,13 @@ libnm_glib_test_la-nm-device-bond.lo: nm-device-bond.c
 @AMDEP_TRUE@@am__fastdepCC_FALSE@	DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
 @am__fastdepCC_FALSE@	$(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libnm_glib_test_la_CFLAGS) $(CFLAGS) -c -o libnm_glib_test_la-nm-device-bond.lo `test -f 'nm-device-bond.c' || echo '$(srcdir)/'`nm-device-bond.c
 
+libnm_glib_test_la-nm-device-team.lo: nm-device-team.c
+@am__fastdepCC_TRUE@	$(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libnm_glib_test_la_CFLAGS) $(CFLAGS) -MT libnm_glib_test_la-nm-device-team.lo -MD -MP -MF $(DEPDIR)/libnm_glib_test_la-nm-device-team.Tpo -c -o libnm_glib_test_la-nm-device-team.lo `test -f 'nm-device-team.c' || echo '$(srcdir)/'`nm-device-team.c
+@am__fastdepCC_TRUE@	$(AM_V_at)$(am__mv) $(DEPDIR)/libnm_glib_test_la-nm-device-team.Tpo $(DEPDIR)/libnm_glib_test_la-nm-device-team.Plo
+@AMDEP_TRUE@@am__fastdepCC_FALSE@	$(AM_V_CC)source='nm-device-team.c' object='libnm_glib_test_la-nm-device-team.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@	DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@	$(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libnm_glib_test_la_CFLAGS) $(CFLAGS) -c -o libnm_glib_test_la-nm-device-team.lo `test -f 'nm-device-team.c' || echo '$(srcdir)/'`nm-device-team.c
+
 libnm_glib_test_la-nm-device-bridge.lo: nm-device-bridge.c
 @am__fastdepCC_TRUE@	$(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libnm_glib_test_la_CFLAGS) $(CFLAGS) -MT libnm_glib_test_la-nm-device-bridge.lo -MD -MP -MF $(DEPDIR)/libnm_glib_test_la-nm-device-bridge.Tpo -c -o libnm_glib_test_la-nm-device-bridge.lo `test -f 'nm-device-bridge.c' || echo '$(srcdir)/'`nm-device-bridge.c
 @am__fastdepCC_TRUE@	$(AM_V_at)$(am__mv) $(DEPDIR)/libnm_glib_test_la-nm-device-bridge.Tpo $(DEPDIR)/libnm_glib_test_la-nm-device-bridge.Plo
@@ -1086,6 +1131,13 @@ libnm_glib_test_la-nm-device-vlan.lo: nm-device-vlan.c
 @AMDEP_TRUE@@am__fastdepCC_FALSE@	DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
 @am__fastdepCC_FALSE@	$(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libnm_glib_test_la_CFLAGS) $(CFLAGS) -c -o libnm_glib_test_la-nm-device-vlan.lo `test -f 'nm-device-vlan.c' || echo '$(srcdir)/'`nm-device-vlan.c
 
+libnm_glib_test_la-nm-device-generic.lo: nm-device-generic.c
+@am__fastdepCC_TRUE@	$(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libnm_glib_test_la_CFLAGS) $(CFLAGS) -MT libnm_glib_test_la-nm-device-generic.lo -MD -MP -MF $(DEPDIR)/libnm_glib_test_la-nm-device-generic.Tpo -c -o libnm_glib_test_la-nm-device-generic.lo `test -f 'nm-device-generic.c' || echo '$(srcdir)/'`nm-device-generic.c
+@am__fastdepCC_TRUE@	$(AM_V_at)$(am__mv) $(DEPDIR)/libnm_glib_test_la-nm-device-generic.Tpo $(DEPDIR)/libnm_glib_test_la-nm-device-generic.Plo
+@AMDEP_TRUE@@am__fastdepCC_FALSE@	$(AM_V_CC)source='nm-device-generic.c' object='libnm_glib_test_la-nm-device-generic.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@	DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@	$(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libnm_glib_test_la_CFLAGS) $(CFLAGS) -c -o libnm_glib_test_la-nm-device-generic.lo `test -f 'nm-device-generic.c' || echo '$(srcdir)/'`nm-device-generic.c
+
 libnm_glib_test_la-nm-access-point.lo: nm-access-point.c
 @am__fastdepCC_TRUE@	$(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libnm_glib_test_la_CFLAGS) $(CFLAGS) -MT libnm_glib_test_la-nm-access-point.lo -MD -MP -MF $(DEPDIR)/libnm_glib_test_la-nm-access-point.Tpo -c -o libnm_glib_test_la-nm-access-point.lo `test -f 'nm-access-point.c' || echo '$(srcdir)/'`nm-access-point.c
 @am__fastdepCC_TRUE@	$(AM_V_at)$(am__mv) $(DEPDIR)/libnm_glib_test_la-nm-access-point.Tpo $(DEPDIR)/libnm_glib_test_la-nm-access-point.Plo
@@ -1198,13 +1250,6 @@ libnm_glib_test_la-nm-glib-enum-types.lo: nm-glib-enum-types.c
 @AMDEP_TRUE@@am__fastdepCC_FALSE@	DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
 @am__fastdepCC_FALSE@	$(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libnm_glib_test_la_CFLAGS) $(CFLAGS) -c -o libnm_glib_test_la-nm-glib-enum-types.lo `test -f 'nm-glib-enum-types.c' || echo '$(srcdir)/'`nm-glib-enum-types.c
 
-libnm_glib_test_la-nm-glib-marshal.lo: nm-glib-marshal.c
-@am__fastdepCC_TRUE@	$(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libnm_glib_test_la_CFLAGS) $(CFLAGS) -MT libnm_glib_test_la-nm-glib-marshal.lo -MD -MP -MF $(DEPDIR)/libnm_glib_test_la-nm-glib-marshal.Tpo -c -o libnm_glib_test_la-nm-glib-marshal.lo `test -f 'nm-glib-marshal.c' || echo '$(srcdir)/'`nm-glib-marshal.c
-@am__fastdepCC_TRUE@	$(AM_V_at)$(am__mv) $(DEPDIR)/libnm_glib_test_la-nm-glib-marshal.Tpo $(DEPDIR)/libnm_glib_test_la-nm-glib-marshal.Plo
-@AMDEP_TRUE@@am__fastdepCC_FALSE@	$(AM_V_CC)source='nm-glib-marshal.c' object='libnm_glib_test_la-nm-glib-marshal.lo' libtool=yes @AMDEPBACKSLASH@
-@AMDEP_TRUE@@am__fastdepCC_FALSE@	DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
-@am__fastdepCC_FALSE@	$(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libnm_glib_test_la_CFLAGS) $(CFLAGS) -c -o libnm_glib_test_la-nm-glib-marshal.lo `test -f 'nm-glib-marshal.c' || echo '$(srcdir)/'`nm-glib-marshal.c
-
 libnm_glib_vpn_la-nm-vpn-plugin.lo: nm-vpn-plugin.c
 @am__fastdepCC_TRUE@	$(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libnm_glib_vpn_la_CFLAGS) $(CFLAGS) -MT libnm_glib_vpn_la-nm-vpn-plugin.lo -MD -MP -MF $(DEPDIR)/libnm_glib_vpn_la-nm-vpn-plugin.Tpo -c -o libnm_glib_vpn_la-nm-vpn-plugin.lo `test -f 'nm-vpn-plugin.c' || echo '$(srcdir)/'`nm-vpn-plugin.c
 @am__fastdepCC_TRUE@	$(AM_V_at)$(am__mv) $(DEPDIR)/libnm_glib_vpn_la-nm-vpn-plugin.Tpo $(DEPDIR)/libnm_glib_vpn_la-nm-vpn-plugin.Plo
@@ -1240,6 +1285,13 @@ libnm_glib_la-nm-object.lo: nm-object.c
 @AMDEP_TRUE@@am__fastdepCC_FALSE@	DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
 @am__fastdepCC_FALSE@	$(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libnm_glib_la_CFLAGS) $(CFLAGS) -c -o libnm_glib_la-nm-object.lo `test -f 'nm-object.c' || echo '$(srcdir)/'`nm-object.c
 
+libnm_glib_la-nm-dbus-helpers.lo: nm-dbus-helpers.c
+@am__fastdepCC_TRUE@	$(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libnm_glib_la_CFLAGS) $(CFLAGS) -MT libnm_glib_la-nm-dbus-helpers.lo -MD -MP -MF $(DEPDIR)/libnm_glib_la-nm-dbus-helpers.Tpo -c -o libnm_glib_la-nm-dbus-helpers.lo `test -f 'nm-dbus-helpers.c' || echo '$(srcdir)/'`nm-dbus-helpers.c
+@am__fastdepCC_TRUE@	$(AM_V_at)$(am__mv) $(DEPDIR)/libnm_glib_la-nm-dbus-helpers.Tpo $(DEPDIR)/libnm_glib_la-nm-dbus-helpers.Plo
+@AMDEP_TRUE@@am__fastdepCC_FALSE@	$(AM_V_CC)source='nm-dbus-helpers.c' object='libnm_glib_la-nm-dbus-helpers.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@	DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@	$(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libnm_glib_la_CFLAGS) $(CFLAGS) -c -o libnm_glib_la-nm-dbus-helpers.lo `test -f 'nm-dbus-helpers.c' || echo '$(srcdir)/'`nm-dbus-helpers.c
+
 libnm_glib_la-nm-client.lo: nm-client.c
 @am__fastdepCC_TRUE@	$(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libnm_glib_la_CFLAGS) $(CFLAGS) -MT libnm_glib_la-nm-client.lo -MD -MP -MF $(DEPDIR)/libnm_glib_la-nm-client.Tpo -c -o libnm_glib_la-nm-client.lo `test -f 'nm-client.c' || echo '$(srcdir)/'`nm-client.c
 @am__fastdepCC_TRUE@	$(AM_V_at)$(am__mv) $(DEPDIR)/libnm_glib_la-nm-client.Tpo $(DEPDIR)/libnm_glib_la-nm-client.Plo
@@ -1303,6 +1355,13 @@ libnm_glib_la-nm-device-bond.lo: nm-device-bond.c
 @AMDEP_TRUE@@am__fastdepCC_FALSE@	DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
 @am__fastdepCC_FALSE@	$(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libnm_glib_la_CFLAGS) $(CFLAGS) -c -o libnm_glib_la-nm-device-bond.lo `test -f 'nm-device-bond.c' || echo '$(srcdir)/'`nm-device-bond.c
 
+libnm_glib_la-nm-device-team.lo: nm-device-team.c
+@am__fastdepCC_TRUE@	$(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libnm_glib_la_CFLAGS) $(CFLAGS) -MT libnm_glib_la-nm-device-team.lo -MD -MP -MF $(DEPDIR)/libnm_glib_la-nm-device-team.Tpo -c -o libnm_glib_la-nm-device-team.lo `test -f 'nm-device-team.c' || echo '$(srcdir)/'`nm-device-team.c
+@am__fastdepCC_TRUE@	$(AM_V_at)$(am__mv) $(DEPDIR)/libnm_glib_la-nm-device-team.Tpo $(DEPDIR)/libnm_glib_la-nm-device-team.Plo
+@AMDEP_TRUE@@am__fastdepCC_FALSE@	$(AM_V_CC)source='nm-device-team.c' object='libnm_glib_la-nm-device-team.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@	DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@	$(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libnm_glib_la_CFLAGS) $(CFLAGS) -c -o libnm_glib_la-nm-device-team.lo `test -f 'nm-device-team.c' || echo '$(srcdir)/'`nm-device-team.c
+
 libnm_glib_la-nm-device-bridge.lo: nm-device-bridge.c
 @am__fastdepCC_TRUE@	$(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libnm_glib_la_CFLAGS) $(CFLAGS) -MT libnm_glib_la-nm-device-bridge.lo -MD -MP -MF $(DEPDIR)/libnm_glib_la-nm-device-bridge.Tpo -c -o libnm_glib_la-nm-device-bridge.lo `test -f 'nm-device-bridge.c' || echo '$(srcdir)/'`nm-device-bridge.c
 @am__fastdepCC_TRUE@	$(AM_V_at)$(am__mv) $(DEPDIR)/libnm_glib_la-nm-device-bridge.Tpo $(DEPDIR)/libnm_glib_la-nm-device-bridge.Plo
@@ -1317,6 +1376,13 @@ libnm_glib_la-nm-device-vlan.lo: nm-device-vlan.c
 @AMDEP_TRUE@@am__fastdepCC_FALSE@	DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
 @am__fastdepCC_FALSE@	$(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libnm_glib_la_CFLAGS) $(CFLAGS) -c -o libnm_glib_la-nm-device-vlan.lo `test -f 'nm-device-vlan.c' || echo '$(srcdir)/'`nm-device-vlan.c
 
+libnm_glib_la-nm-device-generic.lo: nm-device-generic.c
+@am__fastdepCC_TRUE@	$(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libnm_glib_la_CFLAGS) $(CFLAGS) -MT libnm_glib_la-nm-device-generic.lo -MD -MP -MF $(DEPDIR)/libnm_glib_la-nm-device-generic.Tpo -c -o libnm_glib_la-nm-device-generic.lo `test -f 'nm-device-generic.c' || echo '$(srcdir)/'`nm-device-generic.c
+@am__fastdepCC_TRUE@	$(AM_V_at)$(am__mv) $(DEPDIR)/libnm_glib_la-nm-device-generic.Tpo $(DEPDIR)/libnm_glib_la-nm-device-generic.Plo
+@AMDEP_TRUE@@am__fastdepCC_FALSE@	$(AM_V_CC)source='nm-device-generic.c' object='libnm_glib_la-nm-device-generic.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@	DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@	$(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libnm_glib_la_CFLAGS) $(CFLAGS) -c -o libnm_glib_la-nm-device-generic.lo `test -f 'nm-device-generic.c' || echo '$(srcdir)/'`nm-device-generic.c
+
 libnm_glib_la-nm-access-point.lo: nm-access-point.c
 @am__fastdepCC_TRUE@	$(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libnm_glib_la_CFLAGS) $(CFLAGS) -MT libnm_glib_la-nm-access-point.lo -MD -MP -MF $(DEPDIR)/libnm_glib_la-nm-access-point.Tpo -c -o libnm_glib_la-nm-access-point.lo `test -f 'nm-access-point.c' || echo '$(srcdir)/'`nm-access-point.c
 @am__fastdepCC_TRUE@	$(AM_V_at)$(am__mv) $(DEPDIR)/libnm_glib_la-nm-access-point.Tpo $(DEPDIR)/libnm_glib_la-nm-access-point.Plo
@@ -1429,13 +1495,6 @@ libnm_glib_la-nm-glib-enum-types.lo: nm-glib-enum-types.c
 @AMDEP_TRUE@@am__fastdepCC_FALSE@	DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
 @am__fastdepCC_FALSE@	$(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libnm_glib_la_CFLAGS) $(CFLAGS) -c -o libnm_glib_la-nm-glib-enum-types.lo `test -f 'nm-glib-enum-types.c' || echo '$(srcdir)/'`nm-glib-enum-types.c
 
-libnm_glib_la-nm-glib-marshal.lo: nm-glib-marshal.c
-@am__fastdepCC_TRUE@	$(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libnm_glib_la_CFLAGS) $(CFLAGS) -MT libnm_glib_la-nm-glib-marshal.lo -MD -MP -MF $(DEPDIR)/libnm_glib_la-nm-glib-marshal.Tpo -c -o libnm_glib_la-nm-glib-marshal.lo `test -f 'nm-glib-marshal.c' || echo '$(srcdir)/'`nm-glib-marshal.c
-@am__fastdepCC_TRUE@	$(AM_V_at)$(am__mv) $(DEPDIR)/libnm_glib_la-nm-glib-marshal.Tpo $(DEPDIR)/libnm_glib_la-nm-glib-marshal.Plo
-@AMDEP_TRUE@@am__fastdepCC_FALSE@	$(AM_V_CC)source='nm-glib-marshal.c' object='libnm_glib_la-nm-glib-marshal.lo' libtool=yes @AMDEPBACKSLASH@
-@AMDEP_TRUE@@am__fastdepCC_FALSE@	DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
-@am__fastdepCC_FALSE@	$(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libnm_glib_la_CFLAGS) $(CFLAGS) -c -o libnm_glib_la-nm-glib-marshal.lo `test -f 'nm-glib-marshal.c' || echo '$(srcdir)/'`nm-glib-marshal.c
-
 libnm_glib_test-libnm-glib-test.o: libnm-glib-test.c
 @am__fastdepCC_TRUE@	$(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libnm_glib_test_CFLAGS) $(CFLAGS) -MT libnm_glib_test-libnm-glib-test.o -MD -MP -MF $(DEPDIR)/libnm_glib_test-libnm-glib-test.Tpo -c -o libnm_glib_test-libnm-glib-test.o `test -f 'libnm-glib-test.c' || echo '$(srcdir)/'`libnm-glib-test.c
 @am__fastdepCC_TRUE@	$(AM_V_at)$(am__mv) $(DEPDIR)/libnm_glib_test-libnm-glib-test.Tpo $(DEPDIR)/libnm_glib_test-libnm-glib-test.Po
diff --git a/libnm-glib/libnm-glib-test.c b/libnm-glib/libnm-glib-test.c
index 4e80806f..e38457f0 100644
--- a/libnm-glib/libnm-glib-test.c
+++ b/libnm-glib/libnm-glib-test.c
@@ -70,16 +70,16 @@ static gchar *
 ip4_address_as_string (guint32 ip)
 {
 	char buf[INET_ADDRSTRLEN+1];
-	struct in_addr tmp_addr;
+	guint32 tmp_addr;
 
 	memset (&buf, '\0', sizeof (buf));
-	tmp_addr.s_addr = ip;
+	tmp_addr = ip;
 
 	if (inet_ntop (AF_INET, &tmp_addr, buf, INET_ADDRSTRLEN)) {
 		return g_strdup (buf);
 	} else {
 		g_warning ("%s: error converting IP4 address 0x%X",
-		           __func__, ntohl (tmp_addr.s_addr));
+		           __func__, ntohl (tmp_addr));
 		return NULL;
 	}
 }
@@ -173,7 +173,7 @@ dump_access_point (NMAccessPoint *ap)
 	g_print ("\tSsid: %s\n",
 	         ssid ? nm_utils_escape_ssid (ssid->data, ssid->len) : "(none)");
 
-	str = nm_access_point_get_hw_address (ap);
+	str = nm_access_point_get_bssid (ap);
 	g_print ("\tMAC Address: %s\n", str);
 
 	g_print ("\tFlags: 0x%X\n", nm_access_point_get_flags (ap));
@@ -390,7 +390,9 @@ main (int argc, char *argv[])
 {
 	NMClient *client;
 
+#if !GLIB_CHECK_VERSION (2, 35, 0)
 	g_type_init ();
+#endif
 
 	client = nm_client_new ();
 	if (!client) {
diff --git a/libnm-glib/libnm-glib-vpn.ver b/libnm-glib/libnm-glib-vpn.ver
index 9d2bad5e..b2e763b2 100644
--- a/libnm-glib/libnm-glib-vpn.ver
+++ b/libnm-glib/libnm-glib-vpn.ver
@@ -7,6 +7,7 @@ global:
 	nm_vpn_plugin_get_connection;
 	nm_vpn_plugin_get_state;
 	nm_vpn_plugin_get_type;
+	nm_vpn_plugin_secrets_required;
 	nm_vpn_plugin_set_ip4_config;
 	nm_vpn_plugin_set_login_banner;
 	nm_vpn_plugin_set_state;
diff --git a/libnm-glib/libnm-glib.pc.in b/libnm-glib/libnm-glib.pc.in
index 754c43da..2b4e6996 100644
--- a/libnm-glib/libnm-glib.pc.in
+++ b/libnm-glib/libnm-glib.pc.in
@@ -6,7 +6,7 @@ includedir=@includedir@
 Name: libnm-glib
 Description: Convenience library for clients of NetworkManager
 Version: @VERSION@
-Requires: NetworkManager >= @VERSION@ gobject-2.0 dbus-glib-1
+Requires: libnm-util >= @VERSION@ NetworkManager >= @VERSION@ gobject-2.0 dbus-glib-1
 Cflags: -I${includedir}/libnm-glib
 Libs: -L${libdir} -lnm-glib
 
diff --git a/libnm-glib/libnm-glib.ver b/libnm-glib/libnm-glib.ver
index b7d33211..982288e5 100644
--- a/libnm-glib/libnm-glib.ver
+++ b/libnm-glib/libnm-glib.ver
@@ -20,14 +20,21 @@ global:
 	nm_access_point_get_wpa_flags;
 	nm_access_point_new;
 	nm_active_connection_get_connection;
+	nm_active_connection_get_connection_type;
 	nm_active_connection_get_default6;
 	nm_active_connection_get_default;
 	nm_active_connection_get_devices;
+	nm_active_connection_get_dhcp4_config;
+	nm_active_connection_get_dhcp6_config;
+	nm_active_connection_get_id;
+	nm_active_connection_get_ip4_config;
+	nm_active_connection_get_ip6_config;
 	nm_active_connection_get_master;
 	nm_active_connection_get_specific_object;
 	nm_active_connection_get_state;
 	nm_active_connection_get_type;
 	nm_active_connection_get_uuid;
+	nm_active_connection_get_vpn;
 	nm_active_connection_new;
 	nm_client_activate_connection;
 	nm_client_add_and_activate_connection;
@@ -35,6 +42,8 @@ global:
 	nm_client_check_connectivity_async;
 	nm_client_check_connectivity_finish;
 	nm_client_deactivate_connection;
+	nm_client_error_get_type;
+	nm_client_error_quark;
 	nm_client_get_activating_connection;
 	nm_client_get_active_connections;
 	nm_client_get_connectivity;
@@ -45,6 +54,7 @@ global:
 	nm_client_get_manager_running;
 	nm_client_get_permission_result;
 	nm_client_get_primary_connection;
+	nm_client_get_startup;
 	nm_client_get_state;
 	nm_client_get_type;
 	nm_client_get_version;
@@ -94,7 +104,10 @@ global:
 	nm_device_bt_new;
 	nm_device_connection_compatible;
 	nm_device_connection_valid;
+	nm_device_disambiguate_names;
 	nm_device_disconnect;
+	nm_device_error_get_type;
+	nm_device_error_quark;
 	nm_device_ethernet_error_get_type;
 	nm_device_ethernet_error_quark;
 	nm_device_ethernet_get_carrier;
@@ -104,10 +117,16 @@ global:
 	nm_device_ethernet_get_type;
 	nm_device_ethernet_new;
 	nm_device_filter_connections;
+	nm_device_generic_error_get_type;
+	nm_device_generic_error_quark;
+	nm_device_generic_get_hw_address;
+	nm_device_generic_get_type;
+	nm_device_generic_new;
 	nm_device_get_active_connection;
 	nm_device_get_autoconnect;
 	nm_device_get_available_connections;
 	nm_device_get_capabilities;
+	nm_device_get_description;
 	nm_device_get_device_type;
 	nm_device_get_dhcp4_config;
 	nm_device_get_dhcp6_config;
@@ -115,15 +134,20 @@ global:
 	nm_device_get_driver_version;
 	nm_device_get_firmware_missing;
 	nm_device_get_firmware_version;
+	nm_device_get_hw_address;
 	nm_device_get_iface;
 	nm_device_get_ip4_config;
 	nm_device_get_ip6_config;
 	nm_device_get_ip_iface;
 	nm_device_get_managed;
+	nm_device_get_mtu;
+	nm_device_get_physical_port_id;
 	nm_device_get_product;
+	nm_device_get_setting_type;
 	nm_device_get_state;
 	nm_device_get_state_reason;
 	nm_device_get_type;
+	nm_device_get_type_description;
 	nm_device_get_udi;
 	nm_device_get_vendor;
 	nm_device_infiniband_error_get_type;
@@ -146,6 +170,13 @@ global:
 	nm_device_olpc_mesh_get_type;
 	nm_device_olpc_mesh_new;
 	nm_device_set_autoconnect;
+	nm_device_team_error_get_type;
+	nm_device_team_error_quark;
+	nm_device_team_get_carrier;
+	nm_device_team_get_hw_address;
+	nm_device_team_get_slaves;
+	nm_device_team_get_type;
+	nm_device_team_new;
 	nm_device_vlan_error_get_type;
 	nm_device_vlan_error_quark;
 	nm_device_vlan_get_carrier;
@@ -189,8 +220,10 @@ global:
 	nm_dhcp6_config_new;
 	nm_ip4_config_get_addresses;
 	nm_ip4_config_get_domains;
+	nm_ip4_config_get_gateway;
 	nm_ip4_config_get_nameservers;
 	nm_ip4_config_get_routes;
+	nm_ip4_config_get_searches;
 	nm_ip4_config_get_type;
 	nm_ip4_config_get_wins_servers;
 	nm_ip4_config_new;
@@ -198,8 +231,12 @@ global:
 	nm_ip6_address_object_array_get_type;
 	nm_ip6_config_get_addresses;
 	nm_ip6_config_get_domains;
+	nm_ip6_config_get_gateway;
+	nm_ip6_config_get_nameserver;
 	nm_ip6_config_get_nameservers;
+	nm_ip6_config_get_num_nameservers;
 	nm_ip6_config_get_routes;
+	nm_ip6_config_get_searches;
 	nm_ip6_config_get_type;
 	nm_ip6_config_new;
 	nm_ip6_route_object_array_get_type;
@@ -210,21 +247,31 @@ global:
 	nm_object_get_path;
 	nm_object_get_type;
 	nm_remote_connection_commit_changes;
+	nm_remote_connection_commit_changes_unsaved;
 	nm_remote_connection_delete;
+	nm_remote_connection_error_get_type;
+	nm_remote_connection_error_quark;
 	nm_remote_connection_get_secrets;
 	nm_remote_connection_get_type;
+	nm_remote_connection_get_unsaved;
 	nm_remote_connection_new;
+	nm_remote_connection_save;
 	nm_remote_settings_add_connection;
+	nm_remote_settings_add_connection_unsaved;
 	nm_remote_settings_error_get_type;
 	nm_remote_settings_error_quark;
+	nm_remote_settings_get_connection_by_id;
 	nm_remote_settings_get_connection_by_path;
 	nm_remote_settings_get_connection_by_uuid;
 	nm_remote_settings_get_type;
 	nm_remote_settings_list_connections;
+	nm_remote_settings_load_connections;
 	nm_remote_settings_new;
 	nm_remote_settings_new_async;
 	nm_remote_settings_new_finish;
+	nm_remote_settings_reload_connections;
 	nm_remote_settings_save_hostname;
+	nm_secret_agent_capabilities_get_type;
 	nm_secret_agent_delete_secrets;
 	nm_secret_agent_error_get_type;
 	nm_secret_agent_error_quark;
diff --git a/libnm-glib/libnm_glib.c b/libnm-glib/libnm_glib.c
index 1d755786..a2a6d26e 100644
--- a/libnm-glib/libnm_glib.c
+++ b/libnm-glib/libnm_glib.c
@@ -456,8 +456,7 @@ _libnm_glib_ctx_free (libnm_glib_ctx *ctx)
 	if (ctx->callbacks_lock)
 		g_mutex_free (ctx->callbacks_lock);
 
-	g_slist_foreach (ctx->callbacks, (GFunc)g_free, NULL);
-	g_slist_free (ctx->callbacks);
+	g_slist_free_full (ctx->callbacks, g_free);
 
 	if (ctx->thread)
 		g_thread_join (ctx->thread);
@@ -494,7 +493,10 @@ libnm_glib_init (void)
 {
 	libnm_glib_ctx	*ctx = NULL;
 
+#if !GLIB_CHECK_VERSION (2, 35, 0)
 	g_type_init ();
+#endif
+
 	if (!g_thread_supported ())
 		g_thread_init (NULL);
 	dbus_g_thread_init ();
diff --git a/libnm-glib/nm-access-point.c b/libnm-glib/nm-access-point.c
index d13a7d3c..ca3f1bf2 100644
--- a/libnm-glib/nm-access-point.c
+++ b/libnm-glib/nm-access-point.c
@@ -72,16 +72,6 @@ enum {
 	LAST_PROP
 };
 
-#define DBUS_PROP_FLAGS "Flags"
-#define DBUS_PROP_WPA_FLAGS "WpaFlags"
-#define DBUS_PROP_RSN_FLAGS "RsnFlags"
-#define DBUS_PROP_SSID "Ssid"
-#define DBUS_PROP_FREQUENCY "Frequency"
-#define DBUS_PROP_HW_ADDRESS "HwAddress"
-#define DBUS_PROP_MODE "Mode"
-#define DBUS_PROP_MAX_BITRATE "MaxBitrate"
-#define DBUS_PROP_STRENGTH "Strength"
-
 /**
  * nm_access_point_new:
  * @connection: the #DBusGConnection
@@ -194,7 +184,7 @@ nm_access_point_get_frequency (NMAccessPoint *ap)
  * nm_access_point_get_bssid:
  * @ap: a #NMAccessPoint
  *
- * Gets the Basic Service Set ID (BSSID) of the WiFi access point.
+ * Gets the Basic Service Set ID (BSSID) of the Wi-Fi access point.
  *
  * Returns: the BSSID of the access point. This is an internal string and must
  * not be modified or freed.
@@ -246,9 +236,9 @@ nm_access_point_get_mode (NMAccessPoint *ap)
  * nm_access_point_get_max_bitrate:
  * @ap: a #NMAccessPoint
  *
- * Gets the maximum bit rate of the access point.
+ * Gets the maximum bit rate of the access point in kbit/s.
  *
- * Returns: the maximum bit rate
+ * Returns: the maximum bit rate (kbit/s)
  **/
 guint32
 nm_access_point_get_max_bitrate (NMAccessPoint *ap)
@@ -281,12 +271,12 @@ nm_access_point_get_strength (NMAccessPoint *ap)
  * @ap: an #NMAccessPoint to validate @connection against
  * @connection: an #NMConnection to validate against @ap
  *
- * Validates a given connection against a given WiFi access point to ensure that
+ * Validates a given connection against a given Wi-Fi access point to ensure that
  * the connection may be activated with that AP.  The connection must match the
  * @ap's SSID, (if given) BSSID, and other attributes like security settings,
  * channel, band, etc.
  *
- * Returns: %TRUE if the connection may be activated with this WiFi AP,
+ * Returns: %TRUE if the connection may be activated with this Wi-Fi AP,
  * %FALSE if it cannot be.
  **/
 gboolean
@@ -539,12 +529,7 @@ constructed (GObject *object)
 	G_OBJECT_CLASS (nm_access_point_parent_class)->constructed (object);
 
 	priv = NM_ACCESS_POINT_GET_PRIVATE (object);
-
-	priv->proxy = dbus_g_proxy_new_for_name (nm_object_get_connection (NM_OBJECT (object)),
-									    NM_DBUS_SERVICE,
-									    nm_object_get_path (NM_OBJECT (object)),
-									    NM_DBUS_INTERFACE_ACCESS_POINT);
-
+	priv->proxy = _nm_object_new_proxy (NM_OBJECT (object), NULL, NM_DBUS_INTERFACE_ACCESS_POINT);
 	register_properties (NM_ACCESS_POINT (object));
 }
 
@@ -675,7 +660,7 @@ nm_access_point_class_init (NMAccessPointClass *ap_class)
 	/**
 	 * NMAccessPoint:max-bitrate:
 	 *
-	 * The maximum bit rate of the access point.
+	 * The maximum bit rate of the access point in kbit/s.
 	 **/
 	g_object_class_install_property
 		(object_class, PROP_MAX_BITRATE,
diff --git a/libnm-glib/nm-access-point.h b/libnm-glib/nm-access-point.h
index 76275f00..4862e6b7 100644
--- a/libnm-glib/nm-access-point.h
+++ b/libnm-glib/nm-access-point.h
@@ -90,6 +90,7 @@ gboolean               nm_access_point_connection_valid   (NMAccessPoint *ap,
                                                            NMConnection *connection);
 
 /* DEPRECATED */
+NM_DEPRECATED_IN_0_9_10
 const char *           nm_access_point_get_hw_address   (NMAccessPoint *ap);
 
 G_END_DECLS
diff --git a/libnm-glib/nm-active-connection.c b/libnm-glib/nm-active-connection.c
index f170121b..bca21b4d 100644
--- a/libnm-glib/nm-active-connection.c
+++ b/libnm-glib/nm-active-connection.c
@@ -17,7 +17,7 @@
  * Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
  * Boston, MA 02110-1301 USA.
  *
- * Copyright (C) 2007 - 2011 Red Hat, Inc.
+ * Copyright (C) 2007 - 2014 Red Hat, Inc.
  * Copyright (C) 2008 Novell, Inc.
  */
 
@@ -32,6 +32,7 @@
 #include "nm-connection.h"
 #include "nm-vpn-connection.h"
 #include "nm-glib-compat.h"
+#include "nm-dbus-helpers-private.h"
 
 static GType _nm_active_connection_type_for_path (DBusGConnection *connection,
                                                   const char *path);
@@ -52,38 +53,43 @@ typedef struct {
 	DBusGProxy *proxy;
 
 	char *connection;
+	char *id;
 	char *uuid;
+	char *type;
 	char *specific_object;
 	GPtrArray *devices;
 	NMActiveConnectionState state;
 	gboolean is_default;
+	NMIP4Config *ip4_config;
+	NMDHCP4Config *dhcp4_config;
 	gboolean is_default6;
+	NMIP6Config *ip6_config;
+	NMDHCP6Config *dhcp6_config;
+	gboolean is_vpn;
 	char *master;
 } NMActiveConnectionPrivate;
 
 enum {
 	PROP_0,
 	PROP_CONNECTION,
+	PROP_ID,
 	PROP_UUID,
+	PROP_TYPE,
 	PROP_SPECIFIC_OBJECT,
 	PROP_DEVICES,
 	PROP_STATE,
 	PROP_DEFAULT,
+	PROP_IP4_CONFIG,
+	PROP_DHCP4_CONFIG,
 	PROP_DEFAULT6,
+	PROP_IP6_CONFIG,
+	PROP_DHCP6_CONFIG,
+	PROP_VPN,
 	PROP_MASTER,
 
 	LAST_PROP
 };
 
-#define DBUS_PROP_CONNECTION "Connection"
-#define DBUS_PROP_UUID "Uuid"
-#define DBUS_PROP_SPECIFIC_OBJECT "SpecificObject"
-#define DBUS_PROP_DEVICES "Devices"
-#define DBUS_PROP_STATE "State"
-#define DBUS_PROP_DEFAULT "Default"
-#define DBUS_PROP_DEFAULT6 "Default6"
-#define DBUS_PROP_MASTER "Master"
-
 /**
  * nm_active_connection_new:
  * @connection: the #DBusGConnection
@@ -111,13 +117,10 @@ _nm_active_connection_type_for_path (DBusGConnection *connection,
 {
 	DBusGProxy *proxy;
 	GError *error = NULL;
-	GValue value = {0,};
+	GValue value = G_VALUE_INIT;
 	GType type;
 
-	proxy = dbus_g_proxy_new_for_name (connection,
-	                                   NM_DBUS_SERVICE,
-	                                   path,
-	                                   "org.freedesktop.DBus.Properties");
+	proxy = _nm_dbus_new_proxy_for_connection (connection, path, "org.freedesktop.DBus.Properties");
 	if (!proxy) {
 		g_warning ("%s: couldn't create D-Bus object proxy.", __func__);
 		return G_TYPE_INVALID;
@@ -194,8 +197,7 @@ _nm_active_connection_type_for_path_async (DBusGConnection *connection,
 	async_data->callback = callback;
 	async_data->user_data = user_data;
 
-	proxy = dbus_g_proxy_new_for_name (connection, NM_DBUS_SERVICE, path,
-	                                   "org.freedesktop.DBus.Properties");
+	proxy = _nm_dbus_new_proxy_for_connection (connection, path, "org.freedesktop.DBus.Properties");
 	dbus_g_proxy_begin_call (proxy, "Get",
 	                         async_got_type, async_data, NULL,
 	                         G_TYPE_STRING, NM_DBUS_INTERFACE_ACTIVE_CONNECTION,
@@ -207,10 +209,13 @@ _nm_active_connection_type_for_path_async (DBusGConnection *connection,
  * nm_active_connection_get_connection:
  * @connection: a #NMActiveConnection
  *
- * Gets the #NMConnection<!-- -->'s DBus object path.
+ * Gets the #NMConnection's DBus object path.  This is often used with
+ * nm_remote_settings_get_connection_by_path() to retrieve the
+ * #NMRemoteConnection object that describes the connection.
  *
- * Returns: the object path of the #NMConnection inside of #NMActiveConnection.
- * This is the internal string used by the connection, and must not be modified.
+ * Returns: the object path of the #NMConnection which this #NMActiveConnection
+ * is an active instance of.  This is the internal string used by the
+ * connection, and must not be modified.
  **/
 const char *
 nm_active_connection_get_connection (NMActiveConnection *connection)
@@ -222,10 +227,30 @@ nm_active_connection_get_connection (NMActiveConnection *connection)
 }
 
 /**
+ * nm_active_connection_get_id:
+ * @connection: a #NMActiveConnection
+ *
+ * Gets the #NMConnection's ID.
+ *
+ * Returns: the ID of the #NMConnection that backs the #NMActiveConnection.
+ * This is the internal string used by the connection, and must not be modified.
+ *
+ * Since: 0.9.10
+ **/
+const char *
+nm_active_connection_get_id (NMActiveConnection *connection)
+{
+	g_return_val_if_fail (NM_IS_ACTIVE_CONNECTION (connection), NULL);
+
+	_nm_object_ensure_inited (NM_OBJECT (connection));
+	return NM_ACTIVE_CONNECTION_GET_PRIVATE (connection)->id;
+}
+
+/**
  * nm_active_connection_get_uuid:
  * @connection: a #NMActiveConnection
  *
- * Gets the #NMConnection<!-- -->'s UUID.
+ * Gets the #NMConnection's UUID.
  *
  * Returns: the UUID of the #NMConnection that backs the #NMActiveConnection.
  * This is the internal string used by the connection, and must not be modified.
@@ -240,6 +265,26 @@ nm_active_connection_get_uuid (NMActiveConnection *connection)
 }
 
 /**
+ * nm_active_connection_get_connection_type:
+ * @connection: a #NMActiveConnection
+ *
+ * Gets the #NMConnection's type.
+ *
+ * Returns: the type of the #NMConnection that backs the #NMActiveConnection.
+ * This is the internal string used by the connection, and must not be modified.
+ *
+ * Since: 0.9.10
+ **/
+const char *
+nm_active_connection_get_connection_type (NMActiveConnection *connection)
+{
+	g_return_val_if_fail (NM_IS_ACTIVE_CONNECTION (connection), NULL);
+
+	_nm_object_ensure_inited (NM_OBJECT (connection));
+	return NM_ACTIVE_CONNECTION_GET_PRIVATE (connection)->type;
+}
+
+/**
  * nm_active_connection_get_specific_object:
  * @connection: a #NMActiveConnection
  *
@@ -261,9 +306,9 @@ nm_active_connection_get_specific_object (NMActiveConnection *connection)
  * nm_active_connection_get_devices:
  * @connection: a #NMActiveConnection
  *
- * Gets the #NMDevice<!-- -->s used for the active connections.
+ * Gets the #NMDevices used for the active connections.
  *
- * Returns: (element-type NMClient.Device): the #GPtrArray containing #NMDevice<!-- -->s.
+ * Returns: (element-type NMClient.Device): the #GPtrArray containing #NMDevices.
  * This is the internal copy used by the connection, and must not be modified.
  **/
 const GPtrArray *
@@ -311,6 +356,49 @@ nm_active_connection_get_default (NMActiveConnection *connection)
 }
 
 /**
+ * nm_active_connection_get_ip4_config:
+ * @connection: an #NMActiveConnection
+ *
+ * Gets the current #NMIP4Config associated with the #NMActiveConnection.
+ *
+ * Returns: (transfer none): the #NMIP4Config, or %NULL if the
+ *   connection is not in the %NM_ACTIVE_CONNECTION_STATE_ACTIVATED
+ *   state.
+ *
+ * Since: 0.9.10
+ **/
+NMIP4Config *
+nm_active_connection_get_ip4_config (NMActiveConnection *connection)
+{
+	g_return_val_if_fail (NM_IS_ACTIVE_CONNECTION (connection), NULL);
+
+	_nm_object_ensure_inited (NM_OBJECT (connection));
+	return NM_ACTIVE_CONNECTION_GET_PRIVATE (connection)->ip4_config;
+}
+
+/**
+ * nm_active_connection_get_dhcp4_config:
+ * @connection: an #NMActiveConnection
+ *
+ * Gets the current #NMDHCP4Config (if any) associated with the
+ * #NMActiveConnection.
+ *
+ * Returns: (transfer none): the #NMDHCP4Config, or %NULL if the
+ *   connection does not use DHCP, or is not in the
+ *   %NM_ACTIVE_CONNECTION_STATE_ACTIVATED state.
+ *
+ * Since: 0.9.10
+ **/
+NMDHCP4Config *
+nm_active_connection_get_dhcp4_config (NMActiveConnection *connection)
+{
+	g_return_val_if_fail (NM_IS_ACTIVE_CONNECTION (connection), NULL);
+
+	_nm_object_ensure_inited (NM_OBJECT (connection));
+	return NM_ACTIVE_CONNECTION_GET_PRIVATE (connection)->dhcp4_config;
+}
+
+/**
  * nm_active_connection_get_default6:
  * @connection: a #NMActiveConnection
  *
@@ -329,6 +417,68 @@ nm_active_connection_get_default6 (NMActiveConnection *connection)
 }
 
 /**
+ * nm_active_connection_get_ip6_config:
+ * @connection: an #NMActiveConnection
+ *
+ * Gets the current #NMIP6Config associated with the #NMActiveConnection.
+ *
+ * Returns: (transfer none): the #NMIP6Config, or %NULL if the
+ *   connection is not in the %NM_ACTIVE_CONNECTION_STATE_ACTIVATED
+ *   state.
+ *
+ * Since: 0.9.10
+ **/
+NMIP6Config *
+nm_active_connection_get_ip6_config (NMActiveConnection *connection)
+{
+	g_return_val_if_fail (NM_IS_ACTIVE_CONNECTION (connection), NULL);
+
+	_nm_object_ensure_inited (NM_OBJECT (connection));
+	return NM_ACTIVE_CONNECTION_GET_PRIVATE (connection)->ip6_config;
+}
+
+/**
+ * nm_active_connection_get_dhcp6_config:
+ * @connection: an #NMActiveConnection
+ *
+ * Gets the current #NMDHCP6Config (if any) associated with the
+ * #NMActiveConnection.
+ *
+ * Returns: (transfer none): the #NMDHCP6Config, or %NULL if the
+ *   connection does not use DHCPv6, or is not in the
+ *   %NM_ACTIVE_CONNECTION_STATE_ACTIVATED state.
+ *
+ * Since: 0.9.10
+ **/
+NMDHCP6Config *
+nm_active_connection_get_dhcp6_config (NMActiveConnection *connection)
+{
+	g_return_val_if_fail (NM_IS_ACTIVE_CONNECTION (connection), NULL);
+
+	_nm_object_ensure_inited (NM_OBJECT (connection));
+	return NM_ACTIVE_CONNECTION_GET_PRIVATE (connection)->dhcp6_config;
+}
+
+/**
+ * nm_active_connection_get_vpn:
+ * @connection: a #NMActiveConnection
+ *
+ * Whether the active connection is a VPN connection.
+ *
+ * Returns: %TRUE if the active connection is a VPN connection
+ *
+ * Since: 0.9.10
+ **/
+gboolean
+nm_active_connection_get_vpn (NMActiveConnection *connection)
+{
+	g_return_val_if_fail (NM_IS_ACTIVE_CONNECTION (connection), FALSE);
+
+	_nm_object_ensure_inited (NM_OBJECT (connection));
+	return NM_ACTIVE_CONNECTION_GET_PRIVATE (connection)->is_vpn;
+}
+
+/**
  * nm_active_connection_get_master:
  * @connection: a #NMActiveConnection
  *
@@ -357,11 +507,16 @@ dispose (GObject *object)
 	NMActiveConnectionPrivate *priv = NM_ACTIVE_CONNECTION_GET_PRIVATE (object);
 
 	if (priv->devices) {
-		g_ptr_array_foreach (priv->devices, (GFunc) g_object_unref, NULL);
+		g_ptr_array_set_free_func (priv->devices, g_object_unref);
 		g_ptr_array_free (priv->devices, TRUE);
 		priv->devices = NULL;
 	}
 
+	g_clear_object (&priv->ip4_config);
+	g_clear_object (&priv->dhcp4_config);
+	g_clear_object (&priv->ip6_config);
+	g_clear_object (&priv->dhcp6_config);
+
 	g_clear_object (&priv->proxy);
 
 	G_OBJECT_CLASS (nm_active_connection_parent_class)->dispose (object);
@@ -373,7 +528,9 @@ finalize (GObject *object)
 	NMActiveConnectionPrivate *priv = NM_ACTIVE_CONNECTION_GET_PRIVATE (object);
 
 	g_free (priv->connection);
+	g_free (priv->id);
 	g_free (priv->uuid);
+	g_free (priv->type);
 	g_free (priv->specific_object);
 	g_free (priv->master);
 
@@ -394,9 +551,15 @@ get_property (GObject *object,
 	case PROP_CONNECTION:
 		g_value_set_string (value, nm_active_connection_get_connection (self));
 		break;
+	case PROP_ID:
+		g_value_set_string (value, nm_active_connection_get_id (self));
+		break;
 	case PROP_UUID:
 		g_value_set_string (value, nm_active_connection_get_uuid (self));
 		break;
+	case PROP_TYPE:
+		g_value_set_string (value, nm_active_connection_get_connection_type (self));
+		break;
 	case PROP_SPECIFIC_OBJECT:
 		g_value_set_boxed (value, nm_active_connection_get_specific_object (self));
 		break;
@@ -409,9 +572,24 @@ get_property (GObject *object,
 	case PROP_DEFAULT:
 		g_value_set_boolean (value, nm_active_connection_get_default (self));
 		break;
+	case PROP_IP4_CONFIG:
+		g_value_set_object (value, nm_active_connection_get_ip4_config (self));
+		break;
+	case PROP_DHCP4_CONFIG:
+		g_value_set_object (value, nm_active_connection_get_dhcp4_config (self));
+		break;
 	case PROP_DEFAULT6:
 		g_value_set_boolean (value, nm_active_connection_get_default6 (self));
 		break;
+	case PROP_IP6_CONFIG:
+		g_value_set_object (value, nm_active_connection_get_ip6_config (self));
+		break;
+	case PROP_DHCP6_CONFIG:
+		g_value_set_object (value, nm_active_connection_get_dhcp6_config (self));
+		break;
+	case PROP_VPN:
+		g_value_set_boolean (value, nm_active_connection_get_vpn (self));
+		break;
 	case PROP_MASTER:
 		g_value_set_string (value, nm_active_connection_get_master (self));
 		break;
@@ -427,17 +605,21 @@ register_properties (NMActiveConnection *connection)
 	NMActiveConnectionPrivate *priv = NM_ACTIVE_CONNECTION_GET_PRIVATE (connection);
 	const NMPropertiesInfo property_info[] = {
 		{ NM_ACTIVE_CONNECTION_CONNECTION,          &priv->connection },
+		{ NM_ACTIVE_CONNECTION_ID,                  &priv->id },
 		{ NM_ACTIVE_CONNECTION_UUID,                &priv->uuid },
+		{ NM_ACTIVE_CONNECTION_TYPE,                &priv->type },
 		{ NM_ACTIVE_CONNECTION_SPECIFIC_OBJECT,     &priv->specific_object },
 		{ NM_ACTIVE_CONNECTION_DEVICES,             &priv->devices, NULL, NM_TYPE_DEVICE },
 		{ NM_ACTIVE_CONNECTION_STATE,               &priv->state },
 		{ NM_ACTIVE_CONNECTION_DEFAULT,             &priv->is_default },
+		{ NM_ACTIVE_CONNECTION_IP4_CONFIG,          &priv->ip4_config, NULL, NM_TYPE_IP4_CONFIG },
+		{ NM_ACTIVE_CONNECTION_DHCP4_CONFIG,        &priv->dhcp4_config, NULL, NM_TYPE_DHCP4_CONFIG },
 		{ NM_ACTIVE_CONNECTION_DEFAULT6,            &priv->is_default6 },
+		{ NM_ACTIVE_CONNECTION_IP6_CONFIG,          &priv->ip6_config, NULL, NM_TYPE_IP6_CONFIG },
+		{ NM_ACTIVE_CONNECTION_DHCP6_CONFIG,        &priv->dhcp6_config, NULL, NM_TYPE_DHCP6_CONFIG },
+		{ NM_ACTIVE_CONNECTION_VPN,                 &priv->is_vpn },
 		{ NM_ACTIVE_CONNECTION_MASTER,              &priv->master },
 
-		/* not tracked after construction time */
-		{ "vpn", NULL },
-
 		{ NULL },
 	};
 
@@ -449,17 +631,11 @@ register_properties (NMActiveConnection *connection)
 static void
 constructed (GObject *object)
 {
-	NMActiveConnectionPrivate *priv;
+	NMActiveConnectionPrivate *priv = NM_ACTIVE_CONNECTION_GET_PRIVATE (object);
 
 	G_OBJECT_CLASS (nm_active_connection_parent_class)->constructed (object);
 
-	priv = NM_ACTIVE_CONNECTION_GET_PRIVATE (object);
-
-	priv->proxy = dbus_g_proxy_new_for_name (nm_object_get_connection (NM_OBJECT (object)),
-									    NM_DBUS_SERVICE,
-									    nm_object_get_path (NM_OBJECT (object)),
-									    NM_DBUS_INTERFACE_ACTIVE_CONNECTION);
-
+	priv->proxy = _nm_object_new_proxy (NM_OBJECT (object), NULL, NM_DBUS_INTERFACE_ACTIVE_CONNECTION);
 	register_properties (NM_ACTIVE_CONNECTION (object));
 }
 
@@ -493,6 +669,21 @@ nm_active_connection_class_init (NMActiveConnectionClass *ap_class)
 						      G_PARAM_READABLE));
 
 	/**
+	 * NMActiveConnection:id:
+	 *
+	 * The active connection's ID
+	 *
+	 * Since: 0.9.10
+	 **/
+	g_object_class_install_property
+		(object_class, PROP_ID,
+		 g_param_spec_string (NM_ACTIVE_CONNECTION_ID,
+						      "ID",
+						      "ID",
+						      NULL,
+						      G_PARAM_READABLE));
+
+	/**
 	 * NMActiveConnection:uuid:
 	 *
 	 * The active connection's UUID
@@ -506,6 +697,21 @@ nm_active_connection_class_init (NMActiveConnectionClass *ap_class)
 						      G_PARAM_READABLE));
 
 	/**
+	 * NMActiveConnection:type:
+	 *
+	 * The active connection's type
+	 *
+	 * Since: 0.9.10
+	 **/
+	g_object_class_install_property
+		(object_class, PROP_TYPE,
+		 g_param_spec_string (NM_ACTIVE_CONNECTION_TYPE,
+						      "Type",
+						      "Type",
+						      NULL,
+						      G_PARAM_READABLE));
+
+	/**
 	 * NMActiveConnection:specific-object:
 	 *
 	 * The specific object's path of the active connection.
@@ -560,6 +766,36 @@ nm_active_connection_class_init (NMActiveConnectionClass *ap_class)
 							   G_PARAM_READABLE));
 
 	/**
+	 * NMActiveConnection:ip4-config:
+	 *
+	 * The #NMIP4Config of the connection.
+	 *
+	 * Since: 0.9.10
+	 **/
+	g_object_class_install_property
+		(object_class, PROP_IP4_CONFIG,
+		 g_param_spec_object (NM_ACTIVE_CONNECTION_IP4_CONFIG,
+		                      "IP4 Config",
+		                      "IP4 Config",
+		                      NM_TYPE_IP4_CONFIG,
+		                      G_PARAM_READABLE));
+
+	/**
+	 * NMActiveConnection:dhcp4-config:
+	 *
+	 * The #NMDHCP4Config of the connection.
+	 *
+	 * Since: 0.9.10
+	 **/
+	g_object_class_install_property
+		(object_class, PROP_DHCP4_CONFIG,
+		 g_param_spec_object (NM_ACTIVE_CONNECTION_DHCP4_CONFIG,
+		                      "DHCP4 Config",
+		                      "DHCP4 Config",
+		                      NM_TYPE_DHCP4_CONFIG,
+		                      G_PARAM_READABLE));
+
+	/**
 	 * NMActiveConnection:default6:
 	 *
 	 * Whether the active connection is the default IPv6 one.
@@ -573,6 +809,51 @@ nm_active_connection_class_init (NMActiveConnectionClass *ap_class)
 							   G_PARAM_READABLE));
 
 	/**
+	 * NMActiveConnection:ip6-config:
+	 *
+	 * The #NMIP6Config of the connection.
+	 *
+	 * Since: 0.9.10
+	 **/
+	g_object_class_install_property
+		(object_class, PROP_IP6_CONFIG,
+		 g_param_spec_object (NM_ACTIVE_CONNECTION_IP6_CONFIG,
+		                      "IP6 Config",
+		                      "IP6 Config",
+		                      NM_TYPE_IP6_CONFIG,
+		                      G_PARAM_READABLE));
+
+	/**
+	 * NMActiveConnection:dhcp6-config:
+	 *
+	 * The #NMDHCP6Config of the connection.
+	 *
+	 * Since: 0.9.10
+	 **/
+	g_object_class_install_property
+		(object_class, PROP_DHCP6_CONFIG,
+		 g_param_spec_object (NM_ACTIVE_CONNECTION_DHCP6_CONFIG,
+		                      "DHCP6 Config",
+		                      "DHCP6 Config",
+		                      NM_TYPE_DHCP6_CONFIG,
+		                      G_PARAM_READABLE));
+
+	/**
+	 * NMActiveConnection:vpn:
+	 *
+	 * Whether the active connection is a VPN connection.
+	 *
+	 * Since: 0.9.10
+	 **/
+	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));
+
+	/**
 	 * NMActiveConnection:master:
 	 *
 	 * The path of the master device if one exists.
diff --git a/libnm-glib/nm-active-connection.h b/libnm-glib/nm-active-connection.h
index c6777f80..b15e8340 100644
--- a/libnm-glib/nm-active-connection.h
+++ b/libnm-glib/nm-active-connection.h
@@ -17,7 +17,7 @@
  * Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
  * Boston, MA 02110-1301 USA.
  *
- * Copyright (C) 2007 - 2011 Red Hat, Inc.
+ * Copyright (C) 2007 - 2014 Red Hat, Inc.
  * Copyright (C) 2008 Novell, Inc.
  */
 
@@ -29,6 +29,10 @@
 #include "nm-object.h"
 #include <nm-connection.h>
 #include <NetworkManager.h>
+#include "nm-ip4-config.h"
+#include "nm-dhcp4-config.h"
+#include "nm-ip6-config.h"
+#include "nm-dhcp6-config.h"
 
 G_BEGIN_DECLS
 
@@ -40,12 +44,19 @@ G_BEGIN_DECLS
 #define NM_ACTIVE_CONNECTION_GET_CLASS(obj)  (G_TYPE_INSTANCE_GET_CLASS ((obj), NM_TYPE_ACTIVE_CONNECTION, NMActiveConnectionClass))
 
 #define NM_ACTIVE_CONNECTION_CONNECTION          "connection"
+#define NM_ACTIVE_CONNECTION_ID                  "id"
 #define NM_ACTIVE_CONNECTION_UUID                "uuid"
+#define NM_ACTIVE_CONNECTION_TYPE                "type"
 #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_IP4_CONFIG          "ip4-config"
+#define NM_ACTIVE_CONNECTION_DHCP4_CONFIG        "dhcp4-config"
 #define NM_ACTIVE_CONNECTION_DEFAULT6            "default6"
+#define NM_ACTIVE_CONNECTION_IP6_CONFIG          "ip6-config"
+#define NM_ACTIVE_CONNECTION_DHCP6_CONFIG        "dhcp6-config"
+#define NM_ACTIVE_CONNECTION_VPN                 "vpn"
 #define NM_ACTIVE_CONNECTION_MASTER              "master"
 
 typedef struct {
@@ -69,13 +80,27 @@ GType nm_active_connection_get_type (void);
 GObject *nm_active_connection_new (DBusGConnection *connection, const char *path);
 
 const char * nm_active_connection_get_connection          (NMActiveConnection *connection);
+NM_AVAILABLE_IN_0_9_10
+const char * nm_active_connection_get_id                  (NMActiveConnection *connection);
 const char * nm_active_connection_get_uuid                (NMActiveConnection *connection);
+NM_AVAILABLE_IN_0_9_10
+const char * nm_active_connection_get_connection_type     (NMActiveConnection *connection);
 const char * nm_active_connection_get_specific_object     (NMActiveConnection *connection);
 const GPtrArray *nm_active_connection_get_devices         (NMActiveConnection *connection);
 NMActiveConnectionState nm_active_connection_get_state    (NMActiveConnection *connection);
-gboolean nm_active_connection_get_default                 (NMActiveConnection *connection);
-gboolean nm_active_connection_get_default6                (NMActiveConnection *connection);
 const char * nm_active_connection_get_master              (NMActiveConnection *connection);
+gboolean       nm_active_connection_get_default           (NMActiveConnection *connection);
+NM_AVAILABLE_IN_0_9_10
+NMIP4Config *  nm_active_connection_get_ip4_config        (NMActiveConnection *connection);
+NM_AVAILABLE_IN_0_9_10
+NMDHCP4Config *nm_active_connection_get_dhcp4_config      (NMActiveConnection *connection);
+gboolean       nm_active_connection_get_default6          (NMActiveConnection *connection);
+NM_AVAILABLE_IN_0_9_10
+NMIP6Config *  nm_active_connection_get_ip6_config        (NMActiveConnection *connection);
+NM_AVAILABLE_IN_0_9_10
+NMDHCP6Config *nm_active_connection_get_dhcp6_config      (NMActiveConnection *connection);
+NM_AVAILABLE_IN_0_9_10
+gboolean       nm_active_connection_get_vpn               (NMActiveConnection *connection);
 
 G_END_DECLS
 
diff --git a/libnm-glib/nm-client.c b/libnm-glib/nm-client.c
index 658a3995..379c7879 100644
--- a/libnm-glib/nm-client.c
+++ b/libnm-glib/nm-client.c
@@ -18,7 +18,7 @@
  * Boston, MA 02110-1301 USA.
  *
  * Copyright (C) 2007 - 2008 Novell, Inc.
- * Copyright (C) 2007 - 2012 Red Hat, Inc.
+ * Copyright (C) 2007 - 2013 Red Hat, Inc.
  */
 
 #include <dbus/dbus-glib.h>
@@ -29,7 +29,6 @@
 #include "nm-device-ethernet.h"
 #include "nm-device-wifi.h"
 #include "nm-device-private.h"
-#include "nm-glib-marshal.h"
 #include "nm-types-private.h"
 #include "nm-object-private.h"
 #include "nm-active-connection.h"
@@ -58,6 +57,7 @@ typedef struct {
 	gboolean manager_running;
 	char *version;
 	NMState state;
+	gboolean startup;
 	GPtrArray *devices;
 	GPtrArray *active_connections;
 	NMConnectivityState connectivity;
@@ -87,6 +87,7 @@ enum {
 	PROP_0,
 	PROP_VERSION,
 	PROP_STATE,
+	PROP_STARTUP,
 	PROP_MANAGER_RUNNING,
 	PROP_NETWORKING_ENABLED,
 	PROP_WIRELESS_ENABLED,
@@ -99,6 +100,7 @@ enum {
 	PROP_CONNECTIVITY,
 	PROP_PRIMARY_CONNECTION,
 	PROP_ACTIVATING_CONNECTION,
+	PROP_DEVICES,
 
 	LAST_PROP
 };
@@ -119,8 +121,28 @@ static void proxy_name_owner_changed (DBusGProxy *proxy,
 									  const char *new_owner,
 									  gpointer user_data);
 
-static void client_device_added (NMObject *client, NMObject *device);
-static void client_device_removed (NMObject *client, NMObject *device);
+/**********************************************************************/
+
+/**
+ * nm_client_error_quark:
+ *
+ * Registers an error quark for #NMClient if necessary.
+ *
+ * Returns: the error quark used for #NMClient errors.
+ *
+ * Since: 0.9.10
+ **/
+GQuark
+nm_client_error_quark (void)
+{
+	static GQuark quark;
+
+	if (G_UNLIKELY (!quark))
+		quark = g_quark_from_static_string ("nm-client-error-quark");
+	return quark;
+}
+
+/**********************************************************************/
 
 static void
 nm_client_init (NMClient *client)
@@ -159,6 +181,7 @@ register_properties (NMClient *client)
 	const NMPropertiesInfo property_info[] = {
 		{ NM_CLIENT_VERSION,                   &priv->version },
 		{ NM_CLIENT_STATE,                     &priv->state },
+		{ NM_CLIENT_STARTUP,                   &priv->startup },
 		{ NM_CLIENT_NETWORKING_ENABLED,        &priv->networking_enabled },
 		{ NM_CLIENT_WIRELESS_ENABLED,          &priv->wireless_enabled },
 		{ NM_CLIENT_WIRELESS_HARDWARE_ENABLED, &priv->wireless_hw_enabled },
@@ -170,20 +193,13 @@ register_properties (NMClient *client)
 		{ NM_CLIENT_CONNECTIVITY,              &priv->connectivity },
 		{ NM_CLIENT_PRIMARY_CONNECTION,        &priv->primary_connection, NULL, NM_TYPE_ACTIVE_CONNECTION },
 		{ NM_CLIENT_ACTIVATING_CONNECTION,     &priv->activating_connection, NULL, NM_TYPE_ACTIVE_CONNECTION },
+		{ NM_CLIENT_DEVICES,                   &priv->devices, NULL, NM_TYPE_DEVICE, "device" },
 		{ NULL },
 	};
 
 	_nm_object_register_properties (NM_OBJECT (client),
 	                                priv->client_proxy,
 	                                property_info);
-
-	_nm_object_register_pseudo_property (NM_OBJECT (client),
-	                                     priv->client_proxy,
-	                                     "Devices",
-	                                     &priv->devices,
-	                                     NM_TYPE_DEVICE,
-	                                     client_device_added,
-	                                     client_device_removed);
 }
 
 #define NM_AUTH_PERMISSION_ENABLE_DISABLE_NETWORK     "org.freedesktop.NetworkManager.enable-disable-network"
@@ -349,7 +365,7 @@ client_recheck_permissions (DBusGProxy *proxy, gpointer user_data)
  * nm_device_ethernet_get_hw_address().
  *
  * Returns: (transfer none) (element-type NMClient.Device): a #GPtrArray
- * containing all the #NMDevice<!-- -->s.  The returned array is owned by the
+ * containing all the #NMDevices.  The returned array is owned by the
  * #NMClient object and should not be modified.
  **/
 const GPtrArray *
@@ -436,12 +452,15 @@ typedef struct {
 	NMClientAddActivateFn add_act_fn;
 	char *active_path;
 	char *new_connection_path;
+	guint idle_id;
 	gpointer user_data;
 } ActivateInfo;
 
 static void
 activate_info_free (ActivateInfo *info)
 {
+	if (info->idle_id)
+		g_source_remove (info->idle_id);
 	g_free (info->active_path);
 	g_free (info->new_connection_path);
 	memset (info, 0, sizeof (*info));
@@ -546,15 +565,32 @@ activate_cb (DBusGProxy *proxy,
 	}
 }
 
+static gboolean
+activate_nm_not_running (gpointer user_data)
+{
+	ActivateInfo *info = user_data;
+	GError *error;
+
+	info->idle_id = 0;
+
+	error = g_error_new_literal (NM_CLIENT_ERROR,
+	                             NM_CLIENT_ERROR_MANAGER_NOT_RUNNING,
+	                             "NetworkManager is not running");
+	activate_info_complete (info, NULL, error);
+	activate_info_free (info);
+	g_clear_error (&error);
+	return FALSE;
+}
+
 /**
  * nm_client_activate_connection:
  * @client: a #NMClient
- * @connection: an #NMConnection
+ * @connection: (allow-none): an #NMConnection
  * @device: (allow-none): the #NMDevice
  * @specific_object: (allow-none): the object path of a connection-type-specific
  *   object this activation should use. This parameter is currently ignored for
  *   wired and mobile broadband connections, and the value of %NULL should be used
- *   (ie, no specific object).  For WiFi or WiMAX connections, pass the object
+ *   (ie, no specific object).  For Wi-Fi or WiMAX connections, pass the object
  *   path of a #NMAccessPoint or #NMWimaxNsp owned by @device, which you can
  *   get using nm_object_get_path(), and which will be used to complete the
  *   details of the newly added connection.
@@ -564,10 +600,13 @@ activate_cb (DBusGProxy *proxy,
  * Starts a connection to a particular network using the configuration settings
  * from @connection and the network device @device.  Certain connection types
  * also take a "specific object" which is the object path of a connection-
- * specific object, like an #NMAccessPoint for WiFi connections, or an
+ * specific object, like an #NMAccessPoint for Wi-Fi connections, or an
  * #NMWimaxNsp for WiMAX connections, to which you wish to connect.  If the
  * specific object is not given, NetworkManager can, in some cases, automatically
  * determine which network to connect to given the settings in @connection.
+ *
+ * If @connection is not given for a device-based activation, NetworkManager
+ * picks the best available connection for the device and activates it.
  **/
 void
 nm_client_activate_connection (NMClient *client,
@@ -583,7 +622,8 @@ nm_client_activate_connection (NMClient *client,
 	g_return_if_fail (NM_IS_CLIENT (client));
 	if (device)
 		g_return_if_fail (NM_IS_DEVICE (device));
-	g_return_if_fail (NM_IS_CONNECTION (connection));
+	if (connection)
+		g_return_if_fail (NM_IS_CONNECTION (connection));
 
 	info = g_slice_new0 (ActivateInfo);
 	info->act_fn = callback;
@@ -593,9 +633,14 @@ nm_client_activate_connection (NMClient *client,
 	priv = NM_CLIENT_GET_PRIVATE (client);
 	priv->pending_activations = g_slist_prepend (priv->pending_activations, info);
 
+	if (priv->manager_running == FALSE) {
+		info->idle_id = g_idle_add (activate_nm_not_running, info);
+		return;
+	}
+
 	dbus_g_proxy_begin_call (priv->client_proxy, "ActivateConnection",
 	                         activate_cb, info, NULL,
-	                         DBUS_TYPE_G_OBJECT_PATH, nm_connection_get_path (connection),
+	                         DBUS_TYPE_G_OBJECT_PATH, connection ? nm_connection_get_path (connection) : "/",
 	                         DBUS_TYPE_G_OBJECT_PATH, device ? nm_object_get_path (NM_OBJECT (device)) : "/",
 	                         DBUS_TYPE_G_OBJECT_PATH, specific_object ? specific_object : "/",
 	                         G_TYPE_INVALID);
@@ -635,7 +680,7 @@ add_activate_cb (DBusGProxy *proxy,
  * @specific_object: (allow-none): the object path of a connection-type-specific
  *   object this activation should use. This parameter is currently ignored for
  *   wired and mobile broadband connections, and the value of %NULL should be used
- *   (ie, no specific object).  For WiFi or WiMAX connections, pass the object
+ *   (ie, no specific object).  For Wi-Fi or WiMAX connections, pass the object
  *   path of a #NMAccessPoint or #NMWimaxNsp owned by @device, which you can
  *   get using nm_object_get_path(), and which will be used to complete the
  *   details of the newly added connection.
@@ -675,12 +720,16 @@ nm_client_add_and_activate_connection (NMClient *client,
 	priv = NM_CLIENT_GET_PRIVATE (client);
 	priv->pending_activations = g_slist_prepend (priv->pending_activations, info);
 
-	dbus_g_proxy_begin_call (priv->client_proxy, "AddAndActivateConnection",
-	                         add_activate_cb, info, NULL,
-	                         DBUS_TYPE_G_MAP_OF_MAP_OF_VARIANT, hash,
-	                         DBUS_TYPE_G_OBJECT_PATH, nm_object_get_path (NM_OBJECT (device)),
-	                         DBUS_TYPE_G_OBJECT_PATH, specific_object ? specific_object : "/",
-	                         G_TYPE_INVALID);
+	if (priv->manager_running) {
+		dbus_g_proxy_begin_call (priv->client_proxy, "AddAndActivateConnection",
+		                         add_activate_cb, info, NULL,
+		                         DBUS_TYPE_G_MAP_OF_MAP_OF_VARIANT, hash,
+		                         DBUS_TYPE_G_OBJECT_PATH, nm_object_get_path (NM_OBJECT (device)),
+		                         DBUS_TYPE_G_OBJECT_PATH, specific_object ? specific_object : "/",
+		                         G_TYPE_INVALID);
+	} else
+		info->idle_id = g_idle_add (activate_nm_not_running, info);
+
 	g_hash_table_unref (hash);
 }
 
@@ -714,8 +763,10 @@ nm_client_deactivate_connection (NMClient *client, NMActiveConnection *active)
 	g_return_if_fail (NM_IS_CLIENT (client));
 	g_return_if_fail (NM_IS_ACTIVE_CONNECTION (active));
 
-	// FIXME: return errors
 	priv = NM_CLIENT_GET_PRIVATE (client);
+	if (!priv->manager_running)
+		return;
+
 	path = nm_object_get_path (NM_OBJECT (active));
 	if (!dbus_g_proxy_call (priv->client_proxy, "DeactivateConnection", &error,
 	                        DBUS_TYPE_G_OBJECT_PATH, path,
@@ -733,7 +784,7 @@ nm_client_deactivate_connection (NMClient *client, NMActiveConnection *active)
  * Gets the active connections.
  *
  * Returns: (transfer none) (element-type NMClient.ActiveConnection): a #GPtrArray
- *  containing all the active #NMActiveConnection<!-- -->s.
+ *  containing all the active #NMActiveConnections.
  * The returned array is owned by the client and should not be modified.
  **/
 const GPtrArray * 
@@ -779,17 +830,20 @@ nm_client_wireless_get_enabled (NMClient *client)
 void
 nm_client_wireless_set_enabled (NMClient *client, gboolean enabled)
 {
-	GValue value = {0,};
+	GValue value = G_VALUE_INIT;
 
 	g_return_if_fail (NM_IS_CLIENT (client));
 
+	if (!NM_CLIENT_GET_PRIVATE (client)->manager_running)
+		return;
+
 	g_value_init (&value, G_TYPE_BOOLEAN);
 	g_value_set_boolean (&value, enabled);
 
 	_nm_object_set_property (NM_OBJECT (client),
-					    NM_DBUS_INTERFACE,
-					    "WirelessEnabled",
-					    &value);
+	                         NM_DBUS_INTERFACE,
+	                         "WirelessEnabled",
+	                         &value);
 }
 
 /**
@@ -836,10 +890,13 @@ nm_client_wwan_get_enabled (NMClient *client)
 void
 nm_client_wwan_set_enabled (NMClient *client, gboolean enabled)
 {
-	GValue value = {0,};
+	GValue value = G_VALUE_INIT;
 
 	g_return_if_fail (NM_IS_CLIENT (client));
 
+	if (!NM_CLIENT_GET_PRIVATE (client)->manager_running)
+		return;
+
 	g_value_init (&value, G_TYPE_BOOLEAN);
 	g_value_set_boolean (&value, enabled);
 
@@ -893,10 +950,13 @@ nm_client_wimax_get_enabled (NMClient *client)
 void
 nm_client_wimax_set_enabled (NMClient *client, gboolean enabled)
 {
-	GValue value = {0,};
+	GValue value = G_VALUE_INIT;
 
 	g_return_if_fail (NM_IS_CLIENT (client));
 
+	if (!NM_CLIENT_GET_PRIVATE (client)->manager_running)
+		return;
+
 	g_value_init (&value, G_TYPE_BOOLEAN);
 	g_value_set_boolean (&value, enabled);
 
@@ -964,6 +1024,27 @@ nm_client_get_state (NMClient *client)
 }
 
 /**
+ * nm_client_get_startup:
+ * @client: a #NMClient
+ *
+ * Tests whether the daemon is still in the process of activating
+ * connections at startup.
+ *
+ * Returns: whether the daemon is still starting up
+ *
+ * Since: 0.9.10
+ **/
+gboolean
+nm_client_get_startup (NMClient *client)
+{
+	g_return_val_if_fail (NM_IS_CLIENT (client), NM_STATE_UNKNOWN);
+
+	_nm_object_ensure_inited (NM_OBJECT (client));
+
+	return NM_CLIENT_GET_PRIVATE (client)->startup;
+}
+
+/**
  * nm_client_networking_get_enabled:
  * @client: a #NMClient
  *
@@ -996,6 +1077,9 @@ nm_client_networking_set_enabled (NMClient *client, gboolean enable)
 
 	g_return_if_fail (NM_IS_CLIENT (client));
 
+	if (!NM_CLIENT_GET_PRIVATE (client)->manager_running)
+		return;
+
 	if (!dbus_g_proxy_call (NM_CLIENT_GET_PRIVATE (client)->client_proxy, "Enable", &err,
 	                        G_TYPE_BOOLEAN, enable,
 	                        G_TYPE_INVALID,
@@ -1073,28 +1157,30 @@ nm_client_get_permission_result (NMClient *client, NMClientPermission permission
 gboolean
 nm_client_get_logging (NMClient *client, char **level, char **domains, GError **error)
 {
-	GError *err = NULL;
+	NMClientPrivate *priv;
 
 	g_return_val_if_fail (NM_IS_CLIENT (client), FALSE);
 	g_return_val_if_fail (level == NULL || *level == NULL, FALSE);
 	g_return_val_if_fail (domains == NULL || *domains == NULL, FALSE);
 	g_return_val_if_fail (error == NULL || *error == NULL, FALSE);
 
-	if (!level && !domains)
-		return TRUE;
-
-	if (!dbus_g_proxy_call (NM_CLIENT_GET_PRIVATE (client)->client_proxy, "GetLogging", &err,
-	                        G_TYPE_INVALID,
-	                        G_TYPE_STRING, level,
-	                        G_TYPE_STRING, domains,
-	                        G_TYPE_INVALID)) {
-		if (error)
-			*error = g_error_copy (err);
-		g_error_free (err);
+	priv = NM_CLIENT_GET_PRIVATE (client);
+	if (!priv->manager_running) {
+		g_set_error_literal (error,
+		                     NM_CLIENT_ERROR,
+		                     NM_CLIENT_ERROR_MANAGER_NOT_RUNNING,
+		                     "NetworkManager is not running");
 		return FALSE;
 	}
 
-	return TRUE;
+	if (!level && !domains)
+		return TRUE;
+
+	return dbus_g_proxy_call (priv->client_proxy, "GetLogging", error,
+	                          G_TYPE_INVALID,
+	                          G_TYPE_STRING, level,
+	                          G_TYPE_STRING, domains,
+	                          G_TYPE_INVALID);
 }
 
 /**
@@ -1114,26 +1200,28 @@ nm_client_get_logging (NMClient *client, char **level, char **domains, GError **
 gboolean
 nm_client_set_logging (NMClient *client, const char *level, const char *domains, GError **error)
 {
-	GError *err = NULL;
+	NMClientPrivate *priv;
 
 	g_return_val_if_fail (NM_IS_CLIENT (client), FALSE);
 	g_return_val_if_fail (error == NULL || *error == NULL, FALSE);
 
-	if (!level && !domains)
-		return TRUE;
-
-	if (!dbus_g_proxy_call (NM_CLIENT_GET_PRIVATE (client)->client_proxy, "SetLogging", &err,
-	                        G_TYPE_STRING, level ? level : "",
-	                        G_TYPE_STRING, domains ? domains : "",
-	                        G_TYPE_INVALID,
-	                        G_TYPE_INVALID)) {
-		if (error)
-			*error = g_error_copy (err);
-		g_error_free (err);
+	priv = NM_CLIENT_GET_PRIVATE (client);
+	if (!priv->manager_running) {
+		g_set_error_literal (error,
+		                     NM_CLIENT_ERROR,
+		                     NM_CLIENT_ERROR_MANAGER_NOT_RUNNING,
+		                     "NetworkManager is not running");
 		return FALSE;
 	}
 
-	return TRUE;
+	if (!level && !domains)
+		return TRUE;
+
+	return dbus_g_proxy_call (priv->client_proxy, "SetLogging", error,
+	                          G_TYPE_STRING, level ? level : "",
+	                          G_TYPE_STRING, domains ? domains : "",
+	                          G_TYPE_INVALID,
+	                          G_TYPE_INVALID);
 }
 
 /**
@@ -1155,7 +1243,7 @@ nm_client_set_logging (NMClient *client, const char *level, const char *domains,
  * Returns: (transfer none): the appropriate #NMActiveConnection, if
  * any
  *
- * Since: 0.9.8.4
+ * Since: 0.9.8.6
  */
 NMActiveConnection *
 nm_client_get_primary_connection (NMClient *client)
@@ -1177,7 +1265,7 @@ nm_client_get_primary_connection (NMClient *client)
  * Returns: (transfer none): the appropriate #NMActiveConnection, if
  * any.
  *
- * Since: 0.9.8.4
+ * Since: 0.9.8.6
  */
 NMActiveConnection *
 nm_client_get_activating_connection (NMClient *client)
@@ -1278,11 +1366,13 @@ proxy_name_owner_changed (DBusGProxy *proxy,
 	priv->manager_running = new_running;
 	if (!priv->manager_running) {
 		priv->state = NM_STATE_UNKNOWN;
+		priv->startup = FALSE;
 		_nm_object_queue_notify (NM_OBJECT (client), NM_CLIENT_MANAGER_RUNNING);
 		_nm_object_suppress_property_updates (NM_OBJECT (client), TRUE);
 		poke_wireless_devices_with_rf_status (client);
 		free_devices (client, TRUE);
 		free_active_connections (client, TRUE);
+		update_permissions (client, NULL);
 		priv->wireless_enabled = FALSE;
 		priv->wireless_hw_enabled = FALSE;
 		priv->wwan_enabled = FALSE;
@@ -1299,21 +1389,10 @@ proxy_name_owner_changed (DBusGProxy *proxy,
 	} else {
 		_nm_object_suppress_property_updates (NM_OBJECT (client), FALSE);
 		_nm_object_reload_properties_async (NM_OBJECT (client), updated_properties, client);
+		client_recheck_permissions (priv->client_proxy, client);
 	}
 }
 
-static void
-client_device_added (NMObject *client, NMObject *device)
-{
-	g_signal_emit (client, signals[DEVICE_ADDED], 0, device);
-}
-
-static void
-client_device_removed (NMObject *client, NMObject *device)
-{
-	g_signal_emit (client, signals[DEVICE_REMOVED], 0, device);
-}
-
 /**
  * nm_client_get_connectivity:
  * @client: an #NMClient
@@ -1324,7 +1403,7 @@ client_device_removed (NMObject *client, NMObject *device)
  * connectivity state first before returning any information.
  *
  * Returns: the current connectivity state
- * Since: 0.9.8.4
+ * Since: 0.9.8.6
  */
 NMConnectivityState
 nm_client_get_connectivity (NMClient *client)
@@ -1353,7 +1432,7 @@ nm_client_get_connectivity (NMClient *client)
  * if you do not want to block.
  *
  * Returns: the (new) current connectivity state
- * Since: 0.9.8.4
+ * Since: 0.9.8.6
  */
 NMConnectivityState
 nm_client_check_connectivity (NMClient *client,
@@ -1404,11 +1483,9 @@ check_connectivity_cb (DBusGProxy *proxy,
 	CheckConnectivityData *ccd = g_simple_async_result_get_op_res_gpointer (simple);
 	GError *error = NULL;
 
-	if (g_cancellable_set_error_if_cancelled (ccd->cancellable, &error))
-		g_simple_async_result_take_error (simple, error);
-	else if (!dbus_g_proxy_end_call (proxy, call, &error,
-	                                 G_TYPE_UINT, &ccd->connectivity,
-	                                 G_TYPE_INVALID))
+	if (!dbus_g_proxy_end_call (proxy, call, &error,
+	                            G_TYPE_UINT, &ccd->connectivity,
+	                            G_TYPE_INVALID))
 		g_simple_async_result_take_error (simple, error);
 
 	g_simple_async_result_complete (simple);
@@ -1441,7 +1518,7 @@ check_connectivity_cancelled_cb (GCancellable *cancellable,
  * which (immediately) returns the most recent known state without
  * re-checking, and nm_client_check_connectivity(), which blocks.
  *
- * Since: 0.9.8.4
+ * Since: 0.9.8.6
  */
 void
 nm_client_check_connectivity_async (NMClient *client,
@@ -1468,6 +1545,7 @@ nm_client_check_connectivity_async (NMClient *client,
 		ccd->cancelled_id = g_signal_connect (cancellable, "cancelled",
 		                                      G_CALLBACK (check_connectivity_cancelled_cb),
 		                                      simple);
+		g_simple_async_result_set_check_cancellable (simple, cancellable);
 	}
 
 	ccd->call = dbus_g_proxy_begin_call (priv->client_proxy, "CheckConnectivity",
@@ -1485,7 +1563,7 @@ nm_client_check_connectivity_async (NMClient *client,
  * call.
  *
  * Returns: the (new) current connectivity state
- * Since: 0.9.8.4
+ * Since: 0.9.8.6
  */
 NMConnectivityState
 nm_client_check_connectivity_finish (NMClient *client,
@@ -1521,31 +1599,21 @@ nm_client_check_connectivity_finish (NMClient *client,
  * control them.  To access and modify network configuration data, use the
  * #NMRemoteSettings object.
  *
- * Returns: a new #NMClient
+ * Returns: a new #NMClient or NULL on an error
  **/
 NMClient *
 nm_client_new (void)
 {
-	DBusGConnection *connection;
-	GError *err = NULL;
 	NMClient *client;
 
-#ifdef LIBNM_GLIB_TEST
-	connection = dbus_g_bus_get (DBUS_BUS_SESSION, &err);
-#else
-	connection = dbus_g_bus_get (DBUS_BUS_SYSTEM, &err);
-#endif
-	if (!connection) {
-		g_warning ("Couldn't connect to system bus: %s", err->message);
-		g_error_free (err);
-		return NULL;
-	}
+	client = g_object_new (NM_TYPE_CLIENT, NM_OBJECT_DBUS_PATH, NM_DBUS_PATH, NULL);
+
+	/* NMObject's constructor() can fail on a D-Bus connection error. So we can
+	 * get NULL here instead of a valid NMClient object.
+	 */
+	if (client)
+		_nm_object_ensure_inited (NM_OBJECT (client));
 
-	client = g_object_new (NM_TYPE_CLIENT,
-	                       NM_OBJECT_DBUS_CONNECTION, connection,
-	                       NM_OBJECT_DBUS_PATH, NM_DBUS_PATH,
-	                       NULL);
-	_nm_object_ensure_inited (NM_OBJECT (client));
 	return client;
 }
 
@@ -1571,39 +1639,31 @@ client_inited (GObject *source, GAsyncResult *result, gpointer user_data)
  *
  * Creates a new #NMClient and begins asynchronously initializing it.
  * @callback will be called when it is done; use
- * nm_client_new_finish() to get the result.
+ * nm_client_new_finish() to get the result. Note that on an error,
+ * the callback can be invoked with two first parameters as NULL.
  *
  * NOTE: #NMClient provides information about devices and a mechanism to
  * control them.  To access and modify network configuration data, use the
  * #NMRemoteSettings object.
  **/
 void
-nm_client_new_async (GCancellable *cancellable, GAsyncReadyCallback callback,
+nm_client_new_async (GCancellable *cancellable,
+                     GAsyncReadyCallback callback,
                      gpointer user_data)
 {
-	DBusGConnection *connection;
-	GError *err = NULL;
 	NMClient *client;
 	GSimpleAsyncResult *simple;
 
-	simple = g_simple_async_result_new (NULL, callback, user_data, nm_client_new_async);
-
-#ifdef LIBNM_GLIB_TEST
-	connection = dbus_g_bus_get (DBUS_BUS_SESSION, &err);
-#else
-	connection = dbus_g_bus_get (DBUS_BUS_SYSTEM, &err);
-#endif
-	if (!connection) {
-		g_simple_async_result_take_error (simple, err);
-		g_simple_async_result_complete_in_idle (simple);
-		g_object_unref (simple);
+	client = g_object_new (NM_TYPE_CLIENT, NM_OBJECT_DBUS_PATH, NM_DBUS_PATH, NULL);
+	/* When client is NULL, do no continue with initialization and run callback
+	 * directly with result == NULL indicating NMClient creation failure.
+	 */
+	if (!client) {
+		callback (NULL, NULL, user_data);
 		return;
 	}
 
-	client = g_object_new (NM_TYPE_CLIENT,
-	                       NM_OBJECT_DBUS_CONNECTION, connection,
-	                       NM_OBJECT_DBUS_PATH, NM_DBUS_PATH,
-	                       NULL);
+	simple = g_simple_async_result_new (NULL, callback, user_data, nm_client_new_async);
 	g_async_initable_init_async (G_ASYNC_INITABLE (client), G_PRIORITY_DEFAULT,
 	                             cancellable, client_inited, simple);
 }
@@ -1622,6 +1682,16 @@ nm_client_new_finish (GAsyncResult *result, GError **error)
 {
 	GSimpleAsyncResult *simple;
 
+	g_return_val_if_fail (error == NULL || *error == NULL, FALSE);
+
+	if (!result) {
+		g_set_error_literal (error,
+		                     NM_CLIENT_ERROR,
+		                     NM_CLIENT_ERROR_UNKNOWN,
+		                     "NMClient initialization failed (or you passed NULL 'result' by mistake)");
+		return NULL;
+	}
+
 	g_return_val_if_fail (g_simple_async_result_is_valid (result, NULL, nm_client_new_async), NULL);
 
 	simple = G_SIMPLE_ASYNC_RESULT (result);
@@ -1732,20 +1802,18 @@ constructor (GType type,
 static void
 constructed (GObject *object)
 {
-	DBusGConnection *connection;
-	NMClientPrivate *priv;
+	NMClientPrivate *priv = NM_CLIENT_GET_PRIVATE (object);
+	GError *error = NULL;
 
-	nm_utils_init (NULL);
+	if (!nm_utils_init (&error)) {
+		g_warning ("Couldn't initilize nm-utils/crypto system: %d %s",
+		           error->code, error->message);
+		g_clear_error (&error);
+	}
 
 	G_OBJECT_CLASS (nm_client_parent_class)->constructed (object);
 
-	priv = NM_CLIENT_GET_PRIVATE (object);
-	connection = nm_object_get_connection (NM_OBJECT (object));
-
-	priv->client_proxy = dbus_g_proxy_new_for_name (connection,
-										   NM_DBUS_SERVICE,
-										   nm_object_get_path (NM_OBJECT (object)),
-										   NM_DBUS_INTERFACE);
+	priv->client_proxy = _nm_object_new_proxy (NM_OBJECT (object), NULL, NM_DBUS_INTERFACE);
 
 	register_properties (NM_CLIENT (object));
 
@@ -1757,18 +1825,23 @@ constructed (GObject *object)
 	                             object,
 	                             NULL);
 
-	priv->bus_proxy = dbus_g_proxy_new_for_name (connection,
-	                                             DBUS_SERVICE_DBUS,
-	                                             DBUS_PATH_DBUS,
-	                                             DBUS_INTERFACE_DBUS);
-
-	dbus_g_proxy_add_signal (priv->bus_proxy, "NameOwnerChanged",
-						G_TYPE_STRING, G_TYPE_STRING, G_TYPE_STRING,
-						G_TYPE_INVALID);
-	dbus_g_proxy_connect_signal (priv->bus_proxy,
-						    "NameOwnerChanged",
-						    G_CALLBACK (proxy_name_owner_changed),
-						    object, NULL);
+	if (_nm_object_is_connection_private (NM_OBJECT (object)))
+		priv->manager_running = TRUE;
+	else {
+		priv->bus_proxy = dbus_g_proxy_new_for_name (nm_object_get_connection (NM_OBJECT (object)),
+		                                             DBUS_SERVICE_DBUS,
+		                                             DBUS_PATH_DBUS,
+		                                             DBUS_INTERFACE_DBUS);
+		g_assert (priv->bus_proxy);
+
+		dbus_g_proxy_add_signal (priv->bus_proxy, "NameOwnerChanged",
+		                         G_TYPE_STRING, G_TYPE_STRING, G_TYPE_STRING,
+		                         G_TYPE_INVALID);
+		dbus_g_proxy_connect_signal (priv->bus_proxy,
+		                             "NameOwnerChanged",
+		                             G_CALLBACK (proxy_name_owner_changed),
+		                             object, NULL);
+	}
 
 	g_signal_connect (object, "notify::" NM_CLIENT_WIRELESS_ENABLED,
 	                  G_CALLBACK (wireless_enabled_cb), NULL);
@@ -1789,13 +1862,15 @@ init_sync (GInitable *initable, GCancellable *cancellable, GError **error)
 	if (!nm_client_parent_initable_iface->init (initable, cancellable, error))
 		return FALSE;
 
-	if (!dbus_g_proxy_call (priv->bus_proxy,
-	                        "NameHasOwner", error,
-	                        G_TYPE_STRING, NM_DBUS_SERVICE,
-	                        G_TYPE_INVALID,
-	                        G_TYPE_BOOLEAN, &priv->manager_running,
-	                        G_TYPE_INVALID))
-		return FALSE;
+	if (!_nm_object_is_connection_private (NM_OBJECT (client))) {
+		if (!dbus_g_proxy_call (priv->bus_proxy,
+		                        "NameHasOwner", error,
+		                        G_TYPE_STRING, NM_DBUS_SERVICE,
+		                        G_TYPE_INVALID,
+		                        G_TYPE_BOOLEAN, &priv->manager_running,
+		                        G_TYPE_INVALID))
+			return FALSE;
+	}
 
 	if (priv->manager_running && !get_permissions_sync (client, error))
 		return FALSE;
@@ -1852,6 +1927,22 @@ init_async_got_properties (GObject *source, GAsyncResult *result, gpointer user_
 }
 
 static void
+finish_init (NMClientInitData *init_data)
+{
+	NMClientPrivate *priv = NM_CLIENT_GET_PRIVATE (init_data->client);
+
+	nm_client_parent_async_initable_iface->init_async (G_ASYNC_INITABLE (init_data->client),
+	                                                   G_PRIORITY_DEFAULT, NULL, /* FIXME cancellable */
+	                                                   init_async_got_properties, init_data);
+	init_data->properties_pending = TRUE;
+
+	dbus_g_proxy_begin_call (priv->client_proxy, "GetPermissions",
+	                         init_async_got_permissions, init_data, NULL,
+	                         G_TYPE_INVALID);
+	init_data->permissions_pending = TRUE;
+}
+
+static void
 init_async_got_manager_running (DBusGProxy *proxy, DBusGProxyCall *call,
                                 gpointer user_data)
 {
@@ -1872,15 +1963,7 @@ init_async_got_manager_running (DBusGProxy *proxy, DBusGProxyCall *call,
 		return;
 	}
 
-	nm_client_parent_async_initable_iface->init_async (G_ASYNC_INITABLE (init_data->client),
-	                                                   G_PRIORITY_DEFAULT, NULL, /* FIXME cancellable */
-	                                                   init_async_got_properties, init_data);
-	init_data->properties_pending = TRUE;
-
-	dbus_g_proxy_begin_call (priv->client_proxy, "GetPermissions",
-	                         init_async_got_permissions, init_data, NULL,
-	                         G_TYPE_INVALID);
-	init_data->permissions_pending = TRUE;
+	finish_init (init_data);
 }
 
 static void
@@ -1897,12 +1980,16 @@ init_async (GAsyncInitable *initable, int io_priority,
 	                                               user_data, init_async);
 	g_simple_async_result_set_op_res_gboolean (init_data->result, TRUE);
 
-	/* Check if NM is running */
-	dbus_g_proxy_begin_call (priv->bus_proxy, "NameHasOwner",
-	                         init_async_got_manager_running,
-	                         init_data, NULL,
-	                         G_TYPE_STRING, NM_DBUS_SERVICE,
-	                         G_TYPE_INVALID);
+	if (_nm_object_is_connection_private (NM_OBJECT (init_data->client)))
+		finish_init (init_data);
+	else {
+		/* Check if NM is running */
+		dbus_g_proxy_begin_call (priv->bus_proxy, "NameHasOwner",
+			                     init_async_got_manager_running,
+			                     init_data, NULL,
+			                     G_TYPE_STRING, NM_DBUS_SERVICE,
+			                     G_TYPE_INVALID);
+	}
 }
 
 static gboolean
@@ -1935,8 +2022,7 @@ dispose (GObject *object)
 	g_clear_object (&priv->primary_connection);
 	g_clear_object (&priv->activating_connection);
 
-	g_slist_foreach (priv->pending_activations, (GFunc) activate_info_free, NULL);
-	g_slist_free (priv->pending_activations);
+	g_slist_free_full (priv->pending_activations, (GDestroyNotify) activate_info_free);
 	priv->pending_activations = NULL;
 
 	g_hash_table_destroy (priv->permissions);
@@ -2015,6 +2101,9 @@ get_property (GObject *object,
 	case PROP_STATE:
 		g_value_set_uint (value, nm_client_get_state (self));
 		break;
+	case PROP_STARTUP:
+		g_value_set_boolean (value, nm_client_get_startup (self));
+		break;
 	case PROP_MANAGER_RUNNING:
 		g_value_set_boolean (value, priv->manager_running);
 		break;
@@ -2051,6 +2140,9 @@ get_property (GObject *object,
 	case PROP_ACTIVATING_CONNECTION:
 		g_value_set_object (value, priv->activating_connection);
 		break;
+	case PROP_DEVICES:
+		g_value_set_boxed (value, nm_client_get_devices (self));
+		break;
 	default:
 		G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
 		break;
@@ -2100,6 +2192,21 @@ nm_client_class_init (NMClientClass *client_class)
 						    G_PARAM_READABLE));
 
 	/**
+	 * NMClient:startup:
+	 *
+	 * Whether the daemon is still starting up.
+	 *
+	 * Since: 0.9.10
+	 **/
+	g_object_class_install_property
+		(object_class, PROP_STARTUP,
+		 g_param_spec_boolean (NM_CLIENT_STARTUP,
+		                       "Startup",
+		                       "Whether the daemon is still starting up",
+		                       FALSE,
+		                       G_PARAM_READABLE));
+
+	/**
 	 * NMClient::manager-running:
 	 *
 	 * Whether the daemon is running.
@@ -2222,7 +2329,7 @@ nm_client_class_init (NMClientClass *client_class)
 	 *
 	 * The network connectivity state.
 	 *
-	 * Since: 0.9.8.4
+	 * Since: 0.9.8.6
 	 */
 	g_object_class_install_property
 		(object_class, PROP_CONNECTIVITY,
@@ -2238,7 +2345,7 @@ nm_client_class_init (NMClientClass *client_class)
 	 * The #NMActiveConnection of the device with the default route;
 	 * see nm_client_get_primary_connection() for more details.
 	 *
-	 * Since: 0.9.8.4
+	 * Since: 0.9.8.6
 	 **/
 	g_object_class_install_property
 		(object_class, PROP_PRIMARY_CONNECTION,
@@ -2254,7 +2361,7 @@ nm_client_class_init (NMClientClass *client_class)
 	 * The #NMActiveConnection of the activating connection that is
 	 * likely to become the new #NMClient:primary-connection.
 	 *
-	 * Since: 0.9.8.4
+	 * Since: 0.9.8.6
 	 **/
 	g_object_class_install_property
 		(object_class, PROP_ACTIVATING_CONNECTION,
@@ -2264,6 +2371,21 @@ nm_client_class_init (NMClientClass *client_class)
 		                      NM_TYPE_ACTIVE_CONNECTION,
 		                      G_PARAM_READABLE));
 
+	/**
+	 * NMClient:devices:
+	 *
+	 * List of known network devices.
+	 *
+	 * Since: 0.9.10
+	 **/
+	g_object_class_install_property
+		(object_class, PROP_DEVICES,
+		 g_param_spec_boxed (NM_CLIENT_DEVICES,
+		                     "Devices",
+		                     "Devices",
+		                     NM_TYPE_OBJECT_ARRAY,
+		                     G_PARAM_READABLE));
+
 	/* signals */
 
 	/**
@@ -2278,8 +2400,7 @@ nm_client_class_init (NMClientClass *client_class)
 					  G_OBJECT_CLASS_TYPE (object_class),
 					  G_SIGNAL_RUN_FIRST,
 					  G_STRUCT_OFFSET (NMClientClass, device_added),
-					  NULL, NULL,
-					  g_cclosure_marshal_VOID__OBJECT,
+					  NULL, NULL, NULL,
 					  G_TYPE_NONE, 1,
 					  G_TYPE_OBJECT);
 
@@ -2295,8 +2416,7 @@ nm_client_class_init (NMClientClass *client_class)
 		              G_OBJECT_CLASS_TYPE (object_class),
 		              G_SIGNAL_RUN_FIRST,
 		              G_STRUCT_OFFSET (NMClientClass, device_removed),
-		              NULL, NULL,
-		              g_cclosure_marshal_VOID__OBJECT,
+		              NULL, NULL, NULL,
 		              G_TYPE_NONE, 1,
 		              G_TYPE_OBJECT);
 
@@ -2312,8 +2432,7 @@ nm_client_class_init (NMClientClass *client_class)
 		g_signal_new ("permission-changed",
 		              G_OBJECT_CLASS_TYPE (object_class),
 		              G_SIGNAL_RUN_FIRST,
-		              0, NULL, NULL,
-		              _nm_glib_marshal_VOID__UINT_UINT,
+		              0, NULL, NULL, NULL,
 		              G_TYPE_NONE, 2, G_TYPE_UINT, G_TYPE_UINT);
 }
 
diff --git a/libnm-glib/nm-client.h b/libnm-glib/nm-client.h
index b4da609f..1baabecc 100644
--- a/libnm-glib/nm-client.h
+++ b/libnm-glib/nm-client.h
@@ -45,6 +45,7 @@ G_BEGIN_DECLS
 
 #define NM_CLIENT_VERSION "version"
 #define NM_CLIENT_STATE "state"
+#define NM_CLIENT_STARTUP "startup"
 #define NM_CLIENT_MANAGER_RUNNING "manager-running"
 #define NM_CLIENT_NETWORKING_ENABLED "networking-enabled"
 #define NM_CLIENT_WIRELESS_ENABLED "wireless-enabled"
@@ -57,13 +58,14 @@ G_BEGIN_DECLS
 #define NM_CLIENT_CONNECTIVITY "connectivity"
 #define NM_CLIENT_PRIMARY_CONNECTION "primary-connection"
 #define NM_CLIENT_ACTIVATING_CONNECTION "activating-connection"
+#define NM_CLIENT_DEVICES "devices"
 
 /**
  * NMClientPermission:
  * @NM_CLIENT_PERMISSION_NONE: unknown or no permission
  * @NM_CLIENT_PERMISSION_ENABLE_DISABLE_NETWORK: controls whether networking
  *  can be globally enabled or disabled
- * @NM_CLIENT_PERMISSION_ENABLE_DISABLE_WIFI: controls whether WiFi can be
+ * @NM_CLIENT_PERMISSION_ENABLE_DISABLE_WIFI: controls whether Wi-Fi can be
  *  globally enabled or disabled
  * @NM_CLIENT_PERMISSION_ENABLE_DISABLE_WWAN: controls whether WWAN (3G) can be
  *  globally enabled or disabled
@@ -74,8 +76,8 @@ G_BEGIN_DECLS
  * @NM_CLIENT_PERMISSION_NETWORK_CONTROL: controls whether networking connections
  *  can be started, stopped, and changed
  * @NM_CLIENT_PERMISSION_WIFI_SHARE_PROTECTED: controls whether a password
- *  protected WiFi hotspot can be created
- * @NM_CLIENT_PERMISSION_WIFI_SHARE_OPEN: controls whether an open WiFi hotspot
+ *  protected Wi-Fi hotspot can be created
+ * @NM_CLIENT_PERMISSION_WIFI_SHARE_OPEN: controls whether an open Wi-Fi hotspot
  *  can be created
  * @NM_CLIENT_PERMISSION_SETTINGS_MODIFY_SYSTEM: controls whether connections
  *  that are available to all users can be modified
@@ -124,6 +126,22 @@ typedef enum {
 	NM_CLIENT_PERMISSION_RESULT_NO
 } NMClientPermissionResult;
 
+/**
+ * NMClientError:
+ * @NM_CLIENT_ERROR_UNKNOWN: unknown or unclassified error
+ * @NM_CLIENT_ERROR_MANAGER_NOT_RUNNING: an operation that requires NetworkManager
+ *   failed because NetworkManager is not running
+ *
+ * Describes errors that may result from operations involving a #NMClient.
+ **/
+typedef enum {
+	NM_CLIENT_ERROR_UNKNOWN = 0,            /*< nick=UnknownError >*/
+	NM_CLIENT_ERROR_MANAGER_NOT_RUNNING,    /*< nick=ManagerNotRunning >*/
+} NMClientError;
+
+#define NM_CLIENT_ERROR nm_client_error_quark ()
+NM_AVAILABLE_IN_0_9_10
+GQuark nm_client_error_quark (void);
 
 typedef struct {
 	NMObject parent;
@@ -206,6 +224,8 @@ gboolean  nm_client_wimax_hardware_get_enabled (NMClient *client);
 
 const char *nm_client_get_version        (NMClient *client);
 NMState   nm_client_get_state            (NMClient *client);
+NM_AVAILABLE_IN_0_9_10
+gboolean  nm_client_get_startup          (NMClient *client);
 gboolean  nm_client_get_manager_running  (NMClient *client);
 const GPtrArray *nm_client_get_active_connections (NMClient *client);
 void      nm_client_sleep                (NMClient *client, gboolean sleep_);
diff --git a/libnm-glib/nm-dbus-helpers-private.h b/libnm-glib/nm-dbus-helpers-private.h
new file mode 100644
index 00000000..81c77203
--- /dev/null
+++ b/libnm-glib/nm-dbus-helpers-private.h
@@ -0,0 +1,38 @@
+/* -*- Mode: C; tab-width: 4; indent-tabs-mode: t; c-basic-offset: 4 -*- */
+/*
+ * libnm_glib -- Access network status & information from glib applications
+ *
+ * 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., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301 USA.
+ *
+ * Copyright (C) 2013 Red Hat, Inc.
+ */
+
+#ifndef NM_DBUS_HELPERS_PRIVATE_H
+#define NM_DBUS_HELPERS_PRIVATE_H
+
+#include <gio/gio.h>
+#include <dbus/dbus.h>
+#include <dbus/dbus-glib-lowlevel.h>
+
+DBusGConnection *_nm_dbus_new_connection (GError **error);
+
+gboolean         _nm_dbus_is_connection_private (DBusGConnection *connection);
+
+DBusGProxy *     _nm_dbus_new_proxy_for_connection (DBusGConnection *connection,
+                                                    const char *path,
+                                                    const char *interface);
+
+#endif /* NM_DBUS_HELPERS_PRIVATE_H */
diff --git a/libnm-glib/nm-dbus-helpers.c b/libnm-glib/nm-dbus-helpers.c
new file mode 100644
index 00000000..731ad0c8
--- /dev/null
+++ b/libnm-glib/nm-dbus-helpers.c
@@ -0,0 +1,107 @@
+/* -*- Mode: C; tab-width: 4; indent-tabs-mode: t; c-basic-offset: 4 -*- */
+/*
+ * libnm_glib -- Access network status & information from glib applications
+ *
+ * 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., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301 USA.
+ *
+ * Copyright (C) 2013 Red Hat, Inc.
+ */
+
+#include <string.h>
+#include <config.h>
+#include <gio/gio.h>
+#include <dbus/dbus.h>
+#include <dbus/dbus-glib-lowlevel.h>
+#include "nm-dbus-helpers-private.h"
+#include "NetworkManager.h"
+
+static dbus_int32_t priv_slot = -1;
+
+static gboolean
+_ensure_dbus_data_slot (void)
+{
+	static gsize init_value = 0;
+	gboolean success = TRUE;
+
+	if (g_once_init_enter (&init_value)) {
+		success = dbus_connection_allocate_data_slot (&priv_slot);
+		g_once_init_leave (&init_value, 1);
+	}
+	return success;
+}
+
+DBusGConnection *
+_nm_dbus_new_connection (GError **error)
+{
+	DBusGConnection *connection = NULL;
+
+	if (!_ensure_dbus_data_slot ()) {
+		g_set_error (error, DBUS_GERROR, DBUS_GERROR_FAILED, "failed to allocated data slot");
+		return NULL;
+	}
+
+#if HAVE_DBUS_GLIB_100
+	/* If running as root try the private bus first */
+	if (0 == geteuid ()) {
+		connection = dbus_g_connection_open ("unix:path=" NMRUNDIR "/private", error);
+		if (connection) {
+			DBusConnection *dbus_connection = dbus_g_connection_get_connection (connection);
+
+			/* Mark this connection as private */
+			dbus_connection_set_data (dbus_connection, priv_slot, GUINT_TO_POINTER (TRUE), NULL);
+			dbus_connection_set_exit_on_disconnect (dbus_connection, FALSE);
+			return connection;
+		}
+		/* Fall back to a bus if for some reason private socket isn't available */
+		g_clear_error (error);
+	}
+#endif
+
+	if (connection == NULL) {
+#ifdef LIBNM_GLIB_TEST
+		connection = dbus_g_bus_get (DBUS_BUS_SESSION, error);
+#else
+		connection = dbus_g_bus_get (DBUS_BUS_SYSTEM, error);
+#endif
+	}
+
+	return connection;
+}
+
+gboolean
+_nm_dbus_is_connection_private (DBusGConnection *connection)
+{
+	if (!_ensure_dbus_data_slot ())
+		return FALSE;
+	return !!dbus_connection_get_data (dbus_g_connection_get_connection (connection), priv_slot);
+}
+
+DBusGProxy *
+_nm_dbus_new_proxy_for_connection (DBusGConnection *connection,
+                                   const char *path,
+                                   const char *interface)
+{
+	/* Private connections can't use dbus_g_proxy_new_for_name() or
+	 * dbus_g_proxy_new_for_name_owner() because peer-to-peer connections don't
+	 * have either a bus daemon or name owners, both of which those functions
+	 * require.
+	 */
+	if (_nm_dbus_is_connection_private (connection))
+		return dbus_g_proxy_new_for_peer (connection, path, interface);
+
+	return dbus_g_proxy_new_for_name (connection, NM_DBUS_SERVICE, path, interface);
+}
+
diff --git a/libnm-glib/nm-device-adsl.c b/libnm-glib/nm-device-adsl.c
index bef3ceae..b3f9691e 100644
--- a/libnm-glib/nm-device-adsl.c
+++ b/libnm-glib/nm-device-adsl.c
@@ -46,7 +46,6 @@ enum {
 	PROP_CARRIER,
 	LAST_PROP
 };
-#define DBUS_PROP_CARRIER "Carrier"
 
 /**
  * nm_device_adsl_error_quark:
@@ -131,7 +130,13 @@ connection_compatible (NMDevice *device, NMConnection *connection, GError **erro
 		return FALSE;
 	}
 
-	return TRUE;
+	return NM_DEVICE_CLASS (nm_device_adsl_parent_class)->connection_compatible (device, connection, error);
+}
+
+static GType
+get_setting_type (NMDevice *device)
+{
+	return NM_TYPE_SETTING_ADSL;
 }
 
 /******************************************************************/
@@ -159,17 +164,11 @@ register_properties (NMDeviceAdsl *device)
 static void
 constructed (GObject *object)
 {
-	NMDeviceAdslPrivate *priv;
+	NMDeviceAdslPrivate *priv = NM_DEVICE_ADSL_GET_PRIVATE (object);
 
 	G_OBJECT_CLASS (nm_device_adsl_parent_class)->constructed (object);
 
-	priv = NM_DEVICE_ADSL_GET_PRIVATE (object);
-
-	priv->proxy = dbus_g_proxy_new_for_name (nm_object_get_connection (NM_OBJECT (object)),
-	                                         NM_DBUS_SERVICE,
-	                                         nm_object_get_path (NM_OBJECT (object)),
-	                                         NM_DBUS_INTERFACE_DEVICE_ADSL);
-
+	priv->proxy = _nm_object_new_proxy (NM_OBJECT (object), NULL, NM_DBUS_INTERFACE_DEVICE_ADSL);
 	register_properties (NM_DEVICE_ADSL (object));
 }
 
@@ -228,6 +227,7 @@ nm_device_adsl_class_init (NMDeviceAdslClass *adsl_class)
 	object_class->finalize = finalize;
 	object_class->get_property = get_property;
 	device_class->connection_compatible = connection_compatible;
+	device_class->get_setting_type = get_setting_type;
 
 	/* properties */
 	/**
diff --git a/libnm-glib/nm-device-bond.c b/libnm-glib/nm-device-bond.c
index 6261db91..b2af2ec3 100644
--- a/libnm-glib/nm-device-bond.c
+++ b/libnm-glib/nm-device-bond.c
@@ -56,10 +56,6 @@ enum {
 	LAST_PROP
 };
 
-#define DBUS_PROP_HW_ADDRESS "HwAddress"
-#define DBUS_PROP_CARRIER "Carrier"
-#define DBUS_PROP_SLAVES "Slaves"
-
 /**
  * nm_device_bond_error_quark:
  *
@@ -144,7 +140,7 @@ nm_device_bond_get_carrier (NMDeviceBond *device)
  * Gets the devices currently slaved to @device.
  *
  * Returns: (element-type NMClient.Device): the #GPtrArray containing
- * #NMDevice<!-- -->s that are slaves of @device. This is the internal
+ * #NMDevices that are slaves of @device. This is the internal
  * copy used by the device, and must not be modified.
  *
  * Since: 0.9.6.4
@@ -165,8 +161,6 @@ connection_compatible (NMDevice *device, NMConnection *connection, GError **erro
 	NMSettingBond *s_bond;
 	const char *ctype, *dev_iface_name, *bond_iface_name;
 
-	g_return_val_if_fail (error == NULL || *error == NULL, FALSE);
-
 	s_con = nm_connection_get_setting_connection (connection);
 	g_assert (s_con);
 
@@ -194,7 +188,19 @@ connection_compatible (NMDevice *device, NMConnection *connection, GError **erro
 
 	/* FIXME: check slaves? */
 
-	return TRUE;
+	return NM_DEVICE_CLASS (nm_device_bond_parent_class)->connection_compatible (device, connection, error);
+}
+
+static GType
+get_setting_type (NMDevice *device)
+{
+	return NM_TYPE_SETTING_BOND;
+}
+
+static const char *
+get_hw_address (NMDevice *device)
+{
+	return nm_device_bond_get_hw_address (NM_DEVICE_BOND (device));
 }
 
 /***********************************************************/
@@ -224,17 +230,11 @@ register_properties (NMDeviceBond *device)
 static void
 constructed (GObject *object)
 {
-	NMDeviceBondPrivate *priv;
+	NMDeviceBondPrivate *priv = NM_DEVICE_BOND_GET_PRIVATE (object);
 
 	G_OBJECT_CLASS (nm_device_bond_parent_class)->constructed (object);
 
-	priv = NM_DEVICE_BOND_GET_PRIVATE (object);
-
-	priv->proxy = dbus_g_proxy_new_for_name (nm_object_get_connection (NM_OBJECT (object)),
-	                                         NM_DBUS_SERVICE,
-	                                         nm_object_get_path (NM_OBJECT (object)),
-	                                         NM_DBUS_INTERFACE_DEVICE_BOND);
-
+	priv->proxy = _nm_object_new_proxy (NM_OBJECT (object), NULL, NM_DBUS_INTERFACE_DEVICE_BOND);
 	register_properties (NM_DEVICE_BOND (object));
 }
 
@@ -246,7 +246,7 @@ dispose (GObject *object)
 	g_clear_object (&priv->proxy);
 
 	if (priv->slaves) {
-		g_ptr_array_foreach (priv->slaves, (GFunc) g_object_unref, NULL);
+		g_ptr_array_set_free_func (priv->slaves, g_object_unref);
 		g_ptr_array_free (priv->slaves, TRUE);
 		priv->slaves = NULL;
 	}
@@ -304,6 +304,8 @@ nm_device_bond_class_init (NMDeviceBondClass *eth_class)
 	object_class->finalize = finalize;
 	object_class->get_property = get_property;
 	device_class->connection_compatible = connection_compatible;
+	device_class->get_setting_type = get_setting_type;
+	device_class->get_hw_address = get_hw_address;
 
 	/* properties */
 
diff --git a/libnm-glib/nm-device-bridge.c b/libnm-glib/nm-device-bridge.c
index 9327a931..c8967e20 100644
--- a/libnm-glib/nm-device-bridge.c
+++ b/libnm-glib/nm-device-bridge.c
@@ -56,10 +56,6 @@ enum {
 	LAST_PROP
 };
 
-#define DBUS_PROP_HW_ADDRESS "HwAddress"
-#define DBUS_PROP_CARRIER "Carrier"
-#define DBUS_PROP_SLAVES "Slaves"
-
 /**
  * nm_device_bridge_error_quark:
  *
@@ -152,7 +148,7 @@ nm_device_bridge_get_carrier (NMDeviceBridge *device)
  * Gets the devices currently slaved to @device.
  *
  * Returns: (element-type NMClient.Device): the #GPtrArray containing
- * #NMDevice<!-- -->s that are slaves of @device. This is the internal
+ * #NMDevices that are slaves of @device. This is the internal
  * copy used by the device, and must not be modified.
  *
  * Since: 0.9.8
@@ -173,8 +169,6 @@ connection_compatible (NMDevice *device, NMConnection *connection, GError **erro
 	NMSettingBridge *s_bridge;
 	const char *ctype, *dev_iface_name, *bridge_iface_name;
 
-	g_return_val_if_fail (error == NULL || *error == NULL, FALSE);
-
 	s_con = nm_connection_get_setting_connection (connection);
 	g_assert (s_con);
 
@@ -202,7 +196,19 @@ connection_compatible (NMDevice *device, NMConnection *connection, GError **erro
 
 	/* FIXME: check ports? */
 
-	return TRUE;
+	return NM_DEVICE_CLASS (nm_device_bridge_parent_class)->connection_compatible (device, connection, error);
+}
+
+static GType
+get_setting_type (NMDevice *device)
+{
+	return NM_TYPE_SETTING_BRIDGE;
+}
+
+static const char *
+get_hw_address (NMDevice *device)
+{
+	return nm_device_bridge_get_hw_address (NM_DEVICE_BRIDGE (device));
 }
 
 /***********************************************************/
@@ -232,17 +238,11 @@ register_properties (NMDeviceBridge *device)
 static void
 constructed (GObject *object)
 {
-	NMDeviceBridgePrivate *priv;
+	NMDeviceBridgePrivate *priv = NM_DEVICE_BRIDGE_GET_PRIVATE (object);
 
 	G_OBJECT_CLASS (nm_device_bridge_parent_class)->constructed (object);
 
-	priv = NM_DEVICE_BRIDGE_GET_PRIVATE (object);
-
-	priv->proxy = dbus_g_proxy_new_for_name (nm_object_get_connection (NM_OBJECT (object)),
-	                                         NM_DBUS_SERVICE,
-	                                         nm_object_get_path (NM_OBJECT (object)),
-	                                         NM_DBUS_INTERFACE_DEVICE_BRIDGE);
-
+	priv->proxy = _nm_object_new_proxy (NM_OBJECT (object), NULL, NM_DBUS_INTERFACE_DEVICE_BRIDGE);
 	register_properties (NM_DEVICE_BRIDGE (object));
 }
 
@@ -254,7 +254,7 @@ dispose (GObject *object)
 	g_clear_object (&priv->proxy);
 
 	if (priv->slaves) {
-		g_ptr_array_foreach (priv->slaves, (GFunc) g_object_unref, NULL);
+		g_ptr_array_set_free_func (priv->slaves, g_object_unref);
 		g_ptr_array_free (priv->slaves, TRUE);
 		priv->slaves = NULL;
 	}
@@ -312,6 +312,8 @@ nm_device_bridge_class_init (NMDeviceBridgeClass *bridge_class)
 	object_class->finalize = finalize;
 	object_class->get_property = get_property;
 	device_class->connection_compatible = connection_compatible;
+	device_class->get_setting_type = get_setting_type;
+	device_class->get_hw_address = get_hw_address;
 
 	/* properties */
 
diff --git a/libnm-glib/nm-device-bt.c b/libnm-glib/nm-device-bt.c
index ccfa83ca..4c39ad04 100644
--- a/libnm-glib/nm-device-bt.c
+++ b/libnm-glib/nm-device-bt.c
@@ -55,10 +55,6 @@ enum {
 	LAST_PROP
 };
 
-#define DBUS_PROP_HW_ADDRESS      "HwAddress"
-#define DBUS_PROP_NAME            "Name"
-#define DBUS_PROP_BT_CAPABILITIES "BtCapabilities"
-
 /**
  * nm_device_bt_error_quark:
  *
@@ -182,8 +178,6 @@ connection_compatible (NMDevice *device, NMConnection *connection, GError **erro
 	NMBluetoothCapabilities dev_caps;
 	NMBluetoothCapabilities bt_type;
 
-	g_return_val_if_fail (error == NULL || *error == NULL, FALSE);
-
 	s_con = nm_connection_get_setting_connection (connection);
 	g_assert (s_con);
 
@@ -226,7 +220,19 @@ connection_compatible (NMDevice *device, NMConnection *connection, GError **erro
 		return FALSE;
 	}
 
-	return TRUE;
+	return NM_DEVICE_CLASS (nm_device_bt_parent_class)->connection_compatible (device, connection, error);
+}
+
+static GType
+get_setting_type (NMDevice *device)
+{
+	return NM_TYPE_SETTING_BLUETOOTH;
+}
+
+static const char *
+get_hw_address (NMDevice *device)
+{
+	return nm_device_bt_get_hw_address (NM_DEVICE_BT (device));
 }
 
 /************************************************************/
@@ -260,11 +266,7 @@ constructed (GObject *object)
 
 	G_OBJECT_CLASS (nm_device_bt_parent_class)->constructed (object);
 
-	priv->proxy = dbus_g_proxy_new_for_name (nm_object_get_connection (NM_OBJECT (object)),
-	                                         NM_DBUS_SERVICE,
-	                                         nm_object_get_path (NM_OBJECT (object)),
-	                                         NM_DBUS_INTERFACE_DEVICE_BLUETOOTH);
-
+	priv->proxy = _nm_object_new_proxy (NM_OBJECT (object), NULL, NM_DBUS_INTERFACE_DEVICE_BLUETOOTH);
 	register_properties (NM_DEVICE_BT (object));
 }
 
@@ -329,6 +331,8 @@ nm_device_bt_class_init (NMDeviceBtClass *bt_class)
 	object_class->finalize = finalize;
 	object_class->get_property = get_property;
 	device_class->connection_compatible = connection_compatible;
+	device_class->get_setting_type = get_setting_type;
+	device_class->get_hw_address = get_hw_address;
 
 	/* properties */
 
diff --git a/libnm-glib/nm-device-ethernet.c b/libnm-glib/nm-device-ethernet.c
index e9d1b4ad..8f317115 100644
--- a/libnm-glib/nm-device-ethernet.c
+++ b/libnm-glib/nm-device-ethernet.c
@@ -58,11 +58,6 @@ enum {
 	LAST_PROP
 };
 
-#define DBUS_PROP_HW_ADDRESS "HwAddress"
-#define DBUS_PROP_PERM_HW_ADDRESS "PermHwAddress"
-#define DBUS_PROP_SPEED "Speed"
-#define DBUS_PROP_CARRIER "Carrier"
-
 /**
  * nm_device_ethernet_error_quark:
  *
@@ -183,8 +178,6 @@ connection_compatible (NMDevice *device, NMConnection *connection, GError **erro
 	const char *ctype;
 	gboolean is_pppoe = FALSE;
 
-	g_return_val_if_fail (error == NULL || *error == NULL, FALSE);
-
 	s_con = nm_connection_get_setting_connection (connection);
 	g_assert (s_con);
 
@@ -201,7 +194,7 @@ connection_compatible (NMDevice *device, NMConnection *connection, GError **erro
 	/* Wired setting optional for PPPoE */
 	if (!is_pppoe && !s_wired) {
 		g_set_error (error, NM_DEVICE_ETHERNET_ERROR, NM_DEVICE_ETHERNET_ERROR_INVALID_ETHERNET_CONNECTION,
-		             "The connection was not a valid ethernet connection.");
+		             "The connection was not a valid Ethernet connection.");
 		return FALSE;
 	}
 
@@ -230,7 +223,19 @@ connection_compatible (NMDevice *device, NMConnection *connection, GError **erro
 		}
 	}
 
-	return TRUE;
+	return NM_DEVICE_CLASS (nm_device_ethernet_parent_class)->connection_compatible (device, connection, error);
+}
+
+static GType
+get_setting_type (NMDevice *device)
+{
+	return NM_TYPE_SETTING_WIRED;
+}
+
+static const char *
+get_hw_address (NMDevice *device)
+{
+	return nm_device_ethernet_get_hw_address (NM_DEVICE_ETHERNET (device));
 }
 
 /***********************************************************/
@@ -261,17 +266,11 @@ register_properties (NMDeviceEthernet *device)
 static void
 constructed (GObject *object)
 {
-	NMDeviceEthernetPrivate *priv;
+	NMDeviceEthernetPrivate *priv = NM_DEVICE_ETHERNET_GET_PRIVATE (object);
 
 	G_OBJECT_CLASS (nm_device_ethernet_parent_class)->constructed (object);
 
-	priv = NM_DEVICE_ETHERNET_GET_PRIVATE (object);
-
-	priv->proxy = dbus_g_proxy_new_for_name (nm_object_get_connection (NM_OBJECT (object)),
-	                                         NM_DBUS_SERVICE,
-	                                         nm_object_get_path (NM_OBJECT (object)),
-	                                         NM_DBUS_INTERFACE_DEVICE_WIRED);
-
+	priv->proxy = _nm_object_new_proxy (NM_OBJECT (object), NULL, NM_DBUS_INTERFACE_DEVICE_WIRED);
 	register_properties (NM_DEVICE_ETHERNET (object));
 }
 
@@ -339,6 +338,8 @@ nm_device_ethernet_class_init (NMDeviceEthernetClass *eth_class)
 	object_class->finalize = finalize;
 	object_class->get_property = get_property;
 	device_class->connection_compatible = connection_compatible;
+	device_class->get_setting_type = get_setting_type;
+	device_class->get_hw_address = get_hw_address;
 
 	/* properties */
 
diff --git a/libnm-glib/nm-device-ethernet.h b/libnm-glib/nm-device-ethernet.h
index 4028d62c..a68a97ec 100644
--- a/libnm-glib/nm-device-ethernet.h
+++ b/libnm-glib/nm-device-ethernet.h
@@ -38,8 +38,8 @@ G_BEGIN_DECLS
 /**
  * NMDeviceEthernetError:
  * @NM_DEVICE_ETHERNET_ERROR_UNKNOWN: unknown or unclassified error
- * @NM_DEVICE_ETHERNET_ERROR_NOT_ETHERNET_CONNECTION: the connection was not of ethernet or PPPoE type
- * @NM_DEVICE_ETHERNET_ERROR_INVALID_ETHERNET_CONNECTION: the ethernet connection was invalid
+ * @NM_DEVICE_ETHERNET_ERROR_NOT_ETHERNET_CONNECTION: the connection was not of Ethernet or PPPoE type
+ * @NM_DEVICE_ETHERNET_ERROR_INVALID_ETHERNET_CONNECTION: the Ethernet connection was invalid
  * @NM_DEVICE_ETHERNET_ERROR_INVALID_DEVICE_MAC: the device's MAC was invalid
  * @NM_DEVICE_ETHERNET_ERROR_MAC_MISMATCH: the MACs of the connection and the device mismatched
  */
diff --git a/libnm-glib/nm-device-generic.c b/libnm-glib/nm-device-generic.c
new file mode 100644
index 00000000..2a45294f
--- /dev/null
+++ b/libnm-glib/nm-device-generic.c
@@ -0,0 +1,289 @@
+/* -*- Mode: C; tab-width: 4; indent-tabs-mode: t; c-basic-offset: 4 -*- */
+/*
+ * libnm_glib -- Access network status & information from glib applications
+ *
+ * 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., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301 USA.
+ *
+ * Copyright 2013 Red Hat, Inc.
+ */
+
+#include <config.h>
+
+#include <string.h>
+
+#include "nm-device-generic.h"
+#include "nm-device-private.h"
+#include "nm-object-private.h"
+#include "nm-setting-generic.h"
+
+G_DEFINE_TYPE (NMDeviceGeneric, nm_device_generic, NM_TYPE_DEVICE)
+
+#define NM_DEVICE_GENERIC_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), NM_TYPE_DEVICE_GENERIC, NMDeviceGenericPrivate))
+
+typedef struct {
+	DBusGProxy *proxy;
+
+	char *hw_address;
+	char *type_description;
+} NMDeviceGenericPrivate;
+
+enum {
+	PROP_0,
+	PROP_HW_ADDRESS,
+	PROP_TYPE_DESCRIPTION,
+
+	LAST_PROP
+};
+
+/**
+ * nm_device_generic_error_quark:
+ *
+ * Registers an error quark for #NMDeviceGeneric if necessary.
+ *
+ * Returns: the error quark used for #NMDeviceGeneric errors.
+ *
+ * Since: 0.9.10
+ **/
+GQuark
+nm_device_generic_error_quark (void)
+{
+	static GQuark quark = 0;
+
+	if (G_UNLIKELY (quark == 0))
+		quark = g_quark_from_static_string ("nm-device-generic-error-quark");
+	return quark;
+}
+
+/**
+ * nm_device_generic_new:
+ * @connection: the #DBusGConnection
+ * @path: the DBus object path of the device
+ *
+ * Creates a new #NMDeviceGeneric.
+ *
+ * Returns: (transfer full): a new device
+ *
+ * Since: 0.9.10
+ **/
+GObject *
+nm_device_generic_new (DBusGConnection *connection, const char *path)
+{
+	GObject *device;
+
+	g_return_val_if_fail (connection != NULL, NULL);
+	g_return_val_if_fail (path != NULL, NULL);
+
+	device = g_object_new (NM_TYPE_DEVICE_GENERIC,
+	                       NM_OBJECT_DBUS_CONNECTION, connection,
+	                       NM_OBJECT_DBUS_PATH, path,
+	                       NULL);
+	_nm_object_ensure_inited (NM_OBJECT (device));
+	return device;
+}
+
+/**
+ * nm_device_generic_get_hw_address:
+ * @device: a #NMDeviceGeneric
+ *
+ * Gets the hardware address of the #NMDeviceGeneric
+ *
+ * Returns: the hardware address. This is the internal string used by the
+ * device, and must not be modified.
+ *
+ * Since: 0.9.10
+ **/
+const char *
+nm_device_generic_get_hw_address (NMDeviceGeneric *device)
+{
+	g_return_val_if_fail (NM_IS_DEVICE_GENERIC (device), NULL);
+
+	_nm_object_ensure_inited (NM_OBJECT (device));
+	return NM_DEVICE_GENERIC_GET_PRIVATE (device)->hw_address;
+}
+
+/***********************************************************/
+
+static const char *
+get_type_description (NMDevice *device)
+{
+	NMDeviceGenericPrivate *priv = NM_DEVICE_GENERIC_GET_PRIVATE (device);
+
+	_nm_object_ensure_inited (NM_OBJECT (device));
+	return priv->type_description;
+}
+
+static const char *
+get_hw_address (NMDevice *device)
+{
+	return nm_device_generic_get_hw_address (NM_DEVICE_GENERIC (device));
+}
+
+static gboolean
+connection_compatible (NMDevice *device, NMConnection *connection, GError **error)
+{
+	NMSettingConnection *s_con;
+	const char *ctype, *iface_name;
+
+	s_con = nm_connection_get_setting_connection (connection);
+	g_assert (s_con);
+
+	ctype = nm_setting_connection_get_connection_type (s_con);
+	if (strcmp (ctype, NM_SETTING_GENERIC_SETTING_NAME) != 0) {
+		g_set_error (error, NM_DEVICE_GENERIC_ERROR, NM_DEVICE_GENERIC_ERROR_NOT_GENERIC_CONNECTION,
+		             "The connection was not a generic connection.");
+		return FALSE;
+	}
+
+	iface_name = nm_setting_connection_get_interface_name (s_con);
+	if (!iface_name) {
+		g_set_error (error, NM_DEVICE_GENERIC_ERROR, NM_DEVICE_GENERIC_ERROR_MISSING_INTERFACE_NAME,
+		             "The connection did not specify an interface name.");
+		return FALSE;
+	}
+
+	return NM_DEVICE_CLASS (nm_device_generic_parent_class)->connection_compatible (device, connection, error);
+}
+
+static GType
+get_setting_type (NMDevice *device)
+{
+	return NM_TYPE_SETTING_GENERIC;
+}
+
+/***********************************************************/
+
+static void
+nm_device_generic_init (NMDeviceGeneric *device)
+{
+	_nm_device_set_device_type (NM_DEVICE (device), NM_DEVICE_TYPE_GENERIC);
+}
+
+static void
+register_properties (NMDeviceGeneric *device)
+{
+	NMDeviceGenericPrivate *priv = NM_DEVICE_GENERIC_GET_PRIVATE (device);
+	const NMPropertiesInfo property_info[] = {
+		{ NM_DEVICE_GENERIC_HW_ADDRESS, &priv->hw_address },
+		{ NM_DEVICE_GENERIC_TYPE_DESCRIPTION, &priv->type_description },
+		{ NULL },
+	};
+
+	_nm_object_register_properties (NM_OBJECT (device),
+	                                priv->proxy,
+	                                property_info);
+}
+
+static void
+constructed (GObject *object)
+{
+	NMDeviceGenericPrivate *priv = NM_DEVICE_GENERIC_GET_PRIVATE (object);
+
+	G_OBJECT_CLASS (nm_device_generic_parent_class)->constructed (object);
+
+	priv->proxy = _nm_object_new_proxy (NM_OBJECT (object), NULL, NM_DBUS_INTERFACE_DEVICE_GENERIC);
+	register_properties (NM_DEVICE_GENERIC (object));
+}
+
+static void
+dispose (GObject *object)
+{
+	NMDeviceGenericPrivate *priv = NM_DEVICE_GENERIC_GET_PRIVATE (object);
+
+	g_clear_object (&priv->proxy);
+
+	G_OBJECT_CLASS (nm_device_generic_parent_class)->dispose (object);
+}
+
+static void
+finalize (GObject *object)
+{
+	NMDeviceGenericPrivate *priv = NM_DEVICE_GENERIC_GET_PRIVATE (object);
+
+	g_free (priv->hw_address);
+	g_free (priv->type_description);
+
+	G_OBJECT_CLASS (nm_device_generic_parent_class)->finalize (object);
+}
+
+static void
+get_property (GObject *object,
+              guint prop_id,
+              GValue *value,
+              GParamSpec *pspec)
+{
+	NMDeviceGenericPrivate *priv = NM_DEVICE_GENERIC_GET_PRIVATE (object);
+
+	_nm_object_ensure_inited (NM_OBJECT (object));
+
+	switch (prop_id) {
+	case PROP_HW_ADDRESS:
+		g_value_set_string (value, priv->hw_address);
+		break;
+	case PROP_TYPE_DESCRIPTION:
+		g_value_set_string (value, priv->type_description);
+		break;
+	default:
+		G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+		break;
+	}
+}
+
+static void
+nm_device_generic_class_init (NMDeviceGenericClass *klass)
+{
+	GObjectClass *object_class = G_OBJECT_CLASS (klass);
+	NMDeviceClass *device_class = NM_DEVICE_CLASS (klass);
+
+	g_type_class_add_private (klass, sizeof (NMDeviceGenericPrivate));
+
+	object_class->constructed = constructed;
+	object_class->dispose = dispose;
+	object_class->finalize = finalize;
+	object_class->get_property = get_property;
+
+	device_class->get_type_description = get_type_description;
+	device_class->get_hw_address = get_hw_address;
+	device_class->connection_compatible = connection_compatible;
+	device_class->get_setting_type = get_setting_type;
+
+	/**
+	 * NMDeviceGeneric:hw-address:
+	 *
+	 * The hardware address of the device.
+	 **/
+	g_object_class_install_property
+		(object_class, PROP_HW_ADDRESS,
+		 g_param_spec_string (NM_DEVICE_GENERIC_HW_ADDRESS,
+		                      "Hardware Address",
+		                      "Hardware address",
+		                      NULL,
+		                      G_PARAM_READABLE));
+
+	/**
+	 * NMDeviceGeneric:type-description:
+	 *
+	 * A description of the specific type of device this is, or %NULL
+	 * if not known.
+	 **/
+	g_object_class_install_property
+		(object_class, PROP_TYPE_DESCRIPTION,
+		 g_param_spec_string (NM_DEVICE_GENERIC_TYPE_DESCRIPTION,
+		                      "Type Description",
+		                      "Type description",
+		                      NULL,
+		                      G_PARAM_READABLE));
+}
+
diff --git a/libnm-glib/nm-device-generic.h b/libnm-glib/nm-device-generic.h
new file mode 100644
index 00000000..a343d988
--- /dev/null
+++ b/libnm-glib/nm-device-generic.h
@@ -0,0 +1,81 @@
+/* -*- Mode: C; tab-width: 4; indent-tabs-mode: t; c-basic-offset: 4 -*- */
+/*
+ * libnm_glib -- Access network status & information from glib applications
+ *
+ * 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., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301 USA.
+ *
+ * Copyright 2013 Red Hat, Inc.
+ */
+
+#ifndef NM_DEVICE_GENERIC_H
+#define NM_DEVICE_GENERIC_H
+
+#include "nm-device.h"
+
+G_BEGIN_DECLS
+
+#define NM_TYPE_DEVICE_GENERIC            (nm_device_generic_get_type ())
+#define NM_DEVICE_GENERIC(obj)            (G_TYPE_CHECK_INSTANCE_CAST ((obj), NM_TYPE_DEVICE_GENERIC, NMDeviceGeneric))
+#define NM_DEVICE_GENERIC_CLASS(klass)    (G_TYPE_CHECK_CLASS_CAST ((klass), NM_TYPE_DEVICE_GENERIC, NMDeviceGenericClass))
+#define NM_IS_DEVICE_GENERIC(obj)         (G_TYPE_CHECK_INSTANCE_TYPE ((obj), NM_TYPE_DEVICE_GENERIC))
+#define NM_IS_DEVICE_GENERIC_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), NM_TYPE_DEVICE_GENERIC))
+#define NM_DEVICE_GENERIC_GET_CLASS(obj)  (G_TYPE_INSTANCE_GET_CLASS ((obj), NM_TYPE_DEVICE_GENERIC, NMDeviceGenericClass))
+
+/**
+ * NMDeviceGenericError:
+ * @NM_DEVICE_GENERIC_ERROR_UNKNOWN: unknown or unclassified error
+ * @NM_DEVICE_GENERIC_ERROR_NOT_GENERIC_CONNECTION: the connection was not of generic type
+ * @NM_DEVICE_GENERIC_ERROR_MISSING_INTERFACE_NAME: the connection did not specify the interface name
+ */
+typedef enum {
+	NM_DEVICE_GENERIC_ERROR_UNKNOWN = 0,            /*< nick=UnknownError >*/
+	NM_DEVICE_GENERIC_ERROR_NOT_GENERIC_CONNECTION, /*< nick=NotGenericConnection >*/
+	NM_DEVICE_GENERIC_ERROR_MISSING_INTERFACE_NAME, /*< nick=MissingInterfaceName >*/
+} NMDeviceGenericError;
+
+#define NM_DEVICE_GENERIC_ERROR nm_device_generic_error_quark ()
+GQuark nm_device_generic_error_quark (void);
+
+#define NM_DEVICE_GENERIC_HW_ADDRESS       "hw-address"
+#define NM_DEVICE_GENERIC_TYPE_DESCRIPTION "type-description"
+
+typedef struct {
+	NMDevice parent;
+} NMDeviceGeneric;
+
+typedef struct {
+	NMDeviceClass parent;
+
+	/* Padding for future expansion */
+	void (*_reserved1) (void);
+	void (*_reserved2) (void);
+	void (*_reserved3) (void);
+	void (*_reserved4) (void);
+	void (*_reserved5) (void);
+	void (*_reserved6) (void);
+} NMDeviceGenericClass;
+
+NM_AVAILABLE_IN_0_9_10
+GType nm_device_generic_get_type (void);
+
+NM_AVAILABLE_IN_0_9_10
+GObject *nm_device_generic_new (DBusGConnection *connection, const char *path);
+
+const char *nm_device_generic_get_hw_address (NMDeviceGeneric *device);
+
+G_END_DECLS
+
+#endif /* NM_DEVICE_GENERIC_H */
diff --git a/libnm-glib/nm-device-infiniband.c b/libnm-glib/nm-device-infiniband.c
index d611993b..b60b2d82 100644
--- a/libnm-glib/nm-device-infiniband.c
+++ b/libnm-glib/nm-device-infiniband.c
@@ -54,9 +54,6 @@ enum {
 	LAST_PROP
 };
 
-#define DBUS_PROP_HW_ADDRESS "HwAddress"
-#define DBUS_PROP_CARRIER "Carrier"
-
 /**
  * nm_device_infiniband_error_quark:
  *
@@ -143,8 +140,6 @@ connection_compatible (NMDevice *device, NMConnection *connection, GError **erro
 	const GByteArray *mac;
 	guint8 *hwaddr, hwaddr_buf[INFINIBAND_ALEN];
 
-	g_return_val_if_fail (error == NULL || *error == NULL, FALSE);
-
 	s_con = nm_connection_get_setting_connection (connection);
 	g_assert (s_con);
 
@@ -171,14 +166,28 @@ connection_compatible (NMDevice *device, NMConnection *connection, GError **erro
 			return FALSE;
 		}
 		mac = nm_setting_infiniband_get_mac_address (s_infiniband);
-		if (mac && hwaddr && memcmp (mac->data, hwaddr, INFINIBAND_ALEN)) {
+
+		/* We only match against the last 8 bytes */
+		if (mac && hwaddr && memcmp (mac->data + INFINIBAND_ALEN - 8, hwaddr + INFINIBAND_ALEN - 8, 8)) {
 			g_set_error (error, NM_DEVICE_INFINIBAND_ERROR, NM_DEVICE_INFINIBAND_ERROR_MAC_MISMATCH,
 			             "The MACs of the device and the connection didn't match.");
 			return FALSE;
 		}
 	}
 
-	return TRUE;
+	return NM_DEVICE_CLASS (nm_device_infiniband_parent_class)->connection_compatible (device, connection, error);
+}
+
+static GType
+get_setting_type (NMDevice *device)
+{
+	return NM_TYPE_SETTING_INFINIBAND;
+}
+
+static const char *
+get_hw_address (NMDevice *device)
+{
+	return nm_device_infiniband_get_hw_address (NM_DEVICE_INFINIBAND (device));
 }
 
 /***********************************************************/
@@ -207,17 +216,11 @@ register_properties (NMDeviceInfiniband *device)
 static void
 constructed (GObject *object)
 {
-	NMDeviceInfinibandPrivate *priv;
+	NMDeviceInfinibandPrivate *priv = NM_DEVICE_INFINIBAND_GET_PRIVATE (object);
 
 	G_OBJECT_CLASS (nm_device_infiniband_parent_class)->constructed (object);
 
-	priv = NM_DEVICE_INFINIBAND_GET_PRIVATE (object);
-
-	priv->proxy = dbus_g_proxy_new_for_name (nm_object_get_connection (NM_OBJECT (object)),
-	                                         NM_DBUS_SERVICE,
-	                                         nm_object_get_path (NM_OBJECT (object)),
-	                                         NM_DBUS_INTERFACE_DEVICE_INFINIBAND);
-
+	priv->proxy = _nm_object_new_proxy (NM_OBJECT (object), NULL, NM_DBUS_INTERFACE_DEVICE_INFINIBAND);
 	register_properties (NM_DEVICE_INFINIBAND (object));
 }
 
@@ -278,6 +281,8 @@ nm_device_infiniband_class_init (NMDeviceInfinibandClass *eth_class)
 	object_class->finalize = finalize;
 	object_class->get_property = get_property;
 	device_class->connection_compatible = connection_compatible;
+	device_class->get_setting_type = get_setting_type;
+	device_class->get_hw_address = get_hw_address;
 
 	/* properties */
 
diff --git a/libnm-glib/nm-device-modem.c b/libnm-glib/nm-device-modem.c
index f7a9230e..b3b357cf 100644
--- a/libnm-glib/nm-device-modem.c
+++ b/libnm-glib/nm-device-modem.c
@@ -33,7 +33,6 @@
 #include "nm-device-modem.h"
 #include "nm-device-private.h"
 #include "nm-object-private.h"
-#include "nm-glib-marshal.h"
 
 G_DEFINE_TYPE (NMDeviceModem, nm_device_modem, NM_TYPE_DEVICE)
 
@@ -55,9 +54,6 @@ enum {
 	LAST_PROP
 };
 
-#define DBUS_PROP_MODEM_CAPS "ModemCapabilities"
-#define DBUS_PROP_CURRENT_CAPS "CurrentCapabilities"
-
 /**
  * nm_device_modem_error_quark:
  *
@@ -88,7 +84,6 @@ nm_device_modem_error_quark (void)
 NMDeviceModemCapabilities
 nm_device_modem_get_modem_capabilities (NMDeviceModem *self)
 {
-	g_return_val_if_fail (self != NULL, NM_DEVICE_MODEM_CAPABILITY_NONE);
 	g_return_val_if_fail (NM_IS_DEVICE_MODEM (self), NM_DEVICE_MODEM_CAPABILITY_NONE);
 
 	_nm_object_ensure_inited (NM_OBJECT (self));
@@ -109,13 +104,31 @@ nm_device_modem_get_modem_capabilities (NMDeviceModem *self)
 NMDeviceModemCapabilities
 nm_device_modem_get_current_capabilities (NMDeviceModem *self)
 {
-	g_return_val_if_fail (self != NULL, NM_DEVICE_MODEM_CAPABILITY_NONE);
 	g_return_val_if_fail (NM_IS_DEVICE_MODEM (self), NM_DEVICE_MODEM_CAPABILITY_NONE);
 
 	_nm_object_ensure_inited (NM_OBJECT (self));
 	return NM_DEVICE_MODEM_GET_PRIVATE (self)->current_caps;
 }
 
+static const char *
+get_type_description (NMDevice *device)
+{
+	NMDeviceModemCapabilities caps;
+
+	caps = nm_device_modem_get_current_capabilities (NM_DEVICE_MODEM (device));
+	if (caps & NM_DEVICE_MODEM_CAPABILITY_GSM_UMTS)
+		return "gsm";
+	else if (caps & NM_DEVICE_MODEM_CAPABILITY_CDMA_EVDO)
+		return "cdma";
+	else
+		return NULL;
+}
+
+#define MODEM_CAPS_3GPP(caps) (caps & (NM_DEVICE_MODEM_CAPABILITY_GSM_UMTS |    \
+                                       NM_DEVICE_MODEM_CAPABILITY_LTE))
+
+#define MODEM_CAPS_3GPP2(caps) (caps & (NM_DEVICE_MODEM_CAPABILITY_CDMA_EVDO))
+
 static gboolean
 connection_compatible (NMDevice *device, NMConnection *connection, GError **error)
 {
@@ -125,8 +138,6 @@ connection_compatible (NMDevice *device, NMConnection *connection, GError **erro
 	const char *ctype;
 	NMDeviceModemCapabilities current_caps;
 
-	g_return_val_if_fail (error == NULL || *error == NULL, FALSE);
-
 	s_con = nm_connection_get_setting_connection (connection);
 	g_assert (s_con);
 
@@ -147,14 +158,27 @@ connection_compatible (NMDevice *device, NMConnection *connection, GError **erro
 	}
 
 	current_caps = nm_device_modem_get_current_capabilities (NM_DEVICE_MODEM (device));
-	if (   !(s_gsm && (current_caps & NM_DEVICE_MODEM_CAPABILITY_GSM_UMTS))
-	    && !(s_cdma && (current_caps & NM_DEVICE_MODEM_CAPABILITY_CDMA_EVDO))) {
+	if (!(s_gsm && MODEM_CAPS_3GPP (current_caps)) && !(s_cdma && MODEM_CAPS_3GPP2 (current_caps))) {
 		g_set_error (error, NM_DEVICE_MODEM_ERROR, NM_DEVICE_MODEM_ERROR_MISSING_DEVICE_CAPS,
 		             "The device missed capabilities required by the GSM/CDMA connection.");
 		return FALSE;
 	}
 
-	return TRUE;
+	return NM_DEVICE_CLASS (nm_device_modem_parent_class)->connection_compatible (device, connection, error);
+}
+
+static GType
+get_setting_type (NMDevice *device)
+{
+	NMDeviceModemCapabilities caps;
+
+	caps = nm_device_modem_get_current_capabilities (NM_DEVICE_MODEM (device));
+	if (caps & (NM_DEVICE_MODEM_CAPABILITY_GSM_UMTS | NM_DEVICE_MODEM_CAPABILITY_LTE))
+		return NM_TYPE_SETTING_GSM;
+	else if (caps & NM_DEVICE_MODEM_CAPABILITY_CDMA_EVDO)
+		return NM_TYPE_SETTING_CDMA;
+	else
+		return G_TYPE_INVALID;
 }
 
 /*******************************************************************/
@@ -183,17 +207,11 @@ register_properties (NMDeviceModem *device)
 static void
 constructed (GObject *object)
 {
-	NMDeviceModemPrivate *priv;
+	NMDeviceModemPrivate *priv = NM_DEVICE_MODEM_GET_PRIVATE (object);
 
 	G_OBJECT_CLASS (nm_device_modem_parent_class)->constructed (object);
 
-	priv = NM_DEVICE_MODEM_GET_PRIVATE (object);
-
-	priv->proxy = dbus_g_proxy_new_for_name (nm_object_get_connection (NM_OBJECT (object)),
-	                                         NM_DBUS_SERVICE,
-	                                         nm_object_get_path (NM_OBJECT (object)),
-	                                         NM_DBUS_INTERFACE_DEVICE_MODEM);
-
+	priv->proxy = _nm_object_new_proxy (NM_OBJECT (object), NULL, NM_DBUS_INTERFACE_DEVICE_MODEM);
 	register_properties (NM_DEVICE_MODEM (object));
 }
 
@@ -242,7 +260,10 @@ nm_device_modem_class_init (NMDeviceModemClass *modem_class)
 	object_class->constructed = constructed;
 	object_class->get_property = get_property;
 	object_class->dispose = dispose;
+
+	device_class->get_type_description = get_type_description;
 	device_class->connection_compatible = connection_compatible;
+	device_class->get_setting_type = get_setting_type;
 
 	/**
 	 * NMDeviceModem:modem-capabilities:
diff --git a/libnm-glib/nm-device-olpc-mesh.c b/libnm-glib/nm-device-olpc-mesh.c
index 7ca36890..d1789eb9 100644
--- a/libnm-glib/nm-device-olpc-mesh.c
+++ b/libnm-glib/nm-device-olpc-mesh.c
@@ -55,10 +55,6 @@ enum {
 	LAST_PROP
 };
 
-#define DBUS_PROP_HW_ADDRESS      "HwAddress"
-#define DBUS_PROP_COMPANION       "Companion"
-#define DBUS_PROP_ACTIVE_CHANNEL  "ActiveChannel"
-
 /**
  * nm_device_olpc_mesh_error_quark:
  *
@@ -154,6 +150,12 @@ nm_device_olpc_mesh_get_active_channel (NMDeviceOlpcMesh *device)
 	return NM_DEVICE_OLPC_MESH_GET_PRIVATE (device)->active_channel;
 }
 
+static const char *
+get_hw_address (NMDevice *device)
+{
+	return nm_device_olpc_mesh_get_hw_address (NM_DEVICE_OLPC_MESH (device));
+}
+
 static gboolean
 connection_compatible (NMDevice *device, NMConnection *connection, GError **error)
 {
@@ -161,8 +163,6 @@ connection_compatible (NMDevice *device, NMConnection *connection, GError **erro
 	NMSettingOlpcMesh *s_olpc_mesh;
 	const char *ctype;
 
-	g_return_val_if_fail (error == NULL || *error == NULL, FALSE);
-
 	s_con = nm_connection_get_setting_connection (connection);
 	g_assert (s_con);
 
@@ -180,7 +180,13 @@ connection_compatible (NMDevice *device, NMConnection *connection, GError **erro
 		return FALSE;
 	}
 
-	return TRUE;
+	return NM_DEVICE_CLASS (nm_device_olpc_mesh_parent_class)->connection_compatible (device, connection, error);
+}
+
+static GType
+get_setting_type (NMDevice *device)
+{
+	return NM_TYPE_SETTING_OLPC_MESH;
 }
 
 /**************************************************************/
@@ -210,17 +216,11 @@ register_properties (NMDeviceOlpcMesh *device)
 static void
 constructed (GObject *object)
 {
-	NMDeviceOlpcMeshPrivate *priv;
+	NMDeviceOlpcMeshPrivate *priv = NM_DEVICE_OLPC_MESH_GET_PRIVATE (object);
 
 	G_OBJECT_CLASS (nm_device_olpc_mesh_parent_class)->constructed (object);
 
-	priv = NM_DEVICE_OLPC_MESH_GET_PRIVATE (object);
-
-	priv->proxy = dbus_g_proxy_new_for_name (nm_object_get_connection (NM_OBJECT (object)),
-	                                         NM_DBUS_SERVICE,
-	                                         nm_object_get_path (NM_OBJECT (object)),
-	                                         NM_DBUS_INTERFACE_DEVICE_OLPC_MESH);
-
+	priv->proxy = _nm_object_new_proxy (NM_OBJECT (object), NULL, NM_DBUS_INTERFACE_DEVICE_OLPC_MESH);
 	register_properties (NM_DEVICE_OLPC_MESH (object));
 }
 
@@ -285,6 +285,8 @@ nm_device_olpc_mesh_class_init (NMDeviceOlpcMeshClass *olpc_mesh_class)
 	object_class->finalize = finalize;
 	object_class->get_property = get_property;
 	device_class->connection_compatible = connection_compatible;
+	device_class->get_setting_type = get_setting_type;
+	device_class->get_hw_address = get_hw_address;
 
 	/* properties */
 
diff --git a/libnm-glib/nm-device-team.c b/libnm-glib/nm-device-team.c
new file mode 100644
index 00000000..f739e1d8
--- /dev/null
+++ b/libnm-glib/nm-device-team.c
@@ -0,0 +1,356 @@
+/* -*- Mode: C; tab-width: 4; indent-tabs-mode: t; c-basic-offset: 4 -*- */
+/*
+ * Copyright (C) 2013 Jiri Pirko <jiri@resnulli.us>
+ *
+ * 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., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301 USA.
+ */
+
+#include <config.h>
+#include <string.h>
+#include <netinet/ether.h>
+
+#include "nm-glib-compat.h"
+
+#include <nm-setting-connection.h>
+#include <nm-setting-team.h>
+#include <nm-utils.h>
+
+#include "nm-device-team.h"
+#include "nm-device-private.h"
+#include "nm-object-private.h"
+#include "nm-types.h"
+
+G_DEFINE_TYPE (NMDeviceTeam, nm_device_team, NM_TYPE_DEVICE)
+
+#define NM_DEVICE_TEAM_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), NM_TYPE_DEVICE_TEAM, NMDeviceTeamPrivate))
+
+typedef struct {
+	DBusGProxy *proxy;
+
+	char *hw_address;
+	gboolean carrier;
+	GPtrArray *slaves;
+} NMDeviceTeamPrivate;
+
+enum {
+	PROP_0,
+	PROP_HW_ADDRESS,
+	PROP_CARRIER,
+	PROP_SLAVES,
+
+	LAST_PROP
+};
+
+/**
+ * nm_device_team_error_quark:
+ *
+ * Registers an error quark for #NMDeviceTeam if necessary.
+ *
+ * Returns: the error quark used for #NMDeviceTeam errors.
+ *
+ * Since: 0.9.10
+ **/
+GQuark
+nm_device_team_error_quark (void)
+{
+	static GQuark quark = 0;
+
+	if (G_UNLIKELY (quark == 0))
+		quark = g_quark_from_static_string ("nm-device-team-error-quark");
+	return quark;
+}
+
+/**
+ * nm_device_team_new:
+ * @connection: the #DBusGConnection
+ * @path: the DBus object path of the device
+ *
+ * Creates a new #NMDeviceTeam.
+ *
+ * Returns: (transfer full): a new device
+ *
+ * Since: 0.9.10
+ **/
+GObject *
+nm_device_team_new (DBusGConnection *connection, const char *path)
+{
+	GObject *device;
+
+	g_return_val_if_fail (connection != NULL, NULL);
+	g_return_val_if_fail (path != NULL, NULL);
+
+	device = g_object_new (NM_TYPE_DEVICE_TEAM,
+			       NM_OBJECT_DBUS_CONNECTION, connection,
+			       NM_OBJECT_DBUS_PATH, path,
+			       NULL);
+	_nm_object_ensure_inited (NM_OBJECT (device));
+	return device;
+}
+
+/**
+ * nm_device_team_get_hw_address:
+ * @device: a #NMDeviceTeam
+ *
+ * Gets the hardware (MAC) address of the #NMDeviceTeam
+ *
+ * Returns: the hardware address. This is the internal string used by the
+ * device, and must not be modified.
+ *
+ * Since: 0.9.10
+ **/
+const char *
+nm_device_team_get_hw_address (NMDeviceTeam *device)
+{
+	g_return_val_if_fail (NM_IS_DEVICE_TEAM (device), NULL);
+
+	_nm_object_ensure_inited (NM_OBJECT (device));
+	return NM_DEVICE_TEAM_GET_PRIVATE (device)->hw_address;
+}
+
+/**
+ * nm_device_team_get_carrier:
+ * @device: a #NMDeviceTeam
+ *
+ * Whether the device has carrier.
+ *
+ * Returns: %TRUE if the device has carrier
+ *
+ * Since: 0.9.10
+ **/
+gboolean
+nm_device_team_get_carrier (NMDeviceTeam *device)
+{
+	g_return_val_if_fail (NM_IS_DEVICE_TEAM (device), FALSE);
+
+	_nm_object_ensure_inited (NM_OBJECT (device));
+	return NM_DEVICE_TEAM_GET_PRIVATE (device)->carrier;
+}
+
+/**
+ * nm_device_team_get_slaves:
+ * @device: a #NMDeviceTeam
+ *
+ * Gets the devices currently enslaved to @device.
+ *
+ * Returns: (element-type NMClient.Device): the #GPtrArray containing
+ * #NMDevices that are slaves of @device. This is the internal
+ * copy used by the device, and must not be modified.
+ *
+ * Since: 0.9.10
+ **/
+const GPtrArray *
+nm_device_team_get_slaves (NMDeviceTeam *device)
+{
+	g_return_val_if_fail (NM_IS_DEVICE_TEAM (device), FALSE);
+
+	_nm_object_ensure_inited (NM_OBJECT (device));
+	return handle_ptr_array_return (NM_DEVICE_TEAM_GET_PRIVATE (device)->slaves);
+}
+
+static const char *
+get_hw_address (NMDevice *device)
+{
+	return nm_device_team_get_hw_address (NM_DEVICE_TEAM (device));
+}
+
+static gboolean
+connection_compatible (NMDevice *device, NMConnection *connection, GError **error)
+{
+	NMSettingConnection *s_con;
+	NMSettingTeam *s_team;
+	const char *ctype, *dev_iface_name, *team_iface_name;
+
+	s_con = nm_connection_get_setting_connection (connection);
+	g_assert (s_con);
+
+	ctype = nm_setting_connection_get_connection_type (s_con);
+	if (strcmp (ctype, NM_SETTING_TEAM_SETTING_NAME) != 0) {
+		g_set_error (error, NM_DEVICE_TEAM_ERROR, NM_DEVICE_TEAM_ERROR_NOT_TEAM_CONNECTION,
+		             "The connection was not a team connection.");
+		return FALSE;
+	}
+
+	s_team = nm_connection_get_setting_team (connection);
+	if (!s_team) {
+		g_set_error (error, NM_DEVICE_TEAM_ERROR, NM_DEVICE_TEAM_ERROR_INVALID_TEAM_CONNECTION,
+		             "The connection was not a valid team connection.");
+		return FALSE;
+	}
+
+	dev_iface_name = nm_device_get_iface (device);
+	team_iface_name = nm_setting_team_get_interface_name (s_team);
+	if (g_strcmp0 (dev_iface_name, team_iface_name) != 0) {
+		g_set_error (error, NM_DEVICE_TEAM_ERROR, NM_DEVICE_TEAM_ERROR_INTERFACE_MISMATCH,
+		             "The interfaces of the device and the connection didn't match.");
+		return FALSE;
+	}
+
+	/* FIXME: check slaves? */
+
+	return NM_DEVICE_CLASS (nm_device_team_parent_class)->connection_compatible (device, connection, error);
+}
+
+static GType
+get_setting_type (NMDevice *device)
+{
+	return NM_TYPE_SETTING_TEAM;
+}
+
+/***********************************************************/
+
+static void
+nm_device_team_init (NMDeviceTeam *device)
+{
+	_nm_device_set_device_type (NM_DEVICE (device), NM_DEVICE_TYPE_TEAM);
+}
+
+static void
+register_properties (NMDeviceTeam *device)
+{
+	NMDeviceTeamPrivate *priv = NM_DEVICE_TEAM_GET_PRIVATE (device);
+	const NMPropertiesInfo property_info[] = {
+		{ NM_DEVICE_TEAM_HW_ADDRESS, &priv->hw_address },
+		{ NM_DEVICE_TEAM_CARRIER,    &priv->carrier },
+		{ NM_DEVICE_TEAM_SLAVES,     &priv->slaves, NULL, NM_TYPE_DEVICE },
+		{ NULL },
+	};
+
+	_nm_object_register_properties (NM_OBJECT (device),
+	                                priv->proxy,
+	                                property_info);
+}
+
+static void
+constructed (GObject *object)
+{
+	NMDeviceTeamPrivate *priv = NM_DEVICE_TEAM_GET_PRIVATE (object);
+
+	G_OBJECT_CLASS (nm_device_team_parent_class)->constructed (object);
+
+	priv->proxy = _nm_object_new_proxy (NM_OBJECT (object), NULL, NM_DBUS_INTERFACE_DEVICE_TEAM);
+	register_properties (NM_DEVICE_TEAM (object));
+}
+
+static void
+dispose (GObject *object)
+{
+	NMDeviceTeamPrivate *priv = NM_DEVICE_TEAM_GET_PRIVATE (object);
+
+	g_clear_object (&priv->proxy);
+
+	if (priv->slaves) {
+		g_ptr_array_set_free_func (priv->slaves, g_object_unref);
+		g_ptr_array_free (priv->slaves, TRUE);
+		priv->slaves = NULL;
+	}
+
+	G_OBJECT_CLASS (nm_device_team_parent_class)->dispose (object);
+}
+
+static void
+finalize (GObject *object)
+{
+	NMDeviceTeamPrivate *priv = NM_DEVICE_TEAM_GET_PRIVATE (object);
+
+	g_free (priv->hw_address);
+
+	G_OBJECT_CLASS (nm_device_team_parent_class)->finalize (object);
+}
+
+static void
+get_property (GObject *object,
+              guint prop_id,
+              GValue *value,
+              GParamSpec *pspec)
+{
+	NMDeviceTeam *device = NM_DEVICE_TEAM (object);
+
+	_nm_object_ensure_inited (NM_OBJECT (object));
+
+	switch (prop_id) {
+	case PROP_HW_ADDRESS:
+		g_value_set_string (value, nm_device_team_get_hw_address (device));
+		break;
+	case PROP_CARRIER:
+		g_value_set_boolean (value, nm_device_team_get_carrier (device));
+		break;
+	case PROP_SLAVES:
+		g_value_set_boxed (value, nm_device_team_get_slaves (device));
+		break;
+	default:
+		G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+		break;
+	}
+}
+
+static void
+nm_device_team_class_init (NMDeviceTeamClass *eth_class)
+{
+	GObjectClass *object_class = G_OBJECT_CLASS (eth_class);
+	NMDeviceClass *device_class = NM_DEVICE_CLASS (eth_class);
+
+	g_type_class_add_private (eth_class, sizeof (NMDeviceTeamPrivate));
+
+	/* virtual methods */
+	object_class->constructed = constructed;
+	object_class->dispose = dispose;
+	object_class->finalize = finalize;
+	object_class->get_property = get_property;
+	device_class->connection_compatible = connection_compatible;
+	device_class->get_setting_type = get_setting_type;
+	device_class->get_hw_address = get_hw_address;
+
+	/* properties */
+
+	/**
+	 * NMDeviceTeam:hw-address:
+	 *
+	 * The hardware (MAC) address of the device.
+	 **/
+	g_object_class_install_property
+		(object_class, PROP_HW_ADDRESS,
+		 g_param_spec_string (NM_DEVICE_TEAM_HW_ADDRESS,
+		                      "Active MAC Address",
+		                      "Currently set hardware MAC address",
+		                      NULL,
+		                      G_PARAM_READABLE));
+
+	/**
+	 * NMDeviceTeam:carrier:
+	 *
+	 * Whether the device has carrier.
+	 **/
+	g_object_class_install_property
+		(object_class, PROP_CARRIER,
+		 g_param_spec_boolean (NM_DEVICE_TEAM_CARRIER,
+		                       "Carrier",
+		                       "Carrier",
+		                       FALSE,
+		                       G_PARAM_READABLE));
+
+	/**
+	 * NMDeviceTeam:slaves:
+	 *
+	 * The devices (#NMDevice) enslaved to the team device.
+	 **/
+	g_object_class_install_property
+		(object_class, PROP_SLAVES,
+		 g_param_spec_boxed (NM_DEVICE_TEAM_SLAVES,
+		                     "Slaves",
+		                     "Slaves",
+		                     NM_TYPE_OBJECT_ARRAY,
+		                     G_PARAM_READABLE));
+}
diff --git a/libnm-glib/nm-device-team.h b/libnm-glib/nm-device-team.h
new file mode 100644
index 00000000..054f9ae2
--- /dev/null
+++ b/libnm-glib/nm-device-team.h
@@ -0,0 +1,85 @@
+/* -*- Mode: C; tab-width: 4; indent-tabs-mode: t; c-basic-offset: 4 -*- */
+/*
+ * Copyright (C) 2013 Jiri Pirko <jiri@resnulli.us>
+ *
+ * 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., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301 USA.
+ */
+
+#ifndef NM_DEVICE_TEAM_H
+#define NM_DEVICE_TEAM_H
+
+#include "nm-device.h"
+
+G_BEGIN_DECLS
+
+#define NM_TYPE_DEVICE_TEAM            (nm_device_team_get_type ())
+#define NM_DEVICE_TEAM(obj)            (G_TYPE_CHECK_INSTANCE_CAST ((obj), NM_TYPE_DEVICE_TEAM, NMDeviceTeam))
+#define NM_DEVICE_TEAM_CLASS(klass)    (G_TYPE_CHECK_CLASS_CAST ((klass), NM_TYPE_DEVICE_TEAM, NMDeviceTeamClass))
+#define NM_IS_DEVICE_TEAM(obj)         (G_TYPE_CHECK_INSTANCE_TYPE ((obj), NM_TYPE_DEVICE_TEAM))
+#define NM_IS_DEVICE_TEAM_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), NM_TYPE_DEVICE_TEAM))
+#define NM_DEVICE_TEAM_GET_CLASS(obj)  (G_TYPE_INSTANCE_GET_CLASS ((obj), NM_TYPE_DEVICE_TEAM, NMDeviceTeamClass))
+
+/**
+ * NMDeviceTeamError:
+ * @NM_DEVICE_TEAM_ERROR_UNKNOWN: unknown or unclassified error
+ * @NM_DEVICE_TEAM_ERROR_NOT_TEAM_CONNECTION: the connection was not of team type
+ * @NM_DEVICE_TEAM_ERROR_INVALID_TEAM_CONNECTION: the team connection was invalid
+ * @NM_DEVICE_TEAM_ERROR_INTERFACE_MISMATCH: the interfaces of the connection and the device mismatched
+ */
+typedef enum {
+	NM_DEVICE_TEAM_ERROR_UNKNOWN = 0,             /*< nick=UnknownError >*/
+	NM_DEVICE_TEAM_ERROR_NOT_TEAM_CONNECTION,     /*< nick=NotTeamConnection >*/
+	NM_DEVICE_TEAM_ERROR_INVALID_TEAM_CONNECTION, /*< nick=InvalidTeamConnection >*/
+	NM_DEVICE_TEAM_ERROR_INTERFACE_MISMATCH,      /*< nick=InterfaceMismatch >*/
+} NMDeviceTeamError;
+
+#define NM_DEVICE_TEAM_ERROR nm_device_team_error_quark ()
+NM_AVAILABLE_IN_0_9_10
+GQuark nm_device_team_error_quark (void);
+
+#define NM_DEVICE_TEAM_HW_ADDRESS  "hw-address"
+#define NM_DEVICE_TEAM_CARRIER     "carrier"
+#define NM_DEVICE_TEAM_SLAVES      "slaves"
+
+typedef struct {
+	NMDevice parent;
+} NMDeviceTeam;
+
+typedef struct {
+	NMDeviceClass parent;
+
+	/* Padding for future expansion */
+	void (*_reserved1) (void);
+	void (*_reserved2) (void);
+	void (*_reserved3) (void);
+	void (*_reserved4) (void);
+	void (*_reserved5) (void);
+	void (*_reserved6) (void);
+} NMDeviceTeamClass;
+
+NM_AVAILABLE_IN_0_9_10
+GType nm_device_team_get_type (void);
+
+NM_AVAILABLE_IN_0_9_10
+GObject *nm_device_team_new (DBusGConnection *connection, const char *path);
+
+const char      *nm_device_team_get_hw_address (NMDeviceTeam *device);
+gboolean         nm_device_team_get_carrier    (NMDeviceTeam *device);
+const GPtrArray *nm_device_team_get_slaves     (NMDeviceTeam *device);
+
+G_END_DECLS
+
+#endif /* NM_DEVICE_TEAM_H */
diff --git a/libnm-glib/nm-device-vlan.c b/libnm-glib/nm-device-vlan.c
index 13ca3ac3..2a84b946 100644
--- a/libnm-glib/nm-device-vlan.c
+++ b/libnm-glib/nm-device-vlan.c
@@ -55,10 +55,6 @@ enum {
 	LAST_PROP
 };
 
-#define DBUS_PROP_HW_ADDRESS "HwAddress"
-#define DBUS_PROP_CARRIER "Carrier"
-#define DBUS_PROP_VLAN_ID "VlanId"
-
 /**
  * nm_device_vlan_error_quark:
  *
@@ -156,9 +152,10 @@ connection_compatible (NMDevice *device, NMConnection *connection, GError **erro
 {
 	NMSettingConnection *s_con;
 	NMSettingVlan *s_vlan;
+	NMSettingWired *s_wired;
 	const char *ctype, *dev_iface_name, *vlan_iface_name;
-
-	g_return_val_if_fail (error == NULL || *error == NULL, FALSE);
+	const GByteArray *mac_address;
+	char *mac_address_str;
 
 	s_con = nm_connection_get_setting_connection (connection);
 	g_assert (s_con);
@@ -191,7 +188,33 @@ connection_compatible (NMDevice *device, NMConnection *connection, GError **erro
 		return FALSE;
 	}
 
-	return TRUE;
+	s_wired = nm_connection_get_setting_wired (connection);
+	if (s_wired)
+		mac_address = nm_setting_wired_get_mac_address (s_wired);
+	else
+		mac_address = NULL;
+	if (mac_address) {
+		mac_address_str = nm_utils_hwaddr_ntoa_len (mac_address->data, mac_address->len);
+		if (!g_strcmp0 (mac_address_str, NM_DEVICE_VLAN_GET_PRIVATE (device)->hw_address)) {
+			g_set_error (error, NM_DEVICE_VLAN_ERROR, NM_DEVICE_VLAN_ERROR_MAC_MISMATCH,
+			             "The hardware address of the device and the connection didn't match.");
+		}
+		g_free (mac_address_str);
+	}
+
+	return NM_DEVICE_CLASS (nm_device_vlan_parent_class)->connection_compatible (device, connection, error);
+}
+
+static GType
+get_setting_type (NMDevice *device)
+{
+	return NM_TYPE_SETTING_VLAN;
+}
+
+static const char *
+get_hw_address (NMDevice *device)
+{
+	return nm_device_vlan_get_hw_address (NM_DEVICE_VLAN (device));
 }
 
 /***********************************************************/
@@ -221,17 +244,11 @@ register_properties (NMDeviceVlan *device)
 static void
 constructed (GObject *object)
 {
-	NMDeviceVlanPrivate *priv;
+	NMDeviceVlanPrivate *priv = NM_DEVICE_VLAN_GET_PRIVATE (object);
 
 	G_OBJECT_CLASS (nm_device_vlan_parent_class)->constructed (object);
 
-	priv = NM_DEVICE_VLAN_GET_PRIVATE (object);
-
-	priv->proxy = dbus_g_proxy_new_for_name (nm_object_get_connection (NM_OBJECT (object)),
-	                                         NM_DBUS_SERVICE,
-	                                         nm_object_get_path (NM_OBJECT (object)),
-	                                         NM_DBUS_INTERFACE_DEVICE_VLAN);
-
+	priv->proxy = _nm_object_new_proxy (NM_OBJECT (object), NULL, NM_DBUS_INTERFACE_DEVICE_VLAN);
 	register_properties (NM_DEVICE_VLAN (object));
 }
 
@@ -295,6 +312,8 @@ nm_device_vlan_class_init (NMDeviceVlanClass *eth_class)
 	object_class->finalize = finalize;
 	object_class->get_property = get_property;
 	device_class->connection_compatible = connection_compatible;
+	device_class->get_setting_type = get_setting_type;
+	device_class->get_hw_address = get_hw_address;
 
 	/* properties */
 
diff --git a/libnm-glib/nm-device-vlan.h b/libnm-glib/nm-device-vlan.h
index 6ccbb028..96087109 100644
--- a/libnm-glib/nm-device-vlan.h
+++ b/libnm-glib/nm-device-vlan.h
@@ -41,6 +41,7 @@ G_BEGIN_DECLS
  * @NM_DEVICE_VLAN_ERROR_INVALID_VLAN_CONNECTION: the VLAN connection was invalid
  * @NM_DEVICE_VLAN_ERROR_ID_MISMATCH: the VLAN identifiers of the connection and the device mismatched
  * @NM_DEVICE_VLAN_ERROR_INTERFACE_MISMATCH: the interfaces of the connection and the device mismatched
+ * @NM_DEVICE_VLAN_ERROR_MAC_MISMATCH: the MACs of the connection and the device mismatched
  */
 typedef enum {
 	NM_DEVICE_VLAN_ERROR_UNKNOWN = 0,             /*< nick=UnknownError >*/
@@ -48,6 +49,7 @@ typedef enum {
 	NM_DEVICE_VLAN_ERROR_INVALID_VLAN_CONNECTION, /*< nick=InvalidVlanConnection >*/
 	NM_DEVICE_VLAN_ERROR_ID_MISMATCH,             /*< nick=IdMismatch >*/
 	NM_DEVICE_VLAN_ERROR_INTERFACE_MISMATCH,      /*< nick=InterfaceMismatch >*/
+	NM_DEVICE_VLAN_ERROR_MAC_MISMATCH,            /*< nick=MacMismatch >*/
 } NMDeviceVlanError;
 
 #define NM_DEVICE_VLAN_ERROR nm_device_vlan_error_quark ()
diff --git a/libnm-glib/nm-device-wifi.c b/libnm-glib/nm-device-wifi.c
index 47594a50..b9cc31d8 100644
--- a/libnm-glib/nm-device-wifi.c
+++ b/libnm-glib/nm-device-wifi.c
@@ -73,24 +73,17 @@ enum {
 	PROP_BITRATE,
 	PROP_ACTIVE_ACCESS_POINT,
 	PROP_WIRELESS_CAPABILITIES,
+	PROP_ACCESS_POINTS,
 
 	LAST_PROP
 };
 
-#define DBUS_PROP_HW_ADDRESS "HwAddress"
-#define DBUS_PROP_PERM_HW_ADDRESS "PermHwAddress"
-#define DBUS_PROP_MODE "Mode"
-#define DBUS_PROP_BITRATE "Bitrate"
-#define DBUS_PROP_ACTIVE_ACCESS_POINT "ActiveAccessPoint"
-#define DBUS_PROP_WIRELESS_CAPABILITIES "WirelessCapabilities"
-
 enum {
 	ACCESS_POINT_ADDED,
 	ACCESS_POINT_REMOVED,
 
 	LAST_SIGNAL
 };
-
 static guint signals[LAST_SIGNAL] = { 0 };
 
 /**
@@ -117,7 +110,7 @@ nm_device_wifi_error_quark (void)
  *
  * Creates a new #NMDeviceWifi.
  *
- * Returns: (transfer full): a new WiFi device
+ * Returns: (transfer full): a new Wi-Fi device
  **/
 GObject *
 nm_device_wifi_new (DBusGConnection *connection, const char *path)
@@ -192,9 +185,9 @@ nm_device_wifi_get_mode (NMDeviceWifi *device)
  * nm_device_wifi_get_bitrate:
  * @device: a #NMDeviceWifi
  *
- * Gets the bit rate of the #NMDeviceWifi.
+ * Gets the bit rate of the #NMDeviceWifi in kbit/s.
  *
- * Returns: the bit rate
+ * Returns: the bit rate (kbit/s)
  **/
 guint32
 nm_device_wifi_get_bitrate (NMDeviceWifi *device)
@@ -223,7 +216,7 @@ nm_device_wifi_get_bitrate (NMDeviceWifi *device)
  * nm_device_wifi_get_capabilities:
  * @device: a #NMDeviceWifi
  *
- * Gets the WIFI capabilities of the #NMDeviceWifi.
+ * Gets the Wi-Fi capabilities of the #NMDeviceWifi.
  *
  * Returns: the capabilities
  **/
@@ -278,7 +271,7 @@ nm_device_wifi_get_active_access_point (NMDeviceWifi *device)
  * Gets all the scanned access points of the #NMDeviceWifi.
  *
  * Returns: (element-type NMClient.AccessPoint): a #GPtrArray containing all the
- * scanned #NMAccessPoint<!-- -->s.
+ * scanned #NMAccessPoints.
  * The returned array is owned by the client and should not be modified.
  **/
 const GPtrArray *
@@ -390,31 +383,6 @@ nm_device_wifi_request_scan_simple (NMDeviceWifi *device,
 }
 
 static void
-access_point_added (NMObject *self, NMObject *ap)
-{
-	g_signal_emit (self, signals[ACCESS_POINT_ADDED], 0, ap);
-}
-
-static void
-access_point_removed (NMObject *self_obj, NMObject *ap_obj)
-{
-	NMDeviceWifi *self = NM_DEVICE_WIFI (self_obj);
-	NMDeviceWifiPrivate *priv = NM_DEVICE_WIFI_GET_PRIVATE (self);
-	NMAccessPoint *ap = NM_ACCESS_POINT (ap_obj);
-
-	if (ap == priv->active_ap) {
-		g_object_unref (priv->active_ap);
-		priv->active_ap = NULL;
-		_nm_object_queue_notify (NM_OBJECT (self), NM_DEVICE_WIFI_ACTIVE_ACCESS_POINT);
-
-		priv->rate = 0;
-		_nm_object_queue_notify (NM_OBJECT (self), NM_DEVICE_WIFI_BITRATE);
-	}
-
-	g_signal_emit (self, signals[ACCESS_POINT_REMOVED], 0, ap);
-}
-
-static void
 clean_up_aps (NMDeviceWifi *self, gboolean notify)
 {
 	NMDeviceWifiPrivate *priv;
@@ -491,8 +459,6 @@ connection_compatible (NMDevice *device, NMConnection *connection, GError **erro
 	NMDeviceWifiCapabilities wifi_caps;
 	const char *key_mgmt;
 
-	g_return_val_if_fail (error == NULL || *error == NULL, FALSE);
-
 	s_con = nm_connection_get_setting_connection (connection);
 	g_assert (s_con);
 
@@ -554,7 +520,19 @@ connection_compatible (NMDevice *device, NMConnection *connection, GError **erro
 		}
 	}
 
-	return TRUE;
+	return NM_DEVICE_CLASS (nm_device_wifi_parent_class)->connection_compatible (device, connection, error);
+}
+
+static GType
+get_setting_type (NMDevice *device)
+{
+	return NM_TYPE_SETTING_WIRELESS;
+}
+
+static const char *
+get_hw_address (NMDevice *device)
+{
+	return nm_device_wifi_get_hw_address (NM_DEVICE_WIFI (device));
 }
 
 /**************************************************************/
@@ -594,6 +572,9 @@ get_property (GObject *object,
 	case PROP_WIRELESS_CAPABILITIES:
 		g_value_set_uint (value, nm_device_wifi_get_capabilities (self));
 		break;
+	case PROP_ACCESS_POINTS:
+		g_value_set_boxed (value, nm_device_wifi_get_access_points (self));
+		break;
 	default:
 		G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
 		break;
@@ -637,36 +618,38 @@ register_properties (NMDeviceWifi *device)
 		{ NM_DEVICE_WIFI_BITRATE,              &priv->rate },
 		{ NM_DEVICE_WIFI_ACTIVE_ACCESS_POINT,  &priv->active_ap, NULL, NM_TYPE_ACCESS_POINT },
 		{ NM_DEVICE_WIFI_CAPABILITIES,         &priv->wireless_caps },
+		{ NM_DEVICE_WIFI_ACCESS_POINTS,        &priv->aps, NULL, NM_TYPE_ACCESS_POINT, "access-point" },
 		{ NULL },
 	};
 
 	_nm_object_register_properties (NM_OBJECT (device),
 	                                priv->proxy,
 	                                property_info);
+}
+
+static void
+access_point_removed (NMDeviceWifi *self, NMAccessPoint *ap)
+{
+	NMDeviceWifiPrivate *priv = NM_DEVICE_WIFI_GET_PRIVATE (self);
+
+	if (ap == priv->active_ap) {
+		g_object_unref (priv->active_ap);
+		priv->active_ap = NULL;
+		_nm_object_queue_notify (NM_OBJECT (self), NM_DEVICE_WIFI_ACTIVE_ACCESS_POINT);
 
-	_nm_object_register_pseudo_property (NM_OBJECT (device),
-	                                     priv->proxy,
-	                                     "AccessPoints",
-	                                     &priv->aps,
-	                                     NM_TYPE_ACCESS_POINT,
-	                                     access_point_added,
-	                                     access_point_removed);
+		priv->rate = 0;
+		_nm_object_queue_notify (NM_OBJECT (self), NM_DEVICE_WIFI_BITRATE);
+	}
 }
 
 static void
 constructed (GObject *object)
 {
-	NMDeviceWifiPrivate *priv;
+	NMDeviceWifiPrivate *priv = NM_DEVICE_WIFI_GET_PRIVATE (object);
 
 	G_OBJECT_CLASS (nm_device_wifi_parent_class)->constructed (object);
 
-	priv = NM_DEVICE_WIFI_GET_PRIVATE (object);
-
-	priv->proxy = dbus_g_proxy_new_for_name (nm_object_get_connection (NM_OBJECT (object)),
-											NM_DBUS_SERVICE,
-											nm_object_get_path (NM_OBJECT (object)),
-											NM_DBUS_INTERFACE_DEVICE_WIRELESS);
-
+	priv->proxy = _nm_object_new_proxy (NM_OBJECT (object), NULL, NM_DBUS_INTERFACE_DEVICE_WIRELESS);
 	register_properties (NM_DEVICE_WIFI (object));
 
 	g_signal_connect (NM_DEVICE (object),
@@ -727,6 +710,9 @@ nm_device_wifi_class_init (NMDeviceWifiClass *wifi_class)
 	object_class->dispose = dispose;
 	object_class->finalize = finalize;
 	device_class->connection_compatible = connection_compatible;
+	device_class->get_setting_type = get_setting_type;
+	device_class->get_hw_address = get_hw_address;
+	wifi_class->access_point_removed = access_point_removed;
 
 	/* properties */
 
@@ -772,7 +758,7 @@ nm_device_wifi_class_init (NMDeviceWifiClass *wifi_class)
 	/**
 	 * NMDeviceWifi:bitrate:
 	 *
-	 * The bit rate of the device.
+	 * The bit rate of the device in kbit/s.
 	 **/
 	g_object_class_install_property
 		(object_class, PROP_BITRATE,
@@ -808,14 +794,29 @@ nm_device_wifi_class_init (NMDeviceWifiClass *wifi_class)
 		                    0, G_MAXUINT32, 0,
 		                    G_PARAM_READABLE));
 
+	/**
+	 * NMDeviceWifi:access-points:
+	 *
+	 * List of all Wi-Fi access points the device can see.
+	 *
+	 * Since: 0.9.10
+	 **/
+	g_object_class_install_property
+		(object_class, PROP_ACCESS_POINTS,
+		 g_param_spec_boxed (NM_DEVICE_WIFI_ACCESS_POINTS,
+		                     "AccessPoints",
+		                     "Access Points",
+		                     NM_TYPE_OBJECT_ARRAY,
+		                     G_PARAM_READABLE));
+
 	/* signals */
 
 	/**
 	 * NMDeviceWifi::access-point-added:
-	 * @device: the wifi device that received the signal
+	 * @device: the Wi-Fi device that received the signal
 	 * @ap: the new access point
 	 *
-	 * Notifies that a #NMAccessPoint is added to the wifi device.
+	 * Notifies that a #NMAccessPoint is added to the Wi-Fi device.
 	 **/
 	signals[ACCESS_POINT_ADDED] =
 		g_signal_new ("access-point-added",
@@ -829,10 +830,10 @@ nm_device_wifi_class_init (NMDeviceWifiClass *wifi_class)
 
 	/**
 	 * NMDeviceWifi::access-point-removed:
-	 * @device: the wifi device that received the signal
+	 * @device: the Wi-Fi device that received the signal
 	 * @ap: the removed access point
 	 *
-	 * Notifies that a #NMAccessPoint is removed from the wifi device.
+	 * Notifies that a #NMAccessPoint is removed from the Wi-Fi device.
 	 **/
 	signals[ACCESS_POINT_REMOVED] =
 		g_signal_new ("access-point-removed",
diff --git a/libnm-glib/nm-device-wifi.h b/libnm-glib/nm-device-wifi.h
index 76d76b4d..f9b30d92 100644
--- a/libnm-glib/nm-device-wifi.h
+++ b/libnm-glib/nm-device-wifi.h
@@ -67,6 +67,7 @@ GQuark nm_device_wifi_error_quark (void);
 #define NM_DEVICE_WIFI_BITRATE             "bitrate"
 #define NM_DEVICE_WIFI_ACTIVE_ACCESS_POINT "active-access-point"
 #define NM_DEVICE_WIFI_CAPABILITIES        "wireless-capabilities"
+#define NM_DEVICE_WIFI_ACCESS_POINTS       "access-points"
 
 typedef struct {
 	NMDevice parent;
diff --git a/libnm-glib/nm-device-wimax.c b/libnm-glib/nm-device-wimax.c
index 881fce5f..0b052804 100644
--- a/libnm-glib/nm-device-wimax.c
+++ b/libnm-glib/nm-device-wimax.c
@@ -66,25 +66,17 @@ enum {
 	PROP_CINR,
 	PROP_TX_POWER,
 	PROP_BSID,
+	PROP_NSPS,
 
 	LAST_PROP
 };
 
-#define DBUS_PROP_HW_ADDRESS       "HwAddress"
-#define DBUS_PROP_ACTIVE_NSP       "ActiveNsp"
-#define DBUS_PROP_CENTER_FREQUENCY "CenterFrequency"
-#define DBUS_PROP_RSSI             "Rssi"
-#define DBUS_PROP_CINR             "Cinr"
-#define DBUS_PROP_TX_POWER         "TxPower"
-#define DBUS_PROP_BSID             "Bsid"
-
 enum {
 	NSP_ADDED,
 	NSP_REMOVED,
 
 	LAST_SIGNAL
 };
-
 static guint signals[LAST_SIGNAL] = { 0 };
 
 /**
@@ -189,7 +181,7 @@ nm_device_wimax_get_active_nsp (NMDeviceWimax *wimax)
  * Gets all the scanned NSPs of the #NMDeviceWimax.
  *
  * Returns: (element-type NMClient.WimaxNsp): a #GPtrArray containing
- *          all the scanned #NMWimaxNsp<!-- -->s.
+ *          all the scanned #NMWimaxNsps.
  * The returned array is owned by the client and should not be modified.
  **/
 const GPtrArray *
@@ -237,28 +229,6 @@ nm_device_wimax_get_nsp_by_path (NMDeviceWimax *wimax,
 }
 
 static void
-nsp_added (NMObject *self, NMObject *nsp)
-{
-	g_signal_emit (self, signals[NSP_ADDED], 0, nsp);
-}
-
-static void
-nsp_removed (NMObject *self_obj, NMObject *nsp_obj)
-{
-	NMDeviceWimax *self = NM_DEVICE_WIMAX (self_obj);
-	NMDeviceWimaxPrivate *priv = NM_DEVICE_WIMAX_GET_PRIVATE (self);
-	NMWimaxNsp *nsp = NM_WIMAX_NSP (nsp_obj);
-
-	if (nsp == priv->active_nsp) {
-		g_object_unref (priv->active_nsp);
-		priv->active_nsp = NULL;
-		_nm_object_queue_notify (NM_OBJECT (self), NM_DEVICE_WIMAX_ACTIVE_NSP);
-	}
-
-	g_signal_emit (self, signals[NSP_REMOVED], 0, nsp);
-}
-
-static void
 clean_up_nsps (NMDeviceWimax *self, gboolean notify)
 {
 	NMDeviceWimaxPrivate *priv;
@@ -390,8 +360,6 @@ connection_compatible (NMDevice *device, NMConnection *connection, GError **erro
 	const char *hw_str;
 	struct ether_addr *hw_mac;
 
-	g_return_val_if_fail (error == NULL || *error == NULL, FALSE);
-
 	s_con = nm_connection_get_setting_connection (connection);
 	g_assert (s_con);
 
@@ -426,7 +394,19 @@ connection_compatible (NMDevice *device, NMConnection *connection, GError **erro
 		}
 	}
 
-	return TRUE;
+	return NM_DEVICE_CLASS (nm_device_wimax_parent_class)->connection_compatible (device, connection, error);
+}
+
+static GType
+get_setting_type (NMDevice *device)
+{
+	return NM_TYPE_SETTING_WIMAX;
+}
+
+static const char *
+get_hw_address (NMDevice *device)
+{
+	return nm_device_wimax_get_hw_address (NM_DEVICE_WIMAX (device));
 }
 
 /**************************************************************/
@@ -469,6 +449,9 @@ get_property (GObject *object,
 	case PROP_BSID:
 		g_value_set_string (value, nm_device_wimax_get_bsid (self));
 		break;
+	case PROP_NSPS:
+		g_value_set_boxed (value, nm_device_wimax_get_nsps (self));
+		break;
 	default:
 		G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
 		break;
@@ -544,43 +527,42 @@ register_properties (NMDeviceWimax *wimax)
 {
 	NMDeviceWimaxPrivate *priv = NM_DEVICE_WIMAX_GET_PRIVATE (wimax);
 	const NMPropertiesInfo property_info[] = {
-		{ NM_DEVICE_WIMAX_HW_ADDRESS, &priv->hw_address },
-		{ NM_DEVICE_WIMAX_ACTIVE_NSP, &priv->active_nsp, NULL, NM_TYPE_WIMAX_NSP },
+		{ NM_DEVICE_WIMAX_HW_ADDRESS,       &priv->hw_address },
+		{ NM_DEVICE_WIMAX_ACTIVE_NSP,       &priv->active_nsp, NULL, NM_TYPE_WIMAX_NSP },
 		{ NM_DEVICE_WIMAX_CENTER_FREQUENCY, &priv->center_freq },
-		{ NM_DEVICE_WIMAX_RSSI, &priv->rssi },
-		{ NM_DEVICE_WIMAX_CINR, &priv->cinr },
-		{ NM_DEVICE_WIMAX_TX_POWER, &priv->tx_power },
-		{ NM_DEVICE_WIMAX_BSID, &priv->bsid },
+		{ NM_DEVICE_WIMAX_RSSI,             &priv->rssi },
+		{ NM_DEVICE_WIMAX_CINR,             &priv->cinr },
+		{ NM_DEVICE_WIMAX_TX_POWER,         &priv->tx_power },
+		{ NM_DEVICE_WIMAX_BSID,             &priv->bsid },
+		{ NM_DEVICE_WIMAX_NSPS,             &priv->nsps,       NULL, NM_TYPE_WIMAX_NSP, "nsp" },
 		{ NULL },
 	};
 
 	_nm_object_register_properties (NM_OBJECT (wimax),
 	                                priv->proxy,
 	                                property_info);
+}
+
+static void
+nsp_removed (NMDeviceWimax *self, NMWimaxNsp *nsp)
+{
+	NMDeviceWimaxPrivate *priv = NM_DEVICE_WIMAX_GET_PRIVATE (self);
 
-	_nm_object_register_pseudo_property (NM_OBJECT (wimax),
-	                                     priv->proxy,
-	                                     "NspList",
-	                                     &priv->nsps,
-	                                     NM_TYPE_WIMAX_NSP,
-	                                     nsp_added,
-	                                     nsp_removed);
+	if (nsp == priv->active_nsp) {
+		g_object_unref (priv->active_nsp);
+		priv->active_nsp = NULL;
+		_nm_object_queue_notify (NM_OBJECT (self), NM_DEVICE_WIMAX_ACTIVE_NSP);
+	}
 }
 
 static void
 constructed (GObject *object)
 {
-	NMDeviceWimaxPrivate *priv;
+	NMDeviceWimaxPrivate *priv = NM_DEVICE_WIMAX_GET_PRIVATE (object);
 
 	G_OBJECT_CLASS (nm_device_wimax_parent_class)->constructed (object);
 
-	priv = NM_DEVICE_WIMAX_GET_PRIVATE (object);
-
-	priv->proxy = dbus_g_proxy_new_for_name (nm_object_get_connection (NM_OBJECT (object)),
-											 NM_DBUS_SERVICE,
-											 nm_object_get_path (NM_OBJECT (object)),
-											 NM_DBUS_INTERFACE_DEVICE_WIMAX);
-
+	priv->proxy = _nm_object_new_proxy (NM_OBJECT (object), NULL, NM_DBUS_INTERFACE_DEVICE_WIMAX);
 	register_properties (NM_DEVICE_WIMAX (object));
 
 	g_signal_connect (object,
@@ -623,6 +605,9 @@ nm_device_wimax_class_init (NMDeviceWimaxClass *wimax_class)
 	object_class->get_property = get_property;
 	object_class->dispose = dispose;
 	device_class->connection_compatible = connection_compatible;
+	device_class->get_setting_type = get_setting_type;
+	device_class->get_hw_address = get_hw_address;
+	wimax_class->nsp_removed = nsp_removed;
 
 	/* properties */
 
@@ -727,6 +712,21 @@ nm_device_wimax_class_init (NMDeviceWimaxClass *wimax_class)
 		                      NULL,
 		                      G_PARAM_READABLE));
 
+	/**
+	 * NMDeviceWimax:nsps:
+	 *
+	 * List of all WiMAX Network Service Providers the device can see.
+	 *
+	 * Since: 0.9.10
+	 **/
+	g_object_class_install_property
+		(object_class, PROP_NSPS,
+		 g_param_spec_boxed (NM_DEVICE_WIMAX_NSPS,
+		                     "NSPs",
+		                     "Network Service Providers",
+		                     NM_TYPE_OBJECT_ARRAY,
+		                     G_PARAM_READABLE));
+
 	/* signals */
 
 	/**
diff --git a/libnm-glib/nm-device-wimax.h b/libnm-glib/nm-device-wimax.h
index c0550d19..b2282d4f 100644
--- a/libnm-glib/nm-device-wimax.h
+++ b/libnm-glib/nm-device-wimax.h
@@ -62,6 +62,7 @@ GQuark nm_device_wimax_error_quark (void);
 #define NM_DEVICE_WIMAX_CINR             "cinr"
 #define NM_DEVICE_WIMAX_TX_POWER         "tx-power"
 #define NM_DEVICE_WIMAX_BSID             "bsid"
+#define NM_DEVICE_WIMAX_NSPS             "nsps"
 
 typedef struct {
 	NMDevice parent;
diff --git a/libnm-glib/nm-device.c b/libnm-glib/nm-device.c
index 1c4fd736..b328ba3b 100644
--- a/libnm-glib/nm-device.c
+++ b/libnm-glib/nm-device.c
@@ -23,6 +23,7 @@
 
 #include <string.h>
 
+#include <glib/gi18n.h>
 #include <gudev/gudev.h>
 
 #include "NetworkManager.h"
@@ -35,17 +36,20 @@
 #include "nm-device-wimax.h"
 #include "nm-device-infiniband.h"
 #include "nm-device-bond.h"
+#include "nm-device-team.h"
 #include "nm-device-bridge.h"
 #include "nm-device-vlan.h"
+#include "nm-device-generic.h"
 #include "nm-device.h"
 #include "nm-device-private.h"
 #include "nm-object-private.h"
 #include "nm-object-cache.h"
 #include "nm-remote-connection.h"
 #include "nm-types.h"
-#include "nm-glib-marshal.h"
 #include "nm-dbus-glib-types.h"
 #include "nm-glib-compat.h"
+#include "nm-utils.h"
+#include "nm-dbus-helpers-private.h"
 
 static GType _nm_device_type_for_path (DBusGConnection *connection,
                                        const char *path);
@@ -53,6 +57,7 @@ static void _nm_device_type_for_path_async (DBusGConnection *connection,
                                             const char *path,
                                             NMObjectTypeCallbackFunc callback,
                                             gpointer user_data);
+gboolean connection_compatible (NMDevice *device, NMConnection *connection, GError **error);
 
 G_DEFINE_TYPE_WITH_CODE (NMDevice, nm_device, NM_TYPE_OBJECT,
                          _nm_object_register_type_func (g_define_type_id, _nm_device_type_for_path,
@@ -73,6 +78,7 @@ typedef struct {
 	char *driver;
 	char *driver_version;
 	char *firmware_version;
+	char *type_description;
 	NMDeviceCapabilities capabilities;
 	gboolean managed;
 	gboolean firmware_missing;
@@ -89,8 +95,12 @@ typedef struct {
 	GPtrArray *available_connections;
 
 	GUdevClient *client;
-	char *product;
-	char *vendor;
+	char *product, *short_product;
+	char *vendor, *short_vendor;
+	char *description, *bus_name;
+
+	char *physical_port_id;
+	guint32 mtu;
 } NMDevicePrivate;
 
 enum {
@@ -116,6 +126,8 @@ enum {
 	PROP_DEVICE_TYPE,
 	PROP_ACTIVE_CONNECTION,
 	PROP_AVAILABLE_CONNECTIONS,
+	PROP_PHYSICAL_PORT_ID,
+	PROP_MTU,
 
 	LAST_PROP
 };
@@ -128,6 +140,24 @@ enum {
 
 static guint signals[LAST_SIGNAL] = { 0 };
 
+/**
+ * nm_device_error_quark:
+ *
+ * Registers an error quark for #NMDevice if necessary.
+ *
+ * Returns: the error quark used for #NMDevice errors.
+ *
+ * Since: 0.9.10
+ **/
+GQuark
+nm_device_error_quark (void)
+{
+	static GQuark quark = 0;
+
+	if (G_UNLIKELY (quark == 0))
+		quark = g_quark_from_static_string ("nm-device-error-quark");
+	return quark;
+}
 
 static void
 nm_device_init (NMDevice *device)
@@ -178,6 +208,8 @@ register_properties (NMDevice *device)
 		{ NM_DEVICE_STATE_REASON,      &priv->state, demarshal_state_reason },
 		{ NM_DEVICE_ACTIVE_CONNECTION, &priv->active_connection, NULL, NM_TYPE_ACTIVE_CONNECTION },
 		{ NM_DEVICE_AVAILABLE_CONNECTIONS, &priv->available_connections, NULL, NM_TYPE_REMOTE_CONNECTION },
+		{ NM_DEVICE_PHYSICAL_PORT_ID,  &priv->physical_port_id },
+		{ NM_DEVICE_MTU,               &priv->mtu },
 
 		/* Properties that exist in D-Bus but that we don't track */
 		{ "ip4-address", NULL },
@@ -282,10 +314,14 @@ _nm_device_gtype_from_dtype (NMDeviceType dtype)
 		return NM_TYPE_DEVICE_INFINIBAND;
 	case NM_DEVICE_TYPE_BOND:
 		return NM_TYPE_DEVICE_BOND;
+	case NM_DEVICE_TYPE_TEAM:
+		return NM_TYPE_DEVICE_TEAM;
 	case NM_DEVICE_TYPE_BRIDGE:
 		return NM_TYPE_DEVICE_BRIDGE;
 	case NM_DEVICE_TYPE_VLAN:
 		return NM_TYPE_DEVICE_VLAN;
+	case NM_DEVICE_TYPE_GENERIC:
+		return NM_TYPE_DEVICE_GENERIC;
 	default:
 		g_warning ("Unknown device type %d", dtype);
 		return G_TYPE_INVALID;
@@ -305,14 +341,11 @@ constructed (GObject *object)
 	/* Catch a subclass setting the wrong type */
 	g_warn_if_fail (G_OBJECT_TYPE (object) == _nm_device_gtype_from_dtype (priv->device_type));
 
-	priv->proxy = dbus_g_proxy_new_for_name (nm_object_get_connection (NM_OBJECT (object)),
-											 NM_DBUS_SERVICE,
-											 nm_object_get_path (NM_OBJECT (object)),
-											 NM_DBUS_INTERFACE_DEVICE);
+	priv->proxy = _nm_object_new_proxy (NM_OBJECT (object), NULL, NM_DBUS_INTERFACE_DEVICE);
 
 	register_properties (NM_DEVICE (object));
 
-	dbus_g_object_register_marshaller (_nm_glib_marshal_VOID__UINT_UINT_UINT,
+	dbus_g_object_register_marshaller (g_cclosure_marshal_generic,
 									   G_TYPE_NONE,
 									   G_TYPE_UINT, G_TYPE_UINT, G_TYPE_UINT,
 									   G_TYPE_INVALID);
@@ -365,7 +398,13 @@ finalize (GObject *object)
 	g_free (priv->driver_version);
 	g_free (priv->firmware_version);
 	g_free (priv->product);
+	g_free (priv->short_product);
 	g_free (priv->vendor);
+	g_free (priv->short_vendor);
+	g_free (priv->description);
+	g_free (priv->bus_name);
+	g_free (priv->type_description);
+	g_free (priv->physical_port_id);
 
 	G_OBJECT_CLASS (nm_device_parent_class)->finalize (object);
 }
@@ -450,6 +489,12 @@ get_property (GObject *object,
 	case PROP_VENDOR:
 		g_value_set_string (value, nm_device_get_vendor (device));
 		break;
+	case PROP_PHYSICAL_PORT_ID:
+		g_value_set_string (value, nm_device_get_physical_port_id (device));
+		break;
+	case PROP_MTU:
+		g_value_set_uint (value, nm_device_get_mtu (device));
+		break;
 	default:
 		G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
 		break;
@@ -496,6 +541,8 @@ nm_device_class_init (NMDeviceClass *device_class)
 	object_class->dispose = dispose;
 	object_class->finalize = finalize;
 
+	device_class->connection_compatible = connection_compatible;
+
 	/* properties */
 
 	/**
@@ -534,7 +581,7 @@ nm_device_class_init (NMDeviceClass *device_class)
 		(object_class, PROP_DEVICE_TYPE,
 		 g_param_spec_uint (NM_DEVICE_DEVICE_TYPE,
 						  "Device Type",
-						  "Numeric device type (ie ethernet, wifi, etc)",
+						  "Numeric device type (ie Ethernet, Wi-Fi, etc)",
 						  NM_DEVICE_TYPE_UNKNOWN, G_MAXUINT32, NM_DEVICE_TYPE_UNKNOWN,
 						  G_PARAM_READABLE));
 	/**
@@ -779,6 +826,37 @@ nm_device_class_init (NMDeviceClass *device_class)
 						  NULL,
 						  G_PARAM_READABLE));
 
+	/**
+	 * NMDevice:physical-port-id:
+	 *
+	 * The physical port ID of the device. (See
+	 * nm_device_get_physical_port_id().)
+	 *
+	 * Since: 0.9.10
+	 **/
+	g_object_class_install_property
+		(object_class, PROP_PHYSICAL_PORT_ID,
+		 g_param_spec_string (NM_DEVICE_PHYSICAL_PORT_ID,
+		                      "Physical Port ID",
+		                      "Physical port ID",
+		                      NULL,
+		                      G_PARAM_READABLE));
+
+	/**
+	 * NMDevice:mtu:
+	 *
+	 * The MTU of the device.
+	 *
+	 * Since: 0.9.10
+	 **/
+	g_object_class_install_property
+		(object_class, PROP_MTU,
+		 g_param_spec_uint (NM_DEVICE_MTU,
+		                    "MTU",
+		                    "MTU",
+		                    0, G_MAXUINT32, 1500,
+		                    G_PARAM_READABLE));
+
 	/* signals */
 
 	/**
@@ -795,8 +873,7 @@ nm_device_class_init (NMDeviceClass *device_class)
 				    G_OBJECT_CLASS_TYPE (object_class),
 				    G_SIGNAL_RUN_FIRST,
 				    G_STRUCT_OFFSET (NMDeviceClass, state_changed),
-				    NULL, NULL,
-				    _nm_glib_marshal_VOID__UINT_UINT_UINT,
+				    NULL, NULL, NULL,
 				    G_TYPE_NONE, 3,
 				    G_TYPE_UINT, G_TYPE_UINT, G_TYPE_UINT);
 }
@@ -830,27 +907,25 @@ _nm_device_type_for_path (DBusGConnection *connection,
 {
 	DBusGProxy *proxy;
 	GError *err = NULL;
-	GValue value = {0,};
+	GValue value = G_VALUE_INIT;
 	NMDeviceType nm_dtype;
 
-	proxy = dbus_g_proxy_new_for_name (connection,
-									   NM_DBUS_SERVICE,
-									   path,
-									   "org.freedesktop.DBus.Properties");
+	proxy = _nm_dbus_new_proxy_for_connection (connection, path, "org.freedesktop.DBus.Properties");
 	if (!proxy) {
 		g_warning ("%s: couldn't create D-Bus object proxy.", __func__);
 		return G_TYPE_INVALID;
 	}
 
 	if (!dbus_g_proxy_call (proxy,
-						    "Get", &err,
-						    G_TYPE_STRING, NM_DBUS_INTERFACE_DEVICE,
-						    G_TYPE_STRING, "DeviceType",
-						    G_TYPE_INVALID,
-						    G_TYPE_VALUE, &value, G_TYPE_INVALID)) {
-		g_object_unref (proxy);
+	                        "Get", &err,
+	                        G_TYPE_STRING, NM_DBUS_INTERFACE_DEVICE,
+	                        G_TYPE_STRING, "DeviceType",
+	                        G_TYPE_INVALID,
+	                        G_TYPE_VALUE, &value, G_TYPE_INVALID)) {
 		g_warning ("Error in get_property: %s\n", err->message);
 		g_error_free (err);
+		g_object_unref (proxy);
+		return G_TYPE_INVALID;
 	}
 	g_object_unref (proxy);
 
@@ -935,8 +1010,7 @@ _nm_device_type_for_path_async (DBusGConnection *connection,
 	async_data->callback = callback;
 	async_data->user_data = user_data;
 
-	proxy = dbus_g_proxy_new_for_name (connection, NM_DBUS_SERVICE, path,
-	                                   "org.freedesktop.DBus.Properties");
+	proxy = _nm_dbus_new_proxy_for_connection (connection, path, "org.freedesktop.DBus.Properties");
 	dbus_g_proxy_begin_call (proxy, "Get",
 	                         async_got_type, async_data, NULL,
 	                         G_TYPE_STRING, NM_DBUS_INTERFACE_DEVICE,
@@ -985,7 +1059,7 @@ nm_device_get_ip_iface (NMDevice *device)
  * nm_device_get_device_type:
  * @device: a #NMDevice
  *
- * Returns the numeric type of the #NMDevice, ie ethernet, wifi, etc.
+ * Returns the numeric type of the #NMDevice, ie Ethernet, Wi-Fi, etc.
  *
  * Returns: the device type
  **/
@@ -1071,6 +1145,65 @@ nm_device_get_firmware_version (NMDevice *device)
 }
 
 /**
+ * nm_device_get_type_description:
+ * @device: a #NMDevice
+ *
+ * Gets a (non-localized) description of the type of device that
+ * @device is.
+ *
+ * Returns: the type description of the device. This is the internal
+ * string used by the device, and must not be modified.
+ *
+ * Since: 0.9.10
+ **/
+const char *
+nm_device_get_type_description (NMDevice *device)
+{
+	NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE (device);
+	const char *desc, *typename;
+
+	g_return_val_if_fail (NM_IS_DEVICE (device), NULL);
+
+	if (priv->type_description)
+		return priv->type_description;
+
+	if (NM_DEVICE_GET_CLASS (device)->get_type_description) {
+		desc = NM_DEVICE_GET_CLASS (device)->get_type_description (device);
+		if (desc)
+			return desc;
+	}
+
+	typename = G_OBJECT_TYPE_NAME (device);
+	if (g_str_has_prefix (typename, "NMDevice"))
+		typename += 8;
+	priv->type_description = g_ascii_strdown (typename, -1);
+
+	return priv->type_description;
+}
+
+/**
+ * nm_device_get_hw_address:
+ * @device: a #NMDevice
+ *
+ * Gets the current a hardware address (MAC) for the @device.
+ *
+ * Returns: the current MAC of the device, or %NULL.
+ * This is the internal string used by the device, and must not be modified.
+ *
+ * Since: 0.9.10
+ **/
+const char *
+nm_device_get_hw_address (NMDevice *device)
+{
+	g_return_val_if_fail (NM_IS_DEVICE (device), NULL);
+
+	if (NM_DEVICE_GET_CLASS (device)->get_hw_address)
+		return NM_DEVICE_GET_CLASS (device)->get_hw_address (device);
+
+	return NULL;
+}
+
+/**
  * nm_device_get_capabilities:
  * @device: a #NMDevice
  *
@@ -1131,7 +1264,7 @@ nm_device_get_autoconnect (NMDevice *device)
 void
 nm_device_set_autoconnect (NMDevice *device, gboolean autoconnect)
 {
-	GValue value = {0,};
+	GValue value = G_VALUE_INIT;
 
 	g_return_if_fail (NM_IS_DEVICE (device));
 
@@ -1172,6 +1305,10 @@ nm_device_get_firmware_missing (NMDevice *device)
  *
  * Gets the current #NMIP4Config associated with the #NMDevice.
  *
+ * Note that as of NetworkManager 0.9.10, you can alternatively use
+ * nm_active_connection_get_ip4_config(), which also works with VPN
+ * connections.
+ *
  * Returns: (transfer none): the #NMIP4Config or %NULL if the device is not activated.
  **/
 NMIP4Config *
@@ -1189,6 +1326,10 @@ nm_device_get_ip4_config (NMDevice *device)
  *
  * Gets the current #NMDHCP4Config associated with the #NMDevice.
  *
+ * Note that as of NetworkManager 0.9.10, you can alternatively use
+ * nm_active_connection_get_dhcp4_config(), which also works with VPN
+ * connections.
+ *
  * Returns: (transfer none): the #NMDHCP4Config or %NULL if the device is not activated or not
  * using DHCP.
  **/
@@ -1207,6 +1348,10 @@ nm_device_get_dhcp4_config (NMDevice *device)
  *
  * Gets the current #NMIP6Config associated with the #NMDevice.
  *
+ * Note that as of NetworkManager 0.9.10, you can alternatively use
+ * nm_active_connection_get_ip6_config(), which also works with VPN
+ * connections.
+ *
  * Returns: (transfer none): the #NMIP6Config or %NULL if the device is not activated.
  **/
 NMIP6Config *
@@ -1224,6 +1369,10 @@ nm_device_get_ip6_config (NMDevice *device)
  *
  * Gets the current #NMDHCP6Config associated with the #NMDevice.
  *
+ * Note that as of NetworkManager 0.9.10, you can alternatively use
+ * nm_active_connection_get_dhcp6_config(), which also works with VPN
+ * connections.
+ *
  * Returns: (transfer none): the #NMDHCP6Config or %NULL if the device is not activated or not
  * using DHCP.
  **/
@@ -1314,33 +1463,6 @@ nm_device_get_available_connections (NMDevice *device)
 	return handle_ptr_array_return (NM_DEVICE_GET_PRIVATE (device)->available_connections);
 }
 
-/* From hostap, Copyright (c) 2002-2005, Jouni Malinen <jkmaline@cc.hut.fi> */
-
-static int hex2num (char c)
-{
-	if (c >= '0' && c <= '9')
-		return c - '0';
-	if (c >= 'a' && c <= 'f')
-		return c - 'a' + 10;
-	if (c >= 'A' && c <= 'F')
-		return c - 'A' + 10;
-	return -1;
-}
-
-static int hex2byte (const char *hex)
-{
-	int a, b;
-	a = hex2num(*hex++);
-	if (a < 0)
-		return -1;
-	b = hex2num(*hex++);
-	if (b < 0)
-		return -1;
-	return (a << 4) | b;
-}
-
-/* End from hostap */
-
 static char *
 get_decoded_property (GUdevDevice *device, const char *property)
 {
@@ -1356,7 +1478,7 @@ get_decoded_property (GUdevDevice *device, const char *property)
 	n = unescaped = g_malloc0 (len + 1);
 	while (*p) {
 		if ((len >= 4) && (*p == '\\') && (*(p+1) == 'x')) {
-			*n++ = (char) hex2byte (p + 2);
+			*n++ = (char) nm_utils_hex2byte (p + 2);
 			p += 4;
 			len -= 4;
 		} else {
@@ -1368,23 +1490,31 @@ get_decoded_property (GUdevDevice *device, const char *property)
 	return unescaped;
 }
 
+static gboolean
+ensure_udev_client (NMDevice *device)
+{
+	static const char *const subsys[3] = { "net", "tty", NULL };
+	NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE (device);
+
+	if (!priv->client)
+		priv->client = g_udev_client_new (subsys);
+
+	return priv->client != NULL;
+}
+
 static char *
 _get_udev_property (NMDevice *device,
                     const char *enc_prop,  /* ID_XXX_ENC */
                     const char *db_prop)   /* ID_XXX_FROM_DATABASE */
 {
 	NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE (device);
-	const char *subsys[3] = { "net", "tty", NULL };
 	GUdevDevice *udev_device = NULL, *tmpdev, *olddev;
 	const char *ifname;
 	guint32 count = 0;
 	char *enc_value = NULL, *db_value = NULL;
 
-	if (!priv->client) {
-		priv->client = g_udev_client_new (subsys);
-		if (!priv->client)
-			return NULL;
-	}
+	if (!ensure_udev_client (device))
+		return NULL;
 
 	ifname = nm_device_get_iface (device);
 	if (!ifname)
@@ -1424,7 +1554,7 @@ _get_udev_property (NMDevice *device,
 	/* Balance the initial g_udev_client_query_by_subsystem_and_name() */
 	g_object_unref (udev_device);
 
-	/* Prefer the the encoded value which comes directly from the device
+	/* Prefer the encoded value which comes directly from the device
 	 * over the hwdata database value.
 	 */
 	if (enc_value) {
@@ -1487,6 +1617,479 @@ nm_device_get_vendor (NMDevice *device)
 	return priv->vendor;
 }
 
+static const char * const ignored_words[] = {
+	"Semiconductor",
+	"Components",
+	"Corporation",
+	"Communications",
+	"Company",
+	"Corp.",
+	"Corp",
+	"Co.",
+	"Inc.",
+	"Inc",
+	"Incorporated",
+	"Ltd.",
+	"Limited.",
+	"Intel?",
+	"chipset",
+	"adapter",
+	"[hex]",
+	"NDIS",
+	"Module",
+	NULL
+};
+
+static const char * const ignored_phrases[] = {
+	"Multiprotocol MAC/baseband processor",
+	"Wireless LAN Controller",
+	"Wireless LAN Adapter",
+	"Wireless Adapter",
+	"Network Connection",
+	"Wireless Cardbus Adapter",
+	"Wireless CardBus Adapter",
+	"54 Mbps Wireless PC Card",
+	"Wireless PC Card",
+	"Wireless PC",
+	"PC Card with XJACK(r) Antenna",
+	"Wireless cardbus",
+	"Wireless LAN PC Card",
+	"Technology Group Ltd.",
+	"Communication S.p.A.",
+	"Business Mobile Networks BV",
+	"Mobile Broadband Minicard Composite Device",
+	"Mobile Communications AB",
+	"(PC-Suite Mode)",
+	NULL
+};
+
+static char *
+fixup_desc_string (const char *desc)
+{
+	char *p, *temp;
+	char **words, **item;
+	GString *str;
+	int i;
+
+	if (!desc)
+		return NULL;
+
+	p = temp = g_strdup (desc);
+	while (*p) {
+		if (*p == '_' || *p == ',')
+			*p = ' ';
+		p++;
+	}
+
+	/* Attempt to shorten ID by ignoring certain phrases */
+	for (i = 0; ignored_phrases[i]; i++) {
+		p = strstr (temp, ignored_phrases[i]);
+		if (p) {
+			guint32 ignored_len = strlen (ignored_phrases[i]);
+
+			memmove (p, p + ignored_len, strlen (p + ignored_len) + 1); /* +1 for the \0 */
+		}
+	}
+
+	/* Attempt to shorten ID by ignoring certain individual words */
+	words = g_strsplit (temp, " ", 0);
+	str = g_string_new_len (NULL, strlen (temp));
+	g_free (temp);
+
+	for (item = words; *item; item++) {
+		gboolean ignore = FALSE;
+
+		if (**item == '\0')
+			continue;
+
+		for (i = 0; ignored_words[i]; i++) {
+			if (!strcmp (*item, ignored_words[i])) {
+				ignore = TRUE;
+				break;
+			}
+		}
+
+		if (!ignore) {
+			if (str->len)
+				g_string_append_c (str, ' ');
+			g_string_append (str, *item);
+		}
+	}
+	g_strfreev (words);
+
+	temp = str->str;
+	g_string_free (str, FALSE);
+
+	return temp;
+}
+
+static void
+get_description (NMDevice *device)
+{
+	NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE (device);
+	const char *dev_product;
+	const char *dev_vendor;
+	char *pdown;
+	char *vdown;
+	GString *str;
+
+	dev_product = nm_device_get_product (device);
+	priv->short_product = fixup_desc_string (dev_product);
+
+	dev_vendor = nm_device_get_vendor (device);
+	priv->short_vendor = fixup_desc_string (dev_vendor);
+
+	if (!dev_product || !dev_vendor) {
+		priv->description = g_strdup (nm_device_get_iface (device));
+		return;
+	}
+
+	str = g_string_new_len (NULL, strlen (priv->short_vendor) + strlen (priv->short_product) + 1);
+
+	/* Another quick hack; if all of the fixed up vendor string
+	 * is found in product, ignore the vendor.
+	 */
+	pdown = g_ascii_strdown (priv->short_product, -1);
+	vdown = g_ascii_strdown (priv->short_vendor, -1);
+	if (!strstr (pdown, vdown)) {
+		g_string_append (str, priv->short_vendor);
+		g_string_append_c (str, ' ');
+	}
+	g_free (pdown);
+	g_free (vdown);
+
+	g_string_append (str, priv->short_product);
+
+	priv->description = g_string_free (str, FALSE);
+}
+
+static const char *
+get_short_vendor (NMDevice *device)
+{
+	NMDevicePrivate *priv;
+
+	g_return_val_if_fail (NM_IS_DEVICE (device), NULL);
+
+	priv = NM_DEVICE_GET_PRIVATE (device);
+
+	if (!priv->description)
+		get_description (device);
+
+	return priv->short_vendor;
+}
+
+/**
+ * nm_device_get_description:
+ * @device: an #NMDevice
+ *
+ * Gets a description of @device, incorporating the results of
+ * nm_device_get_short_vendor() and nm_device_get_short_product().
+ *
+ * Returns: a description of @device. If either the vendor or the
+ *   product name is unknown, this returns the interface name.
+ *
+ * Since: 0.9.10
+ */
+const char *
+nm_device_get_description (NMDevice *device)
+{
+	NMDevicePrivate *priv;
+
+	g_return_val_if_fail (NM_IS_DEVICE (device), NULL);
+
+	priv = NM_DEVICE_GET_PRIVATE (device);
+
+	if (!priv->description)
+		get_description (device);
+
+	return priv->description;
+}
+
+static const char *
+get_type_name (NMDevice *device)
+{
+	switch (nm_device_get_device_type (device)) {
+	case NM_DEVICE_TYPE_ETHERNET:
+		return _("Ethernet");
+	case NM_DEVICE_TYPE_WIFI:
+		return _("Wi-Fi");
+	case NM_DEVICE_TYPE_BT:
+		return _("Bluetooth");
+	case NM_DEVICE_TYPE_OLPC_MESH:
+		return _("OLPC Mesh");
+	case NM_DEVICE_TYPE_WIMAX:
+		return _("WiMAX");
+	case NM_DEVICE_TYPE_MODEM:
+		return _("Mobile Broadband");
+	case NM_DEVICE_TYPE_INFINIBAND:
+		return _("InfiniBand");
+	case NM_DEVICE_TYPE_BOND:
+		return _("Bond");
+	case NM_DEVICE_TYPE_TEAM:
+		return _("Team");
+	case NM_DEVICE_TYPE_BRIDGE:
+		return _("Bridge");
+	case NM_DEVICE_TYPE_VLAN:
+		return _("VLAN");
+	case NM_DEVICE_TYPE_ADSL:
+		return _("ADSL");
+	default:
+		return _("Unknown");
+	}
+}
+
+static char *
+get_device_type_name_with_iface (NMDevice *device)
+{
+	const char *type_name = get_type_name (device);
+
+	switch (nm_device_get_device_type (device)) {
+	case NM_DEVICE_TYPE_BOND:
+	case NM_DEVICE_TYPE_TEAM:
+	case NM_DEVICE_TYPE_BRIDGE:
+	case NM_DEVICE_TYPE_VLAN:
+		return g_strdup_printf ("%s (%s)", type_name, nm_device_get_iface (device));
+	default:
+		return g_strdup (type_name);
+	}
+}
+
+static char *
+get_device_generic_type_name_with_iface (NMDevice *device)
+{
+	switch (nm_device_get_device_type (device)) {
+	case NM_DEVICE_TYPE_ETHERNET:
+	case NM_DEVICE_TYPE_INFINIBAND:
+		return g_strdup (_("Wired"));
+	default:
+		return get_device_type_name_with_iface (device);
+	}
+}
+
+static const char *
+get_bus_name (NMDevice *device)
+{
+	NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE (device);
+	GUdevDevice *udevice;
+	const char *ifname, *bus;
+
+	if (priv->bus_name)
+		goto out;
+
+	if (!ensure_udev_client (device))
+		return NULL;
+
+	ifname = nm_device_get_iface (device);
+	if (!ifname)
+		return NULL;
+
+	udevice = g_udev_client_query_by_subsystem_and_name (priv->client, "net", ifname);
+	if (!udevice)
+		udevice = g_udev_client_query_by_subsystem_and_name (priv->client, "tty", ifname);
+	if (!udevice)
+		return NULL;
+
+	bus = g_udev_device_get_property (udevice, "ID_BUS");
+	if (!g_strcmp0 (bus, "pci"))
+		priv->bus_name = g_strdup (_("PCI"));
+	else if (!g_strcmp0 (bus, "usb"))
+		priv->bus_name = g_strdup (_("USB"));
+	else {
+		/* Use "" instead of NULL so we can tell later that we've
+		 * already tried.
+		 */
+		priv->bus_name = g_strdup ("");
+	}
+
+out:
+	if (*priv->bus_name)
+		return priv->bus_name;
+	else
+		return NULL;
+}
+
+static gboolean
+find_duplicates (char     **names,
+                 gboolean  *duplicates,
+                 int        num_devices)
+{
+	int i, j;
+	gboolean found_any = FALSE;
+
+	memset (duplicates, 0, num_devices * sizeof (gboolean));
+	for (i = 0; i < num_devices; i++) {
+		if (duplicates[i])
+			continue;
+		for (j = i + 1; j < num_devices; j++) {
+			if (duplicates[j])
+				continue;
+			if (!strcmp (names[i], names[j]))
+				duplicates[i] = duplicates[j] = found_any = TRUE;
+		}
+	}
+
+	return found_any;
+}
+
+/**
+ * nm_device_disambiguate_names:
+ * @devices: (array length=num_devices): an array of #NMDevice
+ * @num_devices: length of @devices
+ *
+ * Generates a list of short-ish unique presentation names for the
+ * devices in @devices.
+ *
+ * Returns: (transfer full) (array zero-terminated=1): the device names
+ *
+ * Since: 0.9.10
+ */
+char **
+nm_device_disambiguate_names (NMDevice **devices,
+                              int        num_devices)
+{
+	char **names;
+	gboolean *duplicates;
+	int i;
+
+	names = g_new (char *, num_devices + 1);
+	duplicates = g_new (gboolean, num_devices);
+
+	/* Generic device name */
+	for (i = 0; i < num_devices; i++)
+		names[i] = get_device_generic_type_name_with_iface (devices[i]);
+	if (!find_duplicates (names, duplicates, num_devices))
+		goto done;
+
+	/* Try specific names (eg, "Ethernet" and "InfiniBand" rather
+	 * than "Wired")
+	 */
+	for (i = 0; i < num_devices; i++) {
+		if (duplicates[i]) {
+			g_free (names[i]);
+			names[i] = get_device_type_name_with_iface (devices[i]);
+		}
+	}
+	if (!find_duplicates (names, duplicates, num_devices))
+		goto done;
+
+	/* Try prefixing bus name (eg, "PCI Ethernet" vs "USB Ethernet") */
+	for (i = 0; i < num_devices; i++) {
+		if (duplicates[i]) {
+			const char *bus = get_bus_name (devices[i]);
+			char *name;
+
+			if (!bus)
+				continue;
+
+			g_free (names[i]);
+			name = get_device_type_name_with_iface (devices[i]);
+			/* Translators: the first %s is a bus name (eg, "USB") or
+			 * product name, the second is a device type (eg,
+			 * "Ethernet"). You can change this to something like
+			 * "%2$s (%1$s)" if there's no grammatical way to combine
+			 * the strings otherwise.
+			 */
+			names[i] = g_strdup_printf (C_("long device name", "%s %s"),
+			                            bus, name);
+			g_free (name);
+		}
+	}
+	if (!find_duplicates (names, duplicates, num_devices))
+		goto done;
+
+	/* Try prefixing vendor name */
+	for (i = 0; i < num_devices; i++) {
+		if (duplicates[i]) {
+			const char *vendor = get_short_vendor (devices[i]);
+			char *name;
+
+			if (!vendor)
+				continue;
+
+			g_free (names[i]);
+			name = get_device_type_name_with_iface (devices[i]);
+			names[i] = g_strdup_printf (C_("long device name", "%s %s"),
+			                            vendor,
+			                            get_type_name (devices[i]));
+			g_free (name);
+		}
+	}
+	if (!find_duplicates (names, duplicates, num_devices))
+		goto done;
+
+	/* We have multiple identical network cards, so we have to differentiate
+	 * them by interface name.
+	 */
+	for (i = 0; i < num_devices; i++) {
+		if (duplicates[i]) {
+			const char *interface = nm_device_get_iface (devices[i]);
+
+			if (!interface)
+				continue;
+
+			g_free (names[i]);
+			names[i] = g_strdup_printf ("%s (%s)",
+			                            get_type_name (devices[i]),
+			                            interface);
+		}
+	}
+
+done:
+	g_free (duplicates);
+	names[num_devices] = NULL;
+	return names;
+}
+
+/**
+ * nm_device_get_physical_port_id:
+ * @device: a #NMDevice
+ *
+ * Gets the physical port ID of the #NMDevice. If non-%NULL, this is
+ * an opaque string that can be used to recognize when
+ * seemingly-unrelated #NMDevices are actually just different virtual
+ * ports on a single physical port. (Eg, NPAR / SR-IOV.)
+ *
+ * Returns: the physical port ID of the device, or %NULL if the port
+ *   ID is unknown. This is the internal string used by the device and
+ *   must not be modified.
+ *
+ * Since: 0.9.10
+ **/
+const char *
+nm_device_get_physical_port_id (NMDevice *device)
+{
+	NMDevicePrivate *priv;
+
+	g_return_val_if_fail (NM_IS_DEVICE (device), NULL);
+
+	priv = NM_DEVICE_GET_PRIVATE (device);
+
+	_nm_object_ensure_inited (NM_OBJECT (device));
+	if (priv->physical_port_id && *priv->physical_port_id)
+		return priv->physical_port_id;
+	else
+		return NULL;
+}
+
+/**
+ * nm_device_get_mtu:
+ * @device: a #NMDevice
+ *
+ * Gets the  MTU of the #NMDevice.
+ *
+ * Returns: the MTU of the device.
+ *
+ * Since: 0.9.10
+ **/
+guint32
+nm_device_get_mtu (NMDevice *device)
+{
+	g_return_val_if_fail (NM_IS_DEVICE (device), 0);
+
+	_nm_object_ensure_inited (NM_OBJECT (device));
+	return NM_DEVICE_GET_PRIVATE (device)->mtu;
+}
+
 typedef struct {
 	NMDevice *device;
 	NMDeviceDeactivateFn fn;
@@ -1555,8 +2158,8 @@ nm_device_disconnect (NMDevice *device,
  *
  * Validates a given connection for a given #NMDevice object and returns
  * whether the connection may be activated with the device. For example if
- * @device is a WiFi device that supports only WEP encryption, the connection
- * will only be valid if it is a WiFi connection which describes a WEP or open
+ * @device is a Wi-Fi device that supports only WEP encryption, the connection
+ * will only be valid if it is a Wi-Fi connection which describes a WEP or open
  * network, and will not be valid if it describes a WPA network, or if it is
  * an Ethernet, Bluetooth, WWAN, etc connection that is incompatible with the
  * device.
@@ -1570,6 +2173,26 @@ nm_device_connection_valid (NMDevice *device, NMConnection *connection)
 	return nm_device_connection_compatible (device, connection, NULL);
 }
 
+gboolean
+connection_compatible (NMDevice *device, NMConnection *connection, GError **error)
+{
+	NMSettingConnection *s_con;
+	const char *config_iface, *device_iface;
+
+	s_con = nm_connection_get_setting_connection (connection);
+	g_assert (s_con);
+
+	config_iface = nm_setting_connection_get_interface_name (s_con);
+	device_iface = nm_device_get_iface (device);
+	if (config_iface && g_strcmp0 (config_iface, device_iface) != 0) {
+		g_set_error (error, NM_DEVICE_ERROR, NM_DEVICE_ERROR_INTERFACE_MISMATCH,
+					 "The interface names of the device and the connection didn't match.");
+		return FALSE;
+	}
+
+	return TRUE;
+}
+
 /**
  * nm_device_connection_compatible:
  * @device: an #NMDevice to validate @connection against
@@ -1578,8 +2201,8 @@ nm_device_connection_valid (NMDevice *device, NMConnection *connection)
  *
  * Validates a given connection for a given #NMDevice object and returns
  * whether the connection may be activated with the device. For example if
- * @device is a WiFi device that supports only WEP encryption, the connection
- * will only be valid if it is a WiFi connection which describes a WEP or open
+ * @device is a Wi-Fi device that supports only WEP encryption, the connection
+ * will only be valid if it is a Wi-Fi connection which describes a WEP or open
  * network, and will not be valid if it describes a WPA network, or if it is
  * an Ethernet, Bluetooth, WWAN, etc connection that is incompatible with the
  * device.
@@ -1594,9 +2217,11 @@ nm_device_connection_valid (NMDevice *device, NMConnection *connection)
 gboolean
 nm_device_connection_compatible (NMDevice *device, NMConnection *connection, GError **error)
 {
-	if (NM_DEVICE_GET_CLASS (device)->connection_compatible)
-		return NM_DEVICE_GET_CLASS (device)->connection_compatible (device, connection, error);
-	return FALSE;
+	g_return_val_if_fail (NM_IS_DEVICE (device), FALSE);
+	g_return_val_if_fail (NM_IS_CONNECTION (connection), FALSE);
+	g_return_val_if_fail (error == NULL || *error == NULL, FALSE);
+
+	return NM_DEVICE_GET_CLASS (device)->connection_compatible (device, connection, error);
 }
 
 /**
@@ -1606,10 +2231,10 @@ nm_device_connection_compatible (NMDevice *device, NMConnection *connection, GEr
  *
  * Filters a given list of connections for a given #NMDevice object and return
  * connections which may be activated with the device. For example if @device
- * is a WiFi device that supports only WEP encryption, the returned list will
- * contain any WiFi connections in @connections that allow connection to
+ * is a Wi-Fi device that supports only WEP encryption, the returned list will
+ * contain any Wi-Fi connections in @connections that allow connection to
  * unencrypted or WEP-enabled SSIDs.  The returned list will not contain
- * Ethernet, Bluetooth, WiFi WPA connections, or any other connection that is
+ * Ethernet, Bluetooth, Wi-Fi WPA connections, or any other connection that is
  * incompatible with the device. To get the full list of connections see
  * nm_remote_settings_list_connections().
  *
@@ -1636,3 +2261,22 @@ nm_device_filter_connections (NMDevice *device, const GSList *connections)
 	return g_slist_reverse (filtered);
 }
 
+/**
+ * nm_device_get_setting_type:
+ * @device: an #NMDevice
+ *
+ * Gets the (primary) #NMSetting subtype associated with connections
+ * that can be used on @device.
+ *
+ * Returns: @device's associated #NMSetting type
+ *
+ * Since: 0.9.10
+ */
+GType
+nm_device_get_setting_type (NMDevice *device)
+{
+	g_return_val_if_fail (NM_IS_DEVICE (device), G_TYPE_INVALID);
+	g_return_val_if_fail (NM_DEVICE_GET_CLASS (device)->get_setting_type != NULL, G_TYPE_INVALID);
+
+	return NM_DEVICE_GET_CLASS (device)->get_setting_type (device);
+}
diff --git a/libnm-glib/nm-device.h b/libnm-glib/nm-device.h
index c49675bc..ed0f6876 100644
--- a/libnm-glib/nm-device.h
+++ b/libnm-glib/nm-device.h
@@ -18,7 +18,7 @@
  * Boston, MA 02110-1301 USA.
  *
  * Copyright (C) 2007 - 2008 Novell, Inc.
- * Copyright (C) 2007 - 2012 Red Hat, Inc.
+ * Copyright (C) 2007 - 2013 Red Hat, Inc.
  */
 
 #ifndef NM_DEVICE_H
@@ -45,6 +45,21 @@ 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))
 
+/**
+ * NMDeviceError:
+ * @NM_DEVICE_ERROR_UNKNOWN: unknown or unclassified error
+ * @NM_DEVICE_ERROR_INTERFACE_MISMATCH: the interface names of the connection and the
+ *   device mismatched
+ */
+typedef enum {
+	NM_DEVICE_ERROR_UNKNOWN = 0,        /*< nick=UnknownError >*/
+	NM_DEVICE_ERROR_INTERFACE_MISMATCH, /*< nick=InterfaceMismatch >*/
+} NMDeviceError;
+
+#define NM_DEVICE_ERROR nm_device_error_quark ()
+NM_AVAILABLE_IN_0_9_10
+GQuark nm_device_error_quark (void);
+
 #define NM_DEVICE_DEVICE_TYPE "device-type"
 #define NM_DEVICE_UDI "udi"
 #define NM_DEVICE_INTERFACE "interface"
@@ -66,6 +81,8 @@ G_BEGIN_DECLS
 #define NM_DEVICE_AVAILABLE_CONNECTIONS "available-connections"
 #define NM_DEVICE_VENDOR "vendor"
 #define NM_DEVICE_PRODUCT "product"
+#define NM_DEVICE_PHYSICAL_PORT_ID "physical-port-id"
+#define NM_DEVICE_MTU "mtu"
 
 typedef struct {
 	NMObject parent;
@@ -84,13 +101,15 @@ typedef struct {
 	                                   NMConnection *connection,
 	                                   GError **error);
 
+	const char * (*get_type_description) (NMDevice *device);
+	const char * (*get_hw_address) (NMDevice *device);
+
+	GType (*get_setting_type) (NMDevice *device);
+
 	/* Padding for future expansion */
 	void (*_reserved1) (void);
 	void (*_reserved2) (void);
 	void (*_reserved3) (void);
-	void (*_reserved4) (void);
-	void (*_reserved5) (void);
-	void (*_reserved6) (void);
 } NMDeviceClass;
 
 GType nm_device_get_type (void);
@@ -104,6 +123,10 @@ const char *         nm_device_get_udi              (NMDevice *device);
 const char *         nm_device_get_driver           (NMDevice *device);
 const char *         nm_device_get_driver_version   (NMDevice *device);
 const char *         nm_device_get_firmware_version (NMDevice *device);
+NM_AVAILABLE_IN_0_9_10
+const char *         nm_device_get_type_description (NMDevice *device);
+NM_AVAILABLE_IN_0_9_10
+const char *         nm_device_get_hw_address       (NMDevice *device);
 NMDeviceCapabilities nm_device_get_capabilities     (NMDevice *device);
 gboolean             nm_device_get_managed          (NMDevice *device);
 gboolean             nm_device_get_autoconnect      (NMDevice *device);
@@ -117,8 +140,18 @@ NMDeviceState        nm_device_get_state            (NMDevice *device);
 NMDeviceState        nm_device_get_state_reason     (NMDevice *device, NMDeviceStateReason *reason);
 NMActiveConnection * nm_device_get_active_connection(NMDevice *device);
 const GPtrArray *    nm_device_get_available_connections(NMDevice *device);
-const char *         nm_device_get_product          (NMDevice *device);
-const char *         nm_device_get_vendor           (NMDevice *device);
+NM_AVAILABLE_IN_0_9_10
+const char *         nm_device_get_physical_port_id (NMDevice *device);
+NM_AVAILABLE_IN_0_9_10
+guint32              nm_device_get_mtu              (NMDevice *device);
+
+const char *         nm_device_get_product           (NMDevice  *device);
+const char *         nm_device_get_vendor            (NMDevice  *device);
+NM_AVAILABLE_IN_0_9_10
+const char *         nm_device_get_description       (NMDevice  *device);
+NM_AVAILABLE_IN_0_9_10
+char **              nm_device_disambiguate_names    (NMDevice **devices,
+                                                      int        num_devices);
 
 typedef void (*NMDeviceDeactivateFn) (NMDevice *device, GError *error, gpointer user_data);
 
@@ -136,6 +169,9 @@ gboolean             nm_device_connection_compatible (NMDevice *device,
                                                       NMConnection *connection,
                                                       GError **error);
 
+NM_AVAILABLE_IN_0_9_10
+GType                nm_device_get_setting_type     (NMDevice *device);
+
 G_END_DECLS
 
 #endif /* NM_DEVICE_H */
diff --git a/libnm-glib/nm-dhcp4-config.c b/libnm-glib/nm-dhcp4-config.c
index b8d7dcdd..a861d982 100644
--- a/libnm-glib/nm-dhcp4-config.c
+++ b/libnm-glib/nm-dhcp4-config.c
@@ -51,26 +51,23 @@ nm_dhcp4_config_init (NMDHCP4Config *config)
 {
 }
 
-static void
-copy_options (gpointer key, gpointer data, gpointer user_data)
-{
-	GHashTable *options = (GHashTable *) user_data;
-	GValue *value = (GValue *) data;
-
-	g_hash_table_insert (options, g_strdup (key), g_value_dup_string (value));
-}
-
 static gboolean
 demarshal_dhcp4_options (NMObject *object, GParamSpec *pspec, GValue *value, gpointer field)
 {
 	NMDHCP4ConfigPrivate *priv = NM_DHCP4_CONFIG_GET_PRIVATE (object);
 	GHashTable *new_options;
+	GHashTableIter iter;
+	const char *key;
+	GValue *opt;
 
 	g_hash_table_remove_all (priv->options);
 
 	new_options = g_value_get_boxed (value);
-	if (new_options)
-		g_hash_table_foreach (new_options, copy_options, priv->options);
+	if (new_options) {
+		g_hash_table_iter_init (&iter, new_options);
+		while (g_hash_table_iter_next (&iter, (gpointer) &key, (gpointer) &opt))
+			g_hash_table_insert (priv->options, g_strdup (key), g_value_dup_string (opt));
+	}
 
 	_nm_object_queue_notify (object, NM_DHCP4_CONFIG_OPTIONS);
 	return TRUE;
@@ -93,21 +90,13 @@ register_properties (NMDHCP4Config *config)
 static void
 constructed (GObject *object)
 {
-	DBusGConnection *connection;
-	NMDHCP4ConfigPrivate *priv;
+	NMDHCP4ConfigPrivate *priv = NM_DHCP4_CONFIG_GET_PRIVATE (object);
 
 	G_OBJECT_CLASS (nm_dhcp4_config_parent_class)->constructed (object);
 
-	priv = NM_DHCP4_CONFIG_GET_PRIVATE (object);
 	priv->options = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, g_free);
 
-	connection = nm_object_get_connection (NM_OBJECT (object));
-
-	priv->proxy = dbus_g_proxy_new_for_name (connection,
-										   NM_DBUS_SERVICE,
-										   nm_object_get_path (NM_OBJECT (object)),
-										   NM_DBUS_INTERFACE_DHCP4_CONFIG);
-
+	priv->proxy = _nm_object_new_proxy (NM_OBJECT (object), NULL, NM_DBUS_INTERFACE_DHCP4_CONFIG);
 	register_properties (NM_DHCP4_CONFIG (object));
 }
 
diff --git a/libnm-glib/nm-dhcp6-config.c b/libnm-glib/nm-dhcp6-config.c
index fd1e6526..ef6006b0 100644
--- a/libnm-glib/nm-dhcp6-config.c
+++ b/libnm-glib/nm-dhcp6-config.c
@@ -51,26 +51,23 @@ nm_dhcp6_config_init (NMDHCP6Config *config)
 {
 }
 
-static void
-copy_options (gpointer key, gpointer data, gpointer user_data)
-{
-	GHashTable *options = (GHashTable *) user_data;
-	GValue *value = (GValue *) data;
-
-	g_hash_table_insert (options, g_strdup (key), g_value_dup_string (value));
-}
-
 static gboolean
 demarshal_dhcp6_options (NMObject *object, GParamSpec *pspec, GValue *value, gpointer field)
 {
 	NMDHCP6ConfigPrivate *priv = NM_DHCP6_CONFIG_GET_PRIVATE (object);
 	GHashTable *new_options;
+	GHashTableIter iter;
+	const char *key;
+	GValue *opt;
 
 	g_hash_table_remove_all (priv->options);
 
 	new_options = g_value_get_boxed (value);
-	if (new_options)
-		g_hash_table_foreach (new_options, copy_options, priv->options);
+	if (new_options) {
+		g_hash_table_iter_init (&iter, new_options);
+		while (g_hash_table_iter_next (&iter, (gpointer) &key, (gpointer) &opt))
+			g_hash_table_insert (priv->options, g_strdup (key), g_value_dup_string (opt));
+	}
 
 	_nm_object_queue_notify (object, NM_DHCP6_CONFIG_OPTIONS);
 	return TRUE;
@@ -93,21 +90,13 @@ register_properties (NMDHCP6Config *config)
 static void
 constructed (GObject *object)
 {
-	DBusGConnection *connection;
-	NMDHCP6ConfigPrivate *priv;
+	NMDHCP6ConfigPrivate *priv = NM_DHCP6_CONFIG_GET_PRIVATE (object);
 
 	G_OBJECT_CLASS (nm_dhcp6_config_parent_class)->constructed (object);
 
-	priv = NM_DHCP6_CONFIG_GET_PRIVATE (object);
 	priv->options = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, g_free);
 
-	connection = nm_object_get_connection (NM_OBJECT (object));
-
-	priv->proxy = dbus_g_proxy_new_for_name (connection,
-										   NM_DBUS_SERVICE,
-										   nm_object_get_path (NM_OBJECT (object)),
-										   NM_DBUS_INTERFACE_DHCP6_CONFIG);
-
+	priv->proxy = _nm_object_new_proxy (NM_OBJECT (object), NULL, NM_DBUS_INTERFACE_DHCP6_CONFIG);
 	register_properties (NM_DHCP6_CONFIG (object));
 }
 
diff --git a/libnm-glib/nm-glib-enum-types.c b/libnm-glib/nm-glib-enum-types.c
index c2e92bee..8e8b0ff9 100644
--- a/libnm-glib/nm-glib-enum-types.c
+++ b/libnm-glib/nm-glib-enum-types.c
@@ -15,8 +15,10 @@
 #include "nm-device-bt.h" 
 #include "nm-device-olpc-mesh.h" 
 #include "nm-device-bond.h" 
+#include "nm-device-team.h" 
 #include "nm-device-bridge.h" 
 #include "nm-device-vlan.h" 
+#include "nm-device-generic.h" 
 #include "nm-access-point.h" 
 #include "nm-ip4-config.h" 
 #include "nm-device-modem.h" 
@@ -103,6 +105,44 @@ nm_client_permission_result_get_type (void)
   return g_define_type_id__volatile;
 }
 GType
+nm_client_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_CLIENT_ERROR_UNKNOWN, "NM_CLIENT_ERROR_UNKNOWN", "UnknownError" },
+        { NM_CLIENT_ERROR_MANAGER_NOT_RUNNING, "NM_CLIENT_ERROR_MANAGER_NOT_RUNNING", "ManagerNotRunning" },
+        { 0, NULL, NULL }
+      };
+      GType g_define_type_id =
+        g_enum_register_static (g_intern_static_string ("NMClientError"), 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_UNKNOWN, "NM_DEVICE_ERROR_UNKNOWN", "UnknownError" },
+        { NM_DEVICE_ERROR_INTERFACE_MISMATCH, "NM_DEVICE_ERROR_INTERFACE_MISMATCH", "InterfaceMismatch" },
+        { 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_device_ethernet_error_get_type (void)
 {
   static volatile gsize g_define_type_id__volatile = 0;
@@ -255,6 +295,27 @@ nm_device_bond_error_get_type (void)
   return g_define_type_id__volatile;
 }
 GType
+nm_device_team_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_TEAM_ERROR_UNKNOWN, "NM_DEVICE_TEAM_ERROR_UNKNOWN", "UnknownError" },
+        { NM_DEVICE_TEAM_ERROR_NOT_TEAM_CONNECTION, "NM_DEVICE_TEAM_ERROR_NOT_TEAM_CONNECTION", "NotTeamConnection" },
+        { NM_DEVICE_TEAM_ERROR_INVALID_TEAM_CONNECTION, "NM_DEVICE_TEAM_ERROR_INVALID_TEAM_CONNECTION", "InvalidTeamConnection" },
+        { NM_DEVICE_TEAM_ERROR_INTERFACE_MISMATCH, "NM_DEVICE_TEAM_ERROR_INTERFACE_MISMATCH", "InterfaceMismatch" },
+        { 0, NULL, NULL }
+      };
+      GType g_define_type_id =
+        g_enum_register_static (g_intern_static_string ("NMDeviceTeamError"), values);
+      g_once_init_leave (&g_define_type_id__volatile, g_define_type_id);
+    }
+
+  return g_define_type_id__volatile;
+}
+GType
 nm_device_bridge_error_get_type (void)
 {
   static volatile gsize g_define_type_id__volatile = 0;
@@ -288,6 +349,7 @@ nm_device_vlan_error_get_type (void)
         { NM_DEVICE_VLAN_ERROR_INVALID_VLAN_CONNECTION, "NM_DEVICE_VLAN_ERROR_INVALID_VLAN_CONNECTION", "InvalidVlanConnection" },
         { NM_DEVICE_VLAN_ERROR_ID_MISMATCH, "NM_DEVICE_VLAN_ERROR_ID_MISMATCH", "IdMismatch" },
         { NM_DEVICE_VLAN_ERROR_INTERFACE_MISMATCH, "NM_DEVICE_VLAN_ERROR_INTERFACE_MISMATCH", "InterfaceMismatch" },
+        { NM_DEVICE_VLAN_ERROR_MAC_MISMATCH, "NM_DEVICE_VLAN_ERROR_MAC_MISMATCH", "MacMismatch" },
         { 0, NULL, NULL }
       };
       GType g_define_type_id =
@@ -298,6 +360,26 @@ nm_device_vlan_error_get_type (void)
   return g_define_type_id__volatile;
 }
 GType
+nm_device_generic_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_GENERIC_ERROR_UNKNOWN, "NM_DEVICE_GENERIC_ERROR_UNKNOWN", "UnknownError" },
+        { NM_DEVICE_GENERIC_ERROR_NOT_GENERIC_CONNECTION, "NM_DEVICE_GENERIC_ERROR_NOT_GENERIC_CONNECTION", "NotGenericConnection" },
+        { NM_DEVICE_GENERIC_ERROR_MISSING_INTERFACE_NAME, "NM_DEVICE_GENERIC_ERROR_MISSING_INTERFACE_NAME", "MissingInterfaceName" },
+        { 0, NULL, NULL }
+      };
+      GType g_define_type_id =
+        g_enum_register_static (g_intern_static_string ("NMDeviceGenericError"), values);
+      g_once_init_leave (&g_define_type_id__volatile, g_define_type_id);
+    }
+
+  return g_define_type_id__volatile;
+}
+GType
 nm_device_modem_error_get_type (void)
 {
   static volatile gsize g_define_type_id__volatile = 0;
@@ -319,6 +401,25 @@ nm_device_modem_error_get_type (void)
   return g_define_type_id__volatile;
 }
 GType
+nm_remote_connection_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_REMOTE_CONNECTION_ERROR_UNKNOWN, "NM_REMOTE_CONNECTION_ERROR_UNKNOWN", "UnknownError" },
+        { NM_REMOTE_CONNECTION_ERROR_DISCONNECTED, "NM_REMOTE_CONNECTION_ERROR_DISCONNECTED", "Disconnected" },
+        { 0, NULL, NULL }
+      };
+      GType g_define_type_id =
+        g_enum_register_static (g_intern_static_string ("NMRemoteConnectionError"), values);
+      g_once_init_leave (&g_define_type_id__volatile, g_define_type_id);
+    }
+
+  return g_define_type_id__volatile;
+}
+GType
 nm_remote_settings_error_get_type (void)
 {
   static volatile gsize g_define_type_id__volatile = 0;
@@ -329,6 +430,7 @@ nm_remote_settings_error_get_type (void)
         { NM_REMOTE_SETTINGS_ERROR_UNKNOWN, "NM_REMOTE_SETTINGS_ERROR_UNKNOWN", "UnknownError" },
         { NM_REMOTE_SETTINGS_ERROR_CONNECTION_REMOVED, "NM_REMOTE_SETTINGS_ERROR_CONNECTION_REMOVED", "ConnectionRemoved" },
         { NM_REMOTE_SETTINGS_ERROR_CONNECTION_UNAVAILABLE, "NM_REMOTE_SETTINGS_ERROR_CONNECTION_UNAVAILABLE", "ConnectionUnavailable" },
+        { NM_REMOTE_SETTINGS_ERROR_SERVICE_UNAVAILABLE, "NM_REMOTE_SETTINGS_ERROR_SERVICE_UNAVAILABLE", "ServiceUnavailable" },
         { 0, NULL, NULL }
       };
       GType g_define_type_id =
@@ -362,6 +464,26 @@ nm_secret_agent_error_get_type (void)
   return g_define_type_id__volatile;
 }
 GType
+nm_secret_agent_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 GFlagsValue values[] = {
+        { NM_SECRET_AGENT_CAPABILITY_NONE, "NM_SECRET_AGENT_CAPABILITY_NONE", "none" },
+        { NM_SECRET_AGENT_CAPABILITY_VPN_HINTS, "NM_SECRET_AGENT_CAPABILITY_VPN_HINTS", "vpn-hints" },
+        { NM_SECRET_AGENT_CAPABILITY_LAST, "NM_SECRET_AGENT_CAPABILITY_LAST", "last" },
+        { 0, NULL, NULL }
+      };
+      GType g_define_type_id =
+        g_flags_register_static (g_intern_static_string ("NMSecretAgentCapabilities"), values);
+      g_once_init_leave (&g_define_type_id__volatile, g_define_type_id);
+    }
+
+  return g_define_type_id__volatile;
+}
+GType
 nm_secret_agent_get_secrets_flags_get_type (void)
 {
   static volatile gsize g_define_type_id__volatile = 0;
diff --git a/libnm-glib/nm-glib-enum-types.h b/libnm-glib/nm-glib-enum-types.h
index f33db002..9353d381 100644
--- a/libnm-glib/nm-glib-enum-types.h
+++ b/libnm-glib/nm-glib-enum-types.h
@@ -15,6 +15,10 @@ GType nm_client_permission_get_type (void) G_GNUC_CONST;
 #define NM_TYPE_CLIENT_PERMISSION (nm_client_permission_get_type ())
 GType nm_client_permission_result_get_type (void) G_GNUC_CONST;
 #define NM_TYPE_CLIENT_PERMISSION_RESULT (nm_client_permission_result_get_type ())
+GType nm_client_error_get_type (void) G_GNUC_CONST;
+#define NM_TYPE_CLIENT_ERROR (nm_client_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_device_ethernet_error_get_type (void) G_GNUC_CONST;
 #define NM_TYPE_DEVICE_ETHERNET_ERROR (nm_device_ethernet_error_get_type ())
 GType nm_device_infiniband_error_get_type (void) G_GNUC_CONST;
@@ -29,16 +33,24 @@ GType nm_device_olpc_mesh_error_get_type (void) G_GNUC_CONST;
 #define NM_TYPE_DEVICE_OLPC_MESH_ERROR (nm_device_olpc_mesh_error_get_type ())
 GType nm_device_bond_error_get_type (void) G_GNUC_CONST;
 #define NM_TYPE_DEVICE_BOND_ERROR (nm_device_bond_error_get_type ())
+GType nm_device_team_error_get_type (void) G_GNUC_CONST;
+#define NM_TYPE_DEVICE_TEAM_ERROR (nm_device_team_error_get_type ())
 GType nm_device_bridge_error_get_type (void) G_GNUC_CONST;
 #define NM_TYPE_DEVICE_BRIDGE_ERROR (nm_device_bridge_error_get_type ())
 GType nm_device_vlan_error_get_type (void) G_GNUC_CONST;
 #define NM_TYPE_DEVICE_VLAN_ERROR (nm_device_vlan_error_get_type ())
+GType nm_device_generic_error_get_type (void) G_GNUC_CONST;
+#define NM_TYPE_DEVICE_GENERIC_ERROR (nm_device_generic_error_get_type ())
 GType nm_device_modem_error_get_type (void) G_GNUC_CONST;
 #define NM_TYPE_DEVICE_MODEM_ERROR (nm_device_modem_error_get_type ())
+GType nm_remote_connection_error_get_type (void) G_GNUC_CONST;
+#define NM_TYPE_REMOTE_CONNECTION_ERROR (nm_remote_connection_error_get_type ())
 GType nm_remote_settings_error_get_type (void) G_GNUC_CONST;
 #define NM_TYPE_REMOTE_SETTINGS_ERROR (nm_remote_settings_error_get_type ())
 GType nm_secret_agent_error_get_type (void) G_GNUC_CONST;
 #define NM_TYPE_SECRET_AGENT_ERROR (nm_secret_agent_error_get_type ())
+GType nm_secret_agent_capabilities_get_type (void) G_GNUC_CONST;
+#define NM_TYPE_SECRET_AGENT_CAPABILITIES (nm_secret_agent_capabilities_get_type ())
 GType nm_secret_agent_get_secrets_flags_get_type (void) G_GNUC_CONST;
 #define NM_TYPE_SECRET_AGENT_GET_SECRETS_FLAGS (nm_secret_agent_get_secrets_flags_get_type ())
 GType nm_device_wimax_error_get_type (void) G_GNUC_CONST;
diff --git a/libnm-glib/nm-glib-marshal.c b/libnm-glib/nm-glib-marshal.c
deleted file mode 100644
index 4f4e4c86..00000000
--- a/libnm-glib/nm-glib-marshal.c
+++ /dev/null
@@ -1,204 +0,0 @@
-#include "nm-glib-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_schar (v)
-#define g_marshal_value_peek_uchar(v)    g_value_get_uchar (v)
-#define g_marshal_value_peek_int(v)      g_value_get_int (v)
-#define g_marshal_value_peek_uint(v)     g_value_get_uint (v)
-#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 */
-
-
-/* VOID:POINTER,POINTER (nm-glib-marshal.list:1) */
-void
-_nm_glib_marshal_VOID__POINTER_POINTER (GClosure     *closure,
-                                        GValue       *return_value G_GNUC_UNUSED,
-                                        guint         n_param_values,
-                                        const GValue *param_values,
-                                        gpointer      invocation_hint G_GNUC_UNUSED,
-                                        gpointer      marshal_data)
-{
-  typedef void (*GMarshalFunc_VOID__POINTER_POINTER) (gpointer     data1,
-                                                      gpointer     arg_1,
-                                                      gpointer     arg_2,
-                                                      gpointer     data2);
-  register GMarshalFunc_VOID__POINTER_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__POINTER_POINTER) (marshal_data ? marshal_data : cc->callback);
-
-  callback (data1,
-            g_marshal_value_peek_pointer (param_values + 1),
-            g_marshal_value_peek_pointer (param_values + 2),
-            data2);
-}
-
-/* VOID:STRING,STRING,STRING (nm-glib-marshal.list:2) */
-void
-_nm_glib_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:UINT,UINT (nm-glib-marshal.list:3) */
-void
-_nm_glib_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-glib-marshal.list:4) */
-void
-_nm_glib_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/libnm-glib/nm-glib-marshal.h b/libnm-glib/nm-glib-marshal.h
deleted file mode 100644
index 01a96a87..00000000
--- a/libnm-glib/nm-glib-marshal.h
+++ /dev/null
@@ -1,44 +0,0 @@
-
-#ifndef ___nm_glib_marshal_MARSHAL_H__
-#define ___nm_glib_marshal_MARSHAL_H__
-
-#include	<glib-object.h>
-
-G_BEGIN_DECLS
-
-/* VOID:POINTER,POINTER (nm-glib-marshal.list:1) */
-extern void _nm_glib_marshal_VOID__POINTER_POINTER (GClosure     *closure,
-                                                    GValue       *return_value,
-                                                    guint         n_param_values,
-                                                    const GValue *param_values,
-                                                    gpointer      invocation_hint,
-                                                    gpointer      marshal_data);
-
-/* VOID:STRING,STRING,STRING (nm-glib-marshal.list:2) */
-extern void _nm_glib_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:UINT,UINT (nm-glib-marshal.list:3) */
-extern void _nm_glib_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-glib-marshal.list:4) */
-extern void _nm_glib_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_glib_marshal_MARSHAL_H__ */
-
diff --git a/libnm-glib/nm-ip4-config.c b/libnm-glib/nm-ip4-config.c
index 80751c31..ec523a03 100644
--- a/libnm-glib/nm-ip4-config.c
+++ b/libnm-glib/nm-ip4-config.c
@@ -37,19 +37,23 @@ G_DEFINE_TYPE (NMIP4Config, nm_ip4_config, NM_TYPE_OBJECT)
 typedef struct {
 	DBusGProxy *proxy;
 
+	char *gateway;
 	GSList *addresses;
+	GSList *routes;
 	GArray *nameservers;
 	GPtrArray *domains;
-	GSList *routes;
+	GPtrArray *searches;
 	GArray *wins;
 } NMIP4ConfigPrivate;
 
 enum {
 	PROP_0,
+	PROP_GATEWAY,
 	PROP_ADDRESSES,
+	PROP_ROUTES,
 	PROP_NAMESERVERS,
 	PROP_DOMAINS,
-	PROP_ROUTES,
+	PROP_SEARCHES,
 	PROP_WINS_SERVERS,
 
 	LAST_PROP
@@ -65,8 +69,7 @@ demarshal_ip4_address_array (NMObject *object, GParamSpec *pspec, GValue *value,
 {
 	NMIP4ConfigPrivate *priv = NM_IP4_CONFIG_GET_PRIVATE (object);
 
-	g_slist_foreach (priv->addresses, (GFunc) nm_ip4_address_unref, NULL);
-	g_slist_free (priv->addresses);
+	g_slist_free_full (priv->addresses, (GDestroyNotify) nm_ip4_address_unref);
 	priv->addresses = NULL;
 
 	priv->addresses = nm_utils_ip4_addresses_from_gvalue (value);
@@ -90,12 +93,12 @@ demarshal_ip4_array (NMObject *object, GParamSpec *pspec, GValue *value, gpointe
 }
 
 static gboolean
-demarshal_domains (NMObject *object, GParamSpec *pspec, GValue *value, gpointer field)
+demarshal_string_array (NMObject *object, GParamSpec *pspec, GValue *value, gpointer field)
 {
 	if (!_nm_string_array_demarshal (value, (GPtrArray **) field))
 		return FALSE;
 
-	_nm_object_queue_notify (object, NM_IP4_CONFIG_DOMAINS);
+	_nm_object_queue_notify (object, pspec->name);
 	return TRUE;
 }
 
@@ -104,8 +107,7 @@ demarshal_ip4_routes_array (NMObject *object, GParamSpec *pspec, GValue *value,
 {
 	NMIP4ConfigPrivate *priv = NM_IP4_CONFIG_GET_PRIVATE (object);
 
-	g_slist_foreach (priv->routes, (GFunc) nm_ip4_route_unref, NULL);
-	g_slist_free (priv->routes);
+	g_slist_free_full (priv->routes, (GDestroyNotify) nm_ip4_route_unref);
 	priv->routes = NULL;
 
 	priv->routes = nm_utils_ip4_routes_from_gvalue (value);
@@ -119,10 +121,12 @@ register_properties (NMIP4Config *config)
 {
 	NMIP4ConfigPrivate *priv = NM_IP4_CONFIG_GET_PRIVATE (config);
 	const NMPropertiesInfo property_info[] = {
+		{ NM_IP4_CONFIG_GATEWAY,      &priv->gateway, },
 		{ NM_IP4_CONFIG_ADDRESSES,    &priv->addresses, demarshal_ip4_address_array },
-		{ NM_IP4_CONFIG_NAMESERVERS,  &priv->nameservers, demarshal_ip4_array },
-		{ NM_IP4_CONFIG_DOMAINS,      &priv->domains, demarshal_domains },
 		{ NM_IP4_CONFIG_ROUTES,       &priv->routes, demarshal_ip4_routes_array },
+		{ NM_IP4_CONFIG_NAMESERVERS,  &priv->nameservers, demarshal_ip4_array },
+		{ NM_IP4_CONFIG_DOMAINS,      &priv->domains, demarshal_string_array },
+		{ NM_IP4_CONFIG_SEARCHES,     &priv->searches, demarshal_string_array },
 		{ NM_IP4_CONFIG_WINS_SERVERS, &priv->wins, demarshal_ip4_array },
 		{ NULL },
 	};
@@ -135,19 +139,11 @@ register_properties (NMIP4Config *config)
 static void
 constructed (GObject *object)
 {
-	DBusGConnection *connection;
-	NMIP4ConfigPrivate *priv;
+	NMIP4ConfigPrivate *priv = NM_IP4_CONFIG_GET_PRIVATE (object);
 
 	G_OBJECT_CLASS (nm_ip4_config_parent_class)->constructed (object);
 
-	priv = NM_IP4_CONFIG_GET_PRIVATE (object);
-	connection = nm_object_get_connection (NM_OBJECT (object));
-
-	priv->proxy = dbus_g_proxy_new_for_name (connection,
-										   NM_DBUS_SERVICE,
-										   nm_object_get_path (NM_OBJECT (object)),
-										   NM_DBUS_INTERFACE_IP4_CONFIG);
-
+	priv->proxy = _nm_object_new_proxy (NM_OBJECT (object), NULL, NM_DBUS_INTERFACE_IP4_CONFIG);
 	register_properties (NM_IP4_CONFIG (object));
 }
 
@@ -156,11 +152,10 @@ finalize (GObject *object)
 {
 	NMIP4ConfigPrivate *priv = NM_IP4_CONFIG_GET_PRIVATE (object);
 
-	g_slist_foreach (priv->addresses, (GFunc) nm_ip4_address_unref, NULL);
-	g_slist_free (priv->addresses);
+	g_free (priv->gateway);
 
-	g_slist_foreach (priv->routes, (GFunc) nm_ip4_route_unref, NULL);
-	g_slist_free (priv->routes);
+	g_slist_free_full (priv->addresses, (GDestroyNotify) nm_ip4_address_unref);
+	g_slist_free_full (priv->routes, (GDestroyNotify) nm_ip4_route_unref);
 
 	if (priv->nameservers)
 		g_array_free (priv->nameservers, TRUE);
@@ -169,10 +164,15 @@ finalize (GObject *object)
 		g_array_free (priv->wins, TRUE);
 
 	if (priv->domains) {
-		g_ptr_array_foreach (priv->domains, (GFunc) g_free, NULL);
+		g_ptr_array_set_free_func (priv->domains, g_free);
 		g_ptr_array_free (priv->domains, TRUE);
 	}
 
+	if (priv->searches) {
+		g_ptr_array_set_free_func (priv->searches, g_free);
+		g_ptr_array_free (priv->searches, TRUE);
+	}
+
 	g_object_unref (priv->proxy);
 
 	G_OBJECT_CLASS (nm_ip4_config_parent_class)->finalize (object);
@@ -190,17 +190,23 @@ get_property (GObject *object,
 	_nm_object_ensure_inited (NM_OBJECT (object));
 
 	switch (prop_id) {
+	case PROP_GATEWAY:
+		g_value_set_string (value, nm_ip4_config_get_gateway (self));
+		break;
 	case PROP_ADDRESSES:
 		nm_utils_ip4_addresses_to_gvalue (priv->addresses, value);
 		break;
+	case PROP_ROUTES:
+		nm_utils_ip4_routes_to_gvalue (priv->routes, value);
+		break;
 	case PROP_NAMESERVERS:
 		g_value_set_boxed (value, nm_ip4_config_get_nameservers (self));
 		break;
 	case PROP_DOMAINS:
 		g_value_set_boxed (value, nm_ip4_config_get_domains (self));
 		break;
-	case PROP_ROUTES:
-		nm_utils_ip4_routes_to_gvalue (priv->routes, value);
+	case PROP_SEARCHES:
+		g_value_set_boxed (value, nm_ip4_config_get_searches (self));
 		break;
 	case PROP_WINS_SERVERS:
 		g_value_set_boxed (value, nm_ip4_config_get_wins_servers (self));
@@ -226,29 +232,56 @@ nm_ip4_config_class_init (NMIP4ConfigClass *config_class)
 	/* properties */
 
 	/**
+	 * NMIP4Config:gateway:
+	 *
+	 * The IP4 gateway address of the configuration as string.
+	 *
+	 * Since: 0.9.10
+	 **/
+	g_object_class_install_property
+	    (object_class, PROP_GATEWAY,
+	     g_param_spec_string (NM_IP4_CONFIG_GATEWAY,
+	                          "Gateway",
+	                          "Gateway",
+	                          NULL,
+	                          G_PARAM_READABLE));
+
+	/**
 	 * NMIP4Config:addresses:
 	 *
-	 * The #GPtrArray containing #NMSettingIP4Address<!-- -->es of the configuration.
+	 * The #GPtrArray containing #NMIP4Address<!-- -->es of the configuration.
+	 **/
+	g_object_class_install_property
+	    (object_class, PROP_ADDRESSES,
+	     g_param_spec_pointer (NM_IP4_CONFIG_ADDRESSES,
+	                           "Addresses",
+	                           "Addresses",
+	                           G_PARAM_READABLE));
+
+	/**
+	 * NMIP4Config:routes:
+	 *
+	 * The #GPtrArray containing #NMSettingIP4Routes of the configuration.
 	 **/
 	g_object_class_install_property
-		(object_class, PROP_ADDRESSES,
-		 g_param_spec_pointer (NM_IP4_CONFIG_ADDRESSES,
-						       "Addresses",
-						       "Addresses",
-						       G_PARAM_READABLE));
+	    (object_class, PROP_ROUTES,
+	     g_param_spec_pointer (NM_IP4_CONFIG_ROUTES,
+	                           "Routes",
+	                           "Routes",
+	                           G_PARAM_READABLE));
 
 	/**
 	 * NMIP4Config:nameservers:
 	 *
-	 * The #GArray containing name servers (%guint32<!-- -->es) of the configuration.
+	 * The #GArray containing name servers (#guint32s) of the configuration.
 	 **/
 	g_object_class_install_property
-		(object_class, PROP_NAMESERVERS,
-		 g_param_spec_boxed (NM_IP4_CONFIG_NAMESERVERS,
-						    "Nameservers",
-						    "Nameservers",
-						    NM_TYPE_UINT_ARRAY,
-						    G_PARAM_READABLE));
+	    (object_class, PROP_NAMESERVERS,
+	     g_param_spec_boxed (NM_IP4_CONFIG_NAMESERVERS,
+	                         "Nameservers",
+	                         "Nameservers",
+	                         NM_TYPE_UINT_ARRAY,
+	                         G_PARAM_READABLE));
 
 	/**
 	 * NMIP4Config:domains:
@@ -256,37 +289,40 @@ nm_ip4_config_class_init (NMIP4ConfigClass *config_class)
 	 * The #GPtrArray containing domain strings of the configuration.
 	 **/
 	g_object_class_install_property
-		(object_class, PROP_DOMAINS,
-		 g_param_spec_boxed (NM_IP4_CONFIG_DOMAINS,
-						    "Domains",
-						    "Domains",
-						    NM_TYPE_STRING_ARRAY,
-						    G_PARAM_READABLE));
+	    (object_class, PROP_DOMAINS,
+	     g_param_spec_boxed (NM_IP4_CONFIG_DOMAINS,
+	                         "Domains",
+	                         "Domains",
+	                         NM_TYPE_STRING_ARRAY,
+	                         G_PARAM_READABLE));
 
 	/**
-	 * NMIP4Config:routes:
+	 * NMIP4Config:searches:
+	 *
+	 * The #GPtrArray containing dns search strings of the configuration.
 	 *
-	 * The #GPtrArray containing #NMSettingIP4Route<!-- -->s of the configuration.
+	 * Since: 0.9.10
 	 **/
 	g_object_class_install_property
-		(object_class, PROP_ROUTES,
-		 g_param_spec_pointer (NM_IP4_CONFIG_ROUTES,
-						       "Routes",
-						       "Routes",
-						       G_PARAM_READABLE));
+	    (object_class, PROP_SEARCHES,
+	     g_param_spec_boxed (NM_IP4_CONFIG_SEARCHES,
+	                         "Searches",
+	                         "DNS searches",
+	                         NM_TYPE_STRING_ARRAY,
+	                         G_PARAM_READABLE));
 
 	/**
 	 * NMIP4Config:wins-servers:
 	 *
-	 * The #GArray containing WINS servers (%guint32<!-- -->es) of the configuration.
+	 * The #GArray containing WINS servers (#guint32s) of the configuration.
 	 **/
 	g_object_class_install_property
-		(object_class, PROP_WINS_SERVERS,
-		 g_param_spec_boxed (NM_IP4_CONFIG_WINS_SERVERS,
-						    "WINS Servers",
-						    "WINS Servers",
-						    NM_TYPE_UINT_ARRAY,
-						    G_PARAM_READABLE));
+	    (object_class, PROP_WINS_SERVERS,
+	     g_param_spec_boxed (NM_IP4_CONFIG_WINS_SERVERS,
+	                         "WINS Servers",
+	                         "WINS Servers",
+	                         NM_TYPE_UINT_ARRAY,
+	                         G_PARAM_READABLE));
 }
 
 /**
@@ -302,9 +338,28 @@ GObject *
 nm_ip4_config_new (DBusGConnection *connection, const char *object_path)
 {
 	return (GObject *) g_object_new (NM_TYPE_IP4_CONFIG,
-									 NM_OBJECT_DBUS_CONNECTION, connection,
-									 NM_OBJECT_DBUS_PATH, object_path,
-									 NULL);
+	                                 NM_OBJECT_DBUS_CONNECTION, connection,
+	                                 NM_OBJECT_DBUS_PATH, object_path,
+	                                 NULL);
+}
+
+/**
+ * nm_ip4_config_get_gateway:
+ * @config: a #NMIP4Config
+ *
+ * Gets the IP4 gateway address.
+ *
+ * Returns: the IP4 address of the gateway.
+ *
+ * Since: 0.9.10
+ **/
+const char *
+nm_ip4_config_get_gateway (NMIP4Config *config)
+{
+	g_return_val_if_fail (NM_IS_IP4_CONFIG (config), NULL);
+
+	_nm_object_ensure_inited (NM_OBJECT (config));
+	return NM_IP4_CONFIG_GET_PRIVATE (config)->gateway;
 }
 
 /**
@@ -331,8 +386,9 @@ nm_ip4_config_get_addresses (NMIP4Config *config)
  *
  * Gets the domain name servers (DNS).
  *
- * Returns: (element-type guint32): the #GArray containing %guint32<!-- -->s. This is the internal copy used by the
- * configuration and must not be modified.
+ * Returns: (element-type guint32): the #GArray containing #guint32s.
+ * This is the internal copy used by the configuration and must not be
+ * modified.
  **/
 const GArray *
 nm_ip4_config_get_nameservers (NMIP4Config *config)
@@ -362,13 +418,34 @@ nm_ip4_config_get_domains (NMIP4Config *config)
 }
 
 /**
+ * nm_ip4_config_get_searches:
+ * @config: a #NMIP4Config
+ *
+ * Gets the dns searches.
+ *
+ * Returns: (element-type utf8): the #GPtrArray containing dns searches as strings. This is the
+ * internal copy used by the configuration, and must not be modified.
+ *
+ * Since: 0.9.10
+ **/
+const GPtrArray *
+nm_ip4_config_get_searches (NMIP4Config *config)
+{
+	g_return_val_if_fail (NM_IS_IP4_CONFIG (config), NULL);
+
+	_nm_object_ensure_inited (NM_OBJECT (config));
+	return handle_ptr_array_return (NM_IP4_CONFIG_GET_PRIVATE (config)->searches);
+}
+
+/**
  * nm_ip4_config_get_wins_servers:
  * @config: a #NMIP4Config
  *
  * Gets the Windows Internet Name Service servers (WINS).
  *
- * Returns: (element-type guint32): the #GArray containing %guint32<!-- -->s.
- * This is the internal copy used by the configuration and must not be modified.
+ * Returns: (element-type guint32): the #GArray containing #guint32s.
+ * This is the internal copy used by the configuration and must not be
+ * modified.
  **/
 const GArray *
 nm_ip4_config_get_wins_servers (NMIP4Config *config)
@@ -386,7 +463,7 @@ nm_ip4_config_get_wins_servers (NMIP4Config *config)
  * Gets the routes.
  *
  * Returns: (element-type NetworkManager.IP4Route): the #GSList containing
- * #NMIP4Route<!-- -->s. This is the internal copy used by the configuration,
+ * #NMIP4Routes. This is the internal copy used by the configuration,
  * and must not be modified.
  **/
 const GSList *
diff --git a/libnm-glib/nm-ip4-config.h b/libnm-glib/nm-ip4-config.h
index b76fdf8b..aa2e66eb 100644
--- a/libnm-glib/nm-ip4-config.h
+++ b/libnm-glib/nm-ip4-config.h
@@ -54,20 +54,26 @@ typedef struct {
 	void (*_reserved6) (void);
 } NMIP4ConfigClass;
 
+#define NM_IP4_CONFIG_GATEWAY "gateway"
 #define NM_IP4_CONFIG_ADDRESSES "addresses"
+#define NM_IP4_CONFIG_ROUTES "routes"
 #define NM_IP4_CONFIG_NAMESERVERS "nameservers"
 #define NM_IP4_CONFIG_DOMAINS "domains"
-#define NM_IP4_CONFIG_ROUTES "routes"
+#define NM_IP4_CONFIG_SEARCHES "searches"
 #define NM_IP4_CONFIG_WINS_SERVERS "wins-servers"
 
 GType nm_ip4_config_get_type (void);
 
 GObject *nm_ip4_config_new (DBusGConnection *connection, const char *object_path);
 
+NM_AVAILABLE_IN_0_9_10
+const char *     nm_ip4_config_get_gateway      (NMIP4Config *config);
 const GSList *   nm_ip4_config_get_addresses    (NMIP4Config *config);
+const GSList *   nm_ip4_config_get_routes       (NMIP4Config *config);
 const GArray *   nm_ip4_config_get_nameservers  (NMIP4Config *config);
 const GPtrArray *nm_ip4_config_get_domains      (NMIP4Config *config);
-const GSList *   nm_ip4_config_get_routes       (NMIP4Config *config);
+NM_AVAILABLE_IN_0_9_10
+const GPtrArray *nm_ip4_config_get_searches     (NMIP4Config *config);
 const GArray *   nm_ip4_config_get_wins_servers (NMIP4Config *config);
 
 G_END_DECLS
diff --git a/libnm-glib/nm-ip6-config.c b/libnm-glib/nm-ip6-config.c
index 9efc32ee..7c9cfca7 100644
--- a/libnm-glib/nm-ip6-config.c
+++ b/libnm-glib/nm-ip6-config.c
@@ -18,7 +18,7 @@
  * Boston, MA 02110-1301 USA.
  *
  * Copyright (C) 2007 - 2008 Novell, Inc.
- * Copyright (C) 2008 - 2011 Red Hat, Inc.
+ * Copyright (C) 2008 - 2014 Red Hat, Inc.
  */
 
 #include <string.h>
@@ -37,18 +37,22 @@ G_DEFINE_TYPE (NMIP6Config, nm_ip6_config, NM_TYPE_OBJECT)
 typedef struct {
 	DBusGProxy *proxy;
 
+	char *gateway;
 	GSList *addresses;
+	GSList *routes;
 	GSList *nameservers;
 	GPtrArray *domains;
-	GSList *routes;
+	GPtrArray *searches;
 } NMIP6ConfigPrivate;
 
 enum {
 	PROP_0,
+	PROP_GATEWAY,
 	PROP_ADDRESSES,
+	PROP_ROUTES,
 	PROP_NAMESERVERS,
 	PROP_DOMAINS,
-	PROP_ROUTES,
+	PROP_SEARCHES,
 
 	LAST_PROP
 };
@@ -76,8 +80,7 @@ demarshal_ip6_address_array (NMObject *object, GParamSpec *pspec, GValue *value,
 {
 	NMIP6ConfigPrivate *priv = NM_IP6_CONFIG_GET_PRIVATE (object);
 
-	g_slist_foreach (priv->addresses, (GFunc) nm_ip6_address_unref, NULL);
-	g_slist_free (priv->addresses);
+	g_slist_free_full (priv->addresses, (GDestroyNotify) nm_ip6_address_unref);
 	priv->addresses = NULL;
 
 	priv->addresses = nm_utils_ip6_addresses_from_gvalue (value);
@@ -109,12 +112,21 @@ demarshal_domains (NMObject *object, GParamSpec *pspec, GValue *value, gpointer
 }
 
 static gboolean
+demarshal_searches (NMObject *object, GParamSpec *pspec, GValue *value, gpointer field)
+{
+	if (!_nm_string_array_demarshal (value, (GPtrArray **) field))
+		return FALSE;
+
+	_nm_object_queue_notify (object, NM_IP6_CONFIG_SEARCHES);
+	return TRUE;
+}
+
+static gboolean
 demarshal_ip6_routes_array (NMObject *object, GParamSpec *pspec, GValue *value, gpointer field)
 {
 	NMIP6ConfigPrivate *priv = NM_IP6_CONFIG_GET_PRIVATE (object);
 
-	g_slist_foreach (priv->routes, (GFunc) nm_ip6_route_unref, NULL);
-	g_slist_free (priv->routes);
+	g_slist_free_full (priv->routes, (GDestroyNotify) nm_ip6_route_unref);
 	priv->routes = NULL;
 
 	priv->routes = nm_utils_ip6_routes_from_gvalue (value);
@@ -128,10 +140,12 @@ register_properties (NMIP6Config *config)
 {
 	NMIP6ConfigPrivate *priv = NM_IP6_CONFIG_GET_PRIVATE (config);
 	const NMPropertiesInfo property_info[] = {
+		{ NM_IP6_CONFIG_GATEWAY,      &priv->gateway, },
 		{ NM_IP6_CONFIG_ADDRESSES,    &priv->addresses, demarshal_ip6_address_array },
+		{ NM_IP6_CONFIG_ROUTES,       &priv->routes, demarshal_ip6_routes_array },
 		{ NM_IP6_CONFIG_NAMESERVERS,  &priv->nameservers, demarshal_ip6_nameserver_array },
 		{ NM_IP6_CONFIG_DOMAINS,      &priv->domains, demarshal_domains },
-		{ NM_IP6_CONFIG_ROUTES,       &priv->routes, demarshal_ip6_routes_array },
+		{ NM_IP6_CONFIG_SEARCHES,     &priv->searches, demarshal_searches },
 		{ NULL },
 	};
 
@@ -141,6 +155,25 @@ register_properties (NMIP6Config *config)
 }
 
 /**
+ * nm_ip6_config_get_gateway:
+ * @config: a #NMIP6Config
+ *
+ * Gets the IP6 gateway.
+ *
+ * Returns: the IPv6 gateway of the configuration.
+ *
+ * Since: 0.9.10
+ **/
+const char *
+nm_ip6_config_get_gateway (NMIP6Config *config)
+{
+	g_return_val_if_fail (NM_IS_IP6_CONFIG (config), NULL);
+
+	_nm_object_ensure_inited (NM_OBJECT (config));
+	return NM_IP6_CONFIG_GET_PRIVATE (config)->gateway;
+}
+
+/**
  * nm_ip6_config_get_addresses:
  * @config: a #NMIP6Config
  *
@@ -159,6 +192,56 @@ nm_ip6_config_get_addresses (NMIP6Config *config)
 	return NM_IP6_CONFIG_GET_PRIVATE (config)->addresses;
 }
 
+/**
+ * nm_ip6_config_get_num_nameservers:
+ * @config: a #NMIP6Config
+ *
+ * Gets the number of the domain name servers in the configuration.
+ *
+ * Returns: the number of domain name servers
+ *
+ * Since: 0.9.10
+ **/
+guint32
+nm_ip6_config_get_num_nameservers (NMIP6Config *config)
+{
+	g_return_val_if_fail (NM_IS_IP6_CONFIG (config), 0);
+
+	_nm_object_ensure_inited (NM_OBJECT (config));
+	return g_slist_length (NM_IP6_CONFIG_GET_PRIVATE (config)->nameservers);
+}
+
+/**
+ * nm_ip6_config_get_nameserver:
+ * @config: a #NMIP6Config
+ * @idx: index of the nameserver to return
+ *
+ * Gets the domain name server at index @idx in the configuration.
+ *
+ * Returns: (array fixed-size=16) (element-type guint8) (transfer none):
+ *          the IPv6 address of domain name server at index @iidx
+ *
+ * Since: 0.9.10
+ **/
+const struct in6_addr *
+nm_ip6_config_get_nameserver (NMIP6Config *config, guint32 idx)
+{
+	NMIP6ConfigPrivate *priv;
+	GSList *item;
+	guint32 i = 0;
+
+	g_return_val_if_fail (NM_IS_IP6_CONFIG (config), NULL);
+
+	_nm_object_ensure_inited (NM_OBJECT (config));
+	priv = NM_IP6_CONFIG_GET_PRIVATE (config);
+
+	for (item = priv->nameservers; item && i < idx; i++)
+		item = item->next;
+
+	g_return_val_if_fail (item, NULL);
+	return item ? (const struct in6_addr *) item->data : NULL;
+}
+
 /* FIXME: like in libnm_util, in6_addr is not introspectable, so skipping here */
 /**
  * nm_ip6_config_get_nameservers: (skip)
@@ -198,13 +281,33 @@ nm_ip6_config_get_domains (NMIP6Config *config)
 }
 
 /**
+ * nm_ip6_config_get_searches:
+ * @config: a #NMIP6Config
+ *
+ * Gets the dns searches.
+ *
+ * Returns: (element-type utf8): the #GPtrArray containing dns searches as strings.
+ * This is the internal copy used by the configuration, and must not be modified.
+ *
+ * Since: 0.9.10
+ **/
+const GPtrArray *
+nm_ip6_config_get_searches (NMIP6Config *config)
+{
+	g_return_val_if_fail (NM_IS_IP6_CONFIG (config), NULL);
+
+	_nm_object_ensure_inited (NM_OBJECT (config));
+	return handle_ptr_array_return (NM_IP6_CONFIG_GET_PRIVATE (config)->searches);
+}
+
+/**
  * nm_ip6_config_get_routes:
  * @config: a #NMIP6Config
  *
  * Gets the routes.
  *
  * Returns: (element-type NetworkManager.IP6Route): the #GSList containing
- * #NMIP6Route<!-- -->s. This is the internal copy used by the configuration,
+ * #NMIP6Routes. This is the internal copy used by the configuration,
  * and must not be modified.
  **/
 const GSList *
@@ -219,19 +322,11 @@ nm_ip6_config_get_routes (NMIP6Config *config)
 static void
 constructed (GObject *object)
 {
-	DBusGConnection *connection;
-	NMIP6ConfigPrivate *priv;
+	NMIP6ConfigPrivate *priv = NM_IP6_CONFIG_GET_PRIVATE (object);
 
 	G_OBJECT_CLASS (nm_ip6_config_parent_class)->constructed (object);
 
-	priv = NM_IP6_CONFIG_GET_PRIVATE (object);
-	connection = nm_object_get_connection (NM_OBJECT (object));
-
-	priv->proxy = dbus_g_proxy_new_for_name (connection,
-	                                         NM_DBUS_SERVICE,
-	                                         nm_object_get_path (NM_OBJECT (object)),
-	                                         NM_DBUS_INTERFACE_IP6_CONFIG);
-
+	priv->proxy = _nm_object_new_proxy (NM_OBJECT (object), NULL, NM_DBUS_INTERFACE_IP6_CONFIG);
 	register_properties (NM_IP6_CONFIG (object));
 }
 
@@ -240,20 +335,22 @@ finalize (GObject *object)
 {
 	NMIP6ConfigPrivate *priv = NM_IP6_CONFIG_GET_PRIVATE (object);
 
-	g_slist_foreach (priv->addresses, (GFunc) nm_ip6_address_unref, NULL);
-	g_slist_free (priv->addresses);
-
-	g_slist_foreach (priv->routes, (GFunc) nm_ip6_route_unref, NULL);
-	g_slist_free (priv->routes);
+	g_free (priv->gateway);
 
-	g_slist_foreach (priv->nameservers, (GFunc) g_free, NULL);
-	g_slist_free (priv->nameservers);
+	g_slist_free_full (priv->addresses, (GDestroyNotify) nm_ip6_address_unref);
+	g_slist_free_full (priv->routes, (GDestroyNotify) nm_ip6_route_unref);
+	g_slist_free_full (priv->nameservers, g_free);
 
 	if (priv->domains) {
-		g_ptr_array_foreach (priv->domains, (GFunc) g_free, NULL);
+		g_ptr_array_set_free_func (priv->domains, g_free);
 		g_ptr_array_free (priv->domains, TRUE);
 	}
 
+	if (priv->searches) {
+		g_ptr_array_set_free_func (priv->searches, g_free);
+		g_ptr_array_free (priv->searches, TRUE);
+	}
+
 	g_object_unref (priv->proxy);
 
 	G_OBJECT_CLASS (nm_ip6_config_parent_class)->finalize (object);
@@ -271,17 +368,23 @@ get_property (GObject *object,
 	_nm_object_ensure_inited (NM_OBJECT (object));
 
 	switch (prop_id) {
+	case PROP_GATEWAY:
+		g_value_set_string (value, nm_ip6_config_get_gateway (self));
+		break;
 	case PROP_ADDRESSES:
 		nm_utils_ip6_addresses_to_gvalue (priv->addresses, value);
 		break;
+	case PROP_ROUTES:
+		nm_utils_ip6_routes_to_gvalue (priv->routes, value);
+		break;
 	case PROP_NAMESERVERS:
 		g_value_set_boxed (value, nm_ip6_config_get_nameservers (self));
 		break;
 	case PROP_DOMAINS:
 		g_value_set_boxed (value, nm_ip6_config_get_domains (self));
 		break;
-	case PROP_ROUTES:
-		nm_utils_ip6_routes_to_gvalue (priv->routes, value);
+	case PROP_SEARCHES:
+		g_value_set_boxed (value, nm_ip6_config_get_searches (self));
 		break;
 	default:
 		G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
@@ -309,6 +412,21 @@ nm_ip6_config_class_init (NMIP6ConfigClass *config_class)
 	/* properties */
 
 	/**
+	 * NMIP6Config:gateway:
+	 *
+	 * The IPv6 gateway as string
+	 *
+	 * Since: 0.9.10
+	 **/
+	g_object_class_install_property
+	    (object_class, PROP_GATEWAY,
+	     g_param_spec_string (NM_IP6_CONFIG_GATEWAY,
+	                          "Gateway",
+	                          "Gateway",
+	                          NULL,
+	                          G_PARAM_READABLE));
+
+	/**
 	 * NMIP6Config:addresses:
 	 *
 	 * The #GPtrArray containing the IPv6 addresses;  use
@@ -316,12 +434,27 @@ nm_ip6_config_class_init (NMIP6ConfigClass *config_class)
 	 * #NMSettingIP6Address objects that is more usable than the raw data.
 	 **/
 	g_object_class_install_property
-		(object_class, PROP_ADDRESSES,
-		 g_param_spec_boxed (NM_IP6_CONFIG_ADDRESSES,
-						     "Addresses",
-						     "Addresses",
-						     NM_TYPE_IP6_ADDRESS_OBJECT_ARRAY,
-						     G_PARAM_READABLE));
+	    (object_class, PROP_ADDRESSES,
+	     g_param_spec_boxed (NM_IP6_CONFIG_ADDRESSES,
+	                         "Addresses",
+	                         "Addresses",
+	                         NM_TYPE_IP6_ADDRESS_OBJECT_ARRAY,
+	                         G_PARAM_READABLE));
+
+	/**
+	 * NMIP6Config:routes:
+	 *
+	 * The #GPtrArray containing the IPv6 routes;  use
+	 * nm_utils_ip6_routes_from_gvalue() to return a #GSList of
+	 * #NMSettingIP6Address objects that is more usable than the raw data.
+	 **/
+	g_object_class_install_property
+	    (object_class, PROP_ROUTES,
+	     g_param_spec_boxed (NM_IP6_CONFIG_ROUTES,
+	                         "Routes",
+	                         "Routes",
+	                         NM_TYPE_IP6_ROUTE_OBJECT_ARRAY,
+	                         G_PARAM_READABLE));
 
 	/**
 	 * NMIP6Config:nameservers:
@@ -330,12 +463,12 @@ nm_ip6_config_class_init (NMIP6ConfigClass *config_class)
 	 * contain the addresses of nameservers of the configuration.
 	 **/
 	g_object_class_install_property
-		(object_class, PROP_NAMESERVERS,
-		 g_param_spec_boxed (NM_IP6_CONFIG_NAMESERVERS,
-						    "Nameservers",
-						    "Nameservers",
-						    NM_TYPE_IP6_ADDRESS_ARRAY,
-						    G_PARAM_READABLE));
+	    (object_class, PROP_NAMESERVERS,
+	     g_param_spec_boxed (NM_IP6_CONFIG_NAMESERVERS,
+	                        "Nameservers",
+	                        "Nameservers",
+	                        NM_TYPE_IP6_ADDRESS_ARRAY,
+	                        G_PARAM_READABLE));
 
 	/**
 	 * NMIP6Config:domains:
@@ -343,26 +476,27 @@ nm_ip6_config_class_init (NMIP6ConfigClass *config_class)
 	 * The #GPtrArray containing domain strings of the configuration.
 	 **/
 	g_object_class_install_property
-		(object_class, PROP_DOMAINS,
-		 g_param_spec_boxed (NM_IP6_CONFIG_DOMAINS,
-						    "Domains",
-						    "Domains",
-						    NM_TYPE_STRING_ARRAY,
-						    G_PARAM_READABLE));
+	    (object_class, PROP_DOMAINS,
+	     g_param_spec_boxed (NM_IP6_CONFIG_DOMAINS,
+	                        "Domains",
+	                        "Domains",
+	                        NM_TYPE_STRING_ARRAY,
+	                        G_PARAM_READABLE));
 
 	/**
-	 * NMIP6Config:routes:
+	 * NMIP6Config:searches:
 	 *
-	 * The #GPtrArray containing the IPv6 routes;  use
-	 * nm_utils_ip6_routes_from_gvalue() to return a #GSList of
-	 * #NMSettingIP6Address objects that is more usable than the raw data.
+	 * The #GPtrArray containing dns search strings of the configuration.
+	 *
+	 * Since: 0.9.10
 	 **/
 	g_object_class_install_property
-		(object_class, PROP_ROUTES,
-		 g_param_spec_boxed (NM_IP6_CONFIG_ROUTES,
-		                     "Routes",
-		                     "Routes",
-		                     NM_TYPE_IP6_ROUTE_OBJECT_ARRAY,
-		                     G_PARAM_READABLE));
+	    (object_class, PROP_SEARCHES,
+	     g_param_spec_boxed (NM_IP6_CONFIG_SEARCHES,
+	                        "Searches",
+	                        "DNS Searches",
+	                        NM_TYPE_STRING_ARRAY,
+	                        G_PARAM_READABLE));
+
 }
 
diff --git a/libnm-glib/nm-ip6-config.h b/libnm-glib/nm-ip6-config.h
index 9692c655..feef69f1 100644
--- a/libnm-glib/nm-ip6-config.h
+++ b/libnm-glib/nm-ip6-config.h
@@ -18,7 +18,7 @@
  * Boston, MA 02110-1301 USA.
  *
  * Copyright (C) 2007 - 2008 Novell, Inc.
- * Copyright (C) 2008 Red Hat, Inc.
+ * Copyright (C) 2008 - 2014 Red Hat, Inc.
  */
 
 #ifndef NM_IP6_CONFIG_H
@@ -54,19 +54,29 @@ typedef struct {
 	void (*_reserved6) (void);
 } NMIP6ConfigClass;
 
+#define NM_IP6_CONFIG_GATEWAY "gateway"
 #define NM_IP6_CONFIG_ADDRESSES "addresses"
+#define NM_IP6_CONFIG_ROUTES "routes"
 #define NM_IP6_CONFIG_NAMESERVERS "nameservers"
 #define NM_IP6_CONFIG_DOMAINS "domains"
-#define NM_IP6_CONFIG_ROUTES "routes"
+#define NM_IP6_CONFIG_SEARCHES "searches"
 
 GType nm_ip6_config_get_type (void);
 
 GObject *nm_ip6_config_new (DBusGConnection *connection, const char *object_path);
 
-const GSList *   nm_ip6_config_get_addresses    (NMIP6Config *config);
-const GSList *   nm_ip6_config_get_nameservers  (NMIP6Config *config);
-const GPtrArray *nm_ip6_config_get_domains      (NMIP6Config *config);
-const GSList *   nm_ip6_config_get_routes       (NMIP6Config *config);
+NM_AVAILABLE_IN_0_9_10
+const char *           nm_ip6_config_get_gateway         (NMIP6Config *config);
+const GSList *         nm_ip6_config_get_addresses       (NMIP6Config *config);
+const GSList *         nm_ip6_config_get_routes          (NMIP6Config *config);
+NM_AVAILABLE_IN_0_9_10
+guint32                nm_ip6_config_get_num_nameservers (NMIP6Config *config);
+NM_AVAILABLE_IN_0_9_10
+const struct in6_addr *nm_ip6_config_get_nameserver      (NMIP6Config *config, guint32 idx);
+const GSList *         nm_ip6_config_get_nameservers     (NMIP6Config *config);
+const GPtrArray *      nm_ip6_config_get_domains         (NMIP6Config *config);
+NM_AVAILABLE_IN_0_9_10
+const GPtrArray *      nm_ip6_config_get_searches        (NMIP6Config *config);
 
 G_END_DECLS
 
diff --git a/libnm-glib/nm-object-private.h b/libnm-glib/nm-object-private.h
index 7ec2162f..3253c2ec 100644
--- a/libnm-glib/nm-object-private.h
+++ b/libnm-glib/nm-object-private.h
@@ -37,8 +37,14 @@ typedef struct {
 	gpointer field;
 	PropertyMarshalFunc func;
 	GType object_type;
+	const char *signal_prefix;
 } NMPropertiesInfo;
 
+DBusGProxy *_nm_object_new_proxy (NMObject *self,
+                                  const char *path,
+                                  const char *interface);
+
+gboolean _nm_object_is_connection_private (NMObject *self);
 
 void _nm_object_register_properties (NMObject *object,
 									 DBusGProxy *proxy,
@@ -53,17 +59,6 @@ gboolean _nm_object_reload_properties_finish (NMObject *object,
                                               GAsyncResult *result,
                                               GError **error);
 
-typedef void (*NMPseudoPropertyChangedFunc) (NMObject *self, NMObject *changed);
-void _nm_object_register_pseudo_property (NMObject *object,
-                                          DBusGProxy *proxy,
-                                          const char *name,
-                                          gpointer field,
-                                          GType object_type,
-                                          NMPseudoPropertyChangedFunc added_func,
-                                          NMPseudoPropertyChangedFunc removed_func);
-void _nm_object_reload_pseudo_property   (NMObject *object,
-                                          const char *name);
-
 void _nm_object_queue_notify (NMObject *object, const char *property);
 
 void _nm_object_suppress_property_updates (NMObject *object, gboolean suppress);
diff --git a/libnm-glib/nm-object.c b/libnm-glib/nm-object.c
index 93919d61..61282cfb 100644
--- a/libnm-glib/nm-object.c
+++ b/libnm-glib/nm-object.c
@@ -24,6 +24,7 @@
 #include <string.h>
 #include <gio/gio.h>
 #include <stdlib.h>
+#include <stdio.h>
 #include <nm-utils.h>
 #include "NetworkManager.h"
 #include "nm-object.h"
@@ -32,7 +33,7 @@
 #include "nm-dbus-glib-types.h"
 #include "nm-glib-compat.h"
 #include "nm-types.h"
-#include "nm-glib-marshal.h"
+#include "nm-dbus-helpers-private.h"
 
 static gboolean debug = FALSE;
 #define dbgmsg(f,...) if (G_UNLIKELY (debug)) { g_message (f, ## __VA_ARGS__ ); }
@@ -52,30 +53,21 @@ static GHashTable *type_funcs, *type_async_funcs;
 typedef struct {
 	PropertyMarshalFunc func;
 	GType object_type;
-
 	gpointer field;
+	const char *signal_prefix;
 } PropertyInfo;
 
 static void reload_complete (NMObject *object);
 
 typedef struct {
-	PropertyInfo pi;
-
-	NMObject *self;
-	DBusGProxy *proxy;
-
-	char *get_method;
-	NMPseudoPropertyChangedFunc added_func;
-	NMPseudoPropertyChangedFunc removed_func;
-} PseudoPropertyInfo;
-
-typedef struct {
 	DBusGConnection *connection;
+	DBusGProxy *bus_proxy;
+	gboolean nm_running;
+
 	char *path;
 	DBusGProxy *properties_proxy;
 	GSList *property_interfaces;
 	GSList *property_tables;
-	GHashTable *pseudo_properties;
 	NMObject *parent;
 	gboolean suppress_property_updates;
 
@@ -122,21 +114,42 @@ nm_object_error_quark (void)
 }
 
 static void
+proxy_name_owner_changed (DBusGProxy *proxy,
+                          const char *name,
+                          const char *old_owner,
+                          const char *new_owner,
+                          gpointer user_data)
+{
+	NMObject *self = NM_OBJECT (user_data);
+	NMObjectPrivate *priv = NM_OBJECT_GET_PRIVATE (self);
+
+	if (g_strcmp0 (name, NM_DBUS_SERVICE) == 0) {
+		gboolean old_good = (old_owner && old_owner[0]);
+		gboolean new_good = (new_owner && new_owner[0]);
+
+		if (!old_good && new_good)
+			priv->nm_running = TRUE;
+		else if (old_good && !new_good)
+			priv->nm_running = FALSE;
+	}
+}
+
+static void
 nm_object_init (NMObject *object)
 {
 }
 
 static GObject*
 constructor (GType type,
-			 guint n_construct_params,
-			 GObjectConstructParam *construct_params)
+             guint n_construct_params,
+             GObjectConstructParam *construct_params)
 {
 	GObject *object;
 	NMObjectPrivate *priv;
 
 	object = G_OBJECT_CLASS (nm_object_parent_class)->constructor (type,
-																   n_construct_params,
-																   construct_params);
+	                                                               n_construct_params,
+	                                                               construct_params);
 
 	priv = NM_OBJECT_GET_PRIVATE (object);
 
@@ -154,15 +167,31 @@ constructor (GType type,
 static void
 constructed (GObject *object)
 {
+	NMObject *self = NM_OBJECT (object);
 	NMObjectPrivate *priv = NM_OBJECT_GET_PRIVATE (object);
 
 	if (G_OBJECT_CLASS (nm_object_parent_class)->constructed)
 		G_OBJECT_CLASS (nm_object_parent_class)->constructed (object);
 
-	priv->properties_proxy = dbus_g_proxy_new_for_name (priv->connection,
-	                                                    NM_DBUS_SERVICE,
-	                                                    priv->path,
-	                                                    "org.freedesktop.DBus.Properties");
+	priv->properties_proxy = _nm_object_new_proxy (self, NULL, "org.freedesktop.DBus.Properties");
+
+	if (_nm_object_is_connection_private (self))
+		priv->nm_running = TRUE;
+	else {
+		priv->bus_proxy = dbus_g_proxy_new_for_name (priv->connection,
+		                                             DBUS_SERVICE_DBUS,
+		                                             DBUS_PATH_DBUS,
+		                                             DBUS_INTERFACE_DBUS);
+		g_assert (priv->bus_proxy);
+
+		dbus_g_proxy_add_signal (priv->bus_proxy, "NameOwnerChanged",
+		                         G_TYPE_STRING, G_TYPE_STRING, G_TYPE_STRING,
+		                         G_TYPE_INVALID);
+		dbus_g_proxy_connect_signal (priv->bus_proxy,
+		                             "NameOwnerChanged",
+		                             G_CALLBACK (proxy_name_owner_changed),
+		                             object, NULL);
+	}
 }
 
 static gboolean
@@ -170,25 +199,68 @@ init_sync (GInitable *initable, GCancellable *cancellable, GError **error)
 {
 	NMObjectPrivate *priv = NM_OBJECT_GET_PRIVATE (initable);
 
+	if (priv->bus_proxy) {
+		if (!dbus_g_proxy_call (priv->bus_proxy,
+		                        "NameHasOwner", error,
+		                        G_TYPE_STRING, NM_DBUS_SERVICE,
+		                        G_TYPE_INVALID,
+		                        G_TYPE_BOOLEAN, &priv->nm_running,
+		                        G_TYPE_INVALID))
+			return FALSE;
+	}
+
 	priv->inited = TRUE;
 	return _nm_object_reload_properties (NM_OBJECT (initable), error);
 }
 
+/* Takes ownership of @error */
+static void
+init_async_complete (GSimpleAsyncResult *simple, GError *error)
+{
+	if (error)
+		g_simple_async_result_take_error (simple, error);
+	else
+		g_simple_async_result_set_op_res_gboolean (simple, TRUE);
+	g_simple_async_result_complete (simple);
+	g_object_unref (simple);
+}
+
 static void
 init_async_got_properties (GObject *object, GAsyncResult *result, gpointer user_data)
 {
-	NMObjectPrivate *priv = NM_OBJECT_GET_PRIVATE (object);
 	GSimpleAsyncResult *simple = user_data;
 	GError *error = NULL;
 
-	priv->inited = TRUE;
-	if (_nm_object_reload_properties_finish (NM_OBJECT (object), result, &error))
-		g_simple_async_result_set_op_res_gboolean (simple, TRUE);
-	else
-		g_simple_async_result_take_error (simple, error);
+	NM_OBJECT_GET_PRIVATE (object)->inited = TRUE;
+	if (!_nm_object_reload_properties_finish (NM_OBJECT (object), result, &error))
+		g_assert (error);
+	init_async_complete (simple, error);
+}
 
-	g_simple_async_result_complete (simple);
-	g_object_unref (simple);
+static void
+init_async_got_manager_running (DBusGProxy *proxy, DBusGProxyCall *call,
+                                gpointer user_data)
+{
+	GSimpleAsyncResult *simple = user_data;
+	NMObject *self;
+	NMObjectPrivate *priv;
+	GError *error = NULL;
+
+	self = NM_OBJECT (g_async_result_get_source_object (G_ASYNC_RESULT (simple)));
+	priv = NM_OBJECT_GET_PRIVATE (self);
+
+	if (!dbus_g_proxy_end_call (proxy, call, &error,
+	                            G_TYPE_BOOLEAN, &priv->nm_running,
+	                            G_TYPE_INVALID)) {
+		init_async_complete (simple, error);
+	} else if (!priv->nm_running) {
+		priv->inited = TRUE;
+		init_async_complete (simple, NULL);
+	} else
+		_nm_object_reload_properties_async (self, init_async_got_properties, simple);
+
+	/* g_async_result_get_source_object() adds a ref */
+	g_object_unref (self);
 }
 
 static void
@@ -196,10 +268,21 @@ init_async (GAsyncInitable *initable, int io_priority,
             GCancellable *cancellable, GAsyncReadyCallback callback,
             gpointer user_data)
 {
+	NMObjectPrivate *priv = NM_OBJECT_GET_PRIVATE (initable);
 	GSimpleAsyncResult *simple;
 
 	simple = g_simple_async_result_new (G_OBJECT (initable), callback, user_data, init_async);
-	_nm_object_reload_properties_async (NM_OBJECT (initable), init_async_got_properties, simple);
+
+	if (_nm_object_is_connection_private (NM_OBJECT (initable)))
+		_nm_object_reload_properties_async (NM_OBJECT (initable), init_async_got_properties, simple);
+	else {
+		/* Check if NM is running */
+		dbus_g_proxy_begin_call (priv->bus_proxy, "NameHasOwner",
+		                         init_async_got_manager_running,
+		                         simple, NULL,
+		                         G_TYPE_STRING, NM_DBUS_SERVICE,
+		                         G_TYPE_INVALID);
+	}
 }
 
 static gboolean
@@ -223,15 +306,14 @@ dispose (GObject *object)
 		priv->notify_id = 0;
 	}
 
-	g_slist_foreach (priv->notify_props, (GFunc) g_free, NULL);
-	g_slist_free (priv->notify_props);
+	g_slist_free_full (priv->notify_props, g_free);
 	priv->notify_props = NULL;
 
-	g_slist_foreach (priv->property_interfaces, (GFunc) g_free, NULL);
-	g_slist_free (priv->property_interfaces);
+	g_slist_free_full (priv->property_interfaces, g_free);
 	priv->property_interfaces = NULL;
 
 	g_clear_object (&priv->properties_proxy);
+	g_clear_object (&priv->bus_proxy);
 
 	if (priv->connection) {
 		dbus_g_connection_unref (priv->connection);
@@ -246,13 +328,9 @@ finalize (GObject *object)
 {
 	NMObjectPrivate *priv = NM_OBJECT_GET_PRIVATE (object);
 
-	g_slist_foreach (priv->property_tables, (GFunc) g_hash_table_destroy, NULL);
-	g_slist_free (priv->property_tables);
+	g_slist_free_full (priv->property_tables, (GDestroyNotify) g_hash_table_destroy);
 	g_free (priv->path);
 
-	if (priv->pseudo_properties)
-		g_hash_table_destroy (priv->pseudo_properties);
-
 	G_OBJECT_CLASS (nm_object_parent_class)->finalize (object);
 }
 
@@ -261,15 +339,13 @@ set_property (GObject *object, guint prop_id,
 			  const GValue *value, GParamSpec *pspec)
 {
 	NMObjectPrivate *priv = NM_OBJECT_GET_PRIVATE (object);
-	DBusGConnection *connection;
 
 	switch (prop_id) {
 	case PROP_CONNECTION:
 		/* Construct only */
-		connection = (DBusGConnection *) g_value_get_boxed (value);
-		if (!connection)
-			connection = dbus_g_bus_get (DBUS_BUS_SYSTEM, NULL);
-		priv->connection = dbus_g_connection_ref (connection);
+		priv->connection = g_value_dup_boxed (value);
+		if (!priv->connection)
+			priv->connection = _nm_dbus_new_connection (NULL);
 		break;
 	case PROP_PATH:
 		/* Construct only */
@@ -367,8 +443,7 @@ nm_object_class_init (NMObjectClass *nm_object_class)
 		              G_OBJECT_CLASS_TYPE (object_class),
 		              G_SIGNAL_RUN_FIRST,
 		              G_STRUCT_OFFSET (NMObjectClass, object_creation_failed),
-		              NULL, NULL,
-		              _nm_glib_marshal_VOID__POINTER_POINTER,
+		              NULL, NULL, NULL,
 		              G_TYPE_NONE, 2, G_TYPE_POINTER, G_TYPE_POINTER);
 }
 
@@ -669,31 +744,120 @@ typedef struct {
 	const char *property_name;
 } ObjectCreatedData;
 
+/* Places items from 'needles' that are not in 'haystack' into 'diff' */
+static void
+array_diff (GPtrArray *needles, GPtrArray *haystack, GPtrArray *diff)
+{
+	guint i, j;
+	GObject *obj;
+
+	g_assert (needles);
+	g_assert (haystack);
+	g_assert (diff);
+
+	for (i = 0; i < needles->len; i++) {
+		obj = g_ptr_array_index (needles, i);
+
+		for (j = 0; j < haystack->len; j++) {
+			if (g_ptr_array_index (haystack, j) == obj)
+				break;
+		}
+
+		if (j == haystack->len)
+			g_ptr_array_add (diff, obj);
+	}
+}
+
+static void
+emit_added_removed_signal (NMObject *self,
+                           const char *signal_prefix,
+                           NMObject *changed,
+                           gboolean added)
+{
+	char buf[50];
+	int ret;
+
+	ret = g_snprintf (buf, sizeof (buf), "%s-%s", signal_prefix, added ? "added" : "removed");
+	g_assert (ret < sizeof (buf));
+	g_signal_emit_by_name (self, buf, changed);
+}
+
 static void
 object_property_complete (ObjectCreatedData *odata)
 {
 	NMObject *self = odata->self;
 	NMObjectPrivate *priv = NM_OBJECT_GET_PRIVATE (self);
 	PropertyInfo *pi = odata->pi;
+	gboolean different = TRUE;
 
 	if (odata->array) {
-		GPtrArray **array = pi->field;
+		GPtrArray *old = *((GPtrArray **) pi->field);
+		GPtrArray *new;
 		int i;
 
-		if (*array)
-			g_boxed_free (NM_TYPE_OBJECT_ARRAY, *array);
-		*array = g_ptr_array_sized_new (odata->length);
+		/* Build up new array */
+		new = g_ptr_array_sized_new (odata->length);
 		for (i = 0; i < odata->length; i++)
-			add_to_object_array_unique (*array, odata->objects[i]);
+			add_to_object_array_unique (new, odata->objects[i]);
+
+		if (pi->signal_prefix) {
+			GPtrArray *added = g_ptr_array_sized_new (3);
+			GPtrArray *removed = g_ptr_array_sized_new (3);
+
+			if (old) {
+				/* Find objects in 'old' that do not exist in 'new' */
+				array_diff (old, new, removed);
+
+				/* Find objects in 'new' that do not exist in old */
+				array_diff (new, old, added);
+			} else {
+				for (i = 0; i < new->len; i++)
+					g_ptr_array_add (added, g_ptr_array_index (new, i));
+			}
+
+			*((GPtrArray **) pi->field) = new;
+
+			/* Emit added & removed */
+			for (i = 0; i < removed->len; i++) {
+				emit_added_removed_signal (self,
+				                           pi->signal_prefix,
+				                           g_ptr_array_index (removed, i),
+				                           FALSE);
+			}
+
+			for (i = 0; i < added->len; i++) {
+				emit_added_removed_signal (self,
+				                           pi->signal_prefix,
+				                           g_ptr_array_index (added, i),
+				                           TRUE);
+			}
+
+			different = removed->len || added->len;
+			g_ptr_array_free (added, TRUE);
+			g_ptr_array_free (removed, TRUE);
+		} else {
+			/* No added/removed signals to send, just replace the property with
+			 * the new values.
+			 */
+			*((GPtrArray **) pi->field) = new;
+			different = TRUE;
+		}
+
+		/* Free old array last since it will release references, thus freeing
+		 * any objects in the 'removed' array.
+		 */
+		if (old)
+			g_boxed_free (NM_TYPE_OBJECT_ARRAY, old);
 	} else {
 		GObject **obj_p = pi->field;
 
+		different = (*obj_p != odata->objects[0]);
 		if (*obj_p)
 			g_object_unref (*obj_p);
 		*obj_p = odata->objects[0];
 	}
 
-	if (odata->property_name)
+	if (different && odata->property_name)
 		_nm_object_queue_notify (self, odata->property_name);
 
 	if (priv->reload_results && --priv->reload_remaining == 0)
@@ -1045,6 +1209,7 @@ _nm_object_register_properties (NMObject *object,
 		pi->func = tmp->func ? tmp->func : demarshal_generic;
 		pi->object_type = tmp->object_type;
 		pi->field = tmp->field;
+		pi->signal_prefix = tmp->signal_prefix;
 		g_hash_table_insert (instance, g_strdup (tmp->name), pi);
 	}
 }
@@ -1055,10 +1220,8 @@ _nm_object_reload_properties (NMObject *object, GError **error)
 	NMObjectPrivate *priv = NM_OBJECT_GET_PRIVATE (object);
 	GHashTable *props = NULL;
 	GSList *p;
-	GHashTableIter pp;
-	gpointer name, info;
 
-	if (!priv->property_interfaces)
+	if (!priv->property_interfaces || !priv->nm_running)
 		return TRUE;
 
 	for (p = priv->property_interfaces; p; p = p->next) {
@@ -1073,12 +1236,6 @@ _nm_object_reload_properties (NMObject *object, GError **error)
 		g_hash_table_destroy (props);
 	}
 
-	if (priv->pseudo_properties) {
-		g_hash_table_iter_init (&pp, priv->pseudo_properties);
-		while (g_hash_table_iter_next (&pp, &name, &info))
-			_nm_object_reload_pseudo_property (object, name);
-	}
-
 	return TRUE;
 }
 
@@ -1116,20 +1273,23 @@ _nm_object_reload_property (NMObject *object,
                             const char *interface,
                             const char *prop_name)
 {
-	GValue value = { 0, };
+	GValue value = G_VALUE_INIT;
 	GError *err = NULL;
 
 	g_return_if_fail (NM_IS_OBJECT (object));
 	g_return_if_fail (interface != NULL);
 	g_return_if_fail (prop_name != NULL);
 
+	if (!NM_OBJECT_GET_PRIVATE (object)->nm_running)
+		return;
+
 	if (!dbus_g_proxy_call_with_timeout (NM_OBJECT_GET_PRIVATE (object)->properties_proxy,
-							"Get", 15000, &err,
-							G_TYPE_STRING, interface,
-							G_TYPE_STRING, prop_name,
-							G_TYPE_INVALID,
-							G_TYPE_VALUE, &value,
-							G_TYPE_INVALID)) {
+	                                     "Get", 15000, &err,
+	                                     G_TYPE_STRING, interface,
+	                                     G_TYPE_STRING, prop_name,
+	                                     G_TYPE_INVALID,
+	                                     G_TYPE_VALUE, &value,
+	                                     G_TYPE_INVALID)) {
 		dbgmsg ("%s: Error getting '%s' for %s: (%d) %s\n",
 		        __func__,
 		        prop_name,
@@ -1146,15 +1306,18 @@ _nm_object_reload_property (NMObject *object,
 
 void
 _nm_object_set_property (NMObject *object,
-						const char *interface,
-						const char *prop_name,
-						GValue *value)
+                         const char *interface,
+                         const char *prop_name,
+                         GValue *value)
 {
 	g_return_if_fail (NM_IS_OBJECT (object));
 	g_return_if_fail (interface != NULL);
 	g_return_if_fail (prop_name != NULL);
 	g_return_if_fail (G_IS_VALUE (value));
 
+	if (!NM_OBJECT_GET_PRIVATE (object)->nm_running)
+		return;
+
 	if (!dbus_g_proxy_call_with_timeout (NM_OBJECT_GET_PRIVATE (object)->properties_proxy,
 	                                     "Set", 2000, NULL,
 	                                     G_TYPE_STRING, interface,
@@ -1169,163 +1332,6 @@ _nm_object_set_property (NMObject *object,
 }
 
 static void
-pseudo_property_object_created (GObject *obj, const char *path, gpointer user_data)
-{
-	PseudoPropertyInfo *ppi = user_data;
-
-	if (obj) {
-		GPtrArray **list_p = (GPtrArray **)ppi->pi.field;
-
-		if (!*list_p)
-			*list_p = g_ptr_array_new ();
-		add_to_object_array_unique (*list_p, obj);
-		ppi->added_func (ppi->self, NM_OBJECT (obj));
-	}
-}
-
-static void
-pseudo_property_added (DBusGProxy *proxy, const char *path, gpointer user_data)
-{
-	PseudoPropertyInfo *ppi = user_data;
-	NMObjectPrivate *priv = NM_OBJECT_GET_PRIVATE (ppi->self);
-	NMObject *obj;
-
-	if (priv->suppress_property_updates)
-		return;
-
-	obj = _nm_object_cache_get (path);
-	if (obj)
-		pseudo_property_object_created (G_OBJECT (obj), path, ppi);
-	else {
-		_nm_object_create_async (ppi->pi.object_type, priv->connection, path,
-		                         pseudo_property_object_created, ppi);
-	}
-}
-
-static void
-pseudo_property_removed (DBusGProxy *proxy, const char *path, gpointer user_data)
-{
-	PseudoPropertyInfo *ppi = user_data;
-	NMObjectPrivate *priv = NM_OBJECT_GET_PRIVATE (ppi->self);
-	GPtrArray *list = *(GPtrArray **)ppi->pi.field;
-	NMObject *obj = NULL;
-	int i;
-
-	if (!list || priv->suppress_property_updates)
-		return;
-
-	for (i = 0; i < list->len; i++) {
-		obj = list->pdata[i];
-		if (!strcmp (path, nm_object_get_path (obj))) {
-			g_ptr_array_remove_index (list, i);
-			ppi->removed_func (ppi->self, obj);
-			g_object_unref (obj);
-			return;
-		}
-	}
-}
-
-static void
-free_pseudo_property (PseudoPropertyInfo *ppi)
-{
-	g_object_unref (ppi->proxy);
-	g_free (ppi->get_method);
-	g_slice_free (PseudoPropertyInfo, ppi);
-}
-
-void
-_nm_object_register_pseudo_property (NMObject *object,
-                                     DBusGProxy *proxy,
-                                     const char *name,
-                                     gpointer field,
-                                     GType object_type,
-                                     NMPseudoPropertyChangedFunc added_func,
-                                     NMPseudoPropertyChangedFunc removed_func)
-{
-	NMObjectPrivate *priv = NM_OBJECT_GET_PRIVATE (object);
-	PseudoPropertyInfo *ppi;
-	int basename_len;
-	char *added_signal, *removed_signal;
-
-	g_return_if_fail (NM_IS_OBJECT (object));
-	g_return_if_fail (proxy != NULL);
-
-	ppi = g_slice_new0 (PseudoPropertyInfo);
-	ppi->pi.field = field;
-	ppi->pi.object_type = object_type;
-	ppi->self = object;
-	ppi->proxy = g_object_ref (proxy);
-	ppi->added_func = added_func;
-	ppi->removed_func = removed_func;
-
-	basename_len = strlen (name);
-	if (basename_len > 4 && !strcmp (name + basename_len - 4, "List"))
-		basename_len -= 4;
-	else if (basename_len > 1 && name[basename_len - 1] == 's')
-		basename_len--;
-	else
-		g_assert_not_reached ();
-
-	ppi->get_method = g_strdup_printf ("Get%s", name);
-	added_signal = g_strdup_printf ("%.*sAdded", basename_len, name);
-	removed_signal = g_strdup_printf ("%.*sRemoved", basename_len, name);
-
-	if (!priv->pseudo_properties) {
-		priv->pseudo_properties = g_hash_table_new_full (g_str_hash, g_str_equal,
-		                                                 g_free, (GDestroyNotify) free_pseudo_property);
-	}
-	g_hash_table_insert (priv->pseudo_properties, g_strdup (name), ppi);
-
-	dbus_g_proxy_add_signal (proxy, added_signal,
-	                         DBUS_TYPE_G_OBJECT_PATH,
-	                         G_TYPE_INVALID);
-	dbus_g_proxy_connect_signal (proxy, added_signal,
-	                             G_CALLBACK (pseudo_property_added),
-	                             ppi, NULL);
-
-	dbus_g_proxy_add_signal (proxy, removed_signal,
-	                         DBUS_TYPE_G_OBJECT_PATH,
-	                         G_TYPE_INVALID);
-	dbus_g_proxy_connect_signal (proxy, removed_signal,
-	                             G_CALLBACK (pseudo_property_removed),
-	                             ppi, NULL);
-
-	g_free (added_signal);
-	g_free (removed_signal);
-}
-
-void
-_nm_object_reload_pseudo_property (NMObject *object,
-                                   const char *name)
-{
-	NMObjectPrivate *priv = NM_OBJECT_GET_PRIVATE (object);
-	PseudoPropertyInfo *ppi;
-	GPtrArray *temp;
-	GError *error = NULL;
-	GValue value = { 0, };
-
-	g_return_if_fail (NM_IS_OBJECT (object));
-	g_return_if_fail (name != NULL);
-
-	ppi = g_hash_table_lookup (priv->pseudo_properties, name);
-	g_return_if_fail (ppi != NULL);
-
-	if (!dbus_g_proxy_call (ppi->proxy, ppi->get_method, &error,
-	                        G_TYPE_INVALID,
-	                        DBUS_TYPE_G_ARRAY_OF_OBJECT_PATH, &temp,
-	                        G_TYPE_INVALID)) {
-		g_warning ("%s: error calling %s: %s", __func__, ppi->get_method, error->message);
-		g_error_free (error);
-		return;
-	}
-
-	g_value_init (&value, DBUS_TYPE_G_ARRAY_OF_OBJECT_PATH);
-	g_value_take_boxed (&value, temp);
-	handle_object_array_property (object, NULL, &value, &ppi->pi, TRUE);
-	g_value_unset (&value);
-}
-
-static void
 reload_complete (NMObject *object)
 {
 	NMObjectPrivate *priv = NM_OBJECT_GET_PRIVATE (object);
@@ -1378,36 +1384,6 @@ reload_got_properties (DBusGProxy *proxy, DBusGProxyCall *call,
 		reload_complete (object);
 }
 
-static void
-reload_got_pseudo_property (DBusGProxy *proxy, DBusGProxyCall *call,
-                            gpointer user_data)
-{
-	PseudoPropertyInfo *ppi = user_data;
-	NMObject *object = ppi->self;
-	NMObjectPrivate *priv = NM_OBJECT_GET_PRIVATE (object);
-	GPtrArray *temp;
-	GValue value = { 0, };
-	GError *error = NULL;
-
-	if (dbus_g_proxy_end_call (proxy, call, &error,
-	                           DBUS_TYPE_G_ARRAY_OF_OBJECT_PATH, &temp,
-	                           G_TYPE_INVALID)) {
-		g_value_init (&value, DBUS_TYPE_G_ARRAY_OF_OBJECT_PATH);
-		g_value_take_boxed (&value, temp);
-		if (!priv->suppress_property_updates)
-			handle_object_array_property (object, NULL, &value, &ppi->pi, FALSE);
-		g_value_unset (&value);
-	} else {
-		if (priv->reload_error)
-			g_error_free (error);
-		else
-			priv->reload_error = error;
-	}
-
-	if (--priv->reload_remaining == 0)
-		reload_complete (object);
-}
-
 void
 _nm_object_reload_properties_async (NMObject *object, GAsyncReadyCallback callback, gpointer user_data)
 {
@@ -1418,7 +1394,7 @@ _nm_object_reload_properties_async (NMObject *object, GAsyncReadyCallback callba
 	simple = g_simple_async_result_new (G_OBJECT (object), callback,
 	                                    user_data, _nm_object_reload_properties_async);
 
-	if (!priv->property_interfaces && !priv->pseudo_properties) {
+	if (!priv->property_interfaces) {
 		g_simple_async_result_complete_in_idle (simple);
 		g_object_unref (simple);
 		return;
@@ -1440,21 +1416,6 @@ _nm_object_reload_properties_async (NMObject *object, GAsyncReadyCallback callba
 		                         G_TYPE_STRING, p->data,
 		                         G_TYPE_INVALID);
 	}
-
-	if (priv->pseudo_properties) {
-		GHashTableIter iter;
-		gpointer key, value;
-		PseudoPropertyInfo *ppi;
-
-		g_hash_table_iter_init (&iter, priv->pseudo_properties);
-		while (g_hash_table_iter_next (&iter, &key, &value)) {
-			ppi = value;
-			priv->reload_remaining++;
-			dbus_g_proxy_begin_call (ppi->proxy, ppi->get_method,
-			                         reload_got_pseudo_property, ppi, NULL,
-			                         G_TYPE_INVALID);
-		}
-	}
 }
 
 gboolean
@@ -1471,3 +1432,18 @@ _nm_object_reload_properties_finish (NMObject *object, GAsyncResult *result, GEr
 
 	return g_simple_async_result_get_op_res_gboolean (simple);
 }
+
+DBusGProxy *
+_nm_object_new_proxy (NMObject *self, const char *path, const char *interface)
+{
+	NMObjectPrivate *priv = NM_OBJECT_GET_PRIVATE (self);
+
+	return _nm_dbus_new_proxy_for_connection (priv->connection, path ? path : priv->path, interface);
+}
+
+gboolean
+_nm_object_is_connection_private (NMObject *self)
+{
+	return _nm_dbus_is_connection_private (NM_OBJECT_GET_PRIVATE (self)->connection);
+}
+
diff --git a/libnm-glib/nm-object.h b/libnm-glib/nm-object.h
index eac713c6..ae97184f 100644
--- a/libnm-glib/nm-object.h
+++ b/libnm-glib/nm-object.h
@@ -28,6 +28,8 @@
 #include <glib-object.h>
 #include <dbus/dbus-glib.h>
 
+#include <nm-version.h>
+
 G_BEGIN_DECLS
 
 #define NM_TYPE_OBJECT            (nm_object_get_type ())
diff --git a/libnm-glib/nm-remote-connection.c b/libnm-glib/nm-remote-connection.c
index 9cadf2f7..38911a43 100644
--- a/libnm-glib/nm-remote-connection.c
+++ b/libnm-glib/nm-remote-connection.c
@@ -23,14 +23,17 @@
 
 #include <string.h>
 #include <gio/gio.h>
+#include <glib/gi18n.h>
 
 #include <NetworkManager.h>
 #include <nm-utils.h>
 #include <nm-setting-connection.h>
 #include "nm-remote-connection.h"
 #include "nm-remote-connection-private.h"
+#include "nm-object-private.h"
 #include "nm-dbus-glib-types.h"
 #include "nm-glib-compat.h"
+#include "nm-dbus-helpers-private.h"
 
 #define NM_REMOTE_CONNECTION_BUS "bus"
 #define NM_REMOTE_CONNECTION_DBUS_CONNECTION "dbus-connection"
@@ -49,6 +52,7 @@ enum {
 	PROP_BUS,
 	PROP_DBUS_CONNECTION,
 	PROP_DBUS_PATH,
+	PROP_UNSAVED,
 
 	LAST_PROP
 };
@@ -62,10 +66,14 @@ enum {
 };
 static guint signals[LAST_SIGNAL] = { 0 };
 
+typedef struct RemoteCall RemoteCall;
+typedef void (*RemoteCallFetchResultCb) (RemoteCall *call, DBusGProxyCall *proxy_call, GError *error);
 
-typedef struct {
+
+typedef struct RemoteCall {
 	NMRemoteConnection *self;
 	DBusGProxyCall *call;
+	RemoteCallFetchResultCb fetch_result_cb;
 	GFunc callback;
 	gpointer user_data;
 } RemoteCall;
@@ -73,44 +81,156 @@ typedef struct {
 typedef struct {
 	DBusGConnection *bus;
 	DBusGProxy *proxy;
+	DBusGProxy *props_proxy;
+	gboolean proxy_is_destroyed;
 	GSList *calls;
 
+	gboolean inited;
+	gboolean unsaved;
+
 	gboolean visible;
 } NMRemoteConnectionPrivate;
 
 #define NM_REMOTE_CONNECTION_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), NM_TYPE_REMOTE_CONNECTION, NMRemoteConnectionPrivate))
 
+/**
+ * nm_remote_connection_error_quark:
+ *
+ * Registers an error quark for #NMRemoteConnection if necessary.
+ *
+ * Returns: the error quark used for #NMRemoteConnection errors.
+ **/
+GQuark
+nm_remote_connection_error_quark (void)
+{
+	static GQuark quark = 0;
+
+	if (G_UNLIKELY (quark == 0))
+		quark = g_quark_from_static_string ("nm-remote-connection-error-quark");
+	return quark;
+}
+
 /****************************************************************/
 
 static void
-remote_call_complete (NMRemoteConnection *self, RemoteCall *call)
+_nm_remote_connection_ensure_inited (NMRemoteConnection *self)
 {
 	NMRemoteConnectionPrivate *priv = NM_REMOTE_CONNECTION_GET_PRIVATE (self);
+	GError *error = NULL;
 
-	priv->calls = g_slist_remove (priv->calls, call);
-	/* Don't need to cancel it since this function should only be called from
-	 * the dispose handler (where the proxy will be destroyed immediately after)
-	 * or from the call's completion callback.
-	 */
-	memset (call, 0, sizeof (RemoteCall));
-	g_free (call);
+	if (!priv->inited) {
+		if (!g_initable_init (G_INITABLE (self), NULL, &error)) {
+			/* Don't warn when the call times out because the settings service can't
+			 * be activated or whatever.
+			 */
+			if (!g_error_matches (error, DBUS_GERROR, DBUS_GERROR_NO_REPLY)) {
+				g_warning ("%s: (NMRemoteConnection) error initializing: %s\n",
+					       __func__, error->message);
+			}
+			g_error_free (error);
+		}
+		priv->inited = TRUE;
+	}
 }
 
+/****************************************************************/
+
 static void
-update_cb (DBusGProxy *proxy, DBusGProxyCall *proxy_call, gpointer user_data)
+remote_call_dbus_cb (DBusGProxy *proxy, DBusGProxyCall *proxy_call, gpointer user_data)
 {
 	RemoteCall *call = user_data;
-	NMRemoteConnectionCommitFunc func = (NMRemoteConnectionCommitFunc) call->callback;
+	NMRemoteConnectionPrivate *priv = NM_REMOTE_CONNECTION_GET_PRIVATE (call->self);
 	GError *error = NULL;
-	NMRemoteConnection *self = g_object_ref (call->self);
 
-	dbus_g_proxy_end_call (proxy, proxy_call, &error,
-	                       G_TYPE_INVALID);
-	if (func != NULL)
-		(*func)(call->self, error, call->user_data);
+	g_assert ( (!proxy && !proxy_call &&  priv->proxy_is_destroyed) ||
+	           ( proxy &&  proxy_call && !priv->proxy_is_destroyed && proxy == priv->proxy) );
+
+	if (priv->proxy_is_destroyed) {
+		error = g_error_new_literal (NM_REMOTE_CONNECTION_ERROR,
+		                             NM_REMOTE_CONNECTION_ERROR_DISCONNECTED,
+		                             _("Disconnected by D-Bus"));
+	}
+	call->fetch_result_cb (call, proxy_call, error);
 	g_clear_error (&error);
-	remote_call_complete (call->self, call);
-	g_object_unref (self);
+
+	priv->calls = g_slist_remove (priv->calls, call);
+	g_object_unref (call->self);
+	g_free (call);
+}
+
+static gboolean
+remote_call_cleanup_cb (void *user_data)
+{
+	remote_call_dbus_cb (NULL, NULL, user_data);
+	return G_SOURCE_REMOVE;
+}
+
+static RemoteCall *
+remote_call_new (NMRemoteConnection *self,
+                 RemoteCallFetchResultCb fetch_result_cb,
+                 GFunc callback,
+                 gpointer user_data)
+{
+	RemoteCall *call;
+	NMRemoteConnectionPrivate *priv = NM_REMOTE_CONNECTION_GET_PRIVATE (self);
+
+	g_assert (fetch_result_cb);
+
+	if (priv->proxy_is_destroyed && !callback)
+		return NULL;
+
+	call = g_malloc0 (sizeof (RemoteCall));
+	call->self = g_object_ref (self);
+	call->fetch_result_cb = fetch_result_cb;
+	call->user_data = user_data;
+	call->callback = callback;
+
+	if (priv->proxy_is_destroyed) {
+		g_idle_add (remote_call_cleanup_cb, call);
+		return NULL;
+	}
+	priv->calls = g_slist_prepend (priv->calls, call);
+	return call;
+}
+
+static void
+proxy_set_destroyed (NMRemoteConnection *self)
+{
+	NMRemoteConnectionPrivate *priv = NM_REMOTE_CONNECTION_GET_PRIVATE (self);
+
+	if (priv->proxy_is_destroyed) {
+		g_assert (!priv->calls);
+		return;
+	}
+
+	priv->proxy_is_destroyed = TRUE;
+
+	priv->calls = g_slist_reverse (priv->calls);
+	while (priv->calls)
+		remote_call_dbus_cb (NULL, NULL, priv->calls->data);
+}
+
+static void
+proxy_destroy_cb (DBusGProxy* proxy, gpointer user_data) {
+	proxy_set_destroyed (user_data);
+}
+
+/****************************************************************/
+
+static void
+result_cb (RemoteCall *call, DBusGProxyCall *proxy_call, GError *error)
+{
+	NMRemoteConnectionResultFunc func = (NMRemoteConnectionResultFunc) call->callback;
+	GError *local_error = NULL;
+
+	if (!error) {
+		dbus_g_proxy_end_call (NM_REMOTE_CONNECTION_GET_PRIVATE (call->self)->proxy,
+		                       proxy_call, &local_error, G_TYPE_INVALID);
+		error = local_error;
+	}
+	if (func)
+		(*func) (call->self, error, call->user_data);
+	g_clear_error (&local_error);
 }
 
 /**
@@ -120,54 +240,105 @@ update_cb (DBusGProxy *proxy, DBusGProxyCall *proxy_call, gpointer user_data)
  * commit completes
  * @user_data: (closure): caller-specific data to be passed to @callback
  *
- * Save any local changes to the settings and properties of this connection and
- * save them in the settings service.
+ * Send any local changes to the settings and properties of this connection to
+ * NetworkManager, which will immediately save them to disk.
  **/
 void
 nm_remote_connection_commit_changes (NMRemoteConnection *self,
-                                     NMRemoteConnectionCommitFunc callback,
+                                     NMRemoteConnectionResultFunc callback,
                                      gpointer user_data)
 {
 	NMRemoteConnectionPrivate *priv;
-	GHashTable *settings = NULL;
 	RemoteCall *call;
+	GHashTable *settings;
 
-	g_return_if_fail (self != NULL);
 	g_return_if_fail (NM_IS_REMOTE_CONNECTION (self));
-	g_return_if_fail (callback != NULL);
 
 	priv = NM_REMOTE_CONNECTION_GET_PRIVATE (self);
 
-	call = g_malloc0 (sizeof (RemoteCall));
-	call->self = self;
-	call->callback = (GFunc) callback;
-	call->user_data = user_data;
+	call = remote_call_new (self, result_cb, (GFunc) callback, user_data);
+	if (!call)
+		return;
 
 	settings = nm_connection_to_hash (NM_CONNECTION (self), NM_SETTING_HASH_FLAG_ALL);
-
 	call->call = dbus_g_proxy_begin_call (priv->proxy, "Update",
-	                                      update_cb, call, NULL,
+	                                      remote_call_dbus_cb, call, NULL,
 	                                      DBUS_TYPE_G_MAP_OF_MAP_OF_VARIANT, settings,
 	                                      G_TYPE_INVALID);
 	g_assert (call->call);
-	priv->calls = g_slist_append (priv->calls, call);
+	g_hash_table_destroy (settings);
+}
 
+/**
+ * nm_remote_connection_commit_changes_unsaved:
+ * @connection: the #NMRemoteConnection
+ * @callback: (scope async) (allow-none): a function to be called when the
+ * commit completes
+ * @user_data: (closure): caller-specific data to be passed to @callback
+ *
+ * Send any local changes to the settings and properties of this connection to
+ * NetworkManager.  The changes are not saved to disk until either
+ * nm_remote_connection_save() or nm_remote_connection_commit_changes() is
+ * called.
+ *
+ * Since: 0.9.10
+ **/
+void
+nm_remote_connection_commit_changes_unsaved (NMRemoteConnection *connection,
+                                             NMRemoteConnectionResultFunc callback,
+                                             gpointer user_data)
+{
+	NMRemoteConnectionPrivate *priv;
+	GHashTable *settings = NULL;
+	RemoteCall *call;
+
+	g_return_if_fail (NM_IS_REMOTE_CONNECTION (connection));
+
+	priv = NM_REMOTE_CONNECTION_GET_PRIVATE (connection);
+
+	call = remote_call_new (connection, result_cb, (GFunc) callback, user_data);
+	if (!call)
+		return;
+
+	settings = nm_connection_to_hash (NM_CONNECTION (connection), NM_SETTING_HASH_FLAG_ALL);
+	call->call = dbus_g_proxy_begin_call (priv->proxy, "UpdateUnsaved",
+	                                      remote_call_dbus_cb, call, NULL,
+	                                      DBUS_TYPE_G_MAP_OF_MAP_OF_VARIANT, settings,
+	                                      G_TYPE_INVALID);
+	g_assert (call->call);
 	g_hash_table_destroy (settings);
 }
 
-static void
-delete_cb (DBusGProxy *proxy, DBusGProxyCall *proxy_call, gpointer user_data)
+/**
+ * nm_remote_connection_save:
+ * @connection: the #NMRemoteConnection
+ * @callback: (scope async) (allow-none): a function to be called when the
+ * save completes
+ * @user_data: (closure): caller-specific data to be passed to @callback
+ *
+ * Saves the connection to disk if the connection has changes that have not yet
+ * been written to disk, or if the connection has never been saved.
+ *
+ * Since: 0.9.10
+ **/
+void
+nm_remote_connection_save (NMRemoteConnection *connection,
+                           NMRemoteConnectionResultFunc callback,
+                           gpointer user_data)
 {
-	RemoteCall *call = user_data;
-	NMRemoteConnectionDeleteFunc func = (NMRemoteConnectionDeleteFunc) call->callback;
-	GError *error = NULL;
+	NMRemoteConnectionPrivate *priv;
+	RemoteCall *call;
 
-	dbus_g_proxy_end_call (proxy, proxy_call, &error,
-	                       G_TYPE_INVALID);
-	if (func != NULL)
-		(*func)(call->self, error, call->user_data);
-	g_clear_error (&error);
-	remote_call_complete (call->self, call);
+	g_return_if_fail (NM_IS_REMOTE_CONNECTION (connection));
+
+	priv = NM_REMOTE_CONNECTION_GET_PRIVATE (connection);
+
+	call = remote_call_new (connection, result_cb, (GFunc) callback, user_data);
+	if (!call)
+		return;
+
+	call->call = dbus_g_proxy_begin_call (priv->proxy, "Save", remote_call_dbus_cb, call, NULL, G_TYPE_INVALID);
+	g_assert (call->call);
 }
 
 /**
@@ -180,47 +351,48 @@ delete_cb (DBusGProxy *proxy, DBusGProxyCall *proxy_call, gpointer user_data)
  **/
 void
 nm_remote_connection_delete (NMRemoteConnection *self,
-                             NMRemoteConnectionDeleteFunc callback,
+                             NMRemoteConnectionResultFunc callback,
                              gpointer user_data)
 {
 	NMRemoteConnectionPrivate *priv;
 	RemoteCall *call;
 
-	g_return_if_fail (self != NULL);
 	g_return_if_fail (NM_IS_REMOTE_CONNECTION (self));
 
 	priv = NM_REMOTE_CONNECTION_GET_PRIVATE (self);
 
-	call = g_malloc0 (sizeof (RemoteCall));
-	call->self = self;
-	call->callback = (GFunc) callback;
-	call->user_data = user_data;
+	call = remote_call_new (self, result_cb, (GFunc) callback, user_data);
+	if (!call)
+		return;
 
 	call->call = dbus_g_proxy_begin_call (priv->proxy, "Delete",
-	                                      delete_cb, call, NULL,
+	                                      remote_call_dbus_cb, call, NULL,
 	                                      G_TYPE_INVALID);
 	g_assert (call->call);
-	priv->calls = g_slist_append (priv->calls, call);
 }
 
 static void
-get_secrets_cb (DBusGProxy *proxy, DBusGProxyCall *proxy_call, gpointer user_data)
+get_secrets_cb (RemoteCall *call, DBusGProxyCall *proxy_call, GError *error)
 {
-	RemoteCall *call = user_data;
 	NMRemoteConnectionGetSecretsFunc func = (NMRemoteConnectionGetSecretsFunc) call->callback;
 	GHashTable *secrets = NULL;
-	GError *error = NULL;
-
-	dbus_g_proxy_end_call (proxy, proxy_call, &error,
-	                       DBUS_TYPE_G_MAP_OF_MAP_OF_VARIANT, &secrets,
-	                       G_TYPE_INVALID);
-	(*func)(call->self, error ? NULL : secrets, error, call->user_data);
+	GError *local_error = NULL;
+
+	if (!error) {
+		dbus_g_proxy_end_call (NM_REMOTE_CONNECTION_GET_PRIVATE (call->self)->proxy,
+		                       proxy_call, &local_error,
+		                       DBUS_TYPE_G_MAP_OF_MAP_OF_VARIANT, &secrets,
+		                       G_TYPE_INVALID);
+		error = local_error;
+	}
+	if (func)
+		(*func) (call->self, error ? NULL : secrets, error, call->user_data);
+	g_clear_error (&local_error);
 	if (secrets)
 		g_hash_table_destroy (secrets);
-	g_clear_error (&error);
-	remote_call_complete (call->self, call);
 }
 
+
 /**
  * nm_remote_connection_get_secrets:
  * @connection: the #NMRemoteConnection
@@ -240,23 +412,39 @@ nm_remote_connection_get_secrets (NMRemoteConnection *self,
 	NMRemoteConnectionPrivate *priv;
 	RemoteCall *call;
 
-	g_return_if_fail (self != NULL);
 	g_return_if_fail (NM_IS_REMOTE_CONNECTION (self));
 	g_return_if_fail (callback != NULL);
 
 	priv = NM_REMOTE_CONNECTION_GET_PRIVATE (self);
 
-	call = g_malloc0 (sizeof (RemoteCall));
-	call->self = self;
-	call->callback = (GFunc) callback;
-	call->user_data = user_data;
+	call = remote_call_new (self, get_secrets_cb, (GFunc) callback, user_data);
+	if (!call)
+		return;
 
 	call->call = dbus_g_proxy_begin_call (priv->proxy, "GetSecrets",
-	                                      get_secrets_cb, call, NULL,
+	                                      remote_call_dbus_cb, call, NULL,
 	                                      G_TYPE_STRING, setting_name,
 	                                      G_TYPE_INVALID);
 	g_assert (call->call);
-	priv->calls = g_slist_append (priv->calls, call);
+}
+
+/**
+ * nm_remote_connection_get_unsaved:
+ * @connection: the #NMRemoteConnection
+ *
+ * Returns: %TRUE if the remote connection contains changes that have not
+ * been saved to disk, %FALSE if the connection is the same as its on-disk
+ * representation.
+ *
+ * Since: 0.9.10
+ **/
+gboolean
+nm_remote_connection_get_unsaved (NMRemoteConnection *connection)
+{
+	g_return_val_if_fail (NM_IS_REMOTE_CONNECTION (connection), FALSE);
+
+	_nm_remote_connection_ensure_inited (connection);
+	return NM_REMOTE_CONNECTION_GET_PRIVATE (connection)->unsaved;
 }
 
 /****************************************************************/
@@ -328,9 +516,11 @@ updated_cb (DBusGProxy *proxy, gpointer user_data)
 	NMRemoteConnectionPrivate *priv = NM_REMOTE_CONNECTION_GET_PRIVATE (self);
 
 	/* The connection got updated; request the replacement settings */
-	dbus_g_proxy_begin_call (priv->proxy, "GetSettings",
-	                         updated_get_settings_cb, self, NULL,
-	                         G_TYPE_INVALID);
+	if (!priv->proxy_is_destroyed) {
+		dbus_g_proxy_begin_call (priv->proxy, "GetSettings",
+		                         updated_get_settings_cb, self, NULL,
+		                         G_TYPE_INVALID);
+	}
 }
 
 static void
@@ -339,6 +529,25 @@ removed_cb (DBusGProxy *proxy, gpointer user_data)
 	g_signal_emit (G_OBJECT (user_data), signals[REMOVED], 0);
 }
 
+static void
+properties_changed_cb (DBusGProxy *proxy,
+                       GHashTable *properties,
+                       gpointer user_data)
+{
+	NMRemoteConnection *self = NM_REMOTE_CONNECTION (user_data);
+	GHashTableIter iter;
+	const char *key;
+	GValue *value;
+
+	g_hash_table_iter_init (&iter, properties);
+	while (g_hash_table_iter_next (&iter, (gpointer) &key, (gpointer) &value)) {
+		if (!strcmp (key, "Unsaved")) {
+			NM_REMOTE_CONNECTION_GET_PRIVATE (self)->unsaved = g_value_get_boolean (value);
+			g_object_notify (G_OBJECT (self), NM_REMOTE_CONNECTION_UNSAVED);
+		}
+	}
+}
+
 /****************************************************************/
 
 /**
@@ -366,16 +575,16 @@ nm_remote_connection_new (DBusGConnection *bus,
 static void
 constructed (GObject *object)
 {
-	NMRemoteConnectionPrivate *priv;
+	NMRemoteConnectionPrivate *priv = NM_REMOTE_CONNECTION_GET_PRIVATE (object);
+
+	G_OBJECT_CLASS (nm_remote_connection_parent_class)->constructed (object);
 
-	priv = NM_REMOTE_CONNECTION_GET_PRIVATE (object);
 	g_assert (priv->bus);
 	g_assert (nm_connection_get_path (NM_CONNECTION (object)));
 
-	priv->proxy = dbus_g_proxy_new_for_name (priv->bus,
-	                                         NM_DBUS_SERVICE,
-	                                         nm_connection_get_path (NM_CONNECTION (object)),
-	                                         NM_DBUS_IFACE_SETTINGS_CONNECTION);
+	priv->proxy = _nm_dbus_new_proxy_for_connection (priv->bus,
+	                                                 nm_connection_get_path (NM_CONNECTION (object)),
+	                                                 NM_DBUS_IFACE_SETTINGS_CONNECTION);
 	g_assert (priv->proxy);
 	dbus_g_proxy_set_default_timeout (priv->proxy, G_MAXINT);
 
@@ -384,23 +593,54 @@ constructed (GObject *object)
 
 	dbus_g_proxy_add_signal (priv->proxy, "Removed", G_TYPE_INVALID);
 	dbus_g_proxy_connect_signal (priv->proxy, "Removed", G_CALLBACK (removed_cb), object, NULL);
+
+	g_signal_connect (priv->proxy, "destroy", G_CALLBACK (proxy_destroy_cb), object);
+
+	/* Monitor properties */
+	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 (priv->proxy, "PropertiesChanged",
+	                         DBUS_TYPE_G_MAP_OF_VARIANT,
+	                         G_TYPE_INVALID);
+	dbus_g_proxy_connect_signal (priv->proxy, "PropertiesChanged",
+	                             G_CALLBACK (properties_changed_cb),
+	                             object,
+	                             NULL);
+
+	priv->props_proxy = _nm_dbus_new_proxy_for_connection (priv->bus,
+	                                                       nm_connection_get_path (NM_CONNECTION (object)),
+	                                                       DBUS_INTERFACE_PROPERTIES);
+	g_assert (priv->props_proxy);
 }
 
 static gboolean
 init_sync (GInitable *initable, GCancellable *cancellable, GError **error)
 {
 	NMRemoteConnectionPrivate *priv = NM_REMOTE_CONNECTION_GET_PRIVATE (initable);
-	GHashTable *settings;
+	GHashTable *hash;
 
 	if (!dbus_g_proxy_call (priv->proxy, "GetSettings", error,
 	                        G_TYPE_INVALID,
-	                        DBUS_TYPE_G_MAP_OF_MAP_OF_VARIANT, &settings,
+	                        DBUS_TYPE_G_MAP_OF_MAP_OF_VARIANT, &hash,
 	                        G_TYPE_INVALID))
 		return FALSE;
-
 	priv->visible = TRUE;
-	replace_settings (NM_REMOTE_CONNECTION (initable), settings);
-	g_hash_table_destroy (settings);
+	replace_settings (NM_REMOTE_CONNECTION (initable), hash);
+	g_hash_table_destroy (hash);
+
+	/* Get properties */
+	hash = NULL;
+	if (!dbus_g_proxy_call (priv->props_proxy, "GetAll", error,
+	                        G_TYPE_STRING, NM_DBUS_IFACE_SETTINGS_CONNECTION,
+	                        G_TYPE_INVALID,
+	                        DBUS_TYPE_G_MAP_OF_VARIANT, &hash,
+	                        G_TYPE_INVALID))
+		return FALSE;
+	properties_changed_cb (priv->props_proxy, hash, NM_REMOTE_CONNECTION (initable));
+	g_hash_table_destroy (hash);
+
 	return TRUE;
 }
 
@@ -410,6 +650,38 @@ typedef struct {
 } NMRemoteConnectionInitData;
 
 static void
+init_async_complete (NMRemoteConnectionInitData *init_data, GError *error)
+{
+	if (error)
+		g_simple_async_result_take_error (init_data->result, error);
+	else {
+		g_simple_async_result_set_op_res_gboolean (init_data->result, TRUE);
+		NM_REMOTE_CONNECTION_GET_PRIVATE (init_data->connection)->inited = TRUE;
+	}
+
+	g_simple_async_result_complete (init_data->result);
+	g_object_unref (init_data->result);
+	g_slice_free (NMRemoteConnectionInitData, init_data);
+}
+
+static void
+init_async_got_properties (DBusGProxy *proxy, DBusGProxyCall *call, gpointer user_data)
+{
+	NMRemoteConnectionInitData *init_data = user_data;
+	NMRemoteConnectionPrivate *priv = NM_REMOTE_CONNECTION_GET_PRIVATE (init_data->connection);
+	GHashTable *props;
+	GError *error = NULL;
+
+	if (dbus_g_proxy_end_call (proxy, call, &error,
+	                           DBUS_TYPE_G_MAP_OF_VARIANT, &props,
+	                           G_TYPE_INVALID)) {
+		properties_changed_cb (priv->props_proxy, props, init_data->connection);
+		g_hash_table_destroy (props);
+	}
+	init_async_complete (init_data, error);
+}
+
+static void
 init_get_settings_cb (DBusGProxy *proxy,
                       DBusGProxyCall *call,
                       gpointer user_data)
@@ -423,17 +695,19 @@ init_get_settings_cb (DBusGProxy *proxy,
 	                       DBUS_TYPE_G_MAP_OF_MAP_OF_VARIANT, &settings,
 	                       G_TYPE_INVALID);
 	if (error) {
-		g_simple_async_result_take_error (init_data->result, error);
-	} else {
-		priv->visible = TRUE;
-		replace_settings (init_data->connection, settings);
-		g_hash_table_destroy (settings);
-		g_simple_async_result_set_op_res_gboolean (init_data->result, TRUE);
+		init_async_complete (init_data, error);
+		return;
 	}
 
-	g_simple_async_result_complete (init_data->result);
-	g_object_unref (init_data->result);
-	g_slice_free (NMRemoteConnectionInitData, init_data);
+	priv->visible = TRUE;
+	replace_settings (init_data->connection, settings);
+	g_hash_table_destroy (settings);
+
+	/* Grab properties */
+	dbus_g_proxy_begin_call (priv->props_proxy, "GetAll",
+	                         init_async_got_properties, init_data, NULL,
+	                         G_TYPE_STRING, NM_DBUS_IFACE_SETTINGS_CONNECTION,
+	                         G_TYPE_INVALID);
 }
 
 static void
@@ -453,7 +727,6 @@ init_async (GAsyncInitable *initable, int io_priority,
 	dbus_g_proxy_begin_call (priv->proxy, "GetSettings",
 	                         init_get_settings_cb, init_data, NULL,
 	                         G_TYPE_INVALID);
-
 }
 
 static gboolean
@@ -510,6 +783,22 @@ constructor (GType type, guint n_construct_properties,
 }
 
 static void
+get_property (GObject *object, guint prop_id,
+              GValue *value, GParamSpec *pspec)
+{
+	_nm_remote_connection_ensure_inited (NM_REMOTE_CONNECTION (object));
+
+	switch (prop_id) {
+	case PROP_UNSAVED:
+		g_value_set_boolean (value, NM_REMOTE_CONNECTION_GET_PRIVATE (object)->unsaved);
+		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)
 {
@@ -519,8 +808,15 @@ set_property (GObject *object, guint prop_id,
 	case PROP_BUS:
 	case PROP_DBUS_CONNECTION:
 		/* Construct only */
-		if (g_value_get_boxed (value))
-			priv->bus = dbus_g_connection_ref ((DBusGConnection *) g_value_get_boxed (value));
+		/* priv->bus is set from either of two properties so that it (a) remains
+		 * backwards compatible with the previous "bus" property, and that (b)
+		 * it can be created just like an NMObject using the "dbus-connection",
+		 * even though it's not a subclass of NMObject.  So don't overwrite the
+		 * a valid value that the other property set with NULL, if one of the
+		 * properties isn't specified at construction time.
+		 */
+		if (!priv->bus)
+			priv->bus = g_value_dup_boxed (value);
 		break;
 	case PROP_DBUS_PATH:
 		/* Don't need to do anything; see constructor(). */
@@ -535,12 +831,15 @@ static void
 dispose (GObject *object)
 {
 	NMRemoteConnection *self = NM_REMOTE_CONNECTION (object);
-	NMRemoteConnectionPrivate *priv = NM_REMOTE_CONNECTION_GET_PRIVATE (object);
+	NMRemoteConnectionPrivate *priv = NM_REMOTE_CONNECTION_GET_PRIVATE (self);
 
-	while (g_slist_length (priv->calls))
-		remote_call_complete (self, priv->calls->data);
+	proxy_set_destroyed (self);
 
-	g_clear_object (&priv->proxy);
+	if (priv->proxy) {
+		g_signal_handlers_disconnect_by_func (priv->proxy, proxy_destroy_cb, object);
+		g_clear_object (&priv->proxy);
+	}
+	g_clear_object (&priv->props_proxy);
 
 	if (priv->bus) {
 		dbus_g_connection_unref (priv->bus);
@@ -559,6 +858,7 @@ nm_remote_connection_class_init (NMRemoteConnectionClass *remote_class)
 
 	/* virtual methods */
 	object_class->constructor = constructor;
+	object_class->get_property = get_property;
 	object_class->set_property = set_property;
 	object_class->dispose = dispose;
 	object_class->constructed = constructed;
@@ -588,6 +888,21 @@ nm_remote_connection_class_init (NMRemoteConnectionClass *remote_class)
 		                      NULL,
 		                      G_PARAM_WRITABLE | G_PARAM_CONSTRUCT_ONLY));
 
+	/**
+	 * NMRemoteConnection:unsaved:
+	 *
+	 * %TRUE if the remote connection contains changes that have not been saved
+	 * to disk, %FALSE if the connection is the same as its on-disk representation.
+	 *
+	 * Since: 0.9.10
+	 **/
+	g_object_class_install_property (object_class, PROP_UNSAVED,
+		 g_param_spec_boolean (NM_REMOTE_CONNECTION_UNSAVED,
+		                       "Unsaved",
+		                       "Unsaved",
+		                       FALSE,
+		                       G_PARAM_READABLE));
+
 	/* Signals */
 	/**
 	 * NMRemoteConnection::updated:
diff --git a/libnm-glib/nm-remote-connection.h b/libnm-glib/nm-remote-connection.h
index eebf9160..911885c4 100644
--- a/libnm-glib/nm-remote-connection.h
+++ b/libnm-glib/nm-remote-connection.h
@@ -38,6 +38,24 @@ G_BEGIN_DECLS
 #define NM_IS_REMOTE_CONNECTION_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), NM_TYPE_REMOTE_CONNECTION))
 #define NM_REMOTE_CONNECTION_GET_CLASS(obj)  (G_TYPE_INSTANCE_GET_CLASS ((obj), NM_TYPE_REMOTE_CONNECTION, NMRemoteConnectionClass))
 
+
+/**
+ * NMRemoteConnectionError:
+ * @NM_REMOTE_CONNECTION_ERROR_UNKNOWN: unknown or unclassified error
+ * @NM_REMOTE_CONNECTION_ERROR_DISCONNECTED: dbus disconnected
+ */
+typedef enum {
+	NM_REMOTE_CONNECTION_ERROR_UNKNOWN = 0,             /*< nick=UnknownError >*/
+	NM_REMOTE_CONNECTION_ERROR_DISCONNECTED,            /*< nick=Disconnected >*/
+} NMRemoteConnectionError;
+
+#define NM_REMOTE_CONNECTION_ERROR (nm_remote_connection_error_quark ())
+GQuark nm_remote_connection_error_quark (void);
+
+/* Properties */
+#define NM_REMOTE_CONNECTION_UNSAVED         "unsaved"
+
+/* Signals */
 #define NM_REMOTE_CONNECTION_UPDATED         "updated"
 #define NM_REMOTE_CONNECTION_REMOVED         "removed"
 
@@ -64,30 +82,21 @@ typedef struct {
 } NMRemoteConnectionClass;
 
 /**
- * NMRemoteConnectionCommitFunc:
- * @connection: the connection for which updates are to be committed
+ * NMRemoteConnectionResultFunc:
+ * @connection: the connection for which an operation was performed
  * @error: on failure, a descriptive error
- * @user_data: user data passed to nm_remote_connection_commit_changes()
+ * @user_data: user data passed to function which began the operation
  *
- * Called when NetworkManager has committed outstanding changes to a connection
- * to backing storage as a result of nm_remote_connection_commit_changes().
+ * Called when NetworkManager has finished an asynchronous operation on a
+ * connection, like commit changes, deleting, saving, etc.
  */
-typedef void (*NMRemoteConnectionCommitFunc) (NMRemoteConnection *connection,
+typedef void (*NMRemoteConnectionResultFunc) (NMRemoteConnection *connection,
                                               GError *error,
                                               gpointer user_data);
 
-/**
- * NMRemoteConnectionDeleteFunc:
- * @connection: the connection to be deleted
- * @error: on failure, a descriptive error
- * @user_data: user data passed to nm_remote_connection_delete()
- *
- * Called when NetworkManager has deleted a connection as a result of
- * nm_remote_connection_delete().
- */
-typedef void (*NMRemoteConnectionDeleteFunc) (NMRemoteConnection *connection,
-                                              GError *error,
-                                              gpointer user_data);
+/* Backwards compatibility */
+typedef NMRemoteConnectionResultFunc NMRemoteConnectionCommitFunc;
+typedef NMRemoteConnectionResultFunc NMRemoteConnectionDeleteFunc;
 
 /**
  * NMRemoteConnectionGetSecretsFunc:
@@ -112,17 +121,31 @@ NMRemoteConnection *nm_remote_connection_new (DBusGConnection *bus,
                                               const char *path);
 
 void nm_remote_connection_commit_changes (NMRemoteConnection *connection,
-                                          NMRemoteConnectionCommitFunc callback,
+                                          NMRemoteConnectionResultFunc callback,
                                           gpointer user_data);
 
+NM_AVAILABLE_IN_0_9_10
+void nm_remote_connection_commit_changes_unsaved (NMRemoteConnection *connection,
+                                                  NMRemoteConnectionResultFunc callback,
+                                                  gpointer user_data);
+
+NM_AVAILABLE_IN_0_9_10
+void nm_remote_connection_save (NMRemoteConnection *connection,
+                                NMRemoteConnectionResultFunc callback,
+                                gpointer user_data);
+
 void nm_remote_connection_delete (NMRemoteConnection *connection,
-                                  NMRemoteConnectionDeleteFunc callback,
+                                  NMRemoteConnectionResultFunc callback,
                                   gpointer user_data);
 
 void nm_remote_connection_get_secrets (NMRemoteConnection *connection,
                                        const char *setting_name,
                                        NMRemoteConnectionGetSecretsFunc callback,
                                        gpointer user_data);
+
+NM_AVAILABLE_IN_0_9_10
+gboolean nm_remote_connection_get_unsaved (NMRemoteConnection *connection);
+
 G_END_DECLS
 
 #endif  /* __NM_REMOTE_CONNECTION__ */
diff --git a/libnm-glib/nm-remote-settings.c b/libnm-glib/nm-remote-settings.c
index 34817e2c..3a2a3e68 100644
--- a/libnm-glib/nm-remote-settings.c
+++ b/libnm-glib/nm-remote-settings.c
@@ -25,11 +25,100 @@
 #include <NetworkManager.h>
 #include <nm-connection.h>
 
-#include "nm-glib-marshal.h"
 #include "nm-dbus-glib-types.h"
 #include "nm-remote-settings.h"
 #include "nm-remote-connection-private.h"
+#include "nm-object-private.h"
+#include "nm-dbus-helpers-private.h"
 #include "nm-glib-compat.h"
+#include "nm-object-private.h"
+
+/**
+ * SECTION:nm-remote-settings
+ * @Short_description: A helper for NetworkManager's settings API
+ * @Title: NMRemoteSettings
+ * @See_also:#NMRemoteConnection, #NMClient
+ *
+ * The #NMRemoteSettings object represents NetworkManager's "settings" service,
+ * which stores network configuration and allows authenticated clients to
+ * add, delete, and modify that configuration.  The data required to connect
+ * to a specific network is called a "connection" and encapsulated by the
+ * #NMConnection object.  Once a connection is known to NetworkManager, having
+ * either been added by a user or read from on-disk storage, the
+ * #NMRemoteSettings object creates a #NMRemoteConnection object which
+ * represents this stored connection.  Use the #NMRemoteConnection object to
+ * perform any operations like modification or deletion.
+ *
+ * To add a new network connection to the NetworkManager settings service, first
+ * build up a template #NMConnection object.  Since this connection is not yet
+ * added to NetworkManager, it is known only to your program and is not yet
+ * an #NMRemoteConnection.  Then ask #NMRemoteSettings to add your connection.
+ * When the connection is added successfully, the supplied callback is called
+ * and returns to your program the new #NMRemoteConnection which represents
+ * the stored object known to NetworkManager.
+ *
+ * |[<!-- language="C" -->
+ * static void
+ * added_cb (NMRemoteSettings *settings,
+ *           NMRemoteConnection *remote,
+ *           GError *error,
+ *           gpointer user_data)
+ * {
+ *    if (error)
+ *        g_print ("Error adding connection: %s", error->message);
+ *    else {
+ *        g_print ("Added: %s\n", nm_connection_get_path (NM_CONNECTION (remote)));
+ *        /&ast; Use 'remote' with nm_remote_connection_commit_changes() to save
+ *         * changes and nm_remote_connection_delete() to delete the connection &ast;/
+ *    }
+ * }
+ *
+ * static gboolean
+ * add_wired_connection (const char *human_name)
+ * {
+ *    NMConnection *connection;
+ *    NMSettingConnection *s_con;
+ *    NMSettingWired *s_wired;
+ *    char *uuid;
+ *    gboolean success;
+ *
+ *    connection = nm_connection_new ();
+ *
+ *    /&ast; Build up the 'connection' setting &ast;/
+ *    s_con = (NMSettingConnection *) nm_setting_connection_new ();
+ *    uuid = nm_utils_uuid_generate ();
+ *    g_object_set (G_OBJECT (s_con),
+ *                  NM_SETTING_CONNECTION_UUID, uuid,
+ *                  NM_SETTING_CONNECTION_ID, human_name,
+ *                  NM_SETTING_CONNECTION_TYPE, NM_SETTING_WIRED_SETTING_NAME,
+ *                  NULL);
+ *    g_free (uuid);
+ *    nm_connection_add_setting (connection, NM_SETTING (s_con));
+ *
+ *    /&ast; Add the required 'wired' setting as this is a wired connection &ast;/
+ *    nm_connection_add_setting (connection, nm_setting_wired_new ());
+ *
+ *    /&ast; Add an 'ipv4' setting using AUTO configuration (eg DHCP) &ast;/
+ *    s_ip4 = (NMSettingIP4Config *) nm_setting_ip4_config_new ();
+ *    g_object_set (G_OBJECT (s_ip4),
+ *                  NM_SETTING_IP4_CONFIG_METHOD, NM_SETTING_IP4_CONFIG_METHOD_AUTO,
+ *                  NULL);
+ *    nm_connection_add_setting (connection, NM_SETTING (s_ip4));
+ *
+ *    /&ast; Ask NetworkManager to store the connection &ast;/
+ *    success = nm_remote_settings_add_connection (settings, connection, added_cb, loop);
+ *
+ *    /&ast; Release the template connection; the actual stored connection will
+ *     * be returned in added_cb() &ast;/
+ *    g_object_unref (connection);
+ *
+ *    /&ast; Let glib event loop run and added_cb() will be called when NetworkManager
+ *     * is done adding the new connection. &ast;/
+ *
+ *    return success;
+ * }
+ * ]|
+ */
 
 static void nm_remote_settings_initable_iface_init (GInitableIface *iface);
 static void nm_remote_settings_async_initable_iface_init (GAsyncInitableIface *iface);
@@ -43,6 +132,7 @@ G_DEFINE_TYPE_WITH_CODE (NMRemoteSettings, nm_remote_settings, G_TYPE_OBJECT,
 
 typedef struct {
 	DBusGConnection *bus;
+	gboolean private_bus;
 	gboolean inited;
 
 	DBusGProxy *proxy;
@@ -60,8 +150,7 @@ typedef struct {
 
 	DBusGProxy *dbus_proxy;
 
-	guint fetch_id;
-	gboolean fetching;
+	DBusGProxyCall *listcon_call;
 } NMRemoteSettingsPrivate;
 
 enum {
@@ -172,6 +261,45 @@ add_connection_info_complete (NMRemoteSettings *self,
 }
 
 /**
+ * nm_remote_settings_get_connection_by_id:
+ * @settings: the %NMRemoteSettings
+ * @id: the id of the remote connection
+ *
+ * Returns the first matching %NMRemoteConnection matching a given @id.
+ *
+ * Returns: (transfer none): the remote connection object on success, or %NULL if no
+ *  matching object was found.
+ *
+ * Since: 0.9.10
+ **/
+NMRemoteConnection *
+nm_remote_settings_get_connection_by_id (NMRemoteSettings *settings, const char *id)
+{
+	NMRemoteSettingsPrivate *priv;
+
+	g_return_val_if_fail (NM_IS_REMOTE_SETTINGS (settings), NULL);
+	g_return_val_if_fail (id != NULL, NULL);
+
+	priv = NM_REMOTE_SETTINGS_GET_PRIVATE (settings);
+
+	_nm_remote_settings_ensure_inited (settings);
+
+	if (priv->service_running) {
+		GHashTableIter iter;
+		NMConnection *candidate;
+
+		g_hash_table_iter_init (&iter, priv->connections);
+		while (g_hash_table_iter_next (&iter, NULL, (gpointer *) &candidate)) {
+
+			if (!strcmp (id, nm_connection_get_id (candidate)))
+				return NM_REMOTE_CONNECTION (candidate);
+		}
+	}
+
+	return NULL;
+}
+
+/**
  * nm_remote_settings_get_connection_by_path:
  * @settings: the %NMRemoteSettings
  * @path: the D-Bus object path of the remote connection
@@ -186,7 +314,6 @@ nm_remote_settings_get_connection_by_path (NMRemoteSettings *settings, const cha
 {
 	NMRemoteSettingsPrivate *priv;
 
-	g_return_val_if_fail (settings != NULL, NULL);
 	g_return_val_if_fail (NM_IS_REMOTE_SETTINGS (settings), NULL);
 	g_return_val_if_fail (path != NULL, NULL);
 
@@ -214,7 +341,6 @@ nm_remote_settings_get_connection_by_uuid (NMRemoteSettings *settings, const cha
 	GHashTableIter iter;
 	NMRemoteConnection *candidate;
 
-	g_return_val_if_fail (settings != NULL, NULL);
 	g_return_val_if_fail (NM_IS_REMOTE_SETTINGS (settings), NULL);
 	g_return_val_if_fail (uuid != NULL, NULL);
 
@@ -363,9 +489,10 @@ connection_inited (GObject *source, GAsyncResult *result, gpointer user_data)
 		g_signal_emit (self, signals[NEW_CONNECTION], 0, remote);
 	} else {
 		if (addinfo) {
-			local = g_error_new_literal (NM_REMOTE_SETTINGS_ERROR,
-			                             NM_REMOTE_SETTINGS_ERROR_CONNECTION_UNAVAILABLE,
-			                             "Connection not visible or not available");
+			local = g_error_new (NM_REMOTE_SETTINGS_ERROR,
+			                     NM_REMOTE_SETTINGS_ERROR_CONNECTION_UNAVAILABLE,
+			                     "Connection not visible or not available: %s",
+			                     error ? error->message : "(unknown)");
 			add_connection_info_complete (self, addinfo, local);
 			g_error_free (local);
 		}
@@ -382,10 +509,8 @@ connection_inited (GObject *source, GAsyncResult *result, gpointer user_data)
 
 	/* Let listeners know that all connections have been found */
 	priv->init_left--;
-	if (priv->init_left == 0) {
-		priv->fetching = FALSE;
+	if (priv->init_left == 0)
 		g_signal_emit (self, signals[CONNECTIONS_READ], 0);
-	}
 }
 
 static NMRemoteConnection *
@@ -431,12 +556,15 @@ fetch_connections_done (DBusGProxy *proxy,
 	GError *error = NULL;
 	int i;
 
+	g_warn_if_fail (priv->listcon_call == call);
+	priv->listcon_call = NULL;
+
 	if (!dbus_g_proxy_end_call (proxy, call, &error, 
 	                            DBUS_TYPE_G_ARRAY_OF_OBJECT_PATH, &connections,
 	                            G_TYPE_INVALID)) {
-		/* Ignore settings service spawn errors */
 		if (   !g_error_matches (error, DBUS_GERROR, DBUS_GERROR_SERVICE_UNKNOWN)
-		    && !g_error_matches (error, DBUS_GERROR, DBUS_GERROR_NAME_HAS_NO_OWNER)) {
+		    && !g_error_matches (error, DBUS_GERROR, DBUS_GERROR_NAME_HAS_NO_OWNER)
+		    && priv->service_running) {
 			g_warning ("%s: error fetching connections: (%d) %s.",
 			           __func__,
 				       error->code,
@@ -445,16 +573,14 @@ fetch_connections_done (DBusGProxy *proxy,
 		g_clear_error (&error);
 
 		/* We tried to read connections and failed */
-		priv->fetching = FALSE;
 		g_signal_emit (self, signals[CONNECTIONS_READ], 0);
 		return;
 	}
 
 	/* Let listeners know we are done getting connections */
-	if (connections->len == 0) {
-		priv->fetching = FALSE;
+	if (connections->len == 0)
 		g_signal_emit (self, signals[CONNECTIONS_READ], 0);
-	} else {
+	else {
 		priv->init_left = connections->len;
 		for (i = 0; i < connections->len; i++) {
 			char *path = g_ptr_array_index (connections, i);
@@ -467,20 +593,6 @@ fetch_connections_done (DBusGProxy *proxy,
 	g_ptr_array_free (connections, TRUE);
 }
 
-static gboolean
-fetch_connections (gpointer user_data)
-{
-	NMRemoteSettings *self = NM_REMOTE_SETTINGS (user_data);
-	NMRemoteSettingsPrivate *priv = NM_REMOTE_SETTINGS_GET_PRIVATE (self);
-
-	priv->fetch_id = 0;
-
-	dbus_g_proxy_begin_call (priv->proxy, "ListConnections",
-	                         fetch_connections_done, self, NULL,
-	                         G_TYPE_INVALID);
-	return FALSE;
-}
-
 /**
  * nm_remote_settings_list_connections:
  * @settings: the %NMRemoteSettings
@@ -500,7 +612,6 @@ nm_remote_settings_list_connections (NMRemoteSettings *settings)
 	GHashTableIter iter;
 	gpointer value;
 
-	g_return_val_if_fail (settings != NULL, NULL);
 	g_return_val_if_fail (NM_IS_REMOTE_SETTINGS (settings), NULL);
 
 	priv = NM_REMOTE_SETTINGS_GET_PRIVATE (settings);
@@ -543,7 +654,14 @@ add_connection_done (DBusGProxy *proxy, DBusGProxyCall *call, gpointer user_data
  * @user_data: (closure): caller-specific data passed to @callback
  *
  * Requests that the remote settings service add the given settings to a new
- * connection.
+ * connection.  The connection is immediately written to disk.  @connection is
+ * untouched by this function and only serves as a template of the settings to
+ * add.  The #NMRemoteConnection object that represents what NetworkManager
+ * actually added is returned to @callback when the addition operation is complete.
+ *
+ * Note that the #NMRemoteConnection returned in @callback may not contain
+ * identical settings to @connection as NetworkManager may perform automatic
+ * completion and/or normalization of connection properties.
  *
  * Returns: %TRUE if the request was successful, %FALSE if it failed
  **/
@@ -557,9 +675,7 @@ nm_remote_settings_add_connection (NMRemoteSettings *settings,
 	AddConnectionInfo *info;
 	GHashTable *new_settings;
 
-	g_return_val_if_fail (settings != NULL, FALSE);
 	g_return_val_if_fail (NM_IS_REMOTE_SETTINGS (settings), FALSE);
-	g_return_val_if_fail (connection != NULL, FALSE);
 	g_return_val_if_fail (NM_IS_CONNECTION (connection), FALSE);
 	g_return_val_if_fail (callback != NULL, FALSE);
 
@@ -567,6 +683,9 @@ nm_remote_settings_add_connection (NMRemoteSettings *settings,
 
 	_nm_remote_settings_ensure_inited (settings);
 
+	if (!priv->service_running)
+		return FALSE;
+
 	info = g_malloc0 (sizeof (AddConnectionInfo));
 	info->self = settings;
 	info->callback = callback;
@@ -586,6 +705,171 @@ nm_remote_settings_add_connection (NMRemoteSettings *settings,
 	return TRUE;
 }
 
+/**
+ * nm_remote_settings_add_connection_unsaved:
+ * @settings: the %NMRemoteSettings
+ * @connection: the connection to add. Note that this object's settings will be
+ *   added, not the object itself
+ * @callback: (scope async): callback to be called when the add operation completes
+ * @user_data: (closure): caller-specific data passed to @callback
+ *
+ * Requests that the remote settings service add the given settings to a new
+ * connection.  The connection is not written to disk, which may be done at
+ * a later time by calling the connection's nm_remote_connection_commit_changes()
+ * method.
+ *
+ * Returns: %TRUE if the request was successful, %FALSE if it failed
+ *
+ * Since: 0.9.10
+ **/
+gboolean
+nm_remote_settings_add_connection_unsaved (NMRemoteSettings *settings,
+                                           NMConnection *connection,
+                                           NMRemoteSettingsAddConnectionFunc callback,
+                                           gpointer user_data)
+{
+	NMRemoteSettingsPrivate *priv;
+	AddConnectionInfo *info;
+	GHashTable *new_settings;
+
+	g_return_val_if_fail (NM_IS_REMOTE_SETTINGS (settings), FALSE);
+	g_return_val_if_fail (NM_IS_CONNECTION (connection), FALSE);
+	g_return_val_if_fail (callback != NULL, FALSE);
+
+	priv = NM_REMOTE_SETTINGS_GET_PRIVATE (settings);
+
+	_nm_remote_settings_ensure_inited (settings);
+
+	if (!priv->service_running)
+		return FALSE;
+
+	info = g_malloc0 (sizeof (AddConnectionInfo));
+	info->self = settings;
+	info->callback = callback;
+	info->callback_data = user_data;
+
+	new_settings = nm_connection_to_hash (connection, NM_SETTING_HASH_FLAG_ALL);
+	dbus_g_proxy_begin_call (priv->proxy, "AddConnectionUnsaved",
+	                         add_connection_done,
+	                         info,
+	                         NULL,
+	                         DBUS_TYPE_G_MAP_OF_MAP_OF_VARIANT, new_settings,
+	                         G_TYPE_INVALID);
+	g_hash_table_destroy (new_settings);
+
+	priv->add_list = g_slist_append (priv->add_list, info);
+
+	return TRUE;
+}
+
+/**
+ * nm_remote_settings_load_connections:
+ * @settings: the %NMRemoteSettings
+ * @filenames: %NULL-terminated array of filenames to load
+ * @failures: (out) (transfer full): on return, a %NULL-terminated array of
+ *   filenames that failed to load
+ * @error: return location for #GError
+ *
+ * Requests that the remote settings service load or reload the given files,
+ * adding or updating the connections described within.
+ *
+ * The changes to the indicated files will not yet be reflected in
+ * @settings's connections array when the function returns.
+ *
+ * If all of the indicated files were successfully loaded, the
+ * function will return %TRUE, and @failures will be set to %NULL. If
+ * NetworkManager tried to load the files, but some (or all) failed,
+ * then @failures will be set to a %NULL-terminated array of the
+ * filenames that failed to load.
+
+ * Returns: %TRUE if NetworkManager at least tried to load @filenames,
+ * %FALSE if an error occurred (eg, permission denied).
+ *
+ * Since: 0.9.10
+ **/
+gboolean
+nm_remote_settings_load_connections (NMRemoteSettings *settings,
+                                     char **filenames,
+                                     char ***failures,
+                                     GError **error)
+{
+	NMRemoteSettingsPrivate *priv;
+	char **my_failures = NULL;
+	gboolean ret;
+
+	g_return_val_if_fail (NM_IS_REMOTE_SETTINGS (settings), FALSE);
+	g_return_val_if_fail (filenames != NULL, FALSE);
+
+	priv = NM_REMOTE_SETTINGS_GET_PRIVATE (settings);
+
+	_nm_remote_settings_ensure_inited (settings);
+
+	if (!priv->service_running) {
+		g_set_error_literal (error, NM_REMOTE_SETTINGS_ERROR,
+		                     NM_REMOTE_SETTINGS_ERROR_SERVICE_UNAVAILABLE,
+		                     "NetworkManager is not running.");
+		return FALSE;
+	}
+
+	if (!dbus_g_proxy_call (priv->proxy, "LoadConnections", error,
+	                        G_TYPE_STRV, filenames,
+	                        G_TYPE_INVALID,
+	                        G_TYPE_BOOLEAN, &ret,
+	                        G_TYPE_STRV, &my_failures,
+	                        G_TYPE_INVALID))
+		ret = FALSE;
+
+	if (failures) {
+		if (my_failures && !*my_failures)
+			g_clear_pointer (&my_failures, g_free);
+		*failures = my_failures;
+	} else
+		g_strfreev (my_failures);
+
+	return ret;
+}
+
+/**
+ * nm_remote_settings_reload_connections:
+ * @settings: the #NMRemoteSettings
+ * @error: return location for #GError
+ *
+ * Requests that the remote settings service reload all connection
+ * files from disk, adding, updating, and removing connections until
+ * the in-memory state matches the on-disk state.
+ *
+ * Return value: %TRUE on success, %FALSE on failure
+ *
+ * Since: 0.9.10
+ **/
+gboolean
+nm_remote_settings_reload_connections (NMRemoteSettings *settings,
+                                       GError **error)
+{
+	NMRemoteSettingsPrivate *priv;
+	gboolean success;
+
+	g_return_val_if_fail (NM_IS_REMOTE_SETTINGS (settings), FALSE);
+
+	priv = NM_REMOTE_SETTINGS_GET_PRIVATE (settings);
+
+	_nm_remote_settings_ensure_inited (settings);
+
+	if (!priv->service_running) {
+		g_set_error_literal (error, NM_REMOTE_SETTINGS_ERROR,
+		                     NM_REMOTE_SETTINGS_ERROR_SERVICE_UNAVAILABLE,
+		                     "NetworkManager is not running.");
+		return FALSE;
+	}
+
+	if (!dbus_g_proxy_call (priv->proxy, "ReloadConnections", error,
+	                        G_TYPE_INVALID,
+	                        G_TYPE_BOOLEAN, &success,
+	                        G_TYPE_INVALID))
+		return FALSE;
+	return success;
+}
+
 static void
 clear_one_hash (GHashTable *table)
 {
@@ -595,7 +879,7 @@ clear_one_hash (GHashTable *table)
 
 	/* Build up the list of connections; we can't emit "removed" during hash
 	 * table iteration because emission of the "removed" signal may trigger code
-	 * that explicitly removes the the connection from the hash table somewhere
+	 * that explicitly removes the connection from the hash table somewhere
 	 * else.
 	 */
 	g_hash_table_iter_init (&iter, table);
@@ -609,17 +893,6 @@ clear_one_hash (GHashTable *table)
 	g_hash_table_remove_all (table);
 }
 
-static gboolean
-remove_connections (gpointer user_data)
-{
-	NMRemoteSettings *self = NM_REMOTE_SETTINGS (user_data);
-	NMRemoteSettingsPrivate *priv = NM_REMOTE_SETTINGS_GET_PRIVATE (self);
-
-	clear_one_hash (priv->pending);
-	clear_one_hash (priv->connections);
-	return FALSE;
-}
-
 typedef struct {
 	NMRemoteSettings *settings;
 	NMRemoteSettingsSaveHostnameFunc callback;
@@ -663,7 +936,6 @@ nm_remote_settings_save_hostname (NMRemoteSettings *settings,
 	NMRemoteSettingsPrivate *priv;
 	SaveHostnameInfo *info;
 
-	g_return_val_if_fail (settings != NULL, FALSE);
 	g_return_val_if_fail (NM_IS_REMOTE_SETTINGS (settings), FALSE);
 	g_return_val_if_fail (hostname != NULL, FALSE);
 	g_return_val_if_fail (callback != NULL, FALSE);
@@ -672,6 +944,9 @@ nm_remote_settings_save_hostname (NMRemoteSettings *settings,
 
 	_nm_remote_settings_ensure_inited (settings);
 
+	if (!priv->service_running)
+		return FALSE;
+
 	info = g_malloc0 (sizeof (SaveHostnameInfo));
 	info->settings = settings;
 	info->callback = callback;
@@ -740,21 +1015,23 @@ name_owner_changed (DBusGProxy *proxy,
 	const char *sname = NM_DBUS_SERVICE;
 
 	if (!strcmp (name, sname)) {
-		if (priv->fetch_id)
-			g_source_remove (priv->fetch_id);
-
 		if (new_owner && strlen (new_owner) > 0) {
-			priv->fetch_id = g_idle_add (fetch_connections, self);
 			priv->service_running = TRUE;
 
+			priv->listcon_call = dbus_g_proxy_begin_call (priv->proxy, "ListConnections",
+			                                              fetch_connections_done, self, NULL,
+			                                              G_TYPE_INVALID);
+
 			dbus_g_proxy_begin_call (priv->props_proxy, "GetAll",
 			                         nm_appeared_got_properties, self, NULL,
 			                         G_TYPE_STRING, NM_DBUS_IFACE_SETTINGS,
 			                         G_TYPE_INVALID);
 		} else {
-			priv->fetch_id = g_idle_add (remove_connections, self);
 			priv->service_running = FALSE;
 
+			clear_one_hash (priv->pending);
+			clear_one_hash (priv->connections);
+
 			/* Clear properties */
 			g_free (priv->hostname);
 			priv->hostname = NULL;
@@ -762,6 +1039,11 @@ name_owner_changed (DBusGProxy *proxy,
 
 			priv->can_modify = FALSE;
 			g_object_notify (G_OBJECT (self), NM_REMOTE_SETTINGS_CAN_MODIFY);
+
+			if (priv->listcon_call) {
+				dbus_g_proxy_cancel_call (priv->proxy, priv->listcon_call);
+				priv->listcon_call = NULL;
+			}
 		}
 		g_object_notify (G_OBJECT (self), NM_REMOTE_SETTINGS_SERVICE_RUNNING);
 	}
@@ -784,7 +1066,11 @@ name_owner_changed (DBusGProxy *proxy,
 NMRemoteSettings *
 nm_remote_settings_new (DBusGConnection *bus)
 {
-	return g_object_new (NM_TYPE_REMOTE_SETTINGS, NM_REMOTE_SETTINGS_BUS, bus, NULL);
+	NMRemoteSettings *self;
+
+	self = g_object_new (NM_TYPE_REMOTE_SETTINGS, NM_REMOTE_SETTINGS_BUS, bus, NULL);
+	_nm_remote_settings_ensure_inited (self);
+	return self;
 }
 
 static void
@@ -880,29 +1166,30 @@ constructed (GObject *object)
 
 	priv = NM_REMOTE_SETTINGS_GET_PRIVATE (object);
 
-	/* D-Bus proxy for clearing connections on NameOwnerChanged */
-	priv->dbus_proxy = dbus_g_proxy_new_for_name (priv->bus,
-	                                              "org.freedesktop.DBus",
-	                                              "/org/freedesktop/DBus",
-	                                              "org.freedesktop.DBus");
-	g_assert (priv->dbus_proxy);
+	if (priv->private_bus == FALSE) {
+		/* D-Bus proxy for clearing connections on NameOwnerChanged */
+		priv->dbus_proxy = dbus_g_proxy_new_for_name (priv->bus,
+		                                              DBUS_SERVICE_DBUS,
+		                                              DBUS_PATH_DBUS,
+		                                              DBUS_INTERFACE_DBUS);
+		g_assert (priv->dbus_proxy);
+
+		dbus_g_object_register_marshaller (g_cclosure_marshal_generic,
+		                                   G_TYPE_NONE,
+		                                   G_TYPE_STRING, G_TYPE_STRING, G_TYPE_STRING,
+		                                   G_TYPE_INVALID);
+		dbus_g_proxy_add_signal (priv->dbus_proxy, "NameOwnerChanged",
+		                         G_TYPE_STRING, G_TYPE_STRING, G_TYPE_STRING,
+		                         G_TYPE_INVALID);
+		dbus_g_proxy_connect_signal (priv->dbus_proxy,
+		                             "NameOwnerChanged",
+		                             G_CALLBACK (name_owner_changed),
+		                             object, NULL);
+	}
 
-	dbus_g_object_register_marshaller (_nm_glib_marshal_VOID__STRING_STRING_STRING,
-	                                   G_TYPE_NONE,
-	                                   G_TYPE_STRING, G_TYPE_STRING, G_TYPE_STRING,
-	                                   G_TYPE_INVALID);
-	dbus_g_proxy_add_signal (priv->dbus_proxy, "NameOwnerChanged",
-	                         G_TYPE_STRING, G_TYPE_STRING, G_TYPE_STRING,
-	                         G_TYPE_INVALID);
-	dbus_g_proxy_connect_signal (priv->dbus_proxy,
-	                             "NameOwnerChanged",
-	                             G_CALLBACK (name_owner_changed),
-	                             object, NULL);
-
-	priv->proxy = dbus_g_proxy_new_for_name (priv->bus,
-	                                         NM_DBUS_SERVICE,
-	                                         NM_DBUS_PATH_SETTINGS,
-	                                         NM_DBUS_IFACE_SETTINGS);
+	priv->proxy = _nm_dbus_new_proxy_for_connection (priv->bus,
+	                                                 NM_DBUS_PATH_SETTINGS,
+	                                                 NM_DBUS_IFACE_SETTINGS);
 	g_assert (priv->proxy);
 	dbus_g_proxy_set_default_timeout (priv->proxy, G_MAXINT);
 
@@ -914,19 +1201,14 @@ constructed (GObject *object)
 	                             object,
 	                             NULL);
 
-	priv->fetching = TRUE;
-	priv->fetch_id = g_idle_add (fetch_connections, object);
-
-
 	/* D-Bus properties proxy */
-	priv->props_proxy = dbus_g_proxy_new_for_name (priv->bus,
-	                                               NM_DBUS_SERVICE,
-	                                               NM_DBUS_PATH_SETTINGS,
-	                                               "org.freedesktop.DBus.Properties");
+	priv->props_proxy = _nm_dbus_new_proxy_for_connection (priv->bus,
+	                                                       NM_DBUS_PATH_SETTINGS,
+	                                                       "org.freedesktop.DBus.Properties");
 	g_assert (priv->props_proxy);
 
 	/* Monitor properties */
-	dbus_g_object_register_marshaller (g_cclosure_marshal_VOID__BOXED,
+	dbus_g_object_register_marshaller (g_cclosure_marshal_generic,
 	                                   G_TYPE_NONE,
 	                                   DBUS_TYPE_G_MAP_OF_VARIANT,
 	                                   G_TYPE_INVALID);
@@ -946,20 +1228,27 @@ init_sync (GInitable *initable, GCancellable *cancellable, GError **error)
 	NMRemoteSettingsPrivate *priv = NM_REMOTE_SETTINGS_GET_PRIVATE (settings);
 	GHashTable *props;
 
-	if (!dbus_g_proxy_call (priv->dbus_proxy, "NameHasOwner", error,
-	                        G_TYPE_STRING, NM_DBUS_SERVICE,
-	                        G_TYPE_INVALID,
-	                        G_TYPE_BOOLEAN, &priv->service_running,
-	                        G_TYPE_INVALID)) {
-		priv->service_running = FALSE;
-		return FALSE;
-	}
+	if (priv->private_bus == FALSE) {
+		if (!dbus_g_proxy_call (priv->dbus_proxy, "NameHasOwner", error,
+		                        G_TYPE_STRING, NM_DBUS_SERVICE,
+		                        G_TYPE_INVALID,
+		                        G_TYPE_BOOLEAN, &priv->service_running,
+		                        G_TYPE_INVALID)) {
+			priv->service_running = FALSE;
+			return FALSE;
+		}
 
-	/* If NM isn't running we'll grab properties from name_owner_changed()
-	 * when it starts.
-	 */
-	if (!priv->service_running)
-		return TRUE;
+		/* If NM isn't running we'll grab properties from name_owner_changed()
+		 * when it starts.
+		 */
+		if (!priv->service_running)
+			return TRUE;
+	} else
+		priv->service_running = TRUE;
+
+	priv->listcon_call = dbus_g_proxy_begin_call (priv->proxy, "ListConnections",
+	                                              fetch_connections_done, NM_REMOTE_SETTINGS (initable), NULL,
+	                                              G_TYPE_INVALID);
 
 	/* Get properties */
 	if (!dbus_g_proxy_call (priv->props_proxy, "GetAll", error,
@@ -1019,14 +1308,23 @@ init_async_got_properties (DBusGProxy *proxy, DBusGProxyCall *call,
 	} else
 		g_simple_async_result_take_error (init_data->result, error);
 
-	if (priv->fetching) {
-		/* Still creating initial connections; wait for that to complete */
-		g_signal_connect (init_data->settings, "connections-read",
-		                  G_CALLBACK (init_read_connections), init_data);
-		return;
-	}
+	/* Read connections and wait for the result */
+	priv->listcon_call = dbus_g_proxy_begin_call (priv->proxy, "ListConnections",
+	                                              fetch_connections_done, init_data->settings, NULL,
+	                                              G_TYPE_INVALID);
+	g_signal_connect (init_data->settings, "connections-read",
+	                  G_CALLBACK (init_read_connections), init_data);
+}
 
-	init_async_complete (init_data);
+static void
+init_get_properties (NMRemoteSettingsInitData *init_data)
+{
+	NMRemoteSettingsPrivate *priv = NM_REMOTE_SETTINGS_GET_PRIVATE (init_data->settings);
+
+	dbus_g_proxy_begin_call (priv->props_proxy, "GetAll",
+	                         init_async_got_properties, init_data, NULL,
+	                         G_TYPE_STRING, NM_DBUS_IFACE_SETTINGS,
+	                         G_TYPE_INVALID);
 }
 
 static void
@@ -1051,10 +1349,7 @@ init_async_got_manager_running (DBusGProxy *proxy, DBusGProxyCall *call,
 		return;
 	}
 
-	dbus_g_proxy_begin_call (priv->props_proxy, "GetAll",
-	                         init_async_got_properties, init_data, NULL,
-	                         G_TYPE_STRING, NM_DBUS_IFACE_SETTINGS,
-	                         G_TYPE_INVALID);
+	init_get_properties (init_data);
 }
 
 static void
@@ -1070,12 +1365,16 @@ init_async (GAsyncInitable *initable, int io_priority,
 	init_data->result = g_simple_async_result_new (G_OBJECT (initable), callback,
 	                                               user_data, init_async);
 
-	/* Check if NM is running */
-	dbus_g_proxy_begin_call (priv->dbus_proxy, "NameHasOwner",
-	                         init_async_got_manager_running,
-	                         init_data, NULL,
-	                         G_TYPE_STRING, NM_DBUS_SERVICE,
-	                         G_TYPE_INVALID);
+	if (priv->private_bus)
+		init_get_properties (init_data);
+	else {
+		/* Check if NM is running */
+		dbus_g_proxy_begin_call (priv->dbus_proxy, "NameHasOwner",
+		                         init_async_got_manager_running,
+		                         init_data, NULL,
+		                         G_TYPE_STRING, NM_DBUS_SERVICE,
+		                         G_TYPE_INVALID);
+	}
 }
 
 static gboolean
@@ -1095,11 +1394,6 @@ dispose (GObject *object)
 	NMRemoteSettings *self = NM_REMOTE_SETTINGS (object);
 	NMRemoteSettingsPrivate *priv = NM_REMOTE_SETTINGS_GET_PRIVATE (self);
 
-	if (priv->fetch_id) {
-		g_source_remove (priv->fetch_id);
-		priv->fetch_id = 0;
-	}
-
 	while (g_slist_length (priv->add_list))
 		add_connection_info_dispose (self, (AddConnectionInfo *) priv->add_list->data);
 
@@ -1133,15 +1427,15 @@ set_property (GObject *object, guint prop_id,
               const GValue *value, GParamSpec *pspec)
 {
 	NMRemoteSettingsPrivate *priv = NM_REMOTE_SETTINGS_GET_PRIVATE (object);
-	DBusGConnection *connection;
 
 	switch (prop_id) {
 	case PROP_BUS:
 		/* Construct only */
-		connection = (DBusGConnection *) g_value_get_boxed (value);
-		if (!connection)
-			connection = dbus_g_bus_get (DBUS_BUS_SYSTEM, NULL);
-		priv->bus = dbus_g_connection_ref (connection);
+		priv->bus = g_value_dup_boxed (value);
+		if (!priv->bus) {
+			priv->bus = _nm_dbus_new_connection (NULL);
+			priv->private_bus = _nm_dbus_is_connection_private (priv->bus);
+		}
 		break;
 	default:
 		G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
@@ -1228,8 +1522,7 @@ nm_remote_settings_class_init (NMRemoteSettingsClass *class)
 	                              G_OBJECT_CLASS_TYPE (object_class),
 	                              G_SIGNAL_RUN_FIRST,
 	                              G_STRUCT_OFFSET (NMRemoteSettingsClass, new_connection),
-	                              NULL, NULL,
-	                              g_cclosure_marshal_VOID__OBJECT,
+	                              NULL, NULL, NULL,
 	                              G_TYPE_NONE, 1, G_TYPE_OBJECT);
 
 	signals[CONNECTIONS_READ] = 
@@ -1237,8 +1530,7 @@ nm_remote_settings_class_init (NMRemoteSettingsClass *class)
 	                              G_OBJECT_CLASS_TYPE (object_class),
 	                              G_SIGNAL_RUN_FIRST,
 	                              G_STRUCT_OFFSET (NMRemoteSettingsClass, connections_read),
-	                              NULL, NULL,
-	                              g_cclosure_marshal_VOID__VOID,
+	                              NULL, NULL, NULL,
 	                              G_TYPE_NONE, 0);
 }
 
diff --git a/libnm-glib/nm-remote-settings.h b/libnm-glib/nm-remote-settings.h
index 20235c0d..5ca646e6 100644
--- a/libnm-glib/nm-remote-settings.h
+++ b/libnm-glib/nm-remote-settings.h
@@ -45,6 +45,8 @@ G_BEGIN_DECLS
  *   was removed before it was completely initialized
  * @NM_REMOTE_SETTINGS_ERROR_CONNECTION_UNAVAILABLE: the #NMRemoteConnection object
  *   is not visible or otherwise unreadable
+ * @NM_REMOTE_SETTINGS_ERROR_SERVICE_UNAVAILABLE: NetworkManager is not running.
+ *   (Since 0.9.10)
  *
  * Describes errors that may result from operations involving a #NMRemoteSettings.
  *
@@ -53,6 +55,7 @@ typedef enum {
 	NM_REMOTE_SETTINGS_ERROR_UNKNOWN = 0,            /*< nick=UnknownError >*/
 	NM_REMOTE_SETTINGS_ERROR_CONNECTION_REMOVED,     /*< nick=ConnectionRemoved >*/
 	NM_REMOTE_SETTINGS_ERROR_CONNECTION_UNAVAILABLE, /*< nick=ConnectionUnavailable >*/
+	NM_REMOTE_SETTINGS_ERROR_SERVICE_UNAVAILABLE,    /*< nick=ServiceUnavailable >*/
 } NMRemoteSettingsError;
 
 #define NM_REMOTE_SETTINGS_ERROR nm_remote_settings_error_quark ()
@@ -76,6 +79,11 @@ typedef void (*NMRemoteSettingsAddConnectionFunc) (NMRemoteSettings *settings,
                                                    GError *error,
                                                    gpointer user_data);
 
+typedef void (*NMRemoteSettingsLoadConnectionsFunc) (NMRemoteSettings *settings,
+                                                     char **failures,
+                                                     GError *error,
+                                                     gpointer user_data);
+
 typedef void (*NMRemoteSettingsSaveHostnameFunc) (NMRemoteSettings *settings,
                                                   GError *error,
                                                   gpointer user_data);
@@ -116,6 +124,9 @@ NMRemoteSettings *nm_remote_settings_new_finish (GAsyncResult         *result,
 
 GSList *nm_remote_settings_list_connections (NMRemoteSettings *settings);
 
+NMRemoteConnection *nm_remote_settings_get_connection_by_id (NMRemoteSettings *settings,
+                                                             const char *id);
+
 NMRemoteConnection * nm_remote_settings_get_connection_by_path (NMRemoteSettings *settings,
                                                                 const char *path);
 
@@ -127,6 +138,22 @@ gboolean nm_remote_settings_add_connection (NMRemoteSettings *settings,
                                             NMRemoteSettingsAddConnectionFunc callback,
                                             gpointer user_data);
 
+NM_AVAILABLE_IN_0_9_10
+gboolean nm_remote_settings_add_connection_unsaved (NMRemoteSettings *settings,
+                                                    NMConnection *connection,
+                                                    NMRemoteSettingsAddConnectionFunc callback,
+                                                    gpointer user_data);
+
+NM_AVAILABLE_IN_0_9_10
+gboolean nm_remote_settings_load_connections (NMRemoteSettings *settings,
+                                              char **filenames,
+                                              char ***failures,
+                                              GError **error);
+
+NM_AVAILABLE_IN_0_9_10
+gboolean nm_remote_settings_reload_connections (NMRemoteSettings *settings,
+                                                GError **error);
+
 gboolean nm_remote_settings_save_hostname (NMRemoteSettings *settings,
                                            const char *hostname,
                                            NMRemoteSettingsSaveHostnameFunc callback,
diff --git a/libnm-glib/nm-secret-agent.c b/libnm-glib/nm-secret-agent.c
index e7dcbbb5..f58f95fe 100644
--- a/libnm-glib/nm-secret-agent.c
+++ b/libnm-glib/nm-secret-agent.c
@@ -23,13 +23,10 @@
 #include <dbus/dbus-glib-lowlevel.h>
 
 #include "nm-glib-compat.h"
-
-#include <NetworkManager.h>
-
+#include "NetworkManager.h"
 #include "nm-secret-agent.h"
 #include "nm-glib-enum-types.h"
-#include "nm-glib-marshal.h"
-#include "NetworkManager.h"
+#include "nm-dbus-helpers-private.h"
 
 static void impl_secret_agent_get_secrets (NMSecretAgent *self,
                                            GHashTable *connection_hash,
@@ -66,8 +63,10 @@ static gboolean auto_register_cb (gpointer user_data);
 
 typedef struct {
 	gboolean registered;
+	NMSecretAgentCapabilities capabilities;
 
 	DBusGConnection *bus;
+	gboolean private_bus;
 	DBusGProxy *dbus_proxy;
 	DBusGProxy *manager_proxy;
 	DBusGProxyCall *reg_call;
@@ -88,6 +87,7 @@ enum {
 	PROP_IDENTIFIER,
 	PROP_AUTO_REGISTER,
 	PROP_REGISTERED,
+	PROP_CAPABILITIES,
 
 	LAST_PROP
 };
@@ -228,6 +228,12 @@ verify_sender (NMSecretAgent *self,
 
 	g_return_val_if_fail (context != NULL, FALSE);
 
+	/* Private bus connection is always to NetworkManager, which is always
+	 * UID 0.
+	 */
+	if (priv->private_bus)
+		return TRUE;
+
 	/* Verify the sender's UID is 0, and that the sender is the same as
 	 * NetworkManager's bus name owner.
 	 */
@@ -527,6 +533,22 @@ impl_secret_agent_delete_secrets (NMSecretAgent *self,
 /**************************************************************/
 
 static void
+reg_result (NMSecretAgent *self, GError *error)
+{
+	NMSecretAgentPrivate *priv = NM_SECRET_AGENT_GET_PRIVATE (self);
+
+	if (error) {
+		/* If registration failed we shouldn't expose ourselves on the bus */
+		_internal_unregister (self);
+	} else {
+		priv->registered = TRUE;
+		g_object_notify (G_OBJECT (self), NM_SECRET_AGENT_REGISTERED);
+	}
+
+	g_signal_emit (self, signals[REGISTRATION_RESULT], 0, error);
+}
+
+static void
 reg_request_cb (DBusGProxy *proxy,
                 DBusGProxyCall *call,
                 gpointer user_data)
@@ -537,16 +559,37 @@ reg_request_cb (DBusGProxy *proxy,
 
 	priv->reg_call = NULL;
 
-	if (dbus_g_proxy_end_call (proxy, call, &error, G_TYPE_INVALID)) {
-		priv->registered = TRUE;
-		g_object_notify (G_OBJECT (self), NM_SECRET_AGENT_REGISTERED);
-	} else {
-		/* If registration failed we shouldn't expose ourselves on the bus */
-		_internal_unregister (self);
+	dbus_g_proxy_end_call (proxy, call, &error, G_TYPE_INVALID);
+	reg_result (self, error);
+	g_clear_error (&error);
+}
+
+static void
+reg_with_caps_cb (DBusGProxy *proxy,
+                  DBusGProxyCall *call,
+                  gpointer user_data)
+{
+	NMSecretAgent *self = NM_SECRET_AGENT (user_data);
+	NMSecretAgentPrivate *priv = NM_SECRET_AGENT_GET_PRIVATE (self);
+
+	priv->reg_call = NULL;
+
+	if (dbus_g_proxy_end_call (proxy, call, NULL, G_TYPE_INVALID)) {
+		reg_result (self, NULL);
+		return;
 	}
 
-	g_signal_emit (self, signals[REGISTRATION_RESULT], 0, error);
-	g_clear_error (&error);
+	/* Might be an old NetworkManager that doesn't support capabilities;
+	 * fall back to old Register() method instead.
+	 */
+	priv->reg_call = dbus_g_proxy_begin_call_with_timeout (priv->manager_proxy,
+	                                                       "Register",
+	                                                       reg_request_cb,
+	                                                       self,
+	                                                       NULL,
+	                                                       5000,
+	                                                       G_TYPE_STRING, priv->identifier,
+	                                                       G_TYPE_INVALID);
 }
 
 /**
@@ -569,7 +612,6 @@ nm_secret_agent_register (NMSecretAgent *self)
 	NMSecretAgentPrivate *priv;
 	NMSecretAgentClass *class;
 
-	g_return_val_if_fail (self != NULL, FALSE);
 	g_return_val_if_fail (NM_IS_SECRET_AGENT (self), FALSE);
 
 	priv = NM_SECRET_AGENT_GET_PRIVATE (self);
@@ -585,6 +627,9 @@ nm_secret_agent_register (NMSecretAgent *self)
 	g_return_val_if_fail (class->save_secrets != NULL, FALSE);
 	g_return_val_if_fail (class->delete_secrets != NULL, FALSE);
 
+	if (!priv->nm_owner && !priv->private_bus)
+		return FALSE;
+
 	priv->suppress_auto = FALSE;
 
 	/* Export our secret agent interface before registering with the manager */
@@ -593,14 +638,14 @@ nm_secret_agent_register (NMSecretAgent *self)
 	                                     G_OBJECT (self));
 
 	priv->reg_call = dbus_g_proxy_begin_call_with_timeout (priv->manager_proxy,
-	                                                       "Register",
-	                                                       reg_request_cb,
+	                                                       "RegisterWithCapabilities",
+	                                                       reg_with_caps_cb,
 	                                                       self,
 	                                                       NULL,
 	                                                       5000,
 	                                                       G_TYPE_STRING, priv->identifier,
+	                                                       G_TYPE_UINT, priv->capabilities,
 	                                                       G_TYPE_INVALID);
-
 	return TRUE;
 }
 
@@ -619,7 +664,6 @@ nm_secret_agent_unregister (NMSecretAgent *self)
 {
 	NMSecretAgentPrivate *priv;
 
-	g_return_val_if_fail (self != NULL, FALSE);
 	g_return_val_if_fail (NM_IS_SECRET_AGENT (self), FALSE);
 
 	priv = NM_SECRET_AGENT_GET_PRIVATE (self);
@@ -628,6 +672,9 @@ nm_secret_agent_unregister (NMSecretAgent *self)
 	g_return_val_if_fail (priv->bus != NULL, FALSE);
 	g_return_val_if_fail (priv->manager_proxy != NULL, FALSE);
 
+	if (!priv->nm_owner && !priv->private_bus)
+		return FALSE;
+
 	dbus_g_proxy_call_no_reply (priv->manager_proxy, "Unregister", G_TYPE_INVALID);
 
 	_internal_unregister (self);
@@ -645,7 +692,6 @@ nm_secret_agent_unregister (NMSecretAgent *self)
 gboolean
 nm_secret_agent_get_registered (NMSecretAgent *self)
 {
-	g_return_val_if_fail (self != NULL, FALSE);
 	g_return_val_if_fail (NM_IS_SECRET_AGENT (self), FALSE);
 
 	return NM_SECRET_AGENT_GET_PRIVATE (self)->registered;
@@ -692,9 +738,7 @@ nm_secret_agent_get_secrets (NMSecretAgent *self,
                              NMSecretAgentGetSecretsFunc callback,
                              gpointer user_data)
 {
-	g_return_if_fail (self != NULL);
 	g_return_if_fail (NM_IS_SECRET_AGENT (self));
-	g_return_if_fail (connection != NULL);
 	g_return_if_fail (NM_IS_CONNECTION (connection));
 	g_return_if_fail (nm_connection_get_path (connection));
 	g_return_if_fail (setting_name != NULL);
@@ -729,9 +773,7 @@ nm_secret_agent_save_secrets (NMSecretAgent *self,
                               NMSecretAgentSaveSecretsFunc callback,
                               gpointer user_data)
 {
-	g_return_if_fail (self != NULL);
 	g_return_if_fail (NM_IS_SECRET_AGENT (self));
-	g_return_if_fail (connection != NULL);
 	g_return_if_fail (NM_IS_CONNECTION (connection));
 	g_return_if_fail (nm_connection_get_path (connection));
 
@@ -760,9 +802,7 @@ nm_secret_agent_delete_secrets (NMSecretAgent *self,
                                 NMSecretAgentDeleteSecretsFunc callback,
                                 gpointer user_data)
 {
-	g_return_if_fail (self != NULL);
 	g_return_if_fail (NM_IS_SECRET_AGENT (self));
-	g_return_if_fail (connection != NULL);
 	g_return_if_fail (NM_IS_CONNECTION (connection));
 	g_return_if_fail (nm_connection_get_path (connection));
 
@@ -807,44 +847,46 @@ nm_secret_agent_init (NMSecretAgent *self)
 	NMSecretAgentPrivate *priv = NM_SECRET_AGENT_GET_PRIVATE (self);
 	GError *error = NULL;
 
-	priv->bus = dbus_g_bus_get (DBUS_BUS_SYSTEM, &error);
+	priv->bus = _nm_dbus_new_connection (&error);
 	if (!priv->bus) {
 		g_warning ("Couldn't connect to system bus: %s", error->message);
 		g_error_free (error);
 		return;
 	}
-
-	priv->dbus_proxy = dbus_g_proxy_new_for_name (priv->bus,
-	                                              DBUS_SERVICE_DBUS,
-	                                              DBUS_PATH_DBUS,
-	                                              DBUS_INTERFACE_DBUS);
-	if (!priv->dbus_proxy) {
-		g_warning ("Couldn't create messagebus proxy.");
-		return;
+	priv->private_bus = _nm_dbus_is_connection_private (priv->bus);
+
+	if (priv->private_bus == FALSE) {
+		priv->dbus_proxy = dbus_g_proxy_new_for_name (priv->bus,
+		                                              DBUS_SERVICE_DBUS,
+		                                              DBUS_PATH_DBUS,
+		                                              DBUS_INTERFACE_DBUS);
+		g_assert (priv->dbus_proxy);
+
+		dbus_g_object_register_marshaller (g_cclosure_marshal_generic,
+		                                   G_TYPE_NONE,
+		                                   G_TYPE_STRING, G_TYPE_STRING, G_TYPE_STRING,
+		                                   G_TYPE_INVALID);
+		dbus_g_proxy_add_signal (priv->dbus_proxy, "NameOwnerChanged",
+		                         G_TYPE_STRING, G_TYPE_STRING, G_TYPE_STRING,
+		                         G_TYPE_INVALID);
+		dbus_g_proxy_connect_signal (priv->dbus_proxy,
+		                             "NameOwnerChanged",
+		                             G_CALLBACK (name_owner_changed),
+		                             self, NULL);
+
+		get_nm_owner (self);
 	}
 
-	dbus_g_object_register_marshaller (_nm_glib_marshal_VOID__STRING_STRING_STRING,
-	                                   G_TYPE_NONE,
-	                                   G_TYPE_STRING, G_TYPE_STRING, G_TYPE_STRING,
-	                                   G_TYPE_INVALID);
-	dbus_g_proxy_add_signal (priv->dbus_proxy, "NameOwnerChanged",
-	                         G_TYPE_STRING, G_TYPE_STRING, G_TYPE_STRING,
-	                         G_TYPE_INVALID);
-	dbus_g_proxy_connect_signal (priv->dbus_proxy,
-	                             "NameOwnerChanged",
-	                             G_CALLBACK (name_owner_changed),
-	                             self, NULL);
-
-	priv->manager_proxy = dbus_g_proxy_new_for_name (priv->bus,
-	                                                 NM_DBUS_SERVICE,
-	                                                 NM_DBUS_PATH_AGENT_MANAGER,
-	                                                 NM_DBUS_INTERFACE_AGENT_MANAGER);
+	priv->manager_proxy = _nm_dbus_new_proxy_for_connection (priv->bus,
+	                                                         NM_DBUS_PATH_AGENT_MANAGER,
+	                                                         NM_DBUS_INTERFACE_AGENT_MANAGER);
 	if (!priv->manager_proxy) {
 		g_warning ("Couldn't create NM agent manager proxy.");
 		return;
 	}
 
-	priv->auto_register_id = g_idle_add (auto_register_cb, self);
+	if (priv->nm_owner || priv->private_bus)
+		priv->auto_register_id = g_idle_add (auto_register_cb, self);
 }
 
 static void
@@ -865,6 +907,9 @@ get_property (GObject *object,
 	case PROP_REGISTERED:
 		g_value_set_boolean (value, priv->registered);
 		break;
+	case PROP_CAPABILITIES:
+		g_value_set_flags (value, priv->capabilities);
+		break;
 	default:
 		G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
 		break;
@@ -892,6 +937,9 @@ set_property (GObject *object,
 	case PROP_AUTO_REGISTER:
 		priv->auto_register = g_value_get_boolean (value);
 		break;
+	case PROP_CAPABILITIES:
+		priv->capabilities = g_value_get_flags (value);
+		break;
 	default:
 		G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
 		break;
@@ -995,6 +1043,20 @@ nm_secret_agent_class_init (NMSecretAgentClass *class)
 		                       G_PARAM_READABLE));
 
 	/**
+	 * NMSecretAgent:capabilities:
+	 *
+	 * A bitfield of %NMSecretAgentCapabilities.
+	 **/
+	g_object_class_install_property
+		(object_class, PROP_CAPABILITIES,
+		 g_param_spec_flags (NM_SECRET_AGENT_CAPABILITIES,
+		                     "Capabilities",
+		                     "Capabilities",
+		                     NM_TYPE_SECRET_AGENT_CAPABILITIES,
+		                     NM_SECRET_AGENT_CAPABILITY_NONE,
+		                     G_PARAM_READWRITE | G_PARAM_CONSTRUCT));
+
+	/**
 	 * NMSecretAgent::registration-result:
 	 * @agent: the agent that received the signal
 	 * @error: the error, if any, that occured while registering
@@ -1006,8 +1068,7 @@ nm_secret_agent_class_init (NMSecretAgentClass *class)
 		g_signal_new (NM_SECRET_AGENT_REGISTRATION_RESULT,
 					  G_OBJECT_CLASS_TYPE (object_class),
 					  G_SIGNAL_RUN_FIRST,
-					  0, NULL, NULL,
-					  g_cclosure_marshal_VOID__POINTER,
+					  0, NULL, NULL, NULL,
 					  G_TYPE_NONE, 1, G_TYPE_POINTER);
 
 	dbus_g_object_type_install_info (G_TYPE_FROM_CLASS (class),
diff --git a/libnm-glib/nm-secret-agent.h b/libnm-glib/nm-secret-agent.h
index eabe9866..c70f8d07 100644
--- a/libnm-glib/nm-secret-agent.h
+++ b/libnm-glib/nm-secret-agent.h
@@ -56,6 +56,26 @@ typedef enum {
 } NMSecretAgentError;
 
 /**
+ * NMSecretAgentCapabilities:
+ * @NM_SECRET_AGENT_CAPABILITY_NONE: the agent supports no special capabilities
+ * @NM_SECRET_AGENT_CAPABILITY_VPN_HINTS: the agent supports sending hints given
+ * by the NMSecretAgentClass::get_secrets() class method to VPN plugin
+ * authentication dialogs.
+ * @NM_SECRET_AGENT_CAPABILITY_LAST: bounds checking value; should not be used.
+ *
+ * #NMSecretAgentCapabilities indicate various capabilities of the agent.
+ *
+ * Since: 0.9.10
+ */
+typedef enum /*< flags >*/ {
+	NM_SECRET_AGENT_CAPABILITY_NONE = 0x0,
+	NM_SECRET_AGENT_CAPABILITY_VPN_HINTS = 0x1,
+
+	/* boundary value */
+	NM_SECRET_AGENT_CAPABILITY_LAST = NM_SECRET_AGENT_CAPABILITY_VPN_HINTS
+} NMSecretAgentCapabilities;
+
+/**
  * NMSecretAgentGetSecretsFlags:
  * @NM_SECRET_AGENT_GET_SECRETS_FLAG_NONE: no special behavior; by default no
  * user interaction is allowed and requests for secrets are fulfilled from
@@ -91,6 +111,7 @@ typedef enum /*< flags >*/ {
 #define NM_SECRET_AGENT_IDENTIFIER          "identifier"
 #define NM_SECRET_AGENT_AUTO_REGISTER       "auto-register"
 #define NM_SECRET_AGENT_REGISTERED          "registered"
+#define NM_SECRET_AGENT_CAPABILITIES        "capabilities"
 
 #define NM_SECRET_AGENT_REGISTRATION_RESULT "registration-result"
 
@@ -120,7 +141,7 @@ typedef struct {
  * return them, or to return an error, this function should be called with
  * those secrets or the error.
  *
- * To easily create the hash table to return the WiFi PSK, you could do
+ * To easily create the hash table to return the Wi-Fi PSK, you could do
  * something like this:
  * <example>
  *  <title>Creating a secrets hash</title>
diff --git a/libnm-glib/nm-types.c b/libnm-glib/nm-types.c
index 098af8d8..f9ba6d24 100644
--- a/libnm-glib/nm-types.c
+++ b/libnm-glib/nm-types.c
@@ -363,8 +363,7 @@ _nm_ip6_address_array_demarshal (GValue *value, GSList **dest)
 		return FALSE;
 
 	if (*dest) {
-		g_slist_foreach (*dest, (GFunc) g_free, NULL);
-		g_slist_free (*dest);
+		g_slist_free_full (*dest, g_free);
 		*dest = NULL;
 	}
 
diff --git a/libnm-glib/nm-vpn-connection.c b/libnm-glib/nm-vpn-connection.c
index 1fe59e5e..12814cf2 100644
--- a/libnm-glib/nm-vpn-connection.c
+++ b/libnm-glib/nm-vpn-connection.c
@@ -25,7 +25,6 @@
 #include "nm-vpn-connection.h"
 #include "NetworkManager.h"
 #include "nm-utils.h"
-#include "nm-glib-marshal.h"
 #include "nm-object-private.h"
 #include "nm-active-connection.h"
 
@@ -47,9 +46,6 @@ enum {
 	LAST_PROP
 };
 
-#define DBUS_PROP_VPN_STATE "VpnState"
-#define DBUS_PROP_BANNER "Banner"
-
 enum {
 	VPN_STATE_CHANGED,
 
@@ -136,6 +132,7 @@ vpn_state_changed_proxy (DBusGProxy *proxy,
 	if (priv->vpn_state != vpn_state) {
 		priv->vpn_state = vpn_state;
 		g_signal_emit (connection, signals[VPN_STATE_CHANGED], 0, vpn_state, reason);
+		g_object_notify (G_OBJECT (connection), NM_VPN_CONNECTION_VPN_STATE);
 	}
 }
 
@@ -167,18 +164,13 @@ register_properties (NMVPNConnection *connection)
 static void
 constructed (GObject *object)
 {
-	NMVPNConnectionPrivate *priv;
+	NMVPNConnectionPrivate *priv = NM_VPN_CONNECTION_GET_PRIVATE (object);
 
 	G_OBJECT_CLASS (nm_vpn_connection_parent_class)->constructed (object);
 
-	priv = NM_VPN_CONNECTION_GET_PRIVATE (object);
-
-	priv->proxy = dbus_g_proxy_new_for_name (nm_object_get_connection (NM_OBJECT (object)),
-									 NM_DBUS_SERVICE,
-									 nm_object_get_path (NM_OBJECT (object)),
-									 NM_DBUS_INTERFACE_VPN_CONNECTION);
+	priv->proxy = _nm_object_new_proxy (NM_OBJECT (object), NULL, NM_DBUS_INTERFACE_VPN_CONNECTION);
 
-	dbus_g_object_register_marshaller (_nm_glib_marshal_VOID__UINT_UINT,
+	dbus_g_object_register_marshaller (g_cclosure_marshal_generic,
 	                                   G_TYPE_NONE,
 	                                   G_TYPE_UINT, G_TYPE_UINT,
 	                                   G_TYPE_INVALID);
@@ -272,8 +264,7 @@ nm_vpn_connection_class_init (NMVPNConnectionClass *connection_class)
 				    G_OBJECT_CLASS_TYPE (object_class),
 				    G_SIGNAL_RUN_FIRST,
 				    G_STRUCT_OFFSET (NMVPNConnectionClass, vpn_state_changed),
-				    NULL, NULL,
-				    _nm_glib_marshal_VOID__UINT_UINT,
+				    NULL, NULL, NULL,
 				    G_TYPE_NONE, 2,
 				    G_TYPE_UINT, G_TYPE_UINT);
 }
diff --git a/libnm-glib/nm-vpn-enum-types.c b/libnm-glib/nm-vpn-enum-types.c
index 0dc5ed23..45418518 100644
--- a/libnm-glib/nm-vpn-enum-types.c
+++ b/libnm-glib/nm-vpn-enum-types.c
@@ -26,6 +26,7 @@ nm_vpn_plugin_error_get_type (void)
         { NM_VPN_PLUGIN_ERROR_BAD_ARGUMENTS, "NM_VPN_PLUGIN_ERROR_BAD_ARGUMENTS", "BadArguments" },
         { NM_VPN_PLUGIN_ERROR_LAUNCH_FAILED, "NM_VPN_PLUGIN_ERROR_LAUNCH_FAILED", "LaunchFailed" },
         { NM_VPN_PLUGIN_ERROR_CONNECTION_INVALID, "NM_VPN_PLUGIN_ERROR_CONNECTION_INVALID", "ConnectionInvalid" },
+        { NM_VPN_PLUGIN_ERROR_INTERACTIVE_NOT_SUPPORTED, "NM_VPN_PLUGIN_ERROR_INTERACTIVE_NOT_SUPPORTED", "InteractiveNotSupported" },
         { 0, NULL, NULL }
       };
       GType g_define_type_id =
diff --git a/libnm-glib/nm-vpn-plugin-ui-interface.h b/libnm-glib/nm-vpn-plugin-ui-interface.h
index 068d8f89..2753de44 100644
--- a/libnm-glib/nm-vpn-plugin-ui-interface.h
+++ b/libnm-glib/nm-vpn-plugin-ui-interface.h
@@ -68,7 +68,7 @@ typedef enum /*< flags >*/ {
 /* Short display name of the VPN plugin */
 #define NM_VPN_PLUGIN_UI_INTERFACE_NAME "name"
 
-/* Longer description of the the VPN plugin */
+/* Longer description of the VPN plugin */
 #define NM_VPN_PLUGIN_UI_INTERFACE_DESC "desc"
 
 /* D-Bus service name of the plugin's VPN service */
@@ -86,10 +86,10 @@ typedef enum /*< flags >*/ {
  * information to UI programs.
  **/
 typedef enum {
-	/*< private >*/
+	/* private */
 	NM_VPN_PLUGIN_UI_INTERFACE_PROP_FIRST = 0x1000,
 
-	/*< public >*/
+	/* public */
 	NM_VPN_PLUGIN_UI_INTERFACE_PROP_NAME = NM_VPN_PLUGIN_UI_INTERFACE_PROP_FIRST,
 	NM_VPN_PLUGIN_UI_INTERFACE_PROP_DESC,
 	NM_VPN_PLUGIN_UI_INTERFACE_PROP_SERVICE
@@ -170,6 +170,7 @@ char *nm_vpn_plugin_ui_interface_get_suggested_name (NMVpnPluginUiInterface *ifa
                                                      NMConnection *connection);
 
 /* Deprecated and no longer used */
+NM_DEPRECATED_IN_0_9_10
 gboolean nm_vpn_plugin_ui_interface_delete_connection (NMVpnPluginUiInterface *iface,
                                                        NMConnection *connection,
                                                        GError **error);
@@ -220,6 +221,7 @@ gboolean nm_vpn_plugin_ui_widget_interface_update_connection (NMVpnPluginUiWidge
                                                               GError **error);
 
 /* Deprecated and no longer used */
+NM_DEPRECATED_IN_0_9_10
 gboolean nm_vpn_plugin_ui_widget_interface_save_secrets (NMVpnPluginUiWidgetInterface *iface,
                                                          NMConnection *connection,
                                                          GError **error);
diff --git a/libnm-glib/nm-vpn-plugin.c b/libnm-glib/nm-vpn-plugin.c
index dd4d7b3a..d5241696 100644
--- a/libnm-glib/nm-vpn-plugin.c
+++ b/libnm-glib/nm-vpn-plugin.c
@@ -31,13 +31,22 @@
 
 static gboolean impl_vpn_plugin_connect    (NMVPNPlugin *plugin,
                                             GHashTable *connection,
-                                            GError **err);
+                                            GError **error);
+
+static gboolean impl_vpn_plugin_connect_interactive (NMVPNPlugin *plugin,
+                                                     GHashTable *connection,
+                                                     GHashTable *details,
+                                                     GError **error);
 
 static gboolean impl_vpn_plugin_need_secrets (NMVPNPlugin *plugin,
                                               GHashTable *connection,
                                               char **service_name,
                                               GError **err);
 
+static gboolean impl_vpn_plugin_new_secrets (NMVPNPlugin *plugin,
+                                             GHashTable *connection,
+                                             GError **err);
+
 static gboolean impl_vpn_plugin_disconnect (NMVPNPlugin *plugin,
                                             GError **err);
 
@@ -59,7 +68,6 @@ static gboolean impl_vpn_plugin_set_failure (NMVPNPlugin *plugin,
 
 #include "nm-vpn-plugin-glue.h"
 
-#define NM_VPN_PLUGIN_CONNECT_TIMER 60
 #define NM_VPN_PLUGIN_QUIT_TIMER    20
 
 G_DEFINE_ABSTRACT_TYPE (NMVPNPlugin, nm_vpn_plugin, G_TYPE_OBJECT)
@@ -75,6 +83,7 @@ typedef struct {
 	guint connect_timer;
 	guint quit_timer;
 	guint fail_stop_id;
+	gboolean interactive;
 
 	gboolean got_config;
 	gboolean has_ip4, got_ip4;
@@ -94,6 +103,7 @@ enum {
 	LOGIN_BANNER,
 	FAILURE,
 	QUIT,
+	SECRETS_REQUIRED,
 
 	LAST_SIGNAL
 };
@@ -276,60 +286,28 @@ fail_stop (gpointer data)
 	return FALSE;
 }
 
-static gboolean
-nm_vpn_plugin_connect (NMVPNPlugin *plugin,
-                       NMConnection *connection,
-                       GError **err)
+static void
+schedule_fail_stop (NMVPNPlugin *plugin)
 {
 	NMVPNPluginPrivate *priv = NM_VPN_PLUGIN_GET_PRIVATE (plugin);
-	gboolean ret = FALSE;
-	NMVPNServiceState state;
-
-	g_return_val_if_fail (NM_IS_VPN_PLUGIN (plugin), FALSE);
-
-	state = nm_vpn_plugin_get_state (plugin);
-	switch (state) {
-	case NM_VPN_SERVICE_STATE_STARTING:
-		g_set_error (err,
-		             NM_VPN_PLUGIN_ERROR,
-		             NM_VPN_PLUGIN_ERROR_STARTING_IN_PROGRESS,
-		             "%s",
-		             "Could not process the request because the VPN connection is already being started.");
-		break;
-	case NM_VPN_SERVICE_STATE_STARTED:
-		g_set_error (err,
-		             NM_VPN_PLUGIN_ERROR,
-		             NM_VPN_PLUGIN_ERROR_ALREADY_STARTED,
-		             "%s",
-		             "Could not process the request because a VPN connection was already active.");
-		break;
-	case NM_VPN_SERVICE_STATE_STOPPING:
-		g_set_error (err,
-		             NM_VPN_PLUGIN_ERROR,
-		             NM_VPN_PLUGIN_ERROR_STOPPING_IN_PROGRESS,
-		             "%s",
-		             "Could not process the request because the VPN connection is being stopped.");
-		break;
-	case NM_VPN_SERVICE_STATE_STOPPED:
-	case NM_VPN_SERVICE_STATE_INIT:
-		nm_vpn_plugin_set_state (plugin, NM_VPN_SERVICE_STATE_STARTING);
-		ret = NM_VPN_PLUGIN_GET_CLASS (plugin)->connect (plugin, connection, err);
-		if (!ret) {
-			/* Stop the plugin from and idle handler so that the Connect
-			 * method return gets sent before the STOP StateChanged signal.
-			 */
-			if (priv->fail_stop_id)
-				g_source_remove (priv->fail_stop_id);
-			priv->fail_stop_id = g_idle_add (fail_stop, plugin);
-		}
-		break;
 
-	default:
-		g_assert_not_reached ();
-		break;
-	}
+	if (priv->fail_stop_id)
+		g_source_remove (priv->fail_stop_id);
+	priv->fail_stop_id = g_idle_add (fail_stop, plugin);
+}
 
-	return ret;
+static void
+_g_value_set (GValue *dst, GValue *src)
+{
+	if (src) {
+		GType type = G_VALUE_TYPE (src);
+
+		if (G_IS_VALUE (dst))
+			g_value_unset (dst);
+		g_value_init (dst, type);
+		g_value_copy (src, dst);
+	} else if (G_IS_VALUE (dst))
+		g_value_unset (dst);
 }
 
 void
@@ -356,26 +334,10 @@ nm_vpn_plugin_set_config (NMVPNPlugin *plugin,
 	/* Record the items that need to also be inserted into the
 	 * ip4config, for compatibility with older daemons.
 	 */
-	val = g_hash_table_lookup (config, NM_VPN_PLUGIN_CONFIG_BANNER);
-	if (val) {
-		g_value_init (&priv->banner, G_VALUE_TYPE (val));
-		g_value_copy (val, &priv->banner);
-	}
-	val = g_hash_table_lookup (config, NM_VPN_PLUGIN_CONFIG_TUNDEV);
-	if (val) {
-		g_value_init (&priv->tundev, G_VALUE_TYPE (val));
-		g_value_copy (val, &priv->tundev);
-	}
-	val = g_hash_table_lookup (config, NM_VPN_PLUGIN_CONFIG_EXT_GATEWAY);
-	if (val) {
-		g_value_init (&priv->gateway, G_VALUE_TYPE (val));
-		g_value_copy (val, &priv->gateway);
-	}
-	val = g_hash_table_lookup (config, NM_VPN_PLUGIN_CONFIG_MTU);
-	if (val) {
-		g_value_init (&priv->mtu, G_VALUE_TYPE (val));
-		g_value_copy (val, &priv->mtu);
-	}
+	_g_value_set (&priv->banner, g_hash_table_lookup (config, NM_VPN_PLUGIN_CONFIG_BANNER));
+	_g_value_set (&priv->tundev, g_hash_table_lookup (config, NM_VPN_PLUGIN_CONFIG_TUNDEV));
+	_g_value_set (&priv->gateway, g_hash_table_lookup (config, NM_VPN_PLUGIN_CONFIG_EXT_GATEWAY));
+	_g_value_set (&priv->mtu, g_hash_table_lookup (config, NM_VPN_PLUGIN_CONFIG_MTU));
 
 	g_signal_emit (plugin, signals[CONFIG], 0, config);
 }
@@ -446,31 +408,103 @@ nm_vpn_plugin_set_ip6_config (NMVPNPlugin *plugin,
 		nm_vpn_plugin_set_state (plugin, NM_VPN_SERVICE_STATE_STARTED);
 }
 
+static void
+connect_timer_removed (gpointer data)
+{
+	NM_VPN_PLUGIN_GET_PRIVATE (data)->connect_timer = 0;
+}
+
+static void
+connect_timer_start (NMVPNPlugin *plugin)
+{
+	NMVPNPluginPrivate *priv = NM_VPN_PLUGIN_GET_PRIVATE (plugin);
+
+	priv->connect_timer = g_timeout_add_seconds_full (G_PRIORITY_DEFAULT,
+	                                                  60,
+	                                                  connect_timer_expired,
+	                                                  plugin,
+	                                                  connect_timer_removed);
+}
 
 static gboolean
-impl_vpn_plugin_connect (NMVPNPlugin *plugin,
-                         GHashTable *properties,
-                         GError **error)
+_connect_generic (NMVPNPlugin *plugin,
+                  GHashTable *properties,
+                  GHashTable *details,
+                  GError **error)
 {
+	NMVPNPluginPrivate *priv = NM_VPN_PLUGIN_GET_PRIVATE (plugin);
+	NMVPNPluginClass *vpn_class = NM_VPN_PLUGIN_GET_CLASS (plugin);
 	NMConnection *connection;
 	gboolean success = FALSE;
+	GError *local = NULL;
+
+	if (priv->state != NM_VPN_SERVICE_STATE_STOPPED &&
+	    priv->state != NM_VPN_SERVICE_STATE_INIT) {
+		g_set_error (error, NM_VPN_PLUGIN_ERROR, NM_VPN_PLUGIN_ERROR_WRONG_STATE,
+		             "Could not start connection: wrong plugin state %d",
+		             priv->state);
+		return FALSE;
+	}
 
-	connection = nm_connection_new_from_hash (properties, error);
+	connection = nm_connection_new_from_hash (properties, &local);
 	if (!connection) {
-		g_warning ("%s: Invalid connection: '%s' / '%s' invalid: %d",
-		           __func__,
-		           g_type_name (nm_connection_lookup_setting_type_by_quark ((*error)->domain)),
-		           (*error)->message,
-		           (*error)->code);
+		g_set_error (error, NM_VPN_PLUGIN_ERROR, NM_VPN_PLUGIN_ERROR_BAD_ARGUMENTS,
+		             "Invalid connection: (%d) %s",
+		             local->code, local->message);
+		g_clear_error (&local);
+		return FALSE;
+	}
+
+
+	priv->interactive = FALSE;
+	if (details && !vpn_class->connect_interactive) {
+		g_set_error_literal (error, NM_VPN_PLUGIN_ERROR, NM_VPN_PLUGIN_ERROR_INTERACTIVE_NOT_SUPPORTED,
+		                     "Plugin does not implement ConnectInteractive()");
+		return FALSE;
+	}
+
+	nm_vpn_plugin_set_state (plugin, NM_VPN_SERVICE_STATE_STARTING);
+
+	if (details) {
+		priv->interactive = TRUE;
+		success = vpn_class->connect_interactive (plugin, connection, details, error);
+	} else
+		success = vpn_class->connect (plugin, connection, error);
+
+	if (success) {
+		/* Add a timer to make sure we do not wait indefinitely for the successful connect. */
+		connect_timer_start (plugin);
 	} else {
-		success = nm_vpn_plugin_connect (plugin, connection, error);
-		g_object_unref (connection);
+		/* Stop the plugin from an idle handler so that the Connect
+		 * method return gets sent before the STOP StateChanged signal.
+		 */
+		schedule_fail_stop (plugin);
 	}
 
+	g_object_unref (connection);
 	return success;
 }
 
 static gboolean
+impl_vpn_plugin_connect (NMVPNPlugin *plugin,
+                         GHashTable *connection,
+                         GError **error)
+{
+	return _connect_generic (plugin, connection, NULL, error);
+}
+
+static gboolean
+impl_vpn_plugin_connect_interactive (NMVPNPlugin *plugin,
+                                     GHashTable *connection,
+                                     GHashTable *details,
+                                     GError **error)
+{
+	return _connect_generic (plugin, connection, details, error);
+}
+
+/***************************************************************/
+
+static gboolean
 impl_vpn_plugin_need_secrets (NMVPNPlugin *plugin,
                               GHashTable *properties,
                               char **setting_name,
@@ -525,6 +559,94 @@ out:
 }
 
 static gboolean
+impl_vpn_plugin_new_secrets (NMVPNPlugin *plugin,
+                             GHashTable *properties,
+                             GError **error)
+{
+	NMVPNPluginPrivate *priv = NM_VPN_PLUGIN_GET_PRIVATE (plugin);
+	NMConnection *connection;
+	GError *local = NULL;
+	gboolean success;
+
+	if (priv->state != NM_VPN_SERVICE_STATE_STARTING) {
+		g_set_error (error, NM_VPN_PLUGIN_ERROR, NM_VPN_PLUGIN_ERROR_WRONG_STATE,
+		             "Could not accept new secrets: wrong plugin state %d",
+		             priv->state);
+		return FALSE;
+	}
+
+	connection = nm_connection_new_from_hash (properties, &local);
+	if (!connection) {
+		g_set_error (error, NM_VPN_PLUGIN_ERROR, NM_VPN_PLUGIN_ERROR_BAD_ARGUMENTS,
+		             "Invalid connection: (%d) %s",
+		             local->code, local->message);
+		g_clear_error (&local);
+		return FALSE;
+	}
+
+	if (!NM_VPN_PLUGIN_GET_CLASS (plugin)->new_secrets) {
+		g_set_error_literal (error, NM_VPN_PLUGIN_ERROR, NM_VPN_PLUGIN_ERROR_INTERACTIVE_NOT_SUPPORTED,
+		                     "Could not accept new secrets: plugin cannot process interactive secrets");
+		g_object_unref (connection);
+		return FALSE;
+	}
+
+	success = NM_VPN_PLUGIN_GET_CLASS (plugin)->new_secrets (plugin, connection, error);
+	if (success) {
+		/* Add a timer to make sure we do not wait indefinitely for the successful connect. */
+		connect_timer_start (plugin);
+	} else {
+		/* Stop the plugin from and idle handler so that the NewSecrets
+		 * method return gets sent before the STOP StateChanged signal.
+		 */
+		schedule_fail_stop (plugin);
+	}
+
+	g_object_unref (connection);
+	return success;
+}
+
+/**
+ * nm_vpn_plugin_secrets_required:
+ * @plugin: the #NMVPNPlugin
+ * @message: an information message about why secrets are required, if any
+ * @hints: VPN specific secret names for required new secrets
+ *
+ * Called by VPN plugin implementations to signal to NetworkManager that secrets
+ * are required during the connection process.  This signal may be used to
+ * request new secrets when the secrets originally provided by NetworkManager
+ * are insufficient, or the VPN process indicates that it needs additional
+ * information to complete the request.
+ *
+ * Since: 0.9.10
+ */
+void
+nm_vpn_plugin_secrets_required (NMVPNPlugin *plugin,
+                                const char *message,
+                                const char **hints)
+{
+	NMVPNPluginPrivate *priv = NM_VPN_PLUGIN_GET_PRIVATE (plugin);
+
+	/* Plugin must be able to accept the new secrets if it calls this method */
+	g_return_if_fail (NM_VPN_PLUGIN_GET_CLASS (plugin)->new_secrets);
+
+	/* Plugin cannot call this method if NetworkManager didn't originally call
+	 * ConnectInteractive().
+	 */
+	g_return_if_fail (priv->interactive == TRUE);
+
+	/* Cancel the connect timer since secrets might take a while.  It'll
+	 * get restarted when the secrets come back via NewSecrets().
+	 */
+	if (priv->connect_timer)
+		g_source_remove (priv->connect_timer);
+
+	g_signal_emit (plugin, signals[SECRETS_REQUIRED], 0, message, hints);
+}
+
+/***************************************************************/
+
+static gboolean
 impl_vpn_plugin_disconnect (NMVPNPlugin *plugin,
                             GError **err)
 {
@@ -767,12 +889,6 @@ finalize (GObject *object)
 }
 
 static void
-connect_timer_removed (gpointer data)
-{
-	NM_VPN_PLUGIN_GET_PRIVATE (data)->connect_timer = 0;
-}
-
-static void
 quit_timer_removed (gpointer data)
 {
 	NM_VPN_PLUGIN_GET_PRIVATE (data)->quit_timer = 0;
@@ -793,13 +909,6 @@ state_changed (NMVPNPlugin *plugin, NMVPNServiceState state)
 			g_source_remove (priv->fail_stop_id);
 			priv->fail_stop_id = 0;
 		}
-
-		/* Add a timer to make sure we do not wait indefinitely for the successful connect. */
-		priv->connect_timer = g_timeout_add_seconds_full (G_PRIORITY_DEFAULT,
-		                                                  NM_VPN_PLUGIN_CONNECT_TIMER,
-		                                                  connect_timer_expired,
-		                                                  plugin,
-		                                                  connect_timer_removed);
 		break;
 	case NM_VPN_SERVICE_STATE_STOPPED:
 		priv->quit_timer = g_timeout_add_seconds_full (G_PRIORITY_DEFAULT,
@@ -873,6 +982,14 @@ nm_vpn_plugin_class_init (NMVPNPluginClass *plugin_class)
 		              G_TYPE_NONE, 1,
 		              G_TYPE_UINT);
 
+	signals[SECRETS_REQUIRED] =
+		g_signal_new ("secrets-required",
+		              G_OBJECT_CLASS_TYPE (object_class),
+		              G_SIGNAL_RUN_FIRST,
+		              0, NULL, NULL,
+		              NULL,
+		              G_TYPE_NONE, 2, G_TYPE_STRING, G_TYPE_STRV);
+
 	signals[CONFIG] =
 		g_signal_new ("config",
 		              G_OBJECT_CLASS_TYPE (object_class),
@@ -934,7 +1051,7 @@ nm_vpn_plugin_class_init (NMVPNPluginClass *plugin_class)
 		              G_TYPE_NONE);
 
 	dbus_g_error_domain_register (NM_VPN_PLUGIN_ERROR,
-	                              NULL,
+	                              NM_DBUS_VPN_ERROR_PREFIX,
 	                              NM_TYPE_VPN_PLUGIN_ERROR);
 
 	setup_unix_signal_handler ();
diff --git a/libnm-glib/nm-vpn-plugin.h b/libnm-glib/nm-vpn-plugin.h
index dee726f7..4f020f31 100644
--- a/libnm-glib/nm-vpn-plugin.h
+++ b/libnm-glib/nm-vpn-plugin.h
@@ -18,7 +18,7 @@
  * Boston, MA 02110-1301 USA.
  *
  * Copyright (C) 2007 - 2008 Novell, Inc.
- * Copyright (C) 2007 - 2008 Red Hat, Inc.
+ * Copyright (C) 2007 - 2013 Red Hat, Inc.
  */
 
 #ifndef NM_VPN_PLUGIN_H
@@ -63,19 +63,23 @@ G_BEGIN_DECLS
  * @NM_VPN_PLUGIN_ERROR_CONNECTION_INVALID: the operation could not be performed
  *  because the connection was invalid.  Usually means that the connection's
  *  VPN setting was missing some required data item or secret.
+ * @NM_VPN_PLUGIN_ERROR_INTERACTIVE_NOT_SUPPORTED: the operation could not be
+ *  performed as the plugin does not support interactive operations, such as
+ *  ConnectInteractive() or NewSecrets()
  *
  * Returned by the VPN service plugin to indicate errors.
  **/
 typedef enum {
-	NM_VPN_PLUGIN_ERROR_GENERAL,              /*< nick=General >*/
-	NM_VPN_PLUGIN_ERROR_STARTING_IN_PROGRESS, /*< nick=StartingInProgress >*/
-	NM_VPN_PLUGIN_ERROR_ALREADY_STARTED,      /*< nick=AlreadyStarted >*/
-	NM_VPN_PLUGIN_ERROR_STOPPING_IN_PROGRESS, /*< nick=StoppingInProgress >*/
-	NM_VPN_PLUGIN_ERROR_ALREADY_STOPPED,      /*< nick=AlreadyStopped >*/
-	NM_VPN_PLUGIN_ERROR_WRONG_STATE,          /*< nick=WrongState >*/
-	NM_VPN_PLUGIN_ERROR_BAD_ARGUMENTS,        /*< nick=BadArguments >*/
-	NM_VPN_PLUGIN_ERROR_LAUNCH_FAILED,        /*< nick=LaunchFailed >*/
-	NM_VPN_PLUGIN_ERROR_CONNECTION_INVALID,   /*< nick=ConnectionInvalid >*/
+	NM_VPN_PLUGIN_ERROR_GENERAL,                   /*< nick=General >*/
+	NM_VPN_PLUGIN_ERROR_STARTING_IN_PROGRESS,      /*< nick=StartingInProgress >*/
+	NM_VPN_PLUGIN_ERROR_ALREADY_STARTED,           /*< nick=AlreadyStarted >*/
+	NM_VPN_PLUGIN_ERROR_STOPPING_IN_PROGRESS,      /*< nick=StoppingInProgress >*/
+	NM_VPN_PLUGIN_ERROR_ALREADY_STOPPED,           /*< nick=AlreadyStopped >*/
+	NM_VPN_PLUGIN_ERROR_WRONG_STATE,               /*< nick=WrongState >*/
+	NM_VPN_PLUGIN_ERROR_BAD_ARGUMENTS,             /*< nick=BadArguments >*/
+	NM_VPN_PLUGIN_ERROR_LAUNCH_FAILED,             /*< nick=LaunchFailed >*/
+	NM_VPN_PLUGIN_ERROR_CONNECTION_INVALID,        /*< nick=ConnectionInvalid >*/
+	NM_VPN_PLUGIN_ERROR_INTERACTIVE_NOT_SUPPORTED  /*< nick=InteractiveNotSupported >*/
 } NMVPNPluginError;
 
 #define NM_VPN_PLUGIN_ERROR      (nm_vpn_plugin_error_quark ())
@@ -121,11 +125,19 @@ typedef struct {
 	void (*ip6_config)     (NMVPNPlugin *plugin,
 	                        GHashTable  *config);
 
+	/* more methods */
+	gboolean (*new_secrets)  (NMVPNPlugin *plugin,
+	                          NMConnection *connection,
+	                          GError **error);
+
+	gboolean (*connect_interactive) (NMVPNPlugin *plugin,
+	                                 NMConnection *connection,
+	                                 GHashTable *details,
+	                                 GError **error);
+
 	/* Padding for future expansion */
 	void (*_reserved1) (void);
 	void (*_reserved2) (void);
-	void (*_reserved3) (void);
-	void (*_reserved4) (void);
 } NMVPNPluginClass;
 
 GType  nm_vpn_plugin_get_type       (void);
@@ -137,6 +149,11 @@ NMVPNServiceState  nm_vpn_plugin_get_state      (NMVPNPlugin *plugin);
 void               nm_vpn_plugin_set_state      (NMVPNPlugin *plugin,
                                                  NMVPNServiceState state);
 
+NM_AVAILABLE_IN_0_9_10
+void               nm_vpn_plugin_secrets_required (NMVPNPlugin *plugin,
+                                                   const char *message,
+                                                   const char **hints);
+
 void               nm_vpn_plugin_set_login_banner (NMVPNPlugin *plugin,
                                                    const char *banner);
 
diff --git a/libnm-glib/nm-wimax-nsp.c b/libnm-glib/nm-wimax-nsp.c
index baa4b3e1..f747aff3 100644
--- a/libnm-glib/nm-wimax-nsp.c
+++ b/libnm-glib/nm-wimax-nsp.c
@@ -55,10 +55,6 @@ enum {
 	LAST_PROP
 };
 
-#define DBUS_PROP_NAME "Name"
-#define DBUS_PROP_SIGNAL_QUALITY "SignalQuality"
-#define DBUS_PROP_NETWORK_TYPE "NetworkType"
-
 /**
  * nm_wimax_nsp_new:
  * @connection: the #DBusGConnection
@@ -278,17 +274,11 @@ register_properties (NMWimaxNsp *nsp)
 static void
 constructed (GObject *object)
 {
-	NMWimaxNspPrivate *priv;
+	NMWimaxNspPrivate *priv = NM_WIMAX_NSP_GET_PRIVATE (object);
 
 	G_OBJECT_CLASS (nm_wimax_nsp_parent_class)->constructed (object);
 
-	priv = NM_WIMAX_NSP_GET_PRIVATE (object);
-
-	priv->proxy = dbus_g_proxy_new_for_name (nm_object_get_connection (NM_OBJECT (object)),
-											 NM_DBUS_SERVICE,
-											 nm_object_get_path (NM_OBJECT (object)),
-											 NM_DBUS_INTERFACE_WIMAX_NSP);
-
+	priv->proxy = _nm_object_new_proxy (NM_OBJECT (object), NULL, NM_DBUS_INTERFACE_WIMAX_NSP);
 	register_properties (NM_WIMAX_NSP (object));
 }
 
diff --git a/libnm-glib/tests/Makefile.am b/libnm-glib/tests/Makefile.am
index 07994481..38f449ac 100644
--- a/libnm-glib/tests/Makefile.am
+++ b/libnm-glib/tests/Makefile.am
@@ -5,20 +5,29 @@ AM_CPPFLAGS = \
 	-I$(top_builddir)/include \
 	-I$(top_srcdir)/libnm-util \
 	-I$(top_builddir)/libnm-util \
-	-I$(top_srcdir)/libnm-glib
+	-I$(top_srcdir)/libnm-glib \
+	-DNM_VERSION_MAX_ALLOWED=NM_VERSION_NEXT_STABLE \
+	$(GLIB_CFLAGS) \
+	$(DBUS_CFLAGS)
+
+noinst_PROGRAMS = test-nm-client test-remote-settings-client
+
+####### NMClient and non-settings tests #######
 
-noinst_PROGRAMS = test-remote-settings-client
+test_nm_client_SOURCES = \
+	test-nm-client.c
+
+test_nm_client_LDADD = \
+	$(top_builddir)/libnm-util/libnm-util.la \
+	$(top_builddir)/libnm-glib/libnm-glib-test.la \
+	$(GLIB_LIBS) \
+	$(DBUS_LIBS)
 
 ####### remote settings client test #######
 
 test_remote_settings_client_SOURCES = \
 	test-remote-settings-client.c
 
-test_remote_settings_client_CPPFLAGS = \
-	$(GLIB_CFLAGS) \
-	$(DBUS_CFLAGS) \
-	$(AM_CPPFLAGS)
-
 test_remote_settings_client_LDADD = \
 	$(top_builddir)/libnm-util/libnm-util.la \
 	$(top_builddir)/libnm-glib/libnm-glib-test.la \
@@ -27,11 +36,18 @@ test_remote_settings_client_LDADD = \
 
 ###########################################
 
+TEST_NM_BIN = test-fake-nm.py
 TEST_RSS_BIN = test-remote-settings-service.py
 
-EXTRA_DIST = $(TEST_RSS_BIN)
+EXTRA_DIST = $(TEST_RSS_BIN) $(TEST_NM_BIN)
 
-check-local: test-remote-settings-client
-	$(abs_builddir)/test-remote-settings-client $(abs_srcdir) $(TEST_RSS_BIN)
+check-local: test-nm-client test-remote-settings-client
+	if test -z "$$DBUS_SESSION_BUS_ADDRESS" ; then \
+	    dbus-launch --exit-with-session $(abs_builddir)/test-nm-client $(abs_srcdir) $(TEST_NM_BIN); \
+	    dbus-launch --exit-with-session $(abs_builddir)/test-remote-settings-client $(abs_srcdir) $(TEST_RSS_BIN); \
+	else \
+	    $(abs_builddir)/test-nm-client $(abs_srcdir) $(TEST_NM_BIN); \
+	    $(abs_builddir)/test-remote-settings-client $(abs_srcdir) $(TEST_RSS_BIN); \
+	fi;
 
 endif
diff --git a/libnm-glib/tests/Makefile.in b/libnm-glib/tests/Makefile.in
index e9ea17b1..28acdea0 100644
--- a/libnm-glib/tests/Makefile.in
+++ b/libnm-glib/tests/Makefile.in
@@ -78,13 +78,14 @@ PRE_UNINSTALL = :
 POST_UNINSTALL = :
 build_triplet = @build@
 host_triplet = @host@
-@ENABLE_TESTS_TRUE@noinst_PROGRAMS =  \
+@ENABLE_TESTS_TRUE@noinst_PROGRAMS = test-nm-client$(EXEEXT) \
 @ENABLE_TESTS_TRUE@	test-remote-settings-client$(EXEEXT)
 subdir = libnm-glib/tests
 DIST_COMMON = $(srcdir)/Makefile.in $(srcdir)/Makefile.am \
 	$(top_srcdir)/build-aux/depcomp
 ACLOCAL_M4 = $(top_srcdir)/aclocal.m4
-am__aclocal_m4_deps = $(top_srcdir)/m4/compiler_warnings.m4 \
+am__aclocal_m4_deps = $(top_srcdir)/m4/ax_lib_readline.m4 \
+	$(top_srcdir)/m4/compiler_warnings.m4 \
 	$(top_srcdir)/m4/gettext.m4 \
 	$(top_srcdir)/m4/gnome-code-coverage.m4 \
 	$(top_srcdir)/m4/gtk-doc.m4 $(top_srcdir)/m4/iconv.m4 \
@@ -103,13 +104,12 @@ CONFIG_HEADER = $(top_builddir)/config.h
 CONFIG_CLEAN_FILES =
 CONFIG_CLEAN_VPATH_FILES =
 PROGRAMS = $(noinst_PROGRAMS)
-am__test_remote_settings_client_SOURCES_DIST =  \
-	test-remote-settings-client.c
-@ENABLE_TESTS_TRUE@am_test_remote_settings_client_OBJECTS = test_remote_settings_client-test-remote-settings-client.$(OBJEXT)
-test_remote_settings_client_OBJECTS =  \
-	$(am_test_remote_settings_client_OBJECTS)
+am__test_nm_client_SOURCES_DIST = test-nm-client.c
+@ENABLE_TESTS_TRUE@am_test_nm_client_OBJECTS =  \
+@ENABLE_TESTS_TRUE@	test-nm-client.$(OBJEXT)
+test_nm_client_OBJECTS = $(am_test_nm_client_OBJECTS)
 am__DEPENDENCIES_1 =
-@ENABLE_TESTS_TRUE@test_remote_settings_client_DEPENDENCIES =  \
+@ENABLE_TESTS_TRUE@test_nm_client_DEPENDENCIES =  \
 @ENABLE_TESTS_TRUE@	$(top_builddir)/libnm-util/libnm-util.la \
 @ENABLE_TESTS_TRUE@	$(top_builddir)/libnm-glib/libnm-glib-test.la \
 @ENABLE_TESTS_TRUE@	$(am__DEPENDENCIES_1) $(am__DEPENDENCIES_1)
@@ -117,6 +117,16 @@ AM_V_lt = $(am__v_lt_@AM_V@)
 am__v_lt_ = $(am__v_lt_@AM_DEFAULT_V@)
 am__v_lt_0 = --silent
 am__v_lt_1 = 
+am__test_remote_settings_client_SOURCES_DIST =  \
+	test-remote-settings-client.c
+@ENABLE_TESTS_TRUE@am_test_remote_settings_client_OBJECTS =  \
+@ENABLE_TESTS_TRUE@	test-remote-settings-client.$(OBJEXT)
+test_remote_settings_client_OBJECTS =  \
+	$(am_test_remote_settings_client_OBJECTS)
+@ENABLE_TESTS_TRUE@test_remote_settings_client_DEPENDENCIES =  \
+@ENABLE_TESTS_TRUE@	$(top_builddir)/libnm-util/libnm-util.la \
+@ENABLE_TESTS_TRUE@	$(top_builddir)/libnm-glib/libnm-glib-test.la \
+@ENABLE_TESTS_TRUE@	$(am__DEPENDENCIES_1) $(am__DEPENDENCIES_1)
 AM_V_P = $(am__v_P_@AM_V@)
 am__v_P_ = $(am__v_P_@AM_DEFAULT_V@)
 am__v_P_0 = false
@@ -151,8 +161,10 @@ AM_V_CCLD = $(am__v_CCLD_@AM_V@)
 am__v_CCLD_ = $(am__v_CCLD_@AM_DEFAULT_V@)
 am__v_CCLD_0 = @echo "  CCLD    " $@;
 am__v_CCLD_1 = 
-SOURCES = $(test_remote_settings_client_SOURCES)
-DIST_SOURCES = $(am__test_remote_settings_client_SOURCES_DIST)
+SOURCES = $(test_nm_client_SOURCES) \
+	$(test_remote_settings_client_SOURCES)
+DIST_SOURCES = $(am__test_nm_client_SOURCES_DIST) \
+	$(am__test_remote_settings_client_SOURCES_DIST)
 am__can_run_installinfo = \
   case $$AM_UPDATE_INFO_DIR in \
     n|no|NO) false;; \
@@ -203,12 +215,15 @@ CXXFLAGS = @CXXFLAGS@
 CYGPATH_W = @CYGPATH_W@
 DATADIRNAME = @DATADIRNAME@
 DBUS_CFLAGS = @DBUS_CFLAGS@
+DBUS_GLIB_100_CFLAGS = @DBUS_GLIB_100_CFLAGS@
+DBUS_GLIB_100_LIBS = @DBUS_GLIB_100_LIBS@
 DBUS_LIBS = @DBUS_LIBS@
 DBUS_SYS_DIR = @DBUS_SYS_DIR@
 DEFS = @DEFS@
 DEPDIR = @DEPDIR@
 DHCLIENT_PATH = @DHCLIENT_PATH@
 DHCPCD_PATH = @DHCPCD_PATH@
+DISTRO_NETWORK_SERVICE = @DISTRO_NETWORK_SERVICE@
 DLLTOOL = @DLLTOOL@
 DNSMASQ_PATH = @DNSMASQ_PATH@
 DSYMUTIL = @DSYMUTIL@
@@ -233,7 +248,6 @@ GNUTLS_CFLAGS = @GNUTLS_CFLAGS@
 GNUTLS_LIBS = @GNUTLS_LIBS@
 GREP = @GREP@
 GTKDOC_CHECK = @GTKDOC_CHECK@
-GTKDOC_CHECK_PATH = @GTKDOC_CHECK_PATH@
 GTKDOC_DEPS_CFLAGS = @GTKDOC_DEPS_CFLAGS@
 GTKDOC_DEPS_LIBS = @GTKDOC_DEPS_LIBS@
 GTKDOC_MKPDF = @GTKDOC_MKPDF@
@@ -278,12 +292,16 @@ LIBGCRYPT_LIBS = @LIBGCRYPT_LIBS@
 LIBICONV = @LIBICONV@
 LIBINTL = @LIBINTL@
 LIBM = @LIBM@
+LIBNDP_CFLAGS = @LIBNDP_CFLAGS@
+LIBNDP_LIBS = @LIBNDP_LIBS@
 LIBNL_CFLAGS = @LIBNL_CFLAGS@
 LIBNL_LIBS = @LIBNL_LIBS@
 LIBOBJS = @LIBOBJS@
 LIBS = @LIBS@
 LIBSOUP_CFLAGS = @LIBSOUP_CFLAGS@
 LIBSOUP_LIBS = @LIBSOUP_LIBS@
+LIBTEAMDCTL_CFLAGS = @LIBTEAMDCTL_CFLAGS@
+LIBTEAMDCTL_LIBS = @LIBTEAMDCTL_LIBS@
 LIBTOOL = @LIBTOOL@
 LIPO = @LIPO@
 LN_S = @LN_S@
@@ -300,6 +318,8 @@ MOC = @MOC@
 MSGFMT = @MSGFMT@
 MSGFMT_015 = @MSGFMT_015@
 MSGMERGE = @MSGMERGE@
+NEWT_CFLAGS = @NEWT_CFLAGS@
+NEWT_LIBS = @NEWT_LIBS@
 NM = @NM@
 NMEDIT = @NMEDIT@
 NM_MAJOR_VERSION = @NM_MAJOR_VERSION@
@@ -327,11 +347,16 @@ PKG_CONFIG_PATH = @PKG_CONFIG_PATH@
 POLKIT_CFLAGS = @POLKIT_CFLAGS@
 POLKIT_LIBS = @POLKIT_LIBS@
 POSUB = @POSUB@
+PPPD_PATH = @PPPD_PATH@
 PPPD_PLUGIN_DIR = @PPPD_PLUGIN_DIR@
+PPPOE_PATH = @PPPOE_PATH@
 QT_CFLAGS = @QT_CFLAGS@
 QT_LIBS = @QT_LIBS@
 RANLIB = @RANLIB@
+READLINE_LIBS = @READLINE_LIBS@
 SED = @SED@
+SELINUX_CFLAGS = @SELINUX_CFLAGS@
+SELINUX_LIBS = @SELINUX_LIBS@
 SET_MAKE = @SET_MAKE@
 SHELL = @SHELL@
 STRIP = @STRIP@
@@ -346,6 +371,7 @@ UDEV_BASE_DIR = @UDEV_BASE_DIR@
 USE_NLS = @USE_NLS@
 UUID_CFLAGS = @UUID_CFLAGS@
 UUID_LIBS = @UUID_LIBS@
+VALGRIND_RULES = @VALGRIND_RULES@
 VAPIGEN = @VAPIGEN@
 VAPIGEN_MAKEFILE = @VAPIGEN_MAKEFILE@
 VAPIGEN_VAPIDIR = @VAPIGEN_VAPIDIR@
@@ -408,6 +434,7 @@ psdir = @psdir@
 sbindir = @sbindir@
 sharedstatedir = @sharedstatedir@
 srcdir = @srcdir@
+subdirs = @subdirs@
 sysconfdir = @sysconfdir@
 systemdsystemunitdir = @systemdsystemunitdir@
 target_alias = @target_alias@
@@ -418,23 +445,33 @@ with_dhclient = @with_dhclient@
 with_dhcpcd = @with_dhcpcd@
 with_netconfig = @with_netconfig@
 with_resolvconf = @with_resolvconf@
+with_valgrind = @with_valgrind@
 @ENABLE_TESTS_TRUE@AM_CPPFLAGS = \
 @ENABLE_TESTS_TRUE@	-I$(top_srcdir)/include \
 @ENABLE_TESTS_TRUE@	-I$(top_builddir)/include \
 @ENABLE_TESTS_TRUE@	-I$(top_srcdir)/libnm-util \
 @ENABLE_TESTS_TRUE@	-I$(top_builddir)/libnm-util \
-@ENABLE_TESTS_TRUE@	-I$(top_srcdir)/libnm-glib
+@ENABLE_TESTS_TRUE@	-I$(top_srcdir)/libnm-glib \
+@ENABLE_TESTS_TRUE@	-DNM_VERSION_MAX_ALLOWED=NM_VERSION_NEXT_STABLE \
+@ENABLE_TESTS_TRUE@	$(GLIB_CFLAGS) \
+@ENABLE_TESTS_TRUE@	$(DBUS_CFLAGS)
+
+
+####### NMClient and non-settings tests #######
+@ENABLE_TESTS_TRUE@test_nm_client_SOURCES = \
+@ENABLE_TESTS_TRUE@	test-nm-client.c
+
+@ENABLE_TESTS_TRUE@test_nm_client_LDADD = \
+@ENABLE_TESTS_TRUE@	$(top_builddir)/libnm-util/libnm-util.la \
+@ENABLE_TESTS_TRUE@	$(top_builddir)/libnm-glib/libnm-glib-test.la \
+@ENABLE_TESTS_TRUE@	$(GLIB_LIBS) \
+@ENABLE_TESTS_TRUE@	$(DBUS_LIBS)
 
 
 ####### remote settings client test #######
 @ENABLE_TESTS_TRUE@test_remote_settings_client_SOURCES = \
 @ENABLE_TESTS_TRUE@	test-remote-settings-client.c
 
-@ENABLE_TESTS_TRUE@test_remote_settings_client_CPPFLAGS = \
-@ENABLE_TESTS_TRUE@	$(GLIB_CFLAGS) \
-@ENABLE_TESTS_TRUE@	$(DBUS_CFLAGS) \
-@ENABLE_TESTS_TRUE@	$(AM_CPPFLAGS)
-
 @ENABLE_TESTS_TRUE@test_remote_settings_client_LDADD = \
 @ENABLE_TESTS_TRUE@	$(top_builddir)/libnm-util/libnm-util.la \
 @ENABLE_TESTS_TRUE@	$(top_builddir)/libnm-glib/libnm-glib-test.la \
@@ -443,8 +480,9 @@ with_resolvconf = @with_resolvconf@
 
 
 ###########################################
+@ENABLE_TESTS_TRUE@TEST_NM_BIN = test-fake-nm.py
 @ENABLE_TESTS_TRUE@TEST_RSS_BIN = test-remote-settings-service.py
-@ENABLE_TESTS_TRUE@EXTRA_DIST = $(TEST_RSS_BIN)
+@ENABLE_TESTS_TRUE@EXTRA_DIST = $(TEST_RSS_BIN) $(TEST_NM_BIN)
 all: all-am
 
 .SUFFIXES:
@@ -489,6 +527,10 @@ clean-noinstPROGRAMS:
 	echo " rm -f" $$list; \
 	rm -f $$list
 
+test-nm-client$(EXEEXT): $(test_nm_client_OBJECTS) $(test_nm_client_DEPENDENCIES) $(EXTRA_test_nm_client_DEPENDENCIES) 
+	@rm -f test-nm-client$(EXEEXT)
+	$(AM_V_CCLD)$(LINK) $(test_nm_client_OBJECTS) $(test_nm_client_LDADD) $(LIBS)
+
 test-remote-settings-client$(EXEEXT): $(test_remote_settings_client_OBJECTS) $(test_remote_settings_client_DEPENDENCIES) $(EXTRA_test_remote_settings_client_DEPENDENCIES) 
 	@rm -f test-remote-settings-client$(EXEEXT)
 	$(AM_V_CCLD)$(LINK) $(test_remote_settings_client_OBJECTS) $(test_remote_settings_client_LDADD) $(LIBS)
@@ -499,7 +541,8 @@ mostlyclean-compile:
 distclean-compile:
 	-rm -f *.tab.c
 
-@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/test_remote_settings_client-test-remote-settings-client.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/test-nm-client.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/test-remote-settings-client.Po@am__quote@
 
 .c.o:
 @am__fastdepCC_TRUE@	$(AM_V_CC)$(COMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $<
@@ -522,20 +565,6 @@ distclean-compile:
 @AMDEP_TRUE@@am__fastdepCC_FALSE@	DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
 @am__fastdepCC_FALSE@	$(AM_V_CC@am__nodep@)$(LTCOMPILE) -c -o $@ $<
 
-test_remote_settings_client-test-remote-settings-client.o: test-remote-settings-client.c
-@am__fastdepCC_TRUE@	$(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(test_remote_settings_client_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT test_remote_settings_client-test-remote-settings-client.o -MD -MP -MF $(DEPDIR)/test_remote_settings_client-test-remote-settings-client.Tpo -c -o test_remote_settings_client-test-remote-settings-client.o `test -f 'test-remote-settings-client.c' || echo '$(srcdir)/'`test-remote-settings-client.c
-@am__fastdepCC_TRUE@	$(AM_V_at)$(am__mv) $(DEPDIR)/test_remote_settings_client-test-remote-settings-client.Tpo $(DEPDIR)/test_remote_settings_client-test-remote-settings-client.Po
-@AMDEP_TRUE@@am__fastdepCC_FALSE@	$(AM_V_CC)source='test-remote-settings-client.c' object='test_remote_settings_client-test-remote-settings-client.o' libtool=no @AMDEPBACKSLASH@
-@AMDEP_TRUE@@am__fastdepCC_FALSE@	DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
-@am__fastdepCC_FALSE@	$(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(test_remote_settings_client_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o test_remote_settings_client-test-remote-settings-client.o `test -f 'test-remote-settings-client.c' || echo '$(srcdir)/'`test-remote-settings-client.c
-
-test_remote_settings_client-test-remote-settings-client.obj: test-remote-settings-client.c
-@am__fastdepCC_TRUE@	$(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(test_remote_settings_client_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT test_remote_settings_client-test-remote-settings-client.obj -MD -MP -MF $(DEPDIR)/test_remote_settings_client-test-remote-settings-client.Tpo -c -o test_remote_settings_client-test-remote-settings-client.obj `if test -f 'test-remote-settings-client.c'; then $(CYGPATH_W) 'test-remote-settings-client.c'; else $(CYGPATH_W) '$(srcdir)/test-remote-settings-client.c'; fi`
-@am__fastdepCC_TRUE@	$(AM_V_at)$(am__mv) $(DEPDIR)/test_remote_settings_client-test-remote-settings-client.Tpo $(DEPDIR)/test_remote_settings_client-test-remote-settings-client.Po
-@AMDEP_TRUE@@am__fastdepCC_FALSE@	$(AM_V_CC)source='test-remote-settings-client.c' object='test_remote_settings_client-test-remote-settings-client.obj' libtool=no @AMDEPBACKSLASH@
-@AMDEP_TRUE@@am__fastdepCC_FALSE@	DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
-@am__fastdepCC_FALSE@	$(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(test_remote_settings_client_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o test_remote_settings_client-test-remote-settings-client.obj `if test -f 'test-remote-settings-client.c'; then $(CYGPATH_W) 'test-remote-settings-client.c'; else $(CYGPATH_W) '$(srcdir)/test-remote-settings-client.c'; fi`
-
 mostlyclean-libtool:
 	-rm -f *.lo
 
@@ -748,8 +777,14 @@ uninstall-am:
 	tags tags-am uninstall uninstall-am
 
 
-@ENABLE_TESTS_TRUE@check-local: test-remote-settings-client
-@ENABLE_TESTS_TRUE@	$(abs_builddir)/test-remote-settings-client $(abs_srcdir) $(TEST_RSS_BIN)
+@ENABLE_TESTS_TRUE@check-local: test-nm-client test-remote-settings-client
+@ENABLE_TESTS_TRUE@	if test -z "$$DBUS_SESSION_BUS_ADDRESS" ; then \
+@ENABLE_TESTS_TRUE@	    dbus-launch --exit-with-session $(abs_builddir)/test-nm-client $(abs_srcdir) $(TEST_NM_BIN); \
+@ENABLE_TESTS_TRUE@	    dbus-launch --exit-with-session $(abs_builddir)/test-remote-settings-client $(abs_srcdir) $(TEST_RSS_BIN); \
+@ENABLE_TESTS_TRUE@	else \
+@ENABLE_TESTS_TRUE@	    $(abs_builddir)/test-nm-client $(abs_srcdir) $(TEST_NM_BIN); \
+@ENABLE_TESTS_TRUE@	    $(abs_builddir)/test-remote-settings-client $(abs_srcdir) $(TEST_RSS_BIN); \
+@ENABLE_TESTS_TRUE@	fi;
 
 # 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/libnm-glib/tests/test-fake-nm.py b/libnm-glib/tests/test-fake-nm.py
new file mode 100755
index 00000000..46ca3ff0
--- /dev/null
+++ b/libnm-glib/tests/test-fake-nm.py
@@ -0,0 +1,776 @@
+#!/usr/bin/env python
+# -*- Mode: python; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*-
+
+from __future__ import print_function
+
+from gi.repository import GLib, GObject
+import sys
+import dbus
+import dbus.service
+import dbus.mainloop.glib
+import random
+
+mainloop = GObject.MainLoop()
+quit_id = 0
+
+# NM State
+NM_STATE_UNKNOWN          = 0
+NM_STATE_ASLEEP           = 10
+NM_STATE_DISCONNECTED     = 20
+NM_STATE_DISCONNECTING    = 30
+NM_STATE_CONNECTING       = 40
+NM_STATE_CONNECTED_LOCAL  = 50
+NM_STATE_CONNECTED_SITE   = 60
+NM_STATE_CONNECTED_GLOBAL = 70
+
+# Device state
+NM_DEVICE_STATE_UNKNOWN      = 0
+NM_DEVICE_STATE_UNMANAGED    = 10
+NM_DEVICE_STATE_UNAVAILABLE  = 20
+NM_DEVICE_STATE_DISCONNECTED = 30
+NM_DEVICE_STATE_PREPARE      = 40
+NM_DEVICE_STATE_CONFIG       = 50
+NM_DEVICE_STATE_NEED_AUTH    = 60
+NM_DEVICE_STATE_IP_CONFIG    = 70
+NM_DEVICE_STATE_IP_CHECK     = 80
+NM_DEVICE_STATE_SECONDARIES  = 90
+NM_DEVICE_STATE_ACTIVATED    = 100
+NM_DEVICE_STATE_DEACTIVATING = 110
+NM_DEVICE_STATE_FAILED       = 120
+
+NM_DEVICE_TYPE_UNKNOWN    = 0
+NM_DEVICE_TYPE_ETHERNET   = 1
+NM_DEVICE_TYPE_WIFI       = 2
+NM_DEVICE_TYPE_UNUSED1    = 3
+NM_DEVICE_TYPE_UNUSED2    = 4
+NM_DEVICE_TYPE_BT         = 5
+NM_DEVICE_TYPE_OLPC_MESH  = 6
+NM_DEVICE_TYPE_WIMAX      = 7
+NM_DEVICE_TYPE_MODEM      = 8
+NM_DEVICE_TYPE_INFINIBAND = 9
+NM_DEVICE_TYPE_BOND       = 10
+NM_DEVICE_TYPE_VLAN       = 11
+NM_DEVICE_TYPE_ADSL       = 12
+NM_DEVICE_TYPE_BRIDGE     = 13
+NM_DEVICE_TYPE_GENERIC    = 14
+NM_DEVICE_TYPE_TEAM       = 15
+
+#########################################################
+IFACE_DBUS = 'org.freedesktop.DBus'
+
+class UnknownInterfaceException(dbus.DBusException):
+    _dbus_error_name = IFACE_DBUS + '.UnknownInterface'
+
+class UnknownPropertyException(dbus.DBusException):
+    _dbus_error_name = IFACE_DBUS + '.UnknownProperty'
+
+def to_path_array(src):
+    array = dbus.Array([], signature=dbus.Signature('o'))
+    for o in src:
+        array.append(o.path)
+    return array
+
+def to_path(src):
+    if src:
+        return dbus.ObjectPath(src.path)
+    return dbus.ObjectPath("/")
+
+class ExportedObj(dbus.service.Object):
+    def __init__(self, bus, object_path):
+        dbus.service.Object.__init__(self, bus, object_path)
+        self._bus = bus
+        self.path = object_path
+        self.__dbus_ifaces = {}
+
+    def add_dbus_interface(self, dbus_iface, get_props_func):
+        self.__dbus_ifaces[dbus_iface] = get_props_func
+
+    def _get_dbus_properties(self, iface):
+        return self.__dbus_ifaces[iface]()
+
+    @dbus.service.method(dbus_interface=dbus.PROPERTIES_IFACE, in_signature='s', out_signature='a{sv}')
+    def GetAll(self, iface):
+        if iface not in self.__dbus_ifaces.keys():
+            raise UnknownInterfaceException()
+        return self._get_dbus_properties(iface)
+
+    @dbus.service.method(dbus_interface=dbus.PROPERTIES_IFACE, in_signature='ss', out_signature='v')
+    def Get(self, iface, name):
+        if iface not in self.__dbus_ifaces.keys():
+            raise UnknownInterfaceException()
+        props = self._get_dbus_properties(iface)
+        if not name in props.keys():
+            raise UnknownPropertyException()
+        return props[name]
+
+###################################################################
+IFACE_DEVICE = 'org.freedesktop.NetworkManager.Device'
+
+PD_UDI = "Udi"
+PD_IFACE = "Interface"
+PD_DRIVER = "Driver"
+PD_STATE = "State"
+PD_ACTIVE_CONNECTION = "ActiveConnection"
+PD_IP4_CONFIG = "Ip4Config"
+PD_IP6_CONFIG = "Ip6Config"
+PD_DHCP4_CONFIG = "Dhcp4Config"
+PD_DHCP6_CONFIG = "Dhcp6Config"
+PD_MANAGED = "Managed"
+PD_AUTOCONNECT = "Autoconnect"
+PD_DEVICE_TYPE = "DeviceType"
+PD_AVAILABLE_CONNECTIONS = "AvailableConnections"
+
+class Device(ExportedObj):
+    counter = 1
+
+    def __init__(self, bus, iface, devtype):
+        object_path = "/org/freedesktop/NetworkManager/Devices/%d" % Device.counter
+        Device.counter = Device.counter + 1
+        ExportedObj.__init__(self, bus, object_path)
+        self.add_dbus_interface(IFACE_DEVICE, self.__get_props)
+
+        self.iface = iface
+        self.udi = "/sys/devices/virtual/%s" % iface
+        self.devtype = devtype
+        self.active_connection = None
+        self.state = NM_DEVICE_STATE_UNAVAILABLE
+        self.ip4_config = None
+        self.ip6_config = None
+        self.dhcp4_config = None
+        self.dhcp6_config = None
+        self.available_connections = []
+
+    # Properties interface
+    def __get_props(self):
+        props = {}
+        props[PD_UDI] = self.udi
+        props[PD_IFACE] = self.iface
+        props[PD_DRIVER] = "virtual"
+        props[PD_STATE] = dbus.UInt32(self.state)
+        props[PD_ACTIVE_CONNECTION] = to_path(self.active_connection)
+        props[PD_IP4_CONFIG] = to_path(self.ip4_config)
+        props[PD_IP6_CONFIG] = to_path(self.ip6_config)
+        props[PD_DHCP4_CONFIG] = to_path(self.dhcp4_config)
+        props[PD_DHCP6_CONFIG] = to_path(self.dhcp6_config)
+        props[PD_MANAGED] = True
+        props[PD_AUTOCONNECT] = True
+        props[PD_DEVICE_TYPE] = dbus.UInt32(self.devtype)
+        props[PD_AVAILABLE_CONNECTIONS] = to_path_array(self.available_connections)
+        return props
+
+    # methods
+    @dbus.service.method(dbus_interface=IFACE_DEVICE, in_signature='', out_signature='')
+    def Disconnect(self):
+        pass
+
+    def __notify(self, propname):
+        props = self._get_dbus_properties(IFACE_DEVICE)
+        changed = { propname: props[propname] }
+        Device.PropertiesChanged(self, changed)
+
+    @dbus.service.signal(IFACE_DEVICE, signature='a{sv}')
+    def PropertiesChanged(self, changed):
+        pass
+
+
+###################################################################
+
+def random_mac():
+    return '%02X:%02X:%02X:%02X:%02X:%02X' % (
+        random.randint(0, 255), random.randint(0, 255), random.randint(0, 255),
+        random.randint(0, 255), random.randint(0, 255), random.randint(0, 255)
+      )
+
+###################################################################
+IFACE_WIRED = 'org.freedesktop.NetworkManager.Device.Wired'
+
+PE_HW_ADDRESS = "HwAddress"
+PE_PERM_HW_ADDRESS = "PermHwAddress"
+PE_SPEED = "Speed"
+PE_CARRIER = "Carrier"
+
+class WiredDevice(Device):
+    def __init__(self, bus, iface):
+        Device.__init__(self, bus, iface, NM_DEVICE_TYPE_ETHERNET)
+        self.add_dbus_interface(IFACE_WIRED, self.__get_props)
+
+        self.mac = random_mac()
+        self.carrier = False
+
+    # Properties interface
+    def __get_props(self):
+        props = {}
+        props[PE_HW_ADDRESS] = self.mac
+        props[PE_PERM_HW_ADDRESS] = self.mac
+        props[PE_SPEED] = dbus.UInt32(100)
+        props[PE_CARRIER] = self.carrier
+        return props
+
+    def __notify(self, propname):
+        props = self._get_dbus_properties(IFACE_WIRED)
+        changed = { propname: props[propname] }
+        WiredDevice.PropertiesChanged(self, changed)
+
+    @dbus.service.signal(IFACE_WIRED, signature='a{sv}')
+    def PropertiesChanged(self, changed):
+        pass
+
+###################################################################
+IFACE_WIFI_AP = 'org.freedesktop.NetworkManager.AccessPoint'
+
+PP_FLAGS = "Flags"
+PP_WPA_FLAGS = "WpaFlags"
+PP_RSN_FLAGS = "RsnFlags"
+PP_SSID = "Ssid"
+PP_FREQUENCY = "Frequency"
+PP_HW_ADDRESS = "HwAddress"
+PP_MODE = "Mode"
+PP_MAX_BITRATE = "MaxBitrate"
+PP_STRENGTH = "Strength"
+
+class WifiAp(ExportedObj):
+    counter = 0
+
+    def __init__(self, bus, ssid, mac, flags, wpaf, rsnf, freq):
+        path = "/org/freedesktop/NetworkManager/AccessPoint/%d" % WifiAp.counter
+        WifiAp.counter = WifiAp.counter + 1
+        ExportedObj.__init__(self, bus, path)
+        self.add_dbus_interface(IFACE_WIFI_AP, self.__get_props)
+
+        self.ssid = ssid
+        if mac:
+            self.bssid = mac
+        else:
+            self.bssid = random_mac()
+        self.flags = flags
+        self.wpaf = wpaf
+        self.rsnf = rsnf
+        self.freq = freq
+        self.strength = random.randint(0, 100)
+        self.strength_id = GLib.timeout_add_seconds(10, self.strength_cb, None)
+
+    def __del__(self):
+        if self.strength_id > 0:
+            GLib.source_remove(self.strength_id)
+        self.strength_id = 0
+
+    def strength_cb(self, ignored):
+        self.strength = random.randint(0, 100)
+        self.__notify(PP_STRENGTH)
+        return True
+
+    # Properties interface
+    def __get_props(self):
+        props = {}
+        props[PP_FLAGS] = dbus.UInt32(self.flags)
+        props[PP_WPA_FLAGS] = dbus.UInt32(self.wpaf)
+        props[PP_RSN_FLAGS] = dbus.UInt32(self.rsnf)
+        props[PP_SSID] = dbus.ByteArray(self.ssid)
+        props[PP_FREQUENCY] = dbus.UInt32(self.freq)
+        props[PP_HW_ADDRESS] = self.bssid
+        props[PP_MODE] = dbus.UInt32(2)  # NM_802_11_MODE_INFRA
+        props[PP_MAX_BITRATE] = dbus.UInt32(54000)
+        props[PP_STRENGTH] = dbus.Byte(self.strength)
+        return props
+
+    def __notify(self, propname):
+        props = self._get_dbus_properties(IFACE_WIFI_AP)
+        changed = { propname: props[propname] }
+        WifiAp.PropertiesChanged(self, changed)
+
+    @dbus.service.signal(IFACE_WIFI_AP, signature='a{sv}')
+    def PropertiesChanged(self, changed):
+        pass
+
+###################################################################
+IFACE_WIFI = 'org.freedesktop.NetworkManager.Device.Wireless'
+
+class ApNotFoundException(dbus.DBusException):
+    _dbus_error_name = IFACE_WIFI + '.AccessPointNotFound'
+
+PW_HW_ADDRESS = "HwAddress"
+PW_PERM_HW_ADDRESS = "PermHwAddress"
+PW_MODE = "Mode"
+PW_BITRATE = "Bitrate"
+PW_ACCESS_POINTS = "AccessPoints"
+PW_ACTIVE_ACCESS_POINT = "ActiveAccessPoint"
+PW_WIRELESS_CAPABILITIES = "WirelessCapabilities"
+
+class WifiDevice(Device):
+    def __init__(self, bus, iface):
+        Device.__init__(self, bus, iface, NM_DEVICE_TYPE_WIFI)
+        self.add_dbus_interface(IFACE_WIFI, self.__get_props)
+
+        self.mac = random_mac()
+        self.aps = []
+        self.active_ap = None
+
+    # methods
+    @dbus.service.method(dbus_interface=IFACE_WIFI, in_signature='', out_signature='ao')
+    def GetAccessPoints(self):
+        # only include non-hidden APs
+        array = []
+        for a in self.aps:
+            if a.ssid():
+                array.append(a)
+        return to_path_array(array)
+
+    @dbus.service.method(dbus_interface=IFACE_WIFI, in_signature='', out_signature='ao')
+    def GetAllAccessPoints(self):
+        # include all APs including hidden ones
+        return to_path_array(self.aps)
+
+    @dbus.service.method(dbus_interface=IFACE_WIFI, in_signature='a{sv}', out_signature='')
+    def RequestScan(self, props):
+        pass
+
+    @dbus.service.signal(IFACE_WIFI, signature='o')
+    def AccessPointAdded(self, ap_path):
+        pass
+
+    def add_ap(self, ap):
+        self.aps.append(ap)
+        self.__notify(PW_ACCESS_POINTS)
+        self.AccessPointAdded(to_path(ap))
+
+    @dbus.service.signal(IFACE_WIFI, signature='o')
+    def AccessPointRemoved(self, ap_path):
+        pass
+
+    def remove_ap(self, ap):
+        self.aps.remove(ap)
+        self.__notify(PW_ACCESS_POINTS)
+        self.AccessPointRemoved(to_path(ap))
+
+    # Properties interface
+    def __get_props(self):
+        props = {}
+        props[PW_HW_ADDRESS] = self.mac
+        props[PW_PERM_HW_ADDRESS] = self.mac
+        props[PW_MODE] = dbus.UInt32(3)  # NM_802_11_MODE_INFRA
+        props[PW_BITRATE] = dbus.UInt32(21000)
+        props[PW_WIRELESS_CAPABILITIES] = dbus.UInt32(0xFF)
+        props[PW_ACCESS_POINTS] = to_path_array(self.aps)
+        props[PW_ACTIVE_ACCESS_POINT] = to_path(self.active_ap)
+        return props
+
+    def __notify(self, propname):
+        props = self._get_dbus_properties(IFACE_WIFI)
+        changed = { propname: props[propname] }
+        WifiDevice.PropertiesChanged(self, changed)
+
+    @dbus.service.signal(IFACE_WIFI, signature='a{sv}')
+    def PropertiesChanged(self, changed):
+        pass
+
+    # test functions
+    def add_test_ap(self, ssid, mac):
+        ap = WifiAp(self._bus, ssid, mac, 0x1, 0x1cc, 0x1cc, 2412)
+        self.add_ap(ap)
+        return ap.path
+
+    def remove_ap_by_path(self, path):
+        for ap in self.aps:
+            if ap.path == path:
+                self.remove_ap(ap)
+                return
+        raise ApNotFoundException("AP %s not found" % path)
+
+
+###################################################################
+IFACE_WIMAX_NSP = 'org.freedesktop.NetworkManager.WiMax.Nsp'
+
+PN_NAME = "Name"
+PN_SIGNAL_QUALITY = "SignalQuality"
+PN_NETWORK_TYPE = "NetworkType"
+
+class WimaxNsp(ExportedObj):
+    counter = 0
+
+    def __init__(self, bus, name):
+        path = "/org/freedesktop/NetworkManager/Nsp/%d" % WimaxNsp.counter
+        WimaxNsp.counter = WimaxNsp.counter + 1
+        ExportedObj.__init__(self, bus, path)
+        self.add_dbus_interface(IFACE_WIMAX_NSP, self.__get_props)
+
+        self.name = name
+        self.strength = random.randint(0, 100)
+        self.strength_id = GLib.timeout_add_seconds(10, self.strength_cb, None)
+
+    def __del__(self):
+        if self.strength_id > 0:
+            GLib.source_remove(self.strength_id)
+        self.strength_id = 0
+
+    def strength_cb(self, ignored):
+        self.strength = random.randint(0, 100)
+        self.__notify(PN_SIGNAL_QUALITY)
+        return True
+
+    # Properties interface
+    def __get_props(self):
+        props = {}
+        props[PN_NAME] = self.name
+        props[PN_SIGNAL_QUALITY] = dbus.UInt32(self.strength)
+        props[PN_NETWORK_TYPE] = dbus.UInt32(0x1)  # NM_WIMAX_NSP_NETWORK_TYPE_HOME
+        return props
+
+    def __notify(self, propname):
+        props = self._get_dbus_properties(IFACE_WIMAX_NSP)
+        changed = { propname: props[propname] }
+        WimaxNsp.PropertiesChanged(self, changed)
+
+    @dbus.service.signal(IFACE_WIMAX_NSP, signature='a{sv}')
+    def PropertiesChanged(self, changed):
+        pass
+
+###################################################################
+IFACE_WIMAX = 'org.freedesktop.NetworkManager.Device.WiMax'
+
+class NspNotFoundException(dbus.DBusException):
+    _dbus_error_name = IFACE_WIMAX + '.NspNotFound'
+
+PX_NSPS = "Nsps"
+PX_HW_ADDRESS = "HwAddress"
+PX_CENTER_FREQUENCY = "CenterFrequency"
+PX_RSSI = "Rssi"
+PX_CINR = "Cinr"
+PX_TX_POWER = "TxPower"
+PX_BSID = "Bsid"
+PX_ACTIVE_NSP = "ActiveNsp"
+
+class WimaxDevice(Device):
+    def __init__(self, bus, iface):
+        Device.__init__(self, bus, iface, NM_DEVICE_TYPE_WIMAX)
+        self.add_dbus_interface(IFACE_WIMAX, self.__get_props)
+
+        self.mac = random_mac()
+        self.bsid = random_mac()
+        self.nsps = []
+        self.active_nsp = None
+
+    # methods
+    @dbus.service.method(dbus_interface=IFACE_WIMAX, in_signature='', out_signature='ao')
+    def GetNspList(self):
+        # include all APs including hidden ones
+        return to_path_array(self.nsps)
+
+    @dbus.service.signal(IFACE_WIMAX, signature='o')
+    def NspAdded(self, nsp_path):
+        pass
+
+    def add_nsp(self, nsp):
+        self.nsps.append(nsp)
+        self.__notify(PX_NSPS)
+        self.NspAdded(to_path(nsp))
+
+    @dbus.service.signal(IFACE_WIMAX, signature='o')
+    def NspRemoved(self, nsp_path):
+        pass
+
+    def remove_nsp(self, nsp):
+        self.nsps.remove(nsp)
+        self.__notify(PX_NSPS)
+        self.NspRemoved(to_path(nsp))
+
+    # Properties interface
+    def __get_props(self):
+        props = {}
+        props[PX_HW_ADDRESS] = self.mac
+        props[PX_CENTER_FREQUENCY] = dbus.UInt32(2525)
+        props[PX_RSSI] = dbus.Int32(-48)
+        props[PX_CINR] = dbus.Int32(24)
+        props[PX_TX_POWER] = dbus.Int32(9)
+        props[PX_BSID] = self.bsid
+        props[PX_NSPS] = to_path_array(self.nsps)
+        props[PX_ACTIVE_NSP] = to_path(self.active_nsp)
+        return props
+
+    def __notify(self, propname):
+        props = self._get_dbus_properties(IFACE_WIMAX)
+        changed = { propname: props[propname] }
+        WimaxDevice.PropertiesChanged(self, changed)
+
+    @dbus.service.signal(IFACE_WIMAX, signature='a{sv}')
+    def PropertiesChanged(self, changed):
+        pass
+
+    # test functions
+    def add_test_nsp(self, name):
+        nsp = WimaxNsp(self._bus, name)
+        self.add_nsp(nsp)
+        return nsp.path
+
+    def remove_nsp_by_path(self, path):
+        for nsp in self.nsps:
+            if nsp.path == path:
+                self.remove_nsp(nsp)
+                return
+        raise NspNotFoundException("NSP %s not found" % path)
+
+###################################################################
+IFACE_TEST = 'org.freedesktop.NetworkManager.LibnmGlibTest'
+IFACE_NM = 'org.freedesktop.NetworkManager'
+
+class PermissionDeniedException(dbus.DBusException):
+    _dbus_error_name = IFACE_NM + '.PermissionDenied'
+
+class UnknownDeviceException(dbus.DBusException):
+    _dbus_error_name = IFACE_NM + '.UnknownDevice'
+
+PM_DEVICES = 'Devices'
+PM_NETWORKING_ENABLED = 'NetworkingEnabled'
+PM_WWAN_ENABLED = 'WwanEnabled'
+PM_WWAN_HARDWARE_ENABLED = 'WwanHardwareEnabled'
+PM_WIRELESS_ENABLED = 'WirelessEnabled'
+PM_WIRELESS_HARDWARE_ENABLED = 'WirelessHardwareEnabled'
+PM_WIMAX_ENABLED = 'WimaxEnabled'
+PM_WIMAX_HARDWARE_ENABLED = 'WimaxHardwareEnabled'
+PM_ACTIVE_CONNECTIONS = 'ActiveConnections'
+PM_PRIMARY_CONNECTION = 'PrimaryConnection'
+PM_ACTIVATING_CONNECTION = 'ActivatingConnection'
+PM_STARTUP = 'Startup'
+PM_STATE = 'State'
+PM_VERSION = 'Version'
+PM_CONNECTIVITY = 'Connectivity'
+
+class NetworkManager(ExportedObj):
+    def __init__(self, bus, object_path):
+        ExportedObj.__init__(self, bus, object_path)
+        self.add_dbus_interface(IFACE_NM, self.__get_props)
+
+        self.devices = []
+        self.active_connections = []
+        self.primary_connection = None
+        self.activating_connection = None
+        self.state = NM_STATE_DISCONNECTED
+        self.connectivity = 1
+
+    @dbus.service.signal(IFACE_NM, signature='u')
+    def StateChanged(self, new_state):
+        pass
+
+    def set_state(self, new_state):
+        self.state = new_state
+        self.__notify(PM_STATE)
+        self.StateChanged(dbus.UInt32(self.state))
+
+    @dbus.service.method(dbus_interface=IFACE_NM, in_signature='', out_signature='ao')
+    def GetDevices(self):
+        return self._get_dbus_properties(IFACE_NM)[PM_DEVICES]
+
+    @dbus.service.method(dbus_interface=IFACE_NM, in_signature='s', out_signature='o')
+    def GetDeviceByIpIface(self, ip_iface):
+        for d in self.devices:
+            # ignore iface/ip_iface distinction for now
+            if d.iface == ip_iface:
+                return d.path
+        raise UnknownDeviceException("No device found for the requested iface.")
+
+    @dbus.service.method(dbus_interface=IFACE_NM, in_signature='ooo', out_signature='o')
+    def ActivateConnection(self, conpath, devpath, specific_object):
+        device = None
+        for d in self.devices:
+            if d.path == devpath:
+                device = d
+                break
+        if not device:
+            raise UnknownDeviceException("No device found for the requested iface.")
+        raise PermissionDeniedException("Not yet implemented")
+
+    @dbus.service.method(dbus_interface=IFACE_NM, in_signature='a{sa{sv}}oo', out_signature='oo')
+    def AddAndActivateConnection(self, connection, devpath, specific_object):
+        device = None
+        for d in self.devices:
+            if d.path == devpath:
+                device = d
+                break
+        if not device:
+            raise UnknownDeviceException("No device found for the requested iface.")
+        raise PermissionDeniedException("Not yet implemented")
+
+    @dbus.service.method(dbus_interface=IFACE_NM, in_signature='o', out_signature='')
+    def DeactivateConnection(self, active_connection):
+        pass
+
+    @dbus.service.method(dbus_interface=IFACE_NM, in_signature='b', out_signature='')
+    def Sleep(self, do_sleep):
+        if do_sleep:
+            self.state = NM_STATE_ASLEEP
+        else:
+            self.state = NM_STATE_DISCONNECTED
+        self.__notify(PM_STATE)
+
+    @dbus.service.method(dbus_interface=IFACE_NM, in_signature='b', out_signature='')
+    def Enable(self, do_enable):
+        pass
+
+    @dbus.service.method(dbus_interface=IFACE_NM, in_signature='', out_signature='a{ss}')
+    def GetPermissions(self):
+        return { "org.freedesktop.NetworkManager.enable-disable-network":   "yes",
+                 "org.freedesktop.NetworkManager.sleep-wake":               "no",
+                 "org.freedesktop.NetworkManager.enable-disable-wifi":      "yes",
+                 "org.freedesktop.NetworkManager.enable-disable-wwan":      "yes",
+                 "org.freedesktop.NetworkManager.enable-disable-wimax":     "yes",
+                 "org.freedesktop.NetworkManager.network-control":          "yes",
+                 "org.freedesktop.NetworkManager.wifi.share.protected":     "yes",
+                 "org.freedesktop.NetworkManager.wifi.share.open":          "yes",
+                 "org.freedesktop.NetworkManager.settings.modify.own":      "yes",
+                 "org.freedesktop.NetworkManager.settings.modify.system":   "yes",
+                 "org.freedesktop.NetworkManager.settings.modify.hostname": "yes" }
+
+    @dbus.service.method(dbus_interface=IFACE_NM, in_signature='ss', out_signature='')
+    def SetLogging(self, level, domains):
+        pass
+
+    @dbus.service.method(dbus_interface=IFACE_NM, in_signature='', out_signature='ss')
+    def GetLogging(self):
+        return ("info", "HW,RFKILL,CORE,DEVICE,WIFI,ETHER")
+
+    @dbus.service.method(dbus_interface=IFACE_NM, in_signature='', out_signature='u')
+    def CheckConnectivity(self):
+        raise PermissionDeniedException("You fail")
+
+    @dbus.service.signal(IFACE_NM, signature='o')
+    def DeviceAdded(self, devpath):
+        pass
+
+    def add_device(self, device):
+        self.devices.append(device)
+        self.__notify(PM_DEVICES)
+        self.DeviceAdded(to_path(device))
+
+    @dbus.service.signal(IFACE_NM, signature='o')
+    def DeviceRemoved(self, devpath):
+        pass
+
+    def remove_device(self, device):
+        self.devices.remove(device)
+        self.__notify(PM_DEVICES)
+        self.DeviceRemoved(to_path(device))
+
+    ################# D-Bus Properties interface
+    def __get_props(self):
+        props = {}
+        props[PM_DEVICES] = to_path_array(self.devices)
+        props[PM_NETWORKING_ENABLED] = True
+        props[PM_WWAN_ENABLED] = True
+        props[PM_WWAN_HARDWARE_ENABLED] = True
+        props[PM_WIRELESS_ENABLED] = True
+        props[PM_WIRELESS_HARDWARE_ENABLED] = True
+        props[PM_WIMAX_ENABLED] = True
+        props[PM_WIMAX_HARDWARE_ENABLED] = True
+        props[PM_ACTIVE_CONNECTIONS] = to_path_array(self.active_connections)
+        props[PM_PRIMARY_CONNECTION] = to_path(self.primary_connection)
+        props[PM_ACTIVATING_CONNECTION] = to_path(self.activating_connection)
+        props[PM_STARTUP] = False
+        props[PM_STATE] = dbus.UInt32(self.state)
+        props[PM_VERSION] = "0.9.9.0"
+        props[PM_CONNECTIVITY] = dbus.UInt32(self.connectivity)
+        return props
+
+    def __notify(self, propname):
+        props = self._get_dbus_properties(IFACE_NM)
+        changed = { propname: props[propname] }
+        NetworkManager.PropertiesChanged(self, changed)
+
+    @dbus.service.signal(IFACE_NM, signature='a{sv}')
+    def PropertiesChanged(self, changed):
+        pass
+
+    ################# Testing methods
+    @dbus.service.method(IFACE_TEST, in_signature='', out_signature='')
+    def Quit(self):
+        mainloop.quit()
+
+    @dbus.service.method(IFACE_TEST, in_signature='s', out_signature='o')
+    def AddWiredDevice(self, ifname):
+        for d in self.devices:
+            if d.iface == ifname:
+                raise PermissionDeniedError("Device already added")
+        dev = WiredDevice(self._bus, ifname)
+        self.add_device(dev)
+        return dbus.ObjectPath(dev.path)
+
+    @dbus.service.method(IFACE_TEST, in_signature='s', out_signature='o')
+    def AddWifiDevice(self, ifname):
+        for d in self.devices:
+            if d.iface == ifname:
+                raise PermissionDeniedError("Device already added")
+        dev = WifiDevice(self._bus, ifname)
+        self.add_device(dev)
+        return dbus.ObjectPath(dev.path)
+
+    @dbus.service.method(IFACE_TEST, in_signature='s', out_signature='o')
+    def AddWimaxDevice(self, ifname):
+        for d in self.devices:
+            if d.iface == ifname:
+                raise PermissionDeniedError("Device already added")
+        dev = WimaxDevice(self._bus, ifname)
+        self.add_device(dev)
+        return dbus.ObjectPath(dev.path)
+
+    @dbus.service.method(IFACE_TEST, in_signature='o', out_signature='')
+    def RemoveDevice(self, path):
+        for d in self.devices:
+            if d.path == path:
+                self.remove_device(d)
+                return
+        raise UnknownDeviceException("Device not found")
+
+    @dbus.service.method(IFACE_TEST, in_signature='sss', out_signature='o')
+    def AddWifiAp(self, ifname, ssid, mac):
+        for d in self.devices:
+            if d.iface == ifname:
+                return dbus.ObjectPath(d.add_test_ap(ssid, mac))
+        raise UnknownDeviceException("Device not found")
+
+    @dbus.service.method(IFACE_TEST, in_signature='so', out_signature='')
+    def RemoveWifiAp(self, ifname, ap_path):
+        for d in self.devices:
+            if d.iface == ifname:
+                d.remove_ap_by_path(ap_path)
+                return
+        raise UnknownDeviceException("Device not found")
+
+    @dbus.service.method(IFACE_TEST, in_signature='ss', out_signature='o')
+    def AddWimaxNsp(self, ifname, name):
+        for d in self.devices:
+            if d.iface == ifname:
+                return dbus.ObjectPath(d.add_test_nsp(name))
+        raise UnknownDeviceException("Device not found")
+
+    @dbus.service.method(IFACE_TEST, in_signature='so', out_signature='')
+    def RemoveWimaxNsp(self, ifname, nsp_path):
+        for d in self.devices:
+            if d.iface == ifname:
+                d.remove_nsp_by_path(nsp_path)
+                return
+        raise UnknownDeviceException("Device not found")
+
+def quit_cb(user_data):
+    mainloop.quit()
+
+def main():
+    dbus.mainloop.glib.DBusGMainLoop(set_as_default=True)
+
+    random.seed()
+
+    bus = dbus.SessionBus()
+    nm = NetworkManager(bus, "/org/freedesktop/NetworkManager")
+    if not bus.request_name("org.freedesktop.NetworkManager"):
+        sys.exit(1)
+
+    # quit after inactivity to ensure we don't stick around if tests fail
+    quit_id = GLib.timeout_add_seconds(20, quit_cb, None)
+
+    try:
+        mainloop.run()
+    except Exception as e:
+        pass
+
+    sys.exit(0)
+
+if __name__ == '__main__':
+    main()
+
diff --git a/libnm-glib/tests/test-nm-client.c b/libnm-glib/tests/test-nm-client.c
new file mode 100644
index 00000000..b181c8fa
--- /dev/null
+++ b/libnm-glib/tests/test-nm-client.c
@@ -0,0 +1,953 @@
+/* -*- Mode: C; tab-width: 4; indent-tabs-mode: t; c-basic-offset: 4 -*- */
+/*
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2, or (at your option)
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Copyright (C) 2010 - 2014 Red Hat, Inc.
+ *
+ */
+
+#include <dbus/dbus.h>
+#include <dbus/dbus-glib.h>
+#include <dbus/dbus-glib-lowlevel.h>
+#include <glib.h>
+#include <string.h>
+#include <sys/types.h>
+#include <signal.h>
+
+#include <NetworkManager.h>
+#include "nm-client.h"
+#include "nm-device-wifi.h"
+#include "nm-device-ethernet.h"
+#include "nm-device-wimax.h"
+#include "nm-glib-compat.h"
+
+static const char *fake_path;
+static const char *fake_bin;
+static const char *fake_exec;
+static GMainLoop *loop = NULL;
+
+/*******************************************************************/
+
+typedef struct {
+	GDBusConnection *bus;
+	GDBusProxy *proxy;
+	GPid pid;
+	NMClient *client;
+} ServiceInfo;
+
+#define test_assert(condition) \
+do { \
+	if (!G_LIKELY (condition)) \
+		service_cleanup (); \
+	g_assert (condition); \
+} while (0)
+
+#define test_assert_cmpint(a, b, c) \
+do { \
+	if (!G_LIKELY (a b c)) \
+		service_cleanup (); \
+	g_assert_cmpint (a, b, c); \
+} while (0)
+
+#define test_assert_cmpstr(a, b, c) \
+do { \
+	if (!G_LIKELY (g_str_hash (a) b g_str_hash (c))) \
+		service_cleanup (); \
+	g_assert_cmpstr (a, b, c); \
+} while (0)
+
+#define test_assert_no_error(e) \
+do { \
+	if (G_UNLIKELY (e)) \
+		service_cleanup (); \
+	g_assert_no_error (e); \
+} while (0)
+
+static ServiceInfo * sinfo_static = NULL;
+
+static void
+service_cleanup (void)
+{
+	ServiceInfo *info = sinfo_static;
+
+	sinfo_static = NULL;
+
+	if (info) {
+		if (info->proxy)
+			g_object_unref (info->proxy);
+		if (info->bus)
+			g_object_unref (info->bus);
+		if (info->client)
+			g_object_unref (info->client);
+		if (info->pid)
+			kill (info->pid, SIGTERM);
+		memset (info, 0, sizeof (*info));
+		g_free (info);
+	} else
+		g_assert_not_reached ();
+}
+
+static gboolean
+name_exists (GDBusConnection *c, const char *name)
+{
+	GVariant *reply;
+	gboolean exists = FALSE;
+
+	reply = g_dbus_connection_call_sync (c,
+	                                     DBUS_SERVICE_DBUS,
+	                                     DBUS_PATH_DBUS,
+	                                     DBUS_INTERFACE_DBUS,
+	                                     "GetNameOwner",
+	                                     g_variant_new ("(s)", name),
+	                                     NULL,
+	                                     G_DBUS_CALL_FLAGS_NO_AUTO_START,
+	                                     -1,
+	                                     NULL,
+	                                     NULL);
+	if (reply != NULL) {
+		exists = TRUE;
+		g_variant_unref (reply);
+	}
+
+	return exists;
+}
+
+static ServiceInfo *
+service_init (void)
+{
+	ServiceInfo *sinfo;
+	const char *args[2] = { fake_exec, NULL };
+	GError *error = NULL;
+	int i = 100;
+
+	g_assert (!sinfo_static);
+
+	sinfo = g_malloc0 (sizeof (*sinfo));
+
+	sinfo_static = sinfo;
+
+	sinfo->bus = g_bus_get_sync (G_BUS_TYPE_SESSION, NULL,  NULL);
+	test_assert (sinfo->bus);
+
+	if (!g_spawn_async (fake_path, (char **) args, NULL, 0, NULL, NULL, &sinfo->pid, &error))
+		test_assert_no_error (error);
+
+	/* Wait until the service is registered on the bus */
+	while (i > 0) {
+		g_usleep (G_USEC_PER_SEC / 50);
+		if (name_exists (sinfo->bus, "org.freedesktop.NetworkManager"))
+			break;
+		i--;
+	}
+	test_assert (i > 0);
+
+	/* Grab a proxy to our fake NM service to trigger tests */
+	sinfo->proxy = g_dbus_proxy_new_sync (sinfo->bus,
+	                                      G_DBUS_PROXY_FLAGS_DO_NOT_LOAD_PROPERTIES |
+	                                        G_DBUS_PROXY_FLAGS_DO_NOT_CONNECT_SIGNALS |
+	                                        G_DBUS_PROXY_FLAGS_DO_NOT_AUTO_START,
+	                                      NULL,
+	                                      NM_DBUS_SERVICE,
+	                                      NM_DBUS_PATH,
+	                                      "org.freedesktop.NetworkManager.LibnmGlibTest",
+	                                      NULL, NULL);
+	test_assert (sinfo->proxy);
+
+	sinfo->client = nm_client_new ();
+	test_assert (sinfo->client != NULL);
+
+	return sinfo;
+}
+
+static ServiceInfo *
+service_get (void)
+{
+	g_assert (sinfo_static);
+	return sinfo_static;
+}
+
+#define _sinfo (service_get ())
+
+/*******************************************************************/
+
+static gboolean
+loop_quit (gpointer user_data)
+{
+	g_main_loop_quit ((GMainLoop *) user_data);
+	return G_SOURCE_REMOVE;
+}
+
+static gboolean
+add_device (const char *method, const char *ifname, char **out_path)
+{
+	GError *error = NULL;
+	GVariant *ret;
+
+	ret = g_dbus_proxy_call_sync (_sinfo->proxy,
+	                              method,
+	                              g_variant_new ("(s)", ifname),
+	                              G_DBUS_CALL_FLAGS_NO_AUTO_START,
+	                              3000,
+	                              NULL,
+	                              &error);
+	test_assert_no_error (error);
+	test_assert (ret);
+	test_assert_cmpstr (g_variant_get_type_string (ret), ==, "(o)");
+	if (out_path)
+		g_variant_get (ret, "(o)", out_path);
+	g_variant_unref (ret);
+	return TRUE;
+}
+
+/*******************************************************************/
+
+typedef struct {
+	GMainLoop *loop;
+	gboolean signaled;
+	gboolean notified;
+	guint quit_count;
+	guint quit_id;
+} DeviceAddedInfo;
+
+static void
+device_add_check_quit (DeviceAddedInfo *info)
+{
+	info->quit_count--;
+	if (info->quit_count == 0) {
+		g_source_remove (info->quit_id);
+		info->quit_id = 0;
+		g_main_loop_quit (info->loop);
+	}
+}
+
+static void
+device_added_cb (NMClient *c,
+                 NMDevice *device,
+                 DeviceAddedInfo *info)
+{
+	test_assert (device);
+	test_assert_cmpstr (nm_device_get_iface (device), ==, "eth0");
+	info->signaled = TRUE;
+	device_add_check_quit (info);
+}
+
+static void
+devices_notify_cb (NMClient *c,
+                   GParamSpec *pspec,
+                   DeviceAddedInfo *info)
+{
+	const GPtrArray *devices;
+	NMDevice *device;
+
+	devices = nm_client_get_devices (c);
+	test_assert (devices);
+	test_assert_cmpint (devices->len, ==, 1);
+
+	device = g_ptr_array_index (devices, 0);
+	test_assert (device);
+	test_assert_cmpstr (nm_device_get_iface (device), ==, "eth0");
+
+	info->notified = TRUE;
+
+	device_add_check_quit (info);
+}
+
+static void
+test_device_added (void)
+{
+	const GPtrArray *devices;
+	NMDevice *device;
+	DeviceAddedInfo info = { loop, FALSE, FALSE, 0, 0 };
+
+	service_init ();
+
+	/* Give NMClient a chance to initialize */
+	g_timeout_add_seconds (5, loop_quit, loop);
+	g_main_loop_run (loop);
+
+	devices = nm_client_get_devices (_sinfo->client);
+	test_assert (devices == NULL);
+
+	/* Tell the test service to add a new device */
+	add_device ("AddWiredDevice", "eth0", NULL);
+
+	g_signal_connect (_sinfo->client,
+	                  "device-added",
+	                  (GCallback) device_added_cb,
+	                  &info);
+	info.quit_count++;
+
+	g_signal_connect (_sinfo->client,
+	                  "notify::devices",
+	                  (GCallback) devices_notify_cb,
+	                  &info);
+	info.quit_count++;
+
+	/* Wait for libnm-glib to find the device */
+	info.quit_id = g_timeout_add_seconds (5, loop_quit, loop);
+	g_main_loop_run (loop);
+
+	test_assert (info.signaled);
+	test_assert (info.notified);
+
+	g_signal_handlers_disconnect_by_func (_sinfo->client, device_added_cb, &info);
+	g_signal_handlers_disconnect_by_func (_sinfo->client, devices_notify_cb, &info);
+
+	devices = nm_client_get_devices (_sinfo->client);
+	test_assert (devices);
+	test_assert_cmpint (devices->len, ==, 1);
+
+	device = g_ptr_array_index (devices, 0);
+	test_assert (device);
+	test_assert_cmpstr (nm_device_get_iface (device), ==, "eth0");
+
+	service_cleanup ();
+}
+
+/*******************************************************************/
+
+static const char *expected_bssid = "66:55:44:33:22:11";
+
+typedef struct {
+	GMainLoop *loop;
+	gboolean found;
+	char *ap_path;
+	gboolean signaled;
+	gboolean notified;
+	guint quit_id;
+	guint quit_count;
+} WifiApInfo;
+
+static void
+wifi_check_quit (WifiApInfo *info)
+{
+	info->quit_count--;
+	if (info->quit_count == 0) {
+		g_source_remove (info->quit_id);
+		info->quit_id = 0;
+		g_main_loop_quit (info->loop);
+	}
+}
+
+static void
+wifi_device_added_cb (NMClient *c,
+                      NMDevice *device,
+                      WifiApInfo *info)
+{
+	test_assert_cmpstr (nm_device_get_iface (device), ==, "wlan0");
+	info->found = TRUE;
+	wifi_check_quit (info);
+}
+
+static void
+got_ap_path (WifiApInfo *info, const char *path)
+{
+	if (info->ap_path)
+		test_assert_cmpstr (info->ap_path, ==, path);
+	else
+		info->ap_path = g_strdup (path);
+}
+
+static void
+wifi_ap_added_cb (NMDeviceWifi *w,
+                  NMAccessPoint *ap,
+                  WifiApInfo *info)
+{
+	test_assert (ap);
+	test_assert_cmpstr (nm_access_point_get_bssid (ap), ==, expected_bssid);
+	got_ap_path (info, nm_object_get_path (NM_OBJECT (ap)));
+
+	info->signaled = TRUE;
+	wifi_check_quit (info);
+}
+
+static void
+wifi_ap_add_notify_cb (NMDeviceWifi *w,
+                       GParamSpec *pspec,
+                       WifiApInfo *info)
+{
+	const GPtrArray *aps;
+	NMAccessPoint *ap;
+
+	aps = nm_device_wifi_get_access_points (w);
+	test_assert (aps);
+	test_assert_cmpint (aps->len, ==, 1);
+
+	ap = g_ptr_array_index (aps, 0);
+	test_assert (ap);
+	test_assert_cmpstr (nm_access_point_get_bssid (ap), ==, "66:55:44:33:22:11");
+	got_ap_path (info, nm_object_get_path (NM_OBJECT (ap)));
+
+	info->notified = TRUE;
+	wifi_check_quit (info);
+}
+
+static void
+wifi_ap_removed_cb (NMDeviceWifi *w,
+                    NMAccessPoint *ap,
+                    WifiApInfo *info)
+{
+	test_assert (ap);
+	test_assert_cmpstr (info->ap_path, ==, nm_object_get_path (NM_OBJECT (ap)));
+
+	info->signaled = TRUE;
+	wifi_check_quit (info);
+}
+
+static void
+wifi_ap_remove_notify_cb (NMDeviceWifi *w,
+                          GParamSpec *pspec,
+                          WifiApInfo *info)
+{
+	const GPtrArray *aps;
+
+	aps = nm_device_wifi_get_access_points (w);
+	test_assert (aps == NULL);
+
+	info->notified = TRUE;
+	wifi_check_quit (info);
+}
+
+static void
+test_wifi_ap_added_removed (void)
+{
+	NMDeviceWifi *wifi;
+	WifiApInfo info = { loop, FALSE, FALSE, 0, 0 };
+	GVariant *ret;
+	GError *error = NULL;
+	char *expected_path = NULL;
+
+	service_init ();
+
+	/* Give NMClient a chance to initialize */
+	g_timeout_add_seconds (5, loop_quit, loop);
+	g_main_loop_run (loop);
+
+	/*************************************/
+	/* Add the wifi device */
+	add_device ("AddWifiDevice", "wlan0", NULL);
+
+	g_signal_connect (_sinfo->client,
+	                  "device-added",
+	                  (GCallback) wifi_device_added_cb,
+	                  &info);
+	info.quit_count = 1;
+
+	/* Wait for libnm-glib to find the device */
+	info.quit_id = g_timeout_add_seconds (5, loop_quit, loop);
+	g_main_loop_run (loop);
+
+	test_assert (info.found);
+	g_signal_handlers_disconnect_by_func (_sinfo->client, wifi_device_added_cb, &info);
+
+	wifi = (NMDeviceWifi *) nm_client_get_device_by_iface (_sinfo->client, "wlan0");
+	test_assert (NM_IS_DEVICE_WIFI (wifi));
+
+	/*************************************/
+	/* Add the wifi device */
+	info.signaled =  FALSE;
+	info.notified = FALSE;
+	info.quit_id = 0;
+
+	ret = g_dbus_proxy_call_sync (_sinfo->proxy,
+	                              "AddWifiAp",
+	                              g_variant_new ("(sss)", "wlan0", "test-ap", expected_bssid),
+	                              G_DBUS_CALL_FLAGS_NO_AUTO_START,
+	                              3000,
+	                              NULL,
+	                              &error);
+	test_assert_no_error (error);
+	test_assert (ret);
+	test_assert_cmpstr (g_variant_get_type_string (ret), ==, "(o)");
+	g_variant_get (ret, "(o)", &expected_path);
+	g_variant_unref (ret);
+
+	g_signal_connect (wifi,
+	                  "access-point-added",
+	                  (GCallback) wifi_ap_added_cb,
+	                  &info);
+	info.quit_count = 1;
+
+	g_signal_connect (wifi,
+	                  "notify::access-points",
+	                  (GCallback) wifi_ap_add_notify_cb,
+	                  &info);
+	info.quit_count++;
+
+	/* Wait for libnm-glib to find the AP */
+	info.quit_id = g_timeout_add_seconds (5, loop_quit, loop);
+	g_main_loop_run (loop);
+
+	test_assert (info.signaled);
+	test_assert (info.notified);
+	test_assert (info.ap_path);
+	test_assert_cmpstr (info.ap_path, ==, expected_path);
+	g_signal_handlers_disconnect_by_func (wifi, wifi_ap_added_cb, &info);
+	g_signal_handlers_disconnect_by_func (wifi, wifi_ap_add_notify_cb, &info);
+
+	/*************************************/
+	/* Remove the wifi device */
+	info.signaled =  FALSE;
+	info.notified = FALSE;
+	info.quit_id = 0;
+
+	ret = g_dbus_proxy_call_sync (_sinfo->proxy,
+	                              "RemoveWifiAp",
+	                              g_variant_new ("(so)", "wlan0", expected_path),
+	                              G_DBUS_CALL_FLAGS_NO_AUTO_START,
+	                              3000,
+	                              NULL,
+	                              &error);
+	test_assert_no_error (error);
+	g_clear_pointer (&ret, g_variant_unref);
+
+	g_signal_connect (wifi,
+	                  "access-point-removed",
+	                  (GCallback) wifi_ap_removed_cb,
+	                  &info);
+	info.quit_count = 1;
+
+	g_signal_connect (wifi,
+	                  "notify::access-points",
+	                  (GCallback) wifi_ap_remove_notify_cb,
+	                  &info);
+	info.quit_count++;
+
+	/* Wait for libnm-glib to find the AP */
+	info.quit_id = g_timeout_add_seconds (5, loop_quit, loop);
+	g_main_loop_run (loop);
+
+	test_assert (info.signaled);
+	test_assert (info.notified);
+	g_signal_handlers_disconnect_by_func (wifi, wifi_ap_removed_cb, &info);
+	g_signal_handlers_disconnect_by_func (wifi, wifi_ap_remove_notify_cb, &info);
+
+	g_free (info.ap_path);
+	g_free (expected_path);
+	service_cleanup ();
+}
+
+/*******************************************************************/
+
+static const char *expected_nsp_name = "Clear";
+
+typedef struct {
+	GMainLoop *loop;
+	gboolean found;
+	char *nsp_path;
+	gboolean signaled;
+	gboolean notified;
+	guint quit_id;
+	guint quit_count;
+} WimaxNspInfo;
+
+static void
+wimax_check_quit (WimaxNspInfo *info)
+{
+	info->quit_count--;
+	if (info->quit_count == 0) {
+		g_source_remove (info->quit_id);
+		info->quit_id = 0;
+		g_main_loop_quit (info->loop);
+	}
+}
+
+static void
+wimax_device_added_cb (NMClient *c,
+                       NMDevice *device,
+                       WimaxNspInfo *info)
+{
+	test_assert_cmpstr (nm_device_get_iface (device), ==, "wmx0");
+	info->found = TRUE;
+	wimax_check_quit (info);
+}
+
+static void
+got_nsp_path (WimaxNspInfo *info, const char *path)
+{
+	if (info->nsp_path)
+		test_assert_cmpstr (info->nsp_path, ==, path);
+	else
+		info->nsp_path = g_strdup (path);
+}
+
+static void
+wimax_nsp_added_cb (NMDeviceWimax *w,
+                    NMWimaxNsp *nsp,
+                    WimaxNspInfo *info)
+{
+	test_assert (nsp);
+	test_assert_cmpstr (nm_wimax_nsp_get_name (nsp), ==, expected_nsp_name);
+	got_nsp_path (info, nm_object_get_path (NM_OBJECT (nsp)));
+
+	info->signaled = TRUE;
+	wimax_check_quit (info);
+}
+
+static void
+wimax_nsp_add_notify_cb (NMDeviceWimax *w,
+                         GParamSpec *pspec,
+                         WimaxNspInfo *info)
+{
+	const GPtrArray *nsps;
+	NMWimaxNsp *nsp;
+
+	nsps = nm_device_wimax_get_nsps (w);
+	test_assert (nsps);
+	test_assert_cmpint (nsps->len, ==, 1);
+
+	nsp = g_ptr_array_index (nsps, 0);
+	test_assert (nsp);
+	test_assert_cmpstr (nm_wimax_nsp_get_name (nsp), ==, expected_nsp_name);
+	got_nsp_path (info, nm_object_get_path (NM_OBJECT (nsp)));
+
+	info->notified = TRUE;
+	wimax_check_quit (info);
+}
+
+static void
+wimax_nsp_removed_cb (NMDeviceWimax *w,
+                      NMWimaxNsp *nsp,
+                      WimaxNspInfo *info)
+{
+	test_assert (nsp);
+	test_assert_cmpstr (info->nsp_path, ==, nm_object_get_path (NM_OBJECT (nsp)));
+
+	info->signaled = TRUE;
+	wimax_check_quit (info);
+}
+
+static void
+wimax_nsp_remove_notify_cb (NMDeviceWimax *w,
+                            GParamSpec *pspec,
+                            WimaxNspInfo *info)
+{
+	const GPtrArray *nsps;
+
+	nsps = nm_device_wimax_get_nsps (w);
+	test_assert (nsps == NULL);
+
+	info->notified = TRUE;
+	wimax_check_quit (info);
+}
+
+static void
+test_wimax_nsp_added_removed (void)
+{
+	NMDeviceWimax *wimax;
+	WimaxNspInfo info = { loop, FALSE, FALSE, 0, 0 };
+	GVariant *ret;
+	GError *error = NULL;
+	char *expected_path = NULL;
+
+	service_init ();
+
+	/* Give NMClient a chance to initialize */
+	g_timeout_add_seconds (5, loop_quit, loop);
+	g_main_loop_run (loop);
+
+	/*************************************/
+	/* Add the wimax device */
+	add_device ("AddWimaxDevice", "wmx0", NULL);
+
+	g_signal_connect (_sinfo->client,
+	                  "device-added",
+	                  (GCallback) wimax_device_added_cb,
+	                  &info);
+	info.quit_count = 1;
+
+	/* Wait for libnm-glib to find the device */
+	info.quit_id = g_timeout_add_seconds (5, loop_quit, loop);
+	g_main_loop_run (loop);
+
+	test_assert (info.found);
+	g_signal_handlers_disconnect_by_func (_sinfo->client, wimax_device_added_cb, &info);
+
+	wimax = (NMDeviceWimax *) nm_client_get_device_by_iface (_sinfo->client, "wmx0");
+	test_assert (NM_IS_DEVICE_WIMAX (wimax));
+
+	/*************************************/
+	/* Add the wimax NSP */
+	info.signaled =  FALSE;
+	info.notified = FALSE;
+	info.quit_id = 0;
+
+	ret = g_dbus_proxy_call_sync (_sinfo->proxy,
+	                              "AddWimaxNsp",
+	                              g_variant_new ("(ss)", "wmx0", expected_nsp_name),
+	                              G_DBUS_CALL_FLAGS_NO_AUTO_START,
+	                              3000,
+	                              NULL,
+	                              &error);
+	test_assert_no_error (error);
+	test_assert (ret);
+	test_assert_cmpstr (g_variant_get_type_string (ret), ==, "(o)");
+	g_variant_get (ret, "(o)", &expected_path);
+	g_variant_unref (ret);
+
+	g_signal_connect (wimax,
+	                  "nsp-added",
+	                  (GCallback) wimax_nsp_added_cb,
+	                  &info);
+	info.quit_count = 1;
+
+	g_signal_connect (wimax,
+	                  "notify::nsps",
+	                  (GCallback) wimax_nsp_add_notify_cb,
+	                  &info);
+	info.quit_count++;
+
+	/* Wait for libnm-glib to find the AP */
+	info.quit_id = g_timeout_add_seconds (5, loop_quit, loop);
+	g_main_loop_run (loop);
+
+	test_assert (info.signaled);
+	test_assert (info.notified);
+	test_assert (info.nsp_path);
+	test_assert_cmpstr (info.nsp_path, ==, expected_path);
+	g_signal_handlers_disconnect_by_func (wimax, wimax_nsp_added_cb, &info);
+	g_signal_handlers_disconnect_by_func (wimax, wimax_nsp_add_notify_cb, &info);
+
+	/*************************************/
+	/* Remove the wimax NSP */
+	info.signaled =  FALSE;
+	info.notified = FALSE;
+	info.quit_id = 0;
+
+	ret = g_dbus_proxy_call_sync (_sinfo->proxy,
+	                              "RemoveWimaxNsp",
+	                              g_variant_new ("(so)", "wmx0", expected_path),
+	                              G_DBUS_CALL_FLAGS_NO_AUTO_START,
+	                              3000,
+	                              NULL,
+	                              &error);
+	test_assert_no_error (error);
+	g_clear_pointer (&ret, g_variant_unref);
+
+	g_signal_connect (wimax,
+	                  "nsp-removed",
+	                  (GCallback) wimax_nsp_removed_cb,
+	                  &info);
+	info.quit_count = 1;
+
+	g_signal_connect (wimax,
+	                  "notify::nsps",
+	                  (GCallback) wimax_nsp_remove_notify_cb,
+	                  &info);
+	info.quit_count++;
+
+	/* Wait for libnm-glib to find the AP */
+	info.quit_id = g_timeout_add_seconds (5, loop_quit, loop);
+	g_main_loop_run (loop);
+
+	test_assert (info.signaled);
+	test_assert (info.notified);
+	g_signal_handlers_disconnect_by_func (wimax, wimax_nsp_removed_cb, &info);
+	g_signal_handlers_disconnect_by_func (wimax, wimax_nsp_remove_notify_cb, &info);
+
+	g_free (info.nsp_path);
+	g_free (expected_path);
+	service_cleanup ();
+}
+
+/*******************************************************************/
+
+typedef struct {
+	GMainLoop *loop;
+	gboolean signaled;
+	gboolean notified;
+	guint quit_count;
+	guint quit_id;
+} DaInfo;
+
+static void
+da_check_quit (DaInfo *info)
+{
+	info->quit_count--;
+	if (info->quit_count == 0) {
+		g_source_remove (info->quit_id);
+		info->quit_id = 0;
+		g_main_loop_quit (info->loop);
+	}
+}
+
+static void
+da_device_added_cb (NMClient *c,
+                    NMDevice *device,
+                    DaInfo *info)
+{
+	da_check_quit (info);
+}
+
+static void
+da_device_removed_cb (NMClient *c,
+                      NMDevice *device,
+                      DaInfo *info)
+{
+	test_assert_cmpstr (nm_device_get_iface (device), ==, "eth0");
+	info->signaled = TRUE;
+	da_check_quit (info);
+}
+
+static void
+da_devices_notify_cb (NMClient *c,
+                      GParamSpec *pspec,
+                      DaInfo *info)
+{
+	const GPtrArray *devices;
+	NMDevice *device;
+	guint i;
+	const char *iface;
+
+	devices = nm_client_get_devices (c);
+	test_assert (devices);
+	test_assert_cmpint (devices->len, ==, 2);
+
+	for (i = 0; i < devices->len; i++) {
+		device = g_ptr_array_index (devices, i);
+		iface = nm_device_get_iface (device);
+
+		test_assert (!strcmp (iface, "wlan0") || !strcmp (iface, "eth1"));
+	}
+
+	info->notified = TRUE;
+	da_check_quit (info);
+}
+
+static void
+test_devices_array (void)
+{
+	DaInfo info = { loop };
+	char *paths[3] = { NULL, NULL, NULL };
+	NMDevice *device;
+	const GPtrArray *devices;
+	GError *error = NULL;
+	GVariant *ret;
+
+	service_init ();
+
+	/* Give NMClient a chance to initialize */
+	g_timeout_add_seconds (5, loop_quit, loop);
+	g_main_loop_run (loop);
+
+	/*************************************/
+	/* Add some devices */
+	add_device ("AddWifiDevice", "wlan0", &paths[0]);
+	add_device ("AddWiredDevice", "eth0", &paths[1]);
+	add_device ("AddWiredDevice", "eth1", &paths[2]);
+	info.quit_count = 3;
+
+	g_signal_connect (_sinfo->client,
+	                  "device-added",
+	                  (GCallback) da_device_added_cb,
+	                  &info);
+
+	/* Wait for libnm-glib to find the device */
+	info.quit_id = g_timeout_add_seconds (5, loop_quit, loop);
+	g_main_loop_run (loop);
+
+	test_assert_cmpint (info.quit_count, ==, 0);
+	g_signal_handlers_disconnect_by_func (_sinfo->client, da_device_added_cb, &info);
+
+	/* Ensure the devices now exist */
+	devices = nm_client_get_devices (_sinfo->client);
+	test_assert (devices);
+	test_assert_cmpint (devices->len, ==, 3);
+
+	device = nm_client_get_device_by_iface (_sinfo->client, "wlan0");
+	test_assert (NM_IS_DEVICE_WIFI (device));
+
+	device = nm_client_get_device_by_iface (_sinfo->client, "eth0");
+	test_assert (NM_IS_DEVICE_ETHERNET (device));
+
+	device = nm_client_get_device_by_iface (_sinfo->client, "eth1");
+	test_assert (NM_IS_DEVICE_ETHERNET (device));
+
+	/********************************/
+	/* Now remove the device in the middle */
+	ret = g_dbus_proxy_call_sync (_sinfo->proxy,
+	                              "RemoveDevice",
+	                              g_variant_new ("(o)", paths[1]),
+	                              G_DBUS_CALL_FLAGS_NO_AUTO_START,
+	                              3000,
+	                              NULL,
+	                              &error);
+	test_assert_no_error (error);
+	test_assert (ret);
+	g_variant_unref (ret);
+
+	g_signal_connect (_sinfo->client,
+	                  "device-removed",
+	                  (GCallback) da_device_removed_cb,
+	                  &info);
+
+	g_signal_connect (_sinfo->client,
+	                  "notify::devices",
+	                  (GCallback) da_devices_notify_cb,
+	                  &info);
+	info.quit_count = 2;
+
+	/* Wait for libnm-glib to find the device */
+	info.quit_id = g_timeout_add_seconds (5, loop_quit, loop);
+	g_main_loop_run (loop);
+
+	test_assert_cmpint (info.quit_count, ==, 0);
+	g_signal_handlers_disconnect_by_func (_sinfo->client, da_device_removed_cb, &info);
+	g_signal_handlers_disconnect_by_func (_sinfo->client, da_devices_notify_cb, &info);
+
+	/* Ensure only two are left */
+	devices = nm_client_get_devices (_sinfo->client);
+	test_assert (devices);
+	test_assert_cmpint (devices->len, ==, 2);
+
+	device = nm_client_get_device_by_iface (_sinfo->client, "wlan0");
+	test_assert (NM_IS_DEVICE_WIFI (device));
+
+	device = nm_client_get_device_by_iface (_sinfo->client, "eth1");
+	test_assert (NM_IS_DEVICE_ETHERNET (device));
+
+	g_free (paths[0]);
+	g_free (paths[1]);
+	g_free (paths[2]);
+	service_cleanup ();
+}
+
+/*******************************************************************/
+
+int
+main (int argc, char **argv)
+{
+	g_assert (argc == 3);
+
+#if !GLIB_CHECK_VERSION (2, 35, 0)
+	g_type_init ();
+#endif
+
+	g_test_init (&argc, &argv, NULL);
+
+	fake_path = argv[1];
+	fake_bin = argv[2];
+	fake_exec = g_strdup_printf ("%s/%s", argv[1], argv[2]);
+
+	loop = g_main_loop_new (NULL, FALSE);
+
+	g_test_add_func ("/libnm-glib/device-added", test_device_added);
+	g_test_add_func ("/libnm-glib/wifi-ap-added-removed", test_wifi_ap_added_removed);
+	g_test_add_func ("/libnm-glib/wimax-nsp-added-removed", test_wimax_nsp_added_removed);
+	g_test_add_func ("/libnm-glib/devices-array", test_devices_array);
+
+	return g_test_run ();
+}
+
diff --git a/libnm-glib/tests/test-remote-settings-client.c b/libnm-glib/tests/test-remote-settings-client.c
index ad62075d..e3ef7f22 100644
--- a/libnm-glib/tests/test-remote-settings-client.c
+++ b/libnm-glib/tests/test-remote-settings-client.c
@@ -342,17 +342,9 @@ test_remove_connection (void)
 
 /*******************************************************************/
 
-#if GLIB_CHECK_VERSION(2,25,12)
-typedef GTestFixtureFunc TCFunc;
-#else
-typedef void (*TCFunc)(void);
-#endif
-
-#define TESTCASE(t, d) g_test_create_case (#t, 0, d, NULL, (TCFunc) t, NULL)
-
-int main (int argc, char **argv)
+int
+main (int argc, char **argv)
 {
-	GTestSuite *suite;
     char *service_argv[3] = { NULL, NULL, NULL };
 	int ret;
 	GError *error = NULL;
@@ -360,7 +352,9 @@ int main (int argc, char **argv)
 
 	g_assert (argc == 3);
 
+#if !GLIB_CHECK_VERSION (2, 35, 0)
 	g_type_init ();
+#endif
 	
 	g_test_init (&argc, &argv, NULL);
 
@@ -390,12 +384,10 @@ int main (int argc, char **argv)
 	settings = nm_remote_settings_new (bus);
 	test_assert (settings != NULL);
 
-	suite = g_test_get_root ();
-
-	g_test_suite_add (suite, TESTCASE (test_add_connection, NULL));
-	g_test_suite_add (suite, TESTCASE (test_make_invisible, NULL));
-	g_test_suite_add (suite, TESTCASE (test_make_visible, NULL));
-	g_test_suite_add (suite, TESTCASE (test_remove_connection, NULL));
+	g_test_add_func ("/remote_settings/add_connection", test_add_connection);
+	g_test_add_func ("/remote_settings/make_invisible", test_make_invisible);
+	g_test_add_func ("/remote_settings/make_visible", test_make_visible);
+	g_test_add_func ("/remote_settings/remove_connection", test_remove_connection);
 
 	ret = g_test_run ();
 
diff --git a/libnm-glib/tests/test-remote-settings-service.py b/libnm-glib/tests/test-remote-settings-service.py
index 86542005..439073ad 100755
--- a/libnm-glib/tests/test-remote-settings-service.py
+++ b/libnm-glib/tests/test-remote-settings-service.py
@@ -1,8 +1,9 @@
 #!/usr/bin/env python
 # -*- Mode: python; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*-
 
-import glib
-import gobject
+from __future__ import print_function
+
+from gi.repository import GLib, GObject
 import sys
 import dbus
 import dbus.service
@@ -21,7 +22,7 @@ class UnknownPropertyException(dbus.DBusException):
 class PermissionDeniedException(dbus.DBusException):
     _dbus_error_name = IFACE_SETTINGS + '.PermissionDenied'
 
-mainloop = gobject.MainLoop()
+mainloop = GObject.MainLoop()
 
 class Connection(dbus.service.Object):
     def __init__(self, bus, object_path, settings, remove_func):
@@ -30,7 +31,25 @@ class Connection(dbus.service.Object):
         self.settings = settings
         self.remove_func = remove_func
         self.visible = True
+        self.props = {}
+        self.props['Unsaved'] = False
+
+    # Properties interface
+    @dbus.service.method(dbus_interface=dbus.PROPERTIES_IFACE, in_signature='s', out_signature='a{sv}')
+    def GetAll(self, iface):
+        if iface != IFACE_CONNECTION:
+            raise UnknownInterfaceException()
+        return self.props
+
+    @dbus.service.method(dbus_interface=dbus.PROPERTIES_IFACE, in_signature='ss', out_signature='v')
+    def Get(self, iface, name):
+        if iface != IFACE_CONNECTION:
+            raise UnknownInterfaceException()
+        if not name in self.props.keys():
+            raise UnknownPropertyException()
+        return self.props[name]
 
+    # Connection methods
     @dbus.service.method(dbus_interface=IFACE_CONNECTION, in_signature='', out_signature='a{sa{sv}}')
     def GetSettings(self):
         if not self.visible:
@@ -72,10 +91,10 @@ class Settings(dbus.service.Object):
 
     @dbus.service.method(dbus_interface=IFACE_SETTINGS, in_signature='a{sa{sv}}', out_signature='o')
     def AddConnection(self, settings):
-        path = "/org/freedesktop/NetworkManager/Settings/Connection/%d" % self.counter
+        path = "/org/freedesktop/NetworkManager/Settings/Connection/{0}".format(self.counter)
         self.counter = self.counter + 1
         self.connections[path] = Connection(self.bus, path, settings, self.delete_connection)
-        print "Added connection %s" % path
+        print("Added connection {0}".format(path))
         return path
 
     def delete_connection(self, connection):
@@ -114,16 +133,16 @@ def main():
     if not bus.request_name("org.freedesktop.NetworkManager"):
         sys.exit(1)
 
-    print "Service started"
+    print("Service started")
 
-    gobject.timeout_add_seconds(20, quit_cb, None)
+    GLib.timeout_add_seconds(20, quit_cb, None)
 
     try:
         mainloop.run()
-    except Exception, e:
+    except Exception as e:
         pass
 
-    print "Service stopped"
+    print("Service stopped")
     sys.exit(0)
 
 if __name__ == '__main__':