about summary refs log tree commit diff
path: root/src/settings/plugins/keyfile
diff options
context:
space:
mode:
Diffstat (limited to 'src/settings/plugins/keyfile')
-rw-r--r--src/settings/plugins/keyfile/Makefile.am13
-rw-r--r--src/settings/plugins/keyfile/Makefile.in88
-rw-r--r--src/settings/plugins/keyfile/common.h2
-rw-r--r--src/settings/plugins/keyfile/nm-keyfile-connection.c15
-rw-r--r--src/settings/plugins/keyfile/nm-keyfile-connection.h3
-rw-r--r--src/settings/plugins/keyfile/plugin.c6
-rw-r--r--src/settings/plugins/keyfile/reader.c770
-rw-r--r--src/settings/plugins/keyfile/tests/Makefile.am5
-rw-r--r--src/settings/plugins/keyfile/tests/Makefile.in146
-rw-r--r--src/settings/plugins/keyfile/tests/keyfiles/Makefile.am4
-rw-r--r--src/settings/plugins/keyfile/tests/keyfiles/Makefile.in61
-rw-r--r--src/settings/plugins/keyfile/tests/keyfiles/Test_Bridge_Component15
-rw-r--r--src/settings/plugins/keyfile/tests/keyfiles/Test_Bridge_Main17
-rw-r--r--src/settings/plugins/keyfile/tests/keyfiles/Test_Wired_Connection8
-rw-r--r--src/settings/plugins/keyfile/tests/test-keyfile.c584
-rw-r--r--src/settings/plugins/keyfile/writer.c71
16 files changed, 920 insertions, 888 deletions
diff --git a/src/settings/plugins/keyfile/Makefile.am b/src/settings/plugins/keyfile/Makefile.am
index 83031c24..a9fbb663 100644
--- a/src/settings/plugins/keyfile/Makefile.am
+++ b/src/settings/plugins/keyfile/Makefile.am
@@ -1,4 +1,4 @@
-SUBDIRS=. tests
+SUBDIRS = . tests
 
 INCLUDES = \
 	-I$(top_srcdir)/src/settings \
@@ -26,8 +26,7 @@ libkeyfile_io_la_SOURCES = \
 libkeyfile_io_la_CPPFLAGS = \
 	$(GLIB_CFLAGS) \
 	$(DBUS_CFLAGS) \
-	-DSYSCONFDIR=\"$(sysconfdir)\" \
-	-DG_DISABLE_DEPRECATED
+	-DNMCONFDIR=\"$(nmconfdir)\"
 
 libkeyfile_io_la_LIBADD = $(GLIB_LIBS)
 
@@ -41,18 +40,14 @@ libnm_settings_plugin_keyfile_la_SOURCES = \
 
 libnm_settings_plugin_keyfile_la_CPPFLAGS = \
 	$(GLIB_CFLAGS) \
-	$(GMODULE_CFLAGS) \
 	$(DBUS_CFLAGS) \
-	-DSYSCONFDIR=\"$(sysconfdir)\" \
-	-DG_DISABLE_DEPRECATED
+	-DNMCONFDIR=\"$(nmconfdir)\"
 
 libnm_settings_plugin_keyfile_la_LIBADD = \
 	$(top_builddir)/libnm-util/libnm-util.la \
 	libkeyfile-io.la \
 	$(GLIB_LIBS) \
-	$(GMODULE_LIBS) \
-	$(DBUS_LIBS) \
-	$(GIO_LIBS)
+	$(DBUS_LIBS)
 
 libnm_settings_plugin_keyfile_la_LDFLAGS = -rdynamic
 
diff --git a/src/settings/plugins/keyfile/Makefile.in b/src/settings/plugins/keyfile/Makefile.in
index 6e70908d..071838b1 100644
--- a/src/settings/plugins/keyfile/Makefile.in
+++ b/src/settings/plugins/keyfile/Makefile.in
@@ -55,16 +55,18 @@ subdir = src/settings/plugins/keyfile
 DIST_COMMON = $(srcdir)/Makefile.am $(srcdir)/Makefile.in
 ACLOCAL_M4 = $(top_srcdir)/aclocal.m4
 am__aclocal_m4_deps = $(top_srcdir)/m4/compiler_warnings.m4 \
-	$(top_srcdir)/m4/gettext.m4 $(top_srcdir)/m4/gtk-doc.m4 \
-	$(top_srcdir)/m4/iconv.m4 $(top_srcdir)/m4/intlmacosx.m4 \
-	$(top_srcdir)/m4/intltool.m4 $(top_srcdir)/m4/introspection.m4 \
-	$(top_srcdir)/m4/lib-ld.m4 $(top_srcdir)/m4/lib-link.m4 \
-	$(top_srcdir)/m4/lib-prefix.m4 $(top_srcdir)/m4/libnl-check.m4 \
-	$(top_srcdir)/m4/libtool.m4 $(top_srcdir)/m4/ltoptions.m4 \
-	$(top_srcdir)/m4/ltsugar.m4 $(top_srcdir)/m4/ltversion.m4 \
-	$(top_srcdir)/m4/lt~obsolete.m4 $(top_srcdir)/m4/nls.m4 \
-	$(top_srcdir)/m4/po.m4 $(top_srcdir)/m4/progtest.m4 \
-	$(top_srcdir)/m4/vapigen.m4 $(top_srcdir)/configure.ac
+	$(top_srcdir)/m4/gettext.m4 \
+	$(top_srcdir)/m4/gnome-code-coverage.m4 \
+	$(top_srcdir)/m4/gtk-doc.m4 $(top_srcdir)/m4/iconv.m4 \
+	$(top_srcdir)/m4/intlmacosx.m4 $(top_srcdir)/m4/intltool.m4 \
+	$(top_srcdir)/m4/introspection.m4 $(top_srcdir)/m4/lib-ld.m4 \
+	$(top_srcdir)/m4/lib-link.m4 $(top_srcdir)/m4/lib-prefix.m4 \
+	$(top_srcdir)/m4/libnl-check.m4 $(top_srcdir)/m4/libtool.m4 \
+	$(top_srcdir)/m4/ltoptions.m4 $(top_srcdir)/m4/ltsugar.m4 \
+	$(top_srcdir)/m4/ltversion.m4 $(top_srcdir)/m4/lt~obsolete.m4 \
+	$(top_srcdir)/m4/nls.m4 $(top_srcdir)/m4/po.m4 \
+	$(top_srcdir)/m4/progtest.m4 $(top_srcdir)/m4/vapigen.m4 \
+	$(top_srcdir)/configure.ac
 am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \
 	$(ACLOCAL_M4)
 mkinstalldirs = $(install_sh) -d
@@ -83,7 +85,6 @@ am__v_lt_ = $(am__v_lt_@AM_DEFAULT_V@)
 am__v_lt_0 = --silent
 libnm_settings_plugin_keyfile_la_DEPENDENCIES =  \
 	$(top_builddir)/libnm-util/libnm-util.la libkeyfile-io.la \
-	$(am__DEPENDENCIES_1) $(am__DEPENDENCIES_1) \
 	$(am__DEPENDENCIES_1) $(am__DEPENDENCIES_1)
 am_libnm_settings_plugin_keyfile_la_OBJECTS =  \
 	libnm_settings_plugin_keyfile_la-nm-keyfile-connection.lo \
@@ -182,6 +183,10 @@ AWK = @AWK@
 CC = @CC@
 CCDEPMODE = @CCDEPMODE@
 CFLAGS = @CFLAGS@
+CKDB_PATH = @CKDB_PATH@
+CODE_COVERAGE_CFLAGS = @CODE_COVERAGE_CFLAGS@
+CODE_COVERAGE_ENABLED = @CODE_COVERAGE_ENABLED@
+CODE_COVERAGE_LDFLAGS = @CODE_COVERAGE_LDFLAGS@
 CPP = @CPP@
 CPPFLAGS = @CPPFLAGS@
 CXX = @CXX@
@@ -196,9 +201,7 @@ DBUS_SYS_DIR = @DBUS_SYS_DIR@
 DEFS = @DEFS@
 DEPDIR = @DEPDIR@
 DHCLIENT_PATH = @DHCLIENT_PATH@
-DHCLIENT_VERSION = @DHCLIENT_VERSION@
 DHCPCD_PATH = @DHCPCD_PATH@
-DISABLE_DEPRECATED = @DISABLE_DEPRECATED@
 DLLTOOL = @DLLTOOL@
 DSYMUTIL = @DSYMUTIL@
 DUMPBIN = @DUMPBIN@
@@ -208,17 +211,14 @@ ECHO_T = @ECHO_T@
 EGREP = @EGREP@
 EXEEXT = @EXEEXT@
 FGREP = @FGREP@
+GENHTML = @GENHTML@
 GETTEXT_MACRO_VERSION = @GETTEXT_MACRO_VERSION@
 GETTEXT_PACKAGE = @GETTEXT_PACKAGE@
-GIO_CFLAGS = @GIO_CFLAGS@
-GIO_LIBS = @GIO_LIBS@
 GLIB_CFLAGS = @GLIB_CFLAGS@
 GLIB_GENMARSHAL = @GLIB_GENMARSHAL@
 GLIB_LIBS = @GLIB_LIBS@
 GLIB_MAKEFILE = @GLIB_MAKEFILE@
 GLIB_MKENUMS = @GLIB_MKENUMS@
-GMODULE_CFLAGS = @GMODULE_CFLAGS@
-GMODULE_LIBS = @GMODULE_LIBS@
 GMSGFMT = @GMSGFMT@
 GMSGFMT_015 = @GMSGFMT_015@
 GNUTLS_CFLAGS = @GNUTLS_CFLAGS@
@@ -259,6 +259,7 @@ IPTABLES_PATH = @IPTABLES_PATH@
 IWMX_SDK_CFLAGS = @IWMX_SDK_CFLAGS@
 IWMX_SDK_LIBS = @IWMX_SDK_LIBS@
 KERNEL_FIRMWARE_DIR = @KERNEL_FIRMWARE_DIR@
+LCOV = @LCOV@
 LD = @LD@
 LDFLAGS = @LDFLAGS@
 LIBDL = @LIBDL@
@@ -275,11 +276,7 @@ LIBNL2_LIBS = @LIBNL2_LIBS@
 LIBNL3_CFLAGS = @LIBNL3_CFLAGS@
 LIBNL3_LIBS = @LIBNL3_LIBS@
 LIBNL_CFLAGS = @LIBNL_CFLAGS@
-LIBNL_GENL3_CFLAGS = @LIBNL_GENL3_CFLAGS@
-LIBNL_GENL3_LIBS = @LIBNL_GENL3_LIBS@
 LIBNL_LIBS = @LIBNL_LIBS@
-LIBNL_ROUTE3_CFLAGS = @LIBNL_ROUTE3_CFLAGS@
-LIBNL_ROUTE3_LIBS = @LIBNL_ROUTE3_LIBS@
 LIBOBJS = @LIBOBJS@
 LIBS = @LIBS@
 LIBSOUP_CFLAGS = @LIBSOUP_CFLAGS@
@@ -294,6 +291,8 @@ MAINT = @MAINT@
 MAKEINFO = @MAKEINFO@
 MANIFEST_TOOL = @MANIFEST_TOOL@
 MKDIR_P = @MKDIR_P@
+MM_GLIB_CFLAGS = @MM_GLIB_CFLAGS@
+MM_GLIB_LIBS = @MM_GLIB_LIBS@
 MOC = @MOC@
 MSGFMT = @MSGFMT@
 MSGFMT_015 = @MSGFMT_015@
@@ -303,6 +302,7 @@ NMEDIT = @NMEDIT@
 NM_MAJOR_VERSION = @NM_MAJOR_VERSION@
 NM_MICRO_VERSION = @NM_MICRO_VERSION@
 NM_MINOR_VERSION = @NM_MINOR_VERSION@
+NM_MODIFY_SYSTEM_POLICY = @NM_MODIFY_SYSTEM_POLICY@
 NM_VERSION = @NM_VERSION@
 NSS_CFLAGS = @NSS_CFLAGS@
 NSS_LIBS = @NSS_LIBS@
@@ -329,13 +329,14 @@ PPPD_PLUGIN_DIR = @PPPD_PLUGIN_DIR@
 QT_CFLAGS = @QT_CFLAGS@
 QT_LIBS = @QT_LIBS@
 RANLIB = @RANLIB@
-RESOLVCONF_PATH = @RESOLVCONF_PATH@
 SED = @SED@
 SET_MAKE = @SET_MAKE@
 SHELL = @SHELL@
 STRIP = @STRIP@
-SYSTEMD_CFLAGS = @SYSTEMD_CFLAGS@
-SYSTEMD_LIBS = @SYSTEMD_LIBS@
+SYSTEMD_INHIBIT_CFLAGS = @SYSTEMD_INHIBIT_CFLAGS@
+SYSTEMD_INHIBIT_LIBS = @SYSTEMD_INHIBIT_LIBS@
+SYSTEMD_LOGIN_CFLAGS = @SYSTEMD_LOGIN_CFLAGS@
+SYSTEMD_LOGIN_LIBS = @SYSTEMD_LOGIN_LIBS@
 SYSTEM_CA_PATH = @SYSTEM_CA_PATH@
 UDEV_BASE_DIR = @UDEV_BASE_DIR@
 USE_NLS = @USE_NLS@
@@ -390,6 +391,11 @@ localedir = @localedir@
 localstatedir = @localstatedir@
 mandir = @mandir@
 mkdir_p = @mkdir_p@
+nmbinary = @nmbinary@
+nmconfdir = @nmconfdir@
+nmdatadir = @nmdatadir@
+nmrundir = @nmrundir@
+nmstatedir = @nmstatedir@
 oldincludedir = @oldincludedir@
 pdfdir = @pdfdir@
 prefix = @prefix@
@@ -404,6 +410,10 @@ target_alias = @target_alias@
 top_build_prefix = @top_build_prefix@
 top_builddir = @top_builddir@
 top_srcdir = @top_srcdir@
+with_dhclient = @with_dhclient@
+with_dhcpcd = @with_dhcpcd@
+with_netconfig = @with_netconfig@
+with_resolvconf = @with_resolvconf@
 SUBDIRS = . tests
 INCLUDES = \
 	-I$(top_srcdir)/src/settings \
@@ -431,8 +441,7 @@ libkeyfile_io_la_SOURCES = \
 libkeyfile_io_la_CPPFLAGS = \
 	$(GLIB_CFLAGS) \
 	$(DBUS_CFLAGS) \
-	-DSYSCONFDIR=\"$(sysconfdir)\" \
-	-DG_DISABLE_DEPRECATED
+	-DNMCONFDIR=\"$(nmconfdir)\"
 
 libkeyfile_io_la_LIBADD = $(GLIB_LIBS)
 
@@ -445,18 +454,14 @@ libnm_settings_plugin_keyfile_la_SOURCES = \
 
 libnm_settings_plugin_keyfile_la_CPPFLAGS = \
 	$(GLIB_CFLAGS) \
-	$(GMODULE_CFLAGS) \
 	$(DBUS_CFLAGS) \
-	-DSYSCONFDIR=\"$(sysconfdir)\" \
-	-DG_DISABLE_DEPRECATED
+	-DNMCONFDIR=\"$(nmconfdir)\"
 
 libnm_settings_plugin_keyfile_la_LIBADD = \
 	$(top_builddir)/libnm-util/libnm-util.la \
 	libkeyfile-io.la \
 	$(GLIB_LIBS) \
-	$(GMODULE_LIBS) \
-	$(DBUS_LIBS) \
-	$(GIO_LIBS)
+	$(DBUS_LIBS)
 
 libnm_settings_plugin_keyfile_la_LDFLAGS = -rdynamic
 keyfiledir = $(sysconfdir)/NetworkManager/system-connections
@@ -522,25 +527,22 @@ distclean-compile:
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libnm_settings_plugin_keyfile_la-plugin.Plo@am__quote@
 
 .c.o:
-@am__fastdepCC_TRUE@	$(AM_V_CC)depbase=`echo $@ | sed 's|[^/]*$$|$(DEPDIR)/&|;s|\.o$$||'`;\
-@am__fastdepCC_TRUE@	$(COMPILE) -MT $@ -MD -MP -MF $$depbase.Tpo -c -o $@ $< &&\
-@am__fastdepCC_TRUE@	$(am__mv) $$depbase.Tpo $$depbase.Po
+@am__fastdepCC_TRUE@	$(AM_V_CC)$(COMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $<
+@am__fastdepCC_TRUE@	$(AM_V_at)$(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po
 @AMDEP_TRUE@@am__fastdepCC_FALSE@	$(AM_V_CC)source='$<' object='$@' libtool=no @AMDEPBACKSLASH@
 @AMDEP_TRUE@@am__fastdepCC_FALSE@	DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
-@am__fastdepCC_FALSE@	$(AM_V_CC@am__nodep@)$(COMPILE) -c -o $@ $<
+@am__fastdepCC_FALSE@	$(AM_V_CC@am__nodep@)$(COMPILE) -c $<
 
 .c.obj:
-@am__fastdepCC_TRUE@	$(AM_V_CC)depbase=`echo $@ | sed 's|[^/]*$$|$(DEPDIR)/&|;s|\.obj$$||'`;\
-@am__fastdepCC_TRUE@	$(COMPILE) -MT $@ -MD -MP -MF $$depbase.Tpo -c -o $@ `$(CYGPATH_W) '$<'` &&\
-@am__fastdepCC_TRUE@	$(am__mv) $$depbase.Tpo $$depbase.Po
+@am__fastdepCC_TRUE@	$(AM_V_CC)$(COMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ `$(CYGPATH_W) '$<'`
+@am__fastdepCC_TRUE@	$(AM_V_at)$(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po
 @AMDEP_TRUE@@am__fastdepCC_FALSE@	$(AM_V_CC)source='$<' object='$@' libtool=no @AMDEPBACKSLASH@
 @AMDEP_TRUE@@am__fastdepCC_FALSE@	DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
-@am__fastdepCC_FALSE@	$(AM_V_CC@am__nodep@)$(COMPILE) -c -o $@ `$(CYGPATH_W) '$<'`
+@am__fastdepCC_FALSE@	$(AM_V_CC@am__nodep@)$(COMPILE) -c `$(CYGPATH_W) '$<'`
 
 .c.lo:
-@am__fastdepCC_TRUE@	$(AM_V_CC)depbase=`echo $@ | sed 's|[^/]*$$|$(DEPDIR)/&|;s|\.lo$$||'`;\
-@am__fastdepCC_TRUE@	$(LTCOMPILE) -MT $@ -MD -MP -MF $$depbase.Tpo -c -o $@ $< &&\
-@am__fastdepCC_TRUE@	$(am__mv) $$depbase.Tpo $$depbase.Plo
+@am__fastdepCC_TRUE@	$(AM_V_CC)$(LTCOMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $<
+@am__fastdepCC_TRUE@	$(AM_V_at)$(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Plo
 @AMDEP_TRUE@@am__fastdepCC_FALSE@	$(AM_V_CC)source='$<' object='$@' libtool=yes @AMDEPBACKSLASH@
 @AMDEP_TRUE@@am__fastdepCC_FALSE@	DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
 @am__fastdepCC_FALSE@	$(AM_V_CC@am__nodep@)$(LTCOMPILE) -c -o $@ $<
diff --git a/src/settings/plugins/keyfile/common.h b/src/settings/plugins/keyfile/common.h
index 7d94a705..d48c32f2 100644
--- a/src/settings/plugins/keyfile/common.h
+++ b/src/settings/plugins/keyfile/common.h
@@ -26,7 +26,7 @@
 #define KEYFILE_PLUGIN_NAME "keyfile"
 #define KEYFILE_PLUGIN_INFO "(c) 2007 - 2010 Red Hat, Inc.  To report bugs please use the NetworkManager mailing list."
 
-#define KEYFILE_DIR SYSCONFDIR "/NetworkManager/system-connections"
+#define KEYFILE_DIR NMCONFDIR "/system-connections"
 
 #define VPN_SECRETS_GROUP "vpn-secrets"
 
diff --git a/src/settings/plugins/keyfile/nm-keyfile-connection.c b/src/settings/plugins/keyfile/nm-keyfile-connection.c
index 23618f7c..6d72bbfe 100644
--- a/src/settings/plugins/keyfile/nm-keyfile-connection.c
+++ b/src/settings/plugins/keyfile/nm-keyfile-connection.c
@@ -16,7 +16,7 @@
  * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
  *
  * Copyright (C) 2008 Novell, Inc.
- * Copyright (C) 2008 - 2011 Red Hat, Inc.
+ * Copyright (C) 2008 - 2012 Red Hat, Inc.
  */
 
 #include <string.h>
@@ -96,6 +96,19 @@ nm_keyfile_connection_get_path (NMKeyfileConnection *self)
 	return NM_KEYFILE_CONNECTION_GET_PRIVATE (self)->path;
 }
 
+void
+nm_keyfile_connection_set_path (NMKeyfileConnection *self, const char *path)
+{
+	NMKeyfileConnectionPrivate *priv;
+
+	g_return_if_fail (NM_IS_KEYFILE_CONNECTION (self));
+	g_return_if_fail (path != NULL);
+
+	priv = NM_KEYFILE_CONNECTION_GET_PRIVATE (self);
+	g_free (priv->path);
+	priv->path = g_strdup (path);
+}
+
 static void
 commit_changes (NMSettingsConnection *connection,
                 NMSettingsConnectionCommitFunc callback,
diff --git a/src/settings/plugins/keyfile/nm-keyfile-connection.h b/src/settings/plugins/keyfile/nm-keyfile-connection.h
index 932b36f7..e3bce11b 100644
--- a/src/settings/plugins/keyfile/nm-keyfile-connection.h
+++ b/src/settings/plugins/keyfile/nm-keyfile-connection.h
@@ -16,7 +16,7 @@
  * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
  *
  * Copyright (C) 2008 Novell, Inc.
- * Copyright (C) 2008 - 2011 Red Hat, Inc.
+ * Copyright (C) 2008 - 2012 Red Hat, Inc.
  */
 
 #ifndef NM_KEYFILE_CONNECTION_H
@@ -48,6 +48,7 @@ NMKeyfileConnection *nm_keyfile_connection_new (const char *filename,
                                                 GError **error);
 
 const char *nm_keyfile_connection_get_path (NMKeyfileConnection *self);
+void        nm_keyfile_connection_set_path (NMKeyfileConnection *self, const char *path);
 
 G_END_DECLS
 
diff --git a/src/settings/plugins/keyfile/plugin.c b/src/settings/plugins/keyfile/plugin.c
index d53907a9..062eb082 100644
--- a/src/settings/plugins/keyfile/plugin.c
+++ b/src/settings/plugins/keyfile/plugin.c
@@ -16,7 +16,7 @@
  * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
  *
  * Copyright (C) 2008 Novell, Inc.
- * Copyright (C) 2008 - 2011 Red Hat, Inc.
+ * Copyright (C) 2008 - 2012 Red Hat, Inc.
  */
 
 #include <config.h>
@@ -268,6 +268,10 @@ dir_changed (GFileMonitor *monitor,
 					 * filename property too.
 					 */
 					update_connection_settings (found, connection);
+					/* However, when connections are the same and only the filename changed
+					 * we need to update the path manually (commit_changes() is not called.
+					 */
+					nm_keyfile_connection_set_path (found, full_path);
 
 					/* Re-insert the connection back into the hash with the new filename */
 					g_hash_table_insert (priv->hash,
diff --git a/src/settings/plugins/keyfile/reader.c b/src/settings/plugins/keyfile/reader.c
index 7f0ab4af..6ddf50d5 100644
--- a/src/settings/plugins/keyfile/reader.c
+++ b/src/settings/plugins/keyfile/reader.c
@@ -39,7 +39,6 @@
 #include <netinet/ether.h>
 #include <linux/if_infiniband.h>
 #include <string.h>
-#include <ctype.h>
 
 #include "nm-dbus-glib-types.h"
 #include "nm-system-config-interface.h"
@@ -58,13 +57,13 @@ read_array_of_uint (GKeyFile *file,
 
 	tmp = g_key_file_get_integer_list (file, nm_setting_get_name (setting), key, &length, NULL);
 	array = g_array_sized_new (FALSE, FALSE, sizeof (guint32), length);
+	g_return_val_if_fail (array != NULL, FALSE);
+
 	for (i = 0; i < length; i++)
 		g_array_append_val (array, tmp[i]);
 
-	if (array) {
-		g_object_set (setting, key, array, NULL);
-		g_array_free (array, TRUE);
-	}
+	g_object_set (setting, key, array, NULL);
+	g_array_unref (array);
 
 	return TRUE;
 }
@@ -85,209 +84,326 @@ get_one_int (const char *str, guint32 max_val, const char *key_name, guint32 *ou
 	return TRUE;
 }
 
-static void
-free_one_ip4_address (gpointer data, gpointer user_data)
+static gpointer
+build_ip4_address_or_route (const char *address_str, guint32 plen, const char *gateway_str, guint32 metric, gboolean route)
 {
-	g_array_free ((GArray *) data, TRUE);
-}
+	GArray *result;
+	struct in_addr addr;
+	guint32 address = 0;
+	guint32 gateway = 0;
+	int err;
+
+	g_return_val_if_fail (address_str, NULL);
+
+	/* Address */
+	err = inet_pton (AF_INET, address_str, &addr);
+	if (err <= 0) {
+		g_warning ("%s: ignoring invalid IPv4 address '%s'", __func__, address_str);
+		return NULL;
+	}
+	address = addr.s_addr;
+	/* Gateway */
+	if (gateway_str) {
+		err = inet_pton (AF_INET, gateway_str, &addr);
+		if (err <= 0) {
+			g_warning ("%s: ignoring invalid IPv4 gateway '%s'", __func__, gateway_str);
+			return NULL;
+		}
+		gateway = addr.s_addr;
+	}
+	else
+		gateway = 0;
 
-static GPtrArray *
-read_ip4_addresses (GKeyFile *file,
-			    const char *setting_name,
-			    const char *key)
-{
-	GPtrArray *addresses;
-	int i = 0;
+	result = g_array_sized_new (FALSE, TRUE, sizeof (guint32), 3);
+	g_array_append_val (result, address);
+	g_array_append_val (result, plen);
+	g_array_append_val (result, gateway);
+	if (route)
+		g_array_append_val (result, metric);
 
-	addresses = g_ptr_array_sized_new (3);
+	return result;
+}
 
-	/* Look for individual addresses */
-	while (i++ < 1000) {
-		gchar **tmp, **iter;
-		char *key_name;
-		gsize length = 0;
-		int ret;
-		GArray *address;
-		guint32 empty = 0;
-		int j;
+static gpointer
+build_ip6_address_or_route (const char *address_str, guint32 plen, const char *gateway_str, guint32 metric, gboolean route)
+{
+	GValueArray *result;
+	struct in6_addr addr;
+	GByteArray *address;
+	GByteArray *gateway;
+	GValue value = { 0, };
+	int err;
 
-		key_name = g_strdup_printf ("%s%d", key, i);
-		tmp = g_key_file_get_string_list (file, setting_name, key_name, &length, NULL);
+	g_return_val_if_fail (address_str, NULL);
 
-		if (!tmp || !length) {
-			g_free (key_name);
-			break; /* all done */
-		}
+	result = g_value_array_new (3);
 
-		if ((length < 2) || (length > 3)) {
-			g_warning ("%s: ignoring invalid IPv4 address item '%s'", __func__, key_name);
-			goto next;
+	/* add address */
+	err = inet_pton (AF_INET6, address_str, &addr);
+	if (err <= 0) {
+		g_warning ("%s: ignoring invalid IPv6 address '%s'", __func__, address_str);
+		g_value_array_free (result);
+		return NULL;
+	}
+	address = g_byte_array_new ();
+	g_byte_array_append (address, (guint8 *) addr.s6_addr, 16);
+	g_value_init (&value, DBUS_TYPE_G_UCHAR_ARRAY);
+	g_value_take_boxed (&value, address);
+	g_value_array_append (result, &value);
+	g_value_unset (&value);
+
+	/* add prefix length */
+	g_value_init (&value, G_TYPE_UINT);
+	g_value_set_uint (&value, plen);
+	g_value_array_append (result, &value);
+	g_value_unset (&value);
+
+	/* add gateway */
+	if (gateway_str) {
+		err = inet_pton (AF_INET6, gateway_str, &addr);
+		if (err <= 0) {
+			g_warning ("%s: ignoring invalid IPv6 gateway '%s'", __func__, gateway_str);
+			g_value_array_free (result);
+			return NULL;
 		}
+	} else
+		memset (&addr, 0, 16);
+	gateway = g_byte_array_new ();
+	g_byte_array_append (gateway, (guint8 *) addr.s6_addr, 16);
+	g_value_init (&value, DBUS_TYPE_G_UCHAR_ARRAY);
+	g_value_take_boxed (&value, gateway);
+	g_value_array_append (result, &value);
+	g_value_unset (&value);
+
+	/* add metric (for routing) */
+	if (route) {
+		g_value_init (&value, G_TYPE_UINT);
+		g_value_set_uint (&value, metric);
+		g_value_array_append (result, &value);
+		g_value_unset (&value);
+	}
 
-		/* convert the string array into IP addresses */
-		address = g_array_sized_new (FALSE, TRUE, sizeof (guint32), 3);
-		for (iter = tmp, j = 0; *iter; iter++, j++) {
-			struct in_addr addr;
+	return result;
+}
 
-			if (j == 1) {
-				guint32 prefix = 0;
+/* On success, returns pointer to the zero-terminated field (original @current).
+ * The @current * pointer target is set to point to the rest of the input
+ * or NULL if there is no more input. Sets error to NULL for convenience.
+ *
+ * On failure, returns NULL (unspecified). The @current pointer target is
+ * resets to its original value to allow skipping fields. The @error target
+ * is set to the character that breaks the parsing or NULL if @current was NULL.
+ *
+ * When @current target is NULL, gracefully fail returning NULL while
+ * leaving the @current target NULL end setting @error to NULL;
+ */
+static char *
+read_field (char **current, char **error, const char *characters, const char *delimiters)
+{
+	char *start;
 
-				/* prefix */
-				if (!get_one_int (*iter, 32, key_name, &prefix)) {
-					g_array_free (address, TRUE);
-					goto next;
-				}
+	g_return_val_if_fail (current, NULL);
+	g_return_val_if_fail (error, NULL);
+	g_return_val_if_fail (characters, NULL);
+	g_return_val_if_fail (delimiters, NULL);
 
-				g_array_append_val (address, prefix);
-			} else {
-				/* address and gateway */
-				ret = inet_pton (AF_INET, *iter, &addr);
-				if (ret <= 0) {
-					g_warning ("%s: ignoring invalid IPv4 %s element '%s'", __func__, key_name, *iter);
-					g_array_free (address, TRUE);
-					goto next;
-				}
-				g_array_append_val (address, addr.s_addr);
-			}
-		}
+	if (!*current) {
+		/* graceful failure, leave '*current' NULL */
+		*error = NULL;
+		return NULL;
+	}
 
-		/* fill in blank gateway if not specified */
-		if (address->len == 2)
-			g_array_append_val (address, empty);
+	/* fail on empty input */
+	g_return_val_if_fail (**current, NULL);
 
-		g_ptr_array_add (addresses, address);
+	/* remember beginning of input */
+	start = *current;
 
-next:
-		g_free (key_name);
-		g_strfreev (tmp);
+	while (**current && strchr (characters, **current))
+		(*current)++;
+	if (**current)
+		if (strchr (delimiters, **current)) {
+			/* success, more data available */
+			*error = NULL;
+			*(*current)++ = '\0';
+			return start;
+		} else {
+			/* error, bad character */
+			*error = *current;
+			*current = start;
+			return NULL;
+		}
+	else {
+		/* success, end of input */
+		*error = NULL;
+		*current = NULL;
+		return start;
 	}
+}
 
-	if (addresses->len < 1) {
-		g_ptr_array_free (addresses, TRUE);
-		addresses = NULL;
-	}
+#define IP_ADDRESS_CHARS "0123456789abcdefABCDEF:.%"
+#define DIGITS "0123456789"
+#define DELIMITERS "/;,"
 
-	return addresses;
-}
 
-static void
-ip4_addr_parser (NMSetting *setting, const char *key, GKeyFile *keyfile, const char *keyfile_path)
+/* The following IPv4 and IPv6 address formats are supported:
+ *
+ * address (DEPRECATED)
+ * address/plen
+ * address/gateway (DEPRECATED)
+ * address/plen/gateway
+ *
+ * The following IPv4 and IPv6 route formats are supported:
+ *
+ * address/plen (NETWORK dev DEVICE)
+ * address/plen/gateway (NETWORK via GATEWAY dev DEVICE)
+ * address/plen//gateway (NETWORK dev DEVICE metric METRIC)
+ * address/plen/gateway/metric (NETWORK via GATEWAY dev DEVICE metric METRIC)
+ *
+ * For backward, forward and sideward compatibility, slash (/),
+ * semicolon (;) and comma (,) are interchangable. The use of
+ * slash in the above examples is therefore not significant.
+ *
+ * Leaving out the prefix length is discouraged and DEPRECATED. The
+ * default value of IPv6 prefix length was 64 and has not been
+ * changed. The default for IPv4 is now 24, which is the closest
+ * IPv4 equivalent. These defaults may just as well be changed to
+ * match the iproute2 defaults (32 for IPv4 and 128 for IPv6).
+ *
+ * The returned result is GArray for IPv4 and GValueArray for IPv6.
+ */
+static gpointer
+read_one_ip_address_or_route (GKeyFile *file,
+	const char *setting_name,
+	const char *key_name,
+	gboolean ipv6,
+	gboolean route)
 {
-	GPtrArray *addresses;
-	const char *setting_name = nm_setting_get_name (setting);
+	guint32 plen, metric;
+	gpointer result;
+	char *address_str, *plen_str, *gateway_str, *metric_str, *value, *current, *error;
 
-	addresses = read_ip4_addresses (keyfile, setting_name, key);
+	current = value = g_key_file_get_string (file, setting_name, key_name, NULL);
+	if (!value)
+		return NULL;
 
-	/* Work around for previous syntax */
-	if (!addresses && !strcmp (key, NM_SETTING_IP4_CONFIG_ADDRESSES))
-		addresses = read_ip4_addresses (keyfile, setting_name, "address");
+	/* get address field */
+	address_str = read_field (&current, &error, IP_ADDRESS_CHARS, DELIMITERS);
+	if (error) {
+		g_warning ("keyfile: Unexpected character '%c' in '%s.%s' address (position %td of '%s').",
+			*error, setting_name, key_name, error - current, current);
+		goto error;
+	}
+	/* get prefix length field (skippable) */
+	plen_str = read_field (&current, &error, DIGITS, DELIMITERS);
+	/* get gateway field */
+	gateway_str = read_field (&current, &error, IP_ADDRESS_CHARS, DELIMITERS);
+	if (error) {
+		g_warning ("keyfile: Unexpected character '%c' in '%s.%s' %s (position %td of '%s').",
+			*error, setting_name, key_name,
+			plen_str ? "gateway" : "gateway or prefix length",
+			error - current, current);
+		goto error;
+	}
+	/* for routes, get metric */
+	if (route) {
+		metric_str = read_field (&current, &error, DIGITS, DELIMITERS);
+		if (error) {
+			g_warning ("keyfile: Unexpected character '%c' in '%s.%s' prefix length (position %td of '%s').",
+				*error, setting_name, key_name, error - current, current);
+			goto error;
+		}
+	} else
+		metric_str = NULL;
+	if (current) {
+		/* there is still some data */
+		if (*current) {
+			/* another field follows */
+			g_warning ("keyfile: %s.%s: Garbage at the and of the line: %s",
+				setting_name, key_name, current);
+			goto error;
+		} else {
+			/* semicolon at the end of input */
+			g_message ("keyfile: %s.%s: Deprecated semicolon at the end of value.",
+				setting_name, key_name);
+		}
+	}
 
-	if (addresses) {
-		g_object_set (setting, key, addresses, NULL);
-		g_ptr_array_foreach (addresses, free_one_ip4_address, NULL);
-		g_ptr_array_free (addresses, TRUE);
+	/* parse plen, fallback to defaults */
+	if (plen_str)
+		g_return_val_if_fail (get_one_int (plen_str, ipv6 ? 128 : 32,
+			key_name, &plen), NULL);
+	else {
+		if (route)
+			plen = ipv6 ? 128 : 24;
+		else
+			plen = ipv6 ? 64 : 24;
+		g_warning ("keyfile: Missing prefix length in '%s.%s', defaulting to %d",
+			setting_name, key_name, plen);
 	}
-}
 
-static void
-free_one_ip4_route (gpointer data, gpointer user_data)
-{
-	g_array_free ((GArray *) data, TRUE);
+	/* parse metric, default to 0 */
+	metric = 0;
+	if (metric_str)
+		g_return_val_if_fail (get_one_int (metric_str, G_MAXUINT32,
+			key_name, &metric), NULL);
+
+	/* build the appropriate data structure for NetworkManager settings */
+	if (route)
+		g_debug ("keyfile: %s.%s: route %s/%d gateway %s metric %d", setting_name, key_name, address_str, plen, gateway_str, metric);
+	else
+		g_debug ("keyfile: %s.%s: address %s/%d gateway %s", setting_name, key_name, address_str, plen, gateway_str);
+	result = (ipv6 ? build_ip6_address_or_route : build_ip4_address_or_route) (
+		address_str, plen, gateway_str, metric, route);
+
+	g_free (value);
+	return result;
+error:
+	g_free (value);
+	return NULL;
 }
 
-static GPtrArray *
-read_ip4_routes (GKeyFile *file,
-			 const char *setting_name,
-			 const char *key)
+static void
+ip_address_or_route_parser (NMSetting *setting, const char *key, GKeyFile *keyfile, const char *keyfile_path)
 {
-	GPtrArray *routes;
-	int i = 0;
-
-	routes = g_ptr_array_sized_new (3);
-
-	/* Look for individual routes */
-	while (i++ < 1000) {
-		gchar **tmp, **iter;
-		char *key_name;
-		gsize length = 0;
-		int ret;
-		GArray *route;
-		int j;
-
-		key_name = g_strdup_printf ("%s%d", key, i);
-		tmp = g_key_file_get_string_list (file, setting_name, key_name, &length, NULL);
-		g_free (key_name);
-
-		if (!tmp || !length)
-			break; /* all done */
-
-		if (length != 4) {
-			g_warning ("%s: ignoring invalid IPv4 route item '%s'", __func__, key_name);
-			goto next;
-		}
+	const char *setting_name = nm_setting_get_name (setting);
+	gboolean ipv6 = !strcmp (setting_name, "ipv6");
+	gboolean routes = !strcmp (key, "routes");
+	static const char *key_names_routes[] = { "route", "routes", NULL };
+	static const char *key_names_addresses[] = { "address", "addresses", NULL };
+	const char **key_names = routes ? key_names_routes : key_names_addresses;
+	GPtrArray *list;
+	int i;
 
-		/* convert the string array into IP addresses */
-		route = g_array_sized_new (FALSE, TRUE, sizeof (guint32), 4);
-		for (iter = tmp, j = 0; *iter; iter++, j++) {
-			struct in_addr addr;
+	list = g_ptr_array_new_with_free_func (
+		ipv6 ? (GDestroyNotify) g_value_array_free : (GDestroyNotify) g_array_unref);
 
-			if (j == 1) {
-				guint32 prefix = 0;
+	for (i = -1; i < 1000; i++) {
+		const char **key_basename;
+		
+		for (key_basename = key_names; *key_basename; key_basename++) {
+			char *key_name;
+			gpointer item;
 
-				/* prefix */
-				if (!get_one_int (*iter, 32, key_name, &prefix)) {
-					g_array_free (route, TRUE);
-					goto next;
-				}
+			/* -1 means no suffix */
+			if (i >= 0)
+				key_name = g_strdup_printf ("%s%d", *key_basename, i);
+			else
+				key_name = g_strdup (*key_basename);
 
-				g_array_append_val (route, prefix);
-			} else if (j == 3) {
-				guint32 metric = 0;
+			item = read_one_ip_address_or_route (keyfile, setting_name, key_name, ipv6, routes);
 
-				/* metric */
-				if (!get_one_int (*iter, G_MAXUINT32, key_name, &metric)) {
-					g_array_free (route, TRUE);
-					goto next;
-				}
+			if (item)
+				g_ptr_array_add (list, item);
 
-				g_array_append_val (route, metric);
-			} else {
-				/* address and next hop */
-				ret = inet_pton (AF_INET, *iter, &addr);
-				if (ret <= 0) {
-					g_warning ("%s: ignoring invalid IPv4 %s element '%s'", __func__, key_name, *iter);
-					g_array_free (route, TRUE);
-					goto next;
-				}
-				g_array_append_val (route, addr.s_addr);
-			}
+			g_free (key_name);
 		}
-		g_ptr_array_add (routes, route);
-
-next:
-		g_strfreev (tmp);
-	}
-
-	if (routes->len < 1) {
-		g_ptr_array_free (routes, TRUE);
-		routes = NULL;
 	}
 
-	return routes;
-}
-
-static void
-ip4_route_parser (NMSetting *setting, const char *key, GKeyFile *keyfile, const char *keyfile_path)
-{
-	GPtrArray *routes;
-	const char *setting_name = nm_setting_get_name (setting);
+	if (list->len >= 1)
+		g_object_set (setting, key, list, NULL);
 
-	routes = read_ip4_routes (keyfile, setting_name, key);
-	if (routes) {
-		g_object_set (setting, key, routes, NULL);
-		g_ptr_array_foreach (routes, free_one_ip4_route, NULL);
-		g_ptr_array_free (routes, TRUE);
-	}
+	g_ptr_array_unref (list);
 }
 
 static void
@@ -319,301 +435,11 @@ ip4_dns_parser (NMSetting *setting, const char *key, GKeyFile *keyfile, const ch
 
 	if (array) {
 		g_object_set (setting, key, array, NULL);
-		g_array_free (array, TRUE);
-	}
-}
-
-static void
-free_one_ip6_address (gpointer data, gpointer user_data)
-{
-	g_value_array_free ((GValueArray *) data);
-}
-
-static char *
-split_prefix (char *addr)
-{
-	char *slash;
-
-	g_return_val_if_fail (addr != NULL, NULL);
-
-	/* Find the prefix and split the string */
-	slash = strchr (addr, '/');
-	if (slash && slash > addr) {
-		slash++;
-		*(slash - 1) = '\0';
-	}
-
-	return slash;
-}
-
-static char *
-split_gw (char *str)
-{
-	char *comma;
-
-	g_return_val_if_fail (str != NULL, NULL);
-
-	/* Find the prefix and split the string */
-	comma = strchr (str, ',');
-	if (comma && comma > str) {
-		comma++;
-		*(comma - 1) = '\0';
-		return comma;
-	}
-	return NULL;
-}
-
-static GPtrArray *
-read_ip6_addresses (GKeyFile *file,
-                    const char *setting_name,
-                    const char *key)
-{
-	GPtrArray *addresses;
-	struct in6_addr addr, gw;
-	guint32 prefix;
-	int i = 0;
-
-	addresses = g_ptr_array_sized_new (3);
-
-	/* Look for individual addresses */
-	while (i++ < 1000) {
-		char *tmp, *key_name, *str_prefix, *str_gw;
-		int ret;
-		GValueArray *values;
-		GByteArray *address;
-		GByteArray *gateway;
-		GValue value = { 0 };
-
-		key_name = g_strdup_printf ("%s%d", key, i);
-		tmp = g_key_file_get_string (file, setting_name, key_name, NULL);
-		g_free (key_name);
-
-		if (!tmp)
-			break; /* all done */
-
-		/* convert the string array into IPv6 addresses */
-		values = g_value_array_new (2); /* NMIP6Address has 2 items */
-
-		/* Split the address and prefix */
-		str_prefix = split_prefix (tmp);
-
-		/* address */
-		ret = inet_pton (AF_INET6, tmp, &addr);
-		if (ret <= 0) {
-			g_warning ("%s: ignoring invalid IPv6 %s element '%s'", __func__, key_name, tmp);
-			g_value_array_free (values);
-			goto next;
-		}
-
-		address = g_byte_array_new ();
-		g_byte_array_append (address, (guint8 *) addr.s6_addr, 16);
-		g_value_init (&value, DBUS_TYPE_G_UCHAR_ARRAY);
-		g_value_take_boxed (&value, address);
-		g_value_array_append (values, &value);
-		g_value_unset (&value);
-
-		/* prefix */
-		prefix = 0;
-		if (str_prefix) {
-			if (!get_one_int (str_prefix, 128, key_name, &prefix)) {
-				g_value_array_free (values);
-				goto next;
-			}
-		} else {
-			/* Missing prefix defaults to /64 */
-			prefix = 64;
-		}
-
-		g_value_init (&value, G_TYPE_UINT);
-		g_value_set_uint (&value, prefix);
-		g_value_array_append (values, &value);
-		g_value_unset (&value);
-
-		/* Gateway (optional) */
-		str_gw = split_gw (str_prefix);
-		if (str_gw) {
-			ret = inet_pton (AF_INET6, str_gw, &gw);
-			if (ret <= 0) {
-				g_warning ("%s: ignoring invalid IPv6 %s gateway '%s'", __func__, key_name, tmp);
-				g_value_array_free (values);
-				goto next;
-			}
-
-			if (!IN6_IS_ADDR_UNSPECIFIED (&gw)) {
-				gateway = g_byte_array_new ();
-				g_byte_array_append (gateway, (guint8 *) gw.s6_addr, 16);
-				g_value_init (&value, DBUS_TYPE_G_UCHAR_ARRAY);
-				g_value_take_boxed (&value, gateway);
-				g_value_array_append (values, &value);
-				g_value_unset (&value);
-			}
-		}
-
-		g_ptr_array_add (addresses, values);
-
-next:
-		g_free (tmp);
-	}
-
-	if (addresses->len < 1) {
-		g_ptr_array_free (addresses, TRUE);
-		addresses = NULL;
-	}
-
-	return addresses;
-}
-
-static void
-ip6_addr_parser (NMSetting *setting, const char *key, GKeyFile *keyfile, const char *keyfile_path)
-{
-	GPtrArray *addresses;
-	const char *setting_name = nm_setting_get_name (setting);
-
-	addresses = read_ip6_addresses (keyfile, setting_name, key);
-	if (addresses) {
-		g_object_set (setting, key, addresses, NULL);
-		g_ptr_array_foreach (addresses, free_one_ip6_address, NULL);
-		g_ptr_array_free (addresses, TRUE);
+		g_array_unref (array);
 	}
 }
 
 static void
-free_one_ip6_route (gpointer data, gpointer user_data)
-{
-	g_value_array_free ((GValueArray *) data);
-}
-
-static GPtrArray *
-read_ip6_routes (GKeyFile *file,
-                 const char *setting_name,
-                 const char *key)
-{
-	GPtrArray *routes;
-	struct in6_addr addr;
-	guint32 prefix, metric;
-	int i = 0;
-
-	routes = g_ptr_array_sized_new (3);
-
-	/* Look for individual routes */
-	while (i++ < 1000) {
-		gchar **tmp;
-		char *key_name, *str_prefix;
-		gsize length = 0;
-		int ret;
-		GValueArray *values;
-		GByteArray *address;
-		GValue value = { 0 };
-
-		key_name = g_strdup_printf ("%s%d", key, i);
-		tmp = g_key_file_get_string_list (file, setting_name, key_name, &length, NULL);
-		g_free (key_name);
-
-		if (!tmp || !length)
-			break; /* all done */
-
-		if (length != 3) {
-			g_warning ("%s: ignoring invalid IPv6 address item '%s'", __func__, key_name);
-			goto next;
-		}
-
-		/* convert the string array into IPv6 routes */
-		values = g_value_array_new (4); /* NMIP6Route has 4 items */
-
-		/* Split the route and prefix */
-		str_prefix = split_prefix (tmp[0]);
-
-		/* destination address */
-		ret = inet_pton (AF_INET6, tmp[0], &addr);
-		if (ret <= 0) {
-			g_warning ("%s: ignoring invalid IPv6 %s element '%s'", __func__, key_name, tmp[0]);
-			g_value_array_free (values);
-			goto next;
-		}
-		address = g_byte_array_new ();
-		g_byte_array_append (address, (guint8 *) addr.s6_addr, 16);
-		g_value_init (&value, DBUS_TYPE_G_UCHAR_ARRAY);
-		g_value_take_boxed (&value, address);
-		g_value_array_append (values, &value);
-		g_value_unset (&value);
-
-		/* prefix */
-		prefix = 0;
-		if (str_prefix) {
-			if (!get_one_int (str_prefix, 128, key_name, &prefix)) {
-				g_value_array_free (values);
-				goto next;
-			}
-		} else {
-			/* default to 64 if unspecified */
-			prefix = 64;
-		}
-		g_value_init (&value, G_TYPE_UINT);
-		g_value_set_uint (&value, prefix);
-		g_value_array_append (values, &value);
-		g_value_unset (&value);
-
-		/* next hop address */
-		ret = inet_pton (AF_INET6, tmp[1], &addr);
-		if (ret <= 0) {
-			g_warning ("%s: ignoring invalid IPv6 %s element '%s'", __func__, key_name, tmp[1]);
-			g_value_array_free (values);
-			goto next;
-		}
-		address = g_byte_array_new ();
-		g_byte_array_append (address, (guint8 *) addr.s6_addr, 16);
-		g_value_init (&value, DBUS_TYPE_G_UCHAR_ARRAY);
-		g_value_take_boxed (&value, address);
-		g_value_array_append (values, &value);
-		g_value_unset (&value);
-
-		/* metric */
-		metric = 0;
-		if (!get_one_int (tmp[2], G_MAXUINT32, key_name, &metric)) {
-			g_value_array_free (values);
-			goto next;
-		}
-		g_value_init (&value, G_TYPE_UINT);
-		g_value_set_uint (&value, metric);
-		g_value_array_append (values, &value);
-		g_value_unset (&value);
-
-		g_ptr_array_add (routes, values);
-
-next:
-		g_strfreev (tmp);
-	}
-
-	if (routes->len < 1) {
-		g_ptr_array_free (routes, TRUE);
-		routes = NULL;
-	}
-
-	return routes;
-}
-
-static void
-ip6_route_parser (NMSetting *setting, const char *key, GKeyFile *keyfile, const char *keyfile_path)
-{
-	GPtrArray *routes;
-	const char *setting_name = nm_setting_get_name (setting);
-
-	routes = read_ip6_routes (keyfile, setting_name, key);
-
-	if (routes) {
-		g_object_set (setting, key, routes, NULL);
-		g_ptr_array_foreach (routes, free_one_ip6_route, NULL);
-		g_ptr_array_free (routes, TRUE);
-	}
-}
-
-static void
-free_one_ip6_dns (gpointer data, gpointer user_data)
-{
-	g_byte_array_free ((GByteArray *) data, TRUE);
-}
-
-static void
 ip6_dns_parser (NMSetting *setting, const char *key, GKeyFile *keyfile, const char *keyfile_path)
 {
 	const char *setting_name = nm_setting_get_name (setting);
@@ -626,7 +452,8 @@ ip6_dns_parser (NMSetting *setting, const char *key, GKeyFile *keyfile, const ch
 	if (!list || !g_strv_length (list))
 		return;
 
-	array = g_ptr_array_sized_new (length);
+	array = g_ptr_array_new_with_free_func ((GDestroyNotify) g_byte_array_unref);
+
 	for (iter = list; *iter; iter++) {
 		GByteArray *byte_array;
 		struct in6_addr addr;
@@ -645,8 +472,7 @@ ip6_dns_parser (NMSetting *setting, const char *key, GKeyFile *keyfile, const ch
 
 	if (array) {
 		g_object_set (setting, key, array, NULL);
-		g_ptr_array_foreach (array, free_one_ip6_dns, NULL);
-		g_ptr_array_free (array, TRUE);
+		g_ptr_array_unref (array);
 	}
 }
 
@@ -988,26 +814,26 @@ typedef struct {
 /* A table of keys that require further parsing/conversion because they are
  * stored in a format that can't be automatically read using the key's type.
  * i.e. IPv4 addresses, which are stored in NetworkManager as guint32, but are
- * stored in keyfiles as strings, eg "10.1.1.2" or IPv6 addresses stored 
+ * stored in keyfiles as strings, eg "10.1.1.2" or IPv6 addresses stored
  * in struct in6_addr internally, but as string in keyfiles.
  */
 static KeyParser key_parsers[] = {
 	{ NM_SETTING_IP4_CONFIG_SETTING_NAME,
 	  NM_SETTING_IP4_CONFIG_ADDRESSES,
 	  FALSE,
-	  ip4_addr_parser },
+	  ip_address_or_route_parser },
 	{ NM_SETTING_IP6_CONFIG_SETTING_NAME,
 	  NM_SETTING_IP6_CONFIG_ADDRESSES,
 	  FALSE,
-	  ip6_addr_parser },
+	  ip_address_or_route_parser },
 	{ NM_SETTING_IP4_CONFIG_SETTING_NAME,
 	  NM_SETTING_IP4_CONFIG_ROUTES,
 	  FALSE,
-	  ip4_route_parser },
+	  ip_address_or_route_parser },
 	{ NM_SETTING_IP6_CONFIG_SETTING_NAME,
 	  NM_SETTING_IP6_CONFIG_ROUTES,
 	  FALSE,
-	  ip6_route_parser },
+	  ip_address_or_route_parser },
 	{ NM_SETTING_IP4_CONFIG_SETTING_NAME,
 	  NM_SETTING_IP4_CONFIG_DNS,
 	  FALSE,
@@ -1044,6 +870,10 @@ static KeyParser key_parsers[] = {
 	  NM_SETTING_INFINIBAND_MAC_ADDRESS,
 	  TRUE,
 	  mac_address_parser },
+	{ NM_SETTING_WIMAX_SETTING_NAME,
+	  NM_SETTING_WIMAX_MAC_ADDRESS,
+	  TRUE,
+	  mac_address_parser },
 	{ NM_SETTING_WIRELESS_SETTING_NAME,
 	  NM_SETTING_WIRELESS_SSID,
 	  TRUE,
@@ -1359,6 +1189,8 @@ nm_keyfile_plugin_connection_from_file (const char *filename, GError **error)
 		g_clear_error (&verify_error);
 		g_object_unref (connection);
 		connection = NULL;
+		g_warning ("Connection failed to verify: %s",
+			verify_error ? g_type_name (nm_connection_lookup_setting_type_by_quark (verify_error->domain)) : "(unknown)");
 	}
 
 out:
diff --git a/src/settings/plugins/keyfile/tests/Makefile.am b/src/settings/plugins/keyfile/tests/Makefile.am
index 2adbf873..26e8eafd 100644
--- a/src/settings/plugins/keyfile/tests/Makefile.am
+++ b/src/settings/plugins/keyfile/tests/Makefile.am
@@ -1,3 +1,5 @@
+if ENABLE_TESTS
+
 SUBDIRS=keyfiles
 
 INCLUDES = \
@@ -25,10 +27,7 @@ test_keyfile_LDADD = \
 	$(top_builddir)/libnm-util/libnm-util.la \
 	$(DBUS_LIBS)
 
-if WITH_TESTS
-
 check-local: test-keyfile
 	$(abs_builddir)/test-keyfile
 
 endif
-
diff --git a/src/settings/plugins/keyfile/tests/Makefile.in b/src/settings/plugins/keyfile/tests/Makefile.in
index 991cd55e..ae5836f5 100644
--- a/src/settings/plugins/keyfile/tests/Makefile.in
+++ b/src/settings/plugins/keyfile/tests/Makefile.in
@@ -51,21 +51,23 @@ PRE_UNINSTALL = :
 POST_UNINSTALL = :
 build_triplet = @build@
 host_triplet = @host@
-noinst_PROGRAMS = test-keyfile$(EXEEXT)
+@ENABLE_TESTS_TRUE@noinst_PROGRAMS = test-keyfile$(EXEEXT)
 subdir = src/settings/plugins/keyfile/tests
 DIST_COMMON = $(srcdir)/Makefile.am $(srcdir)/Makefile.in
 ACLOCAL_M4 = $(top_srcdir)/aclocal.m4
 am__aclocal_m4_deps = $(top_srcdir)/m4/compiler_warnings.m4 \
-	$(top_srcdir)/m4/gettext.m4 $(top_srcdir)/m4/gtk-doc.m4 \
-	$(top_srcdir)/m4/iconv.m4 $(top_srcdir)/m4/intlmacosx.m4 \
-	$(top_srcdir)/m4/intltool.m4 $(top_srcdir)/m4/introspection.m4 \
-	$(top_srcdir)/m4/lib-ld.m4 $(top_srcdir)/m4/lib-link.m4 \
-	$(top_srcdir)/m4/lib-prefix.m4 $(top_srcdir)/m4/libnl-check.m4 \
-	$(top_srcdir)/m4/libtool.m4 $(top_srcdir)/m4/ltoptions.m4 \
-	$(top_srcdir)/m4/ltsugar.m4 $(top_srcdir)/m4/ltversion.m4 \
-	$(top_srcdir)/m4/lt~obsolete.m4 $(top_srcdir)/m4/nls.m4 \
-	$(top_srcdir)/m4/po.m4 $(top_srcdir)/m4/progtest.m4 \
-	$(top_srcdir)/m4/vapigen.m4 $(top_srcdir)/configure.ac
+	$(top_srcdir)/m4/gettext.m4 \
+	$(top_srcdir)/m4/gnome-code-coverage.m4 \
+	$(top_srcdir)/m4/gtk-doc.m4 $(top_srcdir)/m4/iconv.m4 \
+	$(top_srcdir)/m4/intlmacosx.m4 $(top_srcdir)/m4/intltool.m4 \
+	$(top_srcdir)/m4/introspection.m4 $(top_srcdir)/m4/lib-ld.m4 \
+	$(top_srcdir)/m4/lib-link.m4 $(top_srcdir)/m4/lib-prefix.m4 \
+	$(top_srcdir)/m4/libnl-check.m4 $(top_srcdir)/m4/libtool.m4 \
+	$(top_srcdir)/m4/ltoptions.m4 $(top_srcdir)/m4/ltsugar.m4 \
+	$(top_srcdir)/m4/ltversion.m4 $(top_srcdir)/m4/lt~obsolete.m4 \
+	$(top_srcdir)/m4/nls.m4 $(top_srcdir)/m4/po.m4 \
+	$(top_srcdir)/m4/progtest.m4 $(top_srcdir)/m4/vapigen.m4 \
+	$(top_srcdir)/configure.ac
 am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \
 	$(ACLOCAL_M4)
 mkinstalldirs = $(install_sh) -d
@@ -73,12 +75,16 @@ CONFIG_HEADER = $(top_builddir)/config.h
 CONFIG_CLEAN_FILES =
 CONFIG_CLEAN_VPATH_FILES =
 PROGRAMS = $(noinst_PROGRAMS)
-am_test_keyfile_OBJECTS = test_keyfile-test-keyfile.$(OBJEXT)
+am__test_keyfile_SOURCES_DIST = test-keyfile.c
+@ENABLE_TESTS_TRUE@am_test_keyfile_OBJECTS =  \
+@ENABLE_TESTS_TRUE@	test_keyfile-test-keyfile.$(OBJEXT)
 test_keyfile_OBJECTS = $(am_test_keyfile_OBJECTS)
 am__DEPENDENCIES_1 =
-test_keyfile_DEPENDENCIES = $(builddir)/../libkeyfile-io.la \
-	$(top_builddir)/libnm-glib/libnm-glib.la \
-	$(top_builddir)/libnm-util/libnm-util.la $(am__DEPENDENCIES_1)
+@ENABLE_TESTS_TRUE@test_keyfile_DEPENDENCIES =  \
+@ENABLE_TESTS_TRUE@	$(builddir)/../libkeyfile-io.la \
+@ENABLE_TESTS_TRUE@	$(top_builddir)/libnm-glib/libnm-glib.la \
+@ENABLE_TESTS_TRUE@	$(top_builddir)/libnm-util/libnm-util.la \
+@ENABLE_TESTS_TRUE@	$(am__DEPENDENCIES_1)
 AM_V_lt = $(am__v_lt_@AM_V@)
 am__v_lt_ = $(am__v_lt_@AM_DEFAULT_V@)
 am__v_lt_0 = --silent
@@ -109,7 +115,7 @@ AM_V_GEN = $(am__v_GEN_@AM_V@)
 am__v_GEN_ = $(am__v_GEN_@AM_DEFAULT_V@)
 am__v_GEN_0 = @echo "  GEN   " $@;
 SOURCES = $(test_keyfile_SOURCES)
-DIST_SOURCES = $(test_keyfile_SOURCES)
+DIST_SOURCES = $(am__test_keyfile_SOURCES_DIST)
 RECURSIVE_TARGETS = all-recursive check-recursive dvi-recursive \
 	html-recursive info-recursive install-data-recursive \
 	install-dvi-recursive install-exec-recursive \
@@ -129,7 +135,7 @@ AM_RECURSIVE_TARGETS = $(RECURSIVE_TARGETS:-recursive=) \
 	distdir
 ETAGS = etags
 CTAGS = ctags
-DIST_SUBDIRS = $(SUBDIRS)
+DIST_SUBDIRS = keyfiles
 DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST)
 am__relativize = \
   dir0=`pwd`; \
@@ -168,6 +174,10 @@ AWK = @AWK@
 CC = @CC@
 CCDEPMODE = @CCDEPMODE@
 CFLAGS = @CFLAGS@
+CKDB_PATH = @CKDB_PATH@
+CODE_COVERAGE_CFLAGS = @CODE_COVERAGE_CFLAGS@
+CODE_COVERAGE_ENABLED = @CODE_COVERAGE_ENABLED@
+CODE_COVERAGE_LDFLAGS = @CODE_COVERAGE_LDFLAGS@
 CPP = @CPP@
 CPPFLAGS = @CPPFLAGS@
 CXX = @CXX@
@@ -182,9 +192,7 @@ DBUS_SYS_DIR = @DBUS_SYS_DIR@
 DEFS = @DEFS@
 DEPDIR = @DEPDIR@
 DHCLIENT_PATH = @DHCLIENT_PATH@
-DHCLIENT_VERSION = @DHCLIENT_VERSION@
 DHCPCD_PATH = @DHCPCD_PATH@
-DISABLE_DEPRECATED = @DISABLE_DEPRECATED@
 DLLTOOL = @DLLTOOL@
 DSYMUTIL = @DSYMUTIL@
 DUMPBIN = @DUMPBIN@
@@ -194,17 +202,14 @@ ECHO_T = @ECHO_T@
 EGREP = @EGREP@
 EXEEXT = @EXEEXT@
 FGREP = @FGREP@
+GENHTML = @GENHTML@
 GETTEXT_MACRO_VERSION = @GETTEXT_MACRO_VERSION@
 GETTEXT_PACKAGE = @GETTEXT_PACKAGE@
-GIO_CFLAGS = @GIO_CFLAGS@
-GIO_LIBS = @GIO_LIBS@
 GLIB_CFLAGS = @GLIB_CFLAGS@
 GLIB_GENMARSHAL = @GLIB_GENMARSHAL@
 GLIB_LIBS = @GLIB_LIBS@
 GLIB_MAKEFILE = @GLIB_MAKEFILE@
 GLIB_MKENUMS = @GLIB_MKENUMS@
-GMODULE_CFLAGS = @GMODULE_CFLAGS@
-GMODULE_LIBS = @GMODULE_LIBS@
 GMSGFMT = @GMSGFMT@
 GMSGFMT_015 = @GMSGFMT_015@
 GNUTLS_CFLAGS = @GNUTLS_CFLAGS@
@@ -245,6 +250,7 @@ IPTABLES_PATH = @IPTABLES_PATH@
 IWMX_SDK_CFLAGS = @IWMX_SDK_CFLAGS@
 IWMX_SDK_LIBS = @IWMX_SDK_LIBS@
 KERNEL_FIRMWARE_DIR = @KERNEL_FIRMWARE_DIR@
+LCOV = @LCOV@
 LD = @LD@
 LDFLAGS = @LDFLAGS@
 LIBDL = @LIBDL@
@@ -261,11 +267,7 @@ LIBNL2_LIBS = @LIBNL2_LIBS@
 LIBNL3_CFLAGS = @LIBNL3_CFLAGS@
 LIBNL3_LIBS = @LIBNL3_LIBS@
 LIBNL_CFLAGS = @LIBNL_CFLAGS@
-LIBNL_GENL3_CFLAGS = @LIBNL_GENL3_CFLAGS@
-LIBNL_GENL3_LIBS = @LIBNL_GENL3_LIBS@
 LIBNL_LIBS = @LIBNL_LIBS@
-LIBNL_ROUTE3_CFLAGS = @LIBNL_ROUTE3_CFLAGS@
-LIBNL_ROUTE3_LIBS = @LIBNL_ROUTE3_LIBS@
 LIBOBJS = @LIBOBJS@
 LIBS = @LIBS@
 LIBSOUP_CFLAGS = @LIBSOUP_CFLAGS@
@@ -280,6 +282,8 @@ MAINT = @MAINT@
 MAKEINFO = @MAKEINFO@
 MANIFEST_TOOL = @MANIFEST_TOOL@
 MKDIR_P = @MKDIR_P@
+MM_GLIB_CFLAGS = @MM_GLIB_CFLAGS@
+MM_GLIB_LIBS = @MM_GLIB_LIBS@
 MOC = @MOC@
 MSGFMT = @MSGFMT@
 MSGFMT_015 = @MSGFMT_015@
@@ -289,6 +293,7 @@ NMEDIT = @NMEDIT@
 NM_MAJOR_VERSION = @NM_MAJOR_VERSION@
 NM_MICRO_VERSION = @NM_MICRO_VERSION@
 NM_MINOR_VERSION = @NM_MINOR_VERSION@
+NM_MODIFY_SYSTEM_POLICY = @NM_MODIFY_SYSTEM_POLICY@
 NM_VERSION = @NM_VERSION@
 NSS_CFLAGS = @NSS_CFLAGS@
 NSS_LIBS = @NSS_LIBS@
@@ -315,13 +320,14 @@ PPPD_PLUGIN_DIR = @PPPD_PLUGIN_DIR@
 QT_CFLAGS = @QT_CFLAGS@
 QT_LIBS = @QT_LIBS@
 RANLIB = @RANLIB@
-RESOLVCONF_PATH = @RESOLVCONF_PATH@
 SED = @SED@
 SET_MAKE = @SET_MAKE@
 SHELL = @SHELL@
 STRIP = @STRIP@
-SYSTEMD_CFLAGS = @SYSTEMD_CFLAGS@
-SYSTEMD_LIBS = @SYSTEMD_LIBS@
+SYSTEMD_INHIBIT_CFLAGS = @SYSTEMD_INHIBIT_CFLAGS@
+SYSTEMD_INHIBIT_LIBS = @SYSTEMD_INHIBIT_LIBS@
+SYSTEMD_LOGIN_CFLAGS = @SYSTEMD_LOGIN_CFLAGS@
+SYSTEMD_LOGIN_LIBS = @SYSTEMD_LOGIN_LIBS@
 SYSTEM_CA_PATH = @SYSTEM_CA_PATH@
 UDEV_BASE_DIR = @UDEV_BASE_DIR@
 USE_NLS = @USE_NLS@
@@ -376,6 +382,11 @@ localedir = @localedir@
 localstatedir = @localstatedir@
 mandir = @mandir@
 mkdir_p = @mkdir_p@
+nmbinary = @nmbinary@
+nmconfdir = @nmconfdir@
+nmdatadir = @nmdatadir@
+nmrundir = @nmrundir@
+nmstatedir = @nmstatedir@
 oldincludedir = @oldincludedir@
 pdfdir = @pdfdir@
 prefix = @prefix@
@@ -390,29 +401,33 @@ target_alias = @target_alias@
 top_build_prefix = @top_build_prefix@
 top_builddir = @top_builddir@
 top_srcdir = @top_srcdir@
-SUBDIRS = keyfiles
-INCLUDES = \
-	-I$(top_srcdir)/include \
-	-I$(top_builddir)/include \
-	-I$(top_srcdir)/libnm-util \
-	-I$(top_builddir)/libnm-util \
-	-I$(top_srcdir)/libnm-glib \
-	-I$(srcdir)/../
-
-test_keyfile_SOURCES = \
-	test-keyfile.c
-
-test_keyfile_CPPFLAGS = \
-	$(GLIB_CFLAGS) \
-	$(DBUS_CFLAGS) \
-	-DTEST_KEYFILES_DIR=\"$(abs_srcdir)/keyfiles\" \
-	-DTEST_SCRATCH_DIR=\"$(abs_builddir)/keyfiles\"
-
-test_keyfile_LDADD = \
-	$(builddir)/../libkeyfile-io.la \
-	$(top_builddir)/libnm-glib/libnm-glib.la \
-	$(top_builddir)/libnm-util/libnm-util.la \
-	$(DBUS_LIBS)
+with_dhclient = @with_dhclient@
+with_dhcpcd = @with_dhcpcd@
+with_netconfig = @with_netconfig@
+with_resolvconf = @with_resolvconf@
+@ENABLE_TESTS_TRUE@SUBDIRS = keyfiles
+@ENABLE_TESTS_TRUE@INCLUDES = \
+@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$(srcdir)/../
+
+@ENABLE_TESTS_TRUE@test_keyfile_SOURCES = \
+@ENABLE_TESTS_TRUE@	test-keyfile.c
+
+@ENABLE_TESTS_TRUE@test_keyfile_CPPFLAGS = \
+@ENABLE_TESTS_TRUE@	$(GLIB_CFLAGS) \
+@ENABLE_TESTS_TRUE@	$(DBUS_CFLAGS) \
+@ENABLE_TESTS_TRUE@	-DTEST_KEYFILES_DIR=\"$(abs_srcdir)/keyfiles\" \
+@ENABLE_TESTS_TRUE@	-DTEST_SCRATCH_DIR=\"$(abs_builddir)/keyfiles\"
+
+@ENABLE_TESTS_TRUE@test_keyfile_LDADD = \
+@ENABLE_TESTS_TRUE@	$(builddir)/../libkeyfile-io.la \
+@ENABLE_TESTS_TRUE@	$(top_builddir)/libnm-glib/libnm-glib.la \
+@ENABLE_TESTS_TRUE@	$(top_builddir)/libnm-util/libnm-util.la \
+@ENABLE_TESTS_TRUE@	$(DBUS_LIBS)
 
 all: all-recursive
 
@@ -470,25 +485,22 @@ distclean-compile:
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/test_keyfile-test-keyfile.Po@am__quote@
 
 .c.o:
-@am__fastdepCC_TRUE@	$(AM_V_CC)depbase=`echo $@ | sed 's|[^/]*$$|$(DEPDIR)/&|;s|\.o$$||'`;\
-@am__fastdepCC_TRUE@	$(COMPILE) -MT $@ -MD -MP -MF $$depbase.Tpo -c -o $@ $< &&\
-@am__fastdepCC_TRUE@	$(am__mv) $$depbase.Tpo $$depbase.Po
+@am__fastdepCC_TRUE@	$(AM_V_CC)$(COMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $<
+@am__fastdepCC_TRUE@	$(AM_V_at)$(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po
 @AMDEP_TRUE@@am__fastdepCC_FALSE@	$(AM_V_CC)source='$<' object='$@' libtool=no @AMDEPBACKSLASH@
 @AMDEP_TRUE@@am__fastdepCC_FALSE@	DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
-@am__fastdepCC_FALSE@	$(AM_V_CC@am__nodep@)$(COMPILE) -c -o $@ $<
+@am__fastdepCC_FALSE@	$(AM_V_CC@am__nodep@)$(COMPILE) -c $<
 
 .c.obj:
-@am__fastdepCC_TRUE@	$(AM_V_CC)depbase=`echo $@ | sed 's|[^/]*$$|$(DEPDIR)/&|;s|\.obj$$||'`;\
-@am__fastdepCC_TRUE@	$(COMPILE) -MT $@ -MD -MP -MF $$depbase.Tpo -c -o $@ `$(CYGPATH_W) '$<'` &&\
-@am__fastdepCC_TRUE@	$(am__mv) $$depbase.Tpo $$depbase.Po
+@am__fastdepCC_TRUE@	$(AM_V_CC)$(COMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ `$(CYGPATH_W) '$<'`
+@am__fastdepCC_TRUE@	$(AM_V_at)$(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po
 @AMDEP_TRUE@@am__fastdepCC_FALSE@	$(AM_V_CC)source='$<' object='$@' libtool=no @AMDEPBACKSLASH@
 @AMDEP_TRUE@@am__fastdepCC_FALSE@	DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
-@am__fastdepCC_FALSE@	$(AM_V_CC@am__nodep@)$(COMPILE) -c -o $@ `$(CYGPATH_W) '$<'`
+@am__fastdepCC_FALSE@	$(AM_V_CC@am__nodep@)$(COMPILE) -c `$(CYGPATH_W) '$<'`
 
 .c.lo:
-@am__fastdepCC_TRUE@	$(AM_V_CC)depbase=`echo $@ | sed 's|[^/]*$$|$(DEPDIR)/&|;s|\.lo$$||'`;\
-@am__fastdepCC_TRUE@	$(LTCOMPILE) -MT $@ -MD -MP -MF $$depbase.Tpo -c -o $@ $< &&\
-@am__fastdepCC_TRUE@	$(am__mv) $$depbase.Tpo $$depbase.Plo
+@am__fastdepCC_TRUE@	$(AM_V_CC)$(LTCOMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $<
+@am__fastdepCC_TRUE@	$(AM_V_at)$(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Plo
 @AMDEP_TRUE@@am__fastdepCC_FALSE@	$(AM_V_CC)source='$<' object='$@' libtool=yes @AMDEPBACKSLASH@
 @AMDEP_TRUE@@am__fastdepCC_FALSE@	DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
 @am__fastdepCC_FALSE@	$(AM_V_CC@am__nodep@)$(LTCOMPILE) -c -o $@ $<
@@ -703,7 +715,7 @@ distdir: $(DISTFILES)
 	      || exit 1; \
 	  fi; \
 	done
-@WITH_TESTS_FALSE@check-local:
+@ENABLE_TESTS_FALSE@check-local:
 check-am: all-am
 	$(MAKE) $(AM_MAKEFLAGS) check-local
 check: check-recursive
@@ -830,8 +842,8 @@ uninstall-am:
 	tags tags-recursive uninstall uninstall-am
 
 
-@WITH_TESTS_TRUE@check-local: test-keyfile
-@WITH_TESTS_TRUE@	$(abs_builddir)/test-keyfile
+@ENABLE_TESTS_TRUE@check-local: test-keyfile
+@ENABLE_TESTS_TRUE@	$(abs_builddir)/test-keyfile
 
 # Tell versions [3.59,3.63) of GNU make to not export all variables.
 # Otherwise a system limit (for SysV at least) may be exceeded.
diff --git a/src/settings/plugins/keyfile/tests/keyfiles/Makefile.am b/src/settings/plugins/keyfile/tests/keyfiles/Makefile.am
index f163312e..759b29f4 100644
--- a/src/settings/plugins/keyfile/tests/keyfiles/Makefile.am
+++ b/src/settings/plugins/keyfile/tests/keyfiles/Makefile.am
@@ -14,7 +14,9 @@ KEYFILES = \
 	Test_Wired_TLS_New \
 	Test_Wired_TLS_Blob \
 	Test_Wired_TLS_Path_Missing \
-	Test_InfiniBand_Connection
+	Test_InfiniBand_Connection \
+	Test_Bridge_Main \
+	Test_Bridge_Component
 
 CERTS = \
 	test-ca-cert.pem \
diff --git a/src/settings/plugins/keyfile/tests/keyfiles/Makefile.in b/src/settings/plugins/keyfile/tests/keyfiles/Makefile.in
index 930d9af5..0f0a0445 100644
--- a/src/settings/plugins/keyfile/tests/keyfiles/Makefile.in
+++ b/src/settings/plugins/keyfile/tests/keyfiles/Makefile.in
@@ -54,16 +54,18 @@ subdir = src/settings/plugins/keyfile/tests/keyfiles
 DIST_COMMON = $(srcdir)/Makefile.am $(srcdir)/Makefile.in
 ACLOCAL_M4 = $(top_srcdir)/aclocal.m4
 am__aclocal_m4_deps = $(top_srcdir)/m4/compiler_warnings.m4 \
-	$(top_srcdir)/m4/gettext.m4 $(top_srcdir)/m4/gtk-doc.m4 \
-	$(top_srcdir)/m4/iconv.m4 $(top_srcdir)/m4/intlmacosx.m4 \
-	$(top_srcdir)/m4/intltool.m4 $(top_srcdir)/m4/introspection.m4 \
-	$(top_srcdir)/m4/lib-ld.m4 $(top_srcdir)/m4/lib-link.m4 \
-	$(top_srcdir)/m4/lib-prefix.m4 $(top_srcdir)/m4/libnl-check.m4 \
-	$(top_srcdir)/m4/libtool.m4 $(top_srcdir)/m4/ltoptions.m4 \
-	$(top_srcdir)/m4/ltsugar.m4 $(top_srcdir)/m4/ltversion.m4 \
-	$(top_srcdir)/m4/lt~obsolete.m4 $(top_srcdir)/m4/nls.m4 \
-	$(top_srcdir)/m4/po.m4 $(top_srcdir)/m4/progtest.m4 \
-	$(top_srcdir)/m4/vapigen.m4 $(top_srcdir)/configure.ac
+	$(top_srcdir)/m4/gettext.m4 \
+	$(top_srcdir)/m4/gnome-code-coverage.m4 \
+	$(top_srcdir)/m4/gtk-doc.m4 $(top_srcdir)/m4/iconv.m4 \
+	$(top_srcdir)/m4/intlmacosx.m4 $(top_srcdir)/m4/intltool.m4 \
+	$(top_srcdir)/m4/introspection.m4 $(top_srcdir)/m4/lib-ld.m4 \
+	$(top_srcdir)/m4/lib-link.m4 $(top_srcdir)/m4/lib-prefix.m4 \
+	$(top_srcdir)/m4/libnl-check.m4 $(top_srcdir)/m4/libtool.m4 \
+	$(top_srcdir)/m4/ltoptions.m4 $(top_srcdir)/m4/ltsugar.m4 \
+	$(top_srcdir)/m4/ltversion.m4 $(top_srcdir)/m4/lt~obsolete.m4 \
+	$(top_srcdir)/m4/nls.m4 $(top_srcdir)/m4/po.m4 \
+	$(top_srcdir)/m4/progtest.m4 $(top_srcdir)/m4/vapigen.m4 \
+	$(top_srcdir)/configure.ac
 am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \
 	$(ACLOCAL_M4)
 mkinstalldirs = $(install_sh) -d
@@ -96,6 +98,10 @@ AWK = @AWK@
 CC = @CC@
 CCDEPMODE = @CCDEPMODE@
 CFLAGS = @CFLAGS@
+CKDB_PATH = @CKDB_PATH@
+CODE_COVERAGE_CFLAGS = @CODE_COVERAGE_CFLAGS@
+CODE_COVERAGE_ENABLED = @CODE_COVERAGE_ENABLED@
+CODE_COVERAGE_LDFLAGS = @CODE_COVERAGE_LDFLAGS@
 CPP = @CPP@
 CPPFLAGS = @CPPFLAGS@
 CXX = @CXX@
@@ -110,9 +116,7 @@ DBUS_SYS_DIR = @DBUS_SYS_DIR@
 DEFS = @DEFS@
 DEPDIR = @DEPDIR@
 DHCLIENT_PATH = @DHCLIENT_PATH@
-DHCLIENT_VERSION = @DHCLIENT_VERSION@
 DHCPCD_PATH = @DHCPCD_PATH@
-DISABLE_DEPRECATED = @DISABLE_DEPRECATED@
 DLLTOOL = @DLLTOOL@
 DSYMUTIL = @DSYMUTIL@
 DUMPBIN = @DUMPBIN@
@@ -122,17 +126,14 @@ ECHO_T = @ECHO_T@
 EGREP = @EGREP@
 EXEEXT = @EXEEXT@
 FGREP = @FGREP@
+GENHTML = @GENHTML@
 GETTEXT_MACRO_VERSION = @GETTEXT_MACRO_VERSION@
 GETTEXT_PACKAGE = @GETTEXT_PACKAGE@
-GIO_CFLAGS = @GIO_CFLAGS@
-GIO_LIBS = @GIO_LIBS@
 GLIB_CFLAGS = @GLIB_CFLAGS@
 GLIB_GENMARSHAL = @GLIB_GENMARSHAL@
 GLIB_LIBS = @GLIB_LIBS@
 GLIB_MAKEFILE = @GLIB_MAKEFILE@
 GLIB_MKENUMS = @GLIB_MKENUMS@
-GMODULE_CFLAGS = @GMODULE_CFLAGS@
-GMODULE_LIBS = @GMODULE_LIBS@
 GMSGFMT = @GMSGFMT@
 GMSGFMT_015 = @GMSGFMT_015@
 GNUTLS_CFLAGS = @GNUTLS_CFLAGS@
@@ -173,6 +174,7 @@ IPTABLES_PATH = @IPTABLES_PATH@
 IWMX_SDK_CFLAGS = @IWMX_SDK_CFLAGS@
 IWMX_SDK_LIBS = @IWMX_SDK_LIBS@
 KERNEL_FIRMWARE_DIR = @KERNEL_FIRMWARE_DIR@
+LCOV = @LCOV@
 LD = @LD@
 LDFLAGS = @LDFLAGS@
 LIBDL = @LIBDL@
@@ -189,11 +191,7 @@ LIBNL2_LIBS = @LIBNL2_LIBS@
 LIBNL3_CFLAGS = @LIBNL3_CFLAGS@
 LIBNL3_LIBS = @LIBNL3_LIBS@
 LIBNL_CFLAGS = @LIBNL_CFLAGS@
-LIBNL_GENL3_CFLAGS = @LIBNL_GENL3_CFLAGS@
-LIBNL_GENL3_LIBS = @LIBNL_GENL3_LIBS@
 LIBNL_LIBS = @LIBNL_LIBS@
-LIBNL_ROUTE3_CFLAGS = @LIBNL_ROUTE3_CFLAGS@
-LIBNL_ROUTE3_LIBS = @LIBNL_ROUTE3_LIBS@
 LIBOBJS = @LIBOBJS@
 LIBS = @LIBS@
 LIBSOUP_CFLAGS = @LIBSOUP_CFLAGS@
@@ -208,6 +206,8 @@ MAINT = @MAINT@
 MAKEINFO = @MAKEINFO@
 MANIFEST_TOOL = @MANIFEST_TOOL@
 MKDIR_P = @MKDIR_P@
+MM_GLIB_CFLAGS = @MM_GLIB_CFLAGS@
+MM_GLIB_LIBS = @MM_GLIB_LIBS@
 MOC = @MOC@
 MSGFMT = @MSGFMT@
 MSGFMT_015 = @MSGFMT_015@
@@ -217,6 +217,7 @@ NMEDIT = @NMEDIT@
 NM_MAJOR_VERSION = @NM_MAJOR_VERSION@
 NM_MICRO_VERSION = @NM_MICRO_VERSION@
 NM_MINOR_VERSION = @NM_MINOR_VERSION@
+NM_MODIFY_SYSTEM_POLICY = @NM_MODIFY_SYSTEM_POLICY@
 NM_VERSION = @NM_VERSION@
 NSS_CFLAGS = @NSS_CFLAGS@
 NSS_LIBS = @NSS_LIBS@
@@ -243,13 +244,14 @@ PPPD_PLUGIN_DIR = @PPPD_PLUGIN_DIR@
 QT_CFLAGS = @QT_CFLAGS@
 QT_LIBS = @QT_LIBS@
 RANLIB = @RANLIB@
-RESOLVCONF_PATH = @RESOLVCONF_PATH@
 SED = @SED@
 SET_MAKE = @SET_MAKE@
 SHELL = @SHELL@
 STRIP = @STRIP@
-SYSTEMD_CFLAGS = @SYSTEMD_CFLAGS@
-SYSTEMD_LIBS = @SYSTEMD_LIBS@
+SYSTEMD_INHIBIT_CFLAGS = @SYSTEMD_INHIBIT_CFLAGS@
+SYSTEMD_INHIBIT_LIBS = @SYSTEMD_INHIBIT_LIBS@
+SYSTEMD_LOGIN_CFLAGS = @SYSTEMD_LOGIN_CFLAGS@
+SYSTEMD_LOGIN_LIBS = @SYSTEMD_LOGIN_LIBS@
 SYSTEM_CA_PATH = @SYSTEM_CA_PATH@
 UDEV_BASE_DIR = @UDEV_BASE_DIR@
 USE_NLS = @USE_NLS@
@@ -304,6 +306,11 @@ localedir = @localedir@
 localstatedir = @localstatedir@
 mandir = @mandir@
 mkdir_p = @mkdir_p@
+nmbinary = @nmbinary@
+nmconfdir = @nmconfdir@
+nmdatadir = @nmdatadir@
+nmrundir = @nmrundir@
+nmstatedir = @nmstatedir@
 oldincludedir = @oldincludedir@
 pdfdir = @pdfdir@
 prefix = @prefix@
@@ -318,6 +325,10 @@ target_alias = @target_alias@
 top_build_prefix = @top_build_prefix@
 top_builddir = @top_builddir@
 top_srcdir = @top_srcdir@
+with_dhclient = @with_dhclient@
+with_dhcpcd = @with_dhcpcd@
+with_netconfig = @with_netconfig@
+with_resolvconf = @with_resolvconf@
 KEYFILES = \
 	Test_Wired_Connection \
 	Test_GSM_Connection \
@@ -334,7 +345,9 @@ KEYFILES = \
 	Test_Wired_TLS_New \
 	Test_Wired_TLS_Blob \
 	Test_Wired_TLS_Path_Missing \
-	Test_InfiniBand_Connection
+	Test_InfiniBand_Connection \
+	Test_Bridge_Main \
+	Test_Bridge_Component
 
 CERTS = \
 	test-ca-cert.pem \
diff --git a/src/settings/plugins/keyfile/tests/keyfiles/Test_Bridge_Component b/src/settings/plugins/keyfile/tests/keyfiles/Test_Bridge_Component
new file mode 100644
index 00000000..f5463ed0
--- /dev/null
+++ b/src/settings/plugins/keyfile/tests/keyfiles/Test_Bridge_Component
@@ -0,0 +1,15 @@
+[connection]
+id=Test Bridge Component
+uuid=d7b4f96c-c45e-4298-bef8-f48574f8c1c0
+type=802-3-ethernet
+master=br0
+slave-type=bridge
+
+[802-3-ethernet]
+mac-address=00:22:15:59:62:97
+
+[bridge-port]
+priority=28
+hairpin-mode=true
+path-cost=100
+
diff --git a/src/settings/plugins/keyfile/tests/keyfiles/Test_Bridge_Main b/src/settings/plugins/keyfile/tests/keyfiles/Test_Bridge_Main
new file mode 100644
index 00000000..7fbbfe22
--- /dev/null
+++ b/src/settings/plugins/keyfile/tests/keyfiles/Test_Bridge_Main
@@ -0,0 +1,17 @@
+[connection]
+id=Test Bridge Main
+uuid=8f061643-fe41-4d4c-a8d9-097d26e2ad3a
+type=bridge
+
+[bridge]
+interface-name=br0
+stp=true
+forward-delay=0
+priority=32744
+hello-time=7
+max-age=39
+ageing-time=235352
+
+[ipv4]
+method=auto
+
diff --git a/src/settings/plugins/keyfile/tests/keyfiles/Test_Wired_Connection b/src/settings/plugins/keyfile/tests/keyfiles/Test_Wired_Connection
index 5785dc24..203441ef 100644
--- a/src/settings/plugins/keyfile/tests/keyfiles/Test_Wired_Connection
+++ b/src/settings/plugins/keyfile/tests/keyfiles/Test_Wired_Connection
@@ -18,6 +18,10 @@ method=manual
 dns=4.2.2.1;4.2.2.2;
 addresses1=192.168.0.5;24;192.168.0.1;
 addresses2=1.2.3.4;16;1.2.1.1;
+address=2.3.4.5/24,2.3.4.6
+address3=3.4.5.6/16
+routes1=1.2.3.0/24,2.3.4.8,99
+route=5.6.7.8/32
 ignore-auto-routes=false
 ignore-auto-dns=false
 
@@ -27,6 +31,10 @@ dns=1111:dddd::aaaa;1::cafe;
 dns-search=super-domain.com;redhat.com;gnu.org;
 addresses1=abcd:1234:ffff::cdde/64
 addresses2=1:2:3:4:5:6:7:8/96
+address=2:3:4:5:6:7:8:9/64,2:3:4:5:1:2:3:4
+address3=3:4:5:6:7:8:9:0/128
 routes1=a:b:c:d::/64;f:e:d:c:1:2:3:4;99;
+route=d:e:f:0:1:2:3:4/64,f:e:d:c:1:2:3:4
+route2=8:7:6:5:4:3:2:1/128
 ignore-auto-routes=false
 ignore-auto-dns=false
diff --git a/src/settings/plugins/keyfile/tests/test-keyfile.c b/src/settings/plugins/keyfile/tests/test-keyfile.c
index 79fa2f9c..8a646e1c 100644
--- a/src/settings/plugins/keyfile/tests/test-keyfile.c
+++ b/src/settings/plugins/keyfile/tests/test-keyfile.c
@@ -50,6 +50,74 @@
 #define TEST_WIRELESS_FILE TEST_KEYFILES_DIR"/Test_Wireless_Connection"
 
 static void
+check_ip4_address (NMSettingIP4Config *config, int idx, const char *address_str, int plen, const char *gateway_str)
+{
+	NMIP4Address *ip4 = nm_setting_ip4_config_get_address (config, idx);
+	struct in_addr address;
+	struct in_addr gateway;
+
+	g_assert (inet_pton (AF_INET, address_str, &address) == 1);
+	g_assert (inet_pton (AF_INET, gateway_str, &gateway) == 1);
+
+	g_assert (ip4);
+	g_assert (nm_ip4_address_get_address (ip4) == address.s_addr);
+	g_assert (nm_ip4_address_get_prefix (ip4) == plen);
+	g_assert (nm_ip4_address_get_gateway (ip4) == gateway.s_addr);
+}
+
+static void
+check_ip6_address (NMSettingIP6Config *config, int idx, const char *address_str, int plen, const char *gateway_str)
+{
+	NMIP6Address *ip6 = nm_setting_ip6_config_get_address (config, idx);
+	struct in6_addr address;
+	struct in6_addr gateway;
+
+	g_assert (inet_pton (AF_INET6, address_str, &address) == 1);
+	g_assert (inet_pton (AF_INET6, gateway_str, &gateway) == 1);
+
+	g_assert (ip6);
+	g_assert (!memcmp (nm_ip6_address_get_address (ip6), &address, sizeof(address)));
+	g_assert (nm_ip6_address_get_prefix (ip6) == plen);
+	g_assert (!memcmp (nm_ip6_address_get_gateway (ip6), &gateway, sizeof(gateway)));
+}
+
+static void
+check_ip4_route (NMSettingIP4Config *config, int idx, const char *destination_str, int plen,
+		const char *nexthop_str, int metric)
+{
+	NMIP4Route *route = nm_setting_ip4_config_get_route (config, idx);
+	struct in_addr destination;
+	struct in_addr nexthop;
+
+	g_assert (inet_pton (AF_INET, destination_str, &destination) == 1);
+	g_assert (inet_pton (AF_INET, nexthop_str, &nexthop) == 1);
+
+	g_assert (route);
+	g_assert (nm_ip4_route_get_dest (route) == destination.s_addr);
+	g_assert (nm_ip4_route_get_prefix (route) == plen);
+	g_assert (nm_ip4_route_get_next_hop (route) == nexthop.s_addr);
+	g_assert (nm_ip4_route_get_metric (route) == metric);
+}
+
+static void
+check_ip6_route (NMSettingIP6Config *config, int idx, const char *destination_str, int plen,
+		const char *next_hop_str, int metric)
+{
+	NMIP6Route *route = nm_setting_ip6_config_get_route (config, idx);
+	struct in6_addr destination;
+	struct in6_addr next_hop;
+
+	g_assert (inet_pton (AF_INET6, destination_str, &destination) == 1);
+	g_assert (inet_pton (AF_INET6, next_hop_str, &next_hop) == 1);
+
+	g_assert (route);
+	g_assert (!memcmp (nm_ip6_route_get_dest (route), &destination, sizeof(destination)));
+	g_assert (nm_ip6_route_get_prefix (route) == plen);
+	g_assert (!memcmp (nm_ip6_route_get_next_hop (route), &next_hop, sizeof(next_hop)));
+	g_assert (nm_ip6_route_get_metric (route) == metric);
+}
+
+static void
 test_read_valid_wired_connection (void)
 {
 	NMConnection *connection;
@@ -68,23 +136,12 @@ test_read_valid_wired_connection (void)
 	const char *expected_dns1 = "4.2.2.1";
 	const char *expected_dns2 = "4.2.2.2";
 	struct in_addr addr;
-	const char *expected_address1 = "192.168.0.5";
-	const char *expected_address2 = "1.2.3.4";
-	const char *expected_address1_gw = "192.168.0.1";
-	const char *expected_address2_gw = "1.2.1.1";
-	NMIP4Address *ip4_addr;
+	struct in6_addr addr6;
 	const char *expected6_dns1 = "1111:dddd::aaaa";
 	const char *expected6_dns2 = "1::cafe";
 	const char *expected6_dnssearch1 = "super-domain.com";
 	const char *expected6_dnssearch2 = "redhat.com";
 	const char *expected6_dnssearch3 = "gnu.org";
-	struct in6_addr addr6;
-	const char *expected6_address1 = "abcd:1234:ffff::cdde";
-	const char *expected6_address2 = "1:2:3:4:5:6:7:8";
-	const char *expected6_route_dest = "a:b:c:d::";
-	const char *expected6_route_nh = "f:e:d:c:1:2:3:4";
-	NMIP6Address *ip6_addr;
-	NMIP6Route *ip6_route;
 
 	connection = nm_keyfile_plugin_connection_from_file (TEST_WIRED_FILE, NULL);
 	ASSERT (connection != NULL,
@@ -219,83 +276,17 @@ test_read_valid_wired_connection (void)
 	        NM_SETTING_IP4_CONFIG_SETTING_NAME,
 	        NM_SETTING_IP4_CONFIG_DNS);
 
-	ASSERT (nm_setting_ip4_config_get_num_addresses (s_ip4) == 2,
-	        "connection-verify-wired", "failed to verify %s: unexpected %s / %s key value",
-	        TEST_WIRED_FILE,
-	        NM_SETTING_IP4_CONFIG_SETTING_NAME,
-	        NM_SETTING_IP4_CONFIG_DNS);
-
-	/* Address #1 */
-	ip4_addr = nm_setting_ip4_config_get_address (s_ip4, 0);
-	ASSERT (ip4_addr,
-	        "connection-verify-wired", "failed to verify %s: missing IP4 address #1",
-	        TEST_WIRED_FILE,
-	        NM_SETTING_IP4_CONFIG_SETTING_NAME,
-	        NM_SETTING_IP4_CONFIG_ADDRESSES);
-
-	ASSERT (nm_ip4_address_get_prefix (ip4_addr) == 24,
-	        "connection-verify-wired", "failed to verify %s: unexpected IP4 address #1 prefix",
-	        TEST_WIRED_FILE,
-	        NM_SETTING_IP4_CONFIG_SETTING_NAME,
-	        NM_SETTING_IP4_CONFIG_ADDRESSES);
-
-	ASSERT (inet_pton (AF_INET, expected_address1, &addr) > 0,
-	        "connection-verify-wired", "failed to verify %s: couldn't convert IP address #1",
-	        TEST_WIRED_FILE,
-	        NM_SETTING_IP4_CONFIG_SETTING_NAME,
-	        NM_SETTING_IP4_CONFIG_DNS);
-	ASSERT (nm_ip4_address_get_address (ip4_addr) == addr.s_addr,
-	        "connection-verify-wired", "failed to verify %s: unexpected IP4 address #1",
-	        TEST_WIRED_FILE,
-	        NM_SETTING_IP4_CONFIG_SETTING_NAME,
-	        NM_SETTING_IP4_CONFIG_ADDRESSES);
-
-	ASSERT (inet_pton (AF_INET, expected_address1_gw, &addr) > 0,
-	        "connection-verify-wired", "failed to verify %s: couldn't convert IP address #1 gateway",
-	        TEST_WIRED_FILE,
-	        NM_SETTING_IP4_CONFIG_SETTING_NAME,
-	        NM_SETTING_IP4_CONFIG_ADDRESSES);
-	ASSERT (nm_ip4_address_get_gateway (ip4_addr) == addr.s_addr,
-	        "connection-verify-wired", "failed to verify %s: unexpected IP4 address #1 gateway",
-	        TEST_WIRED_FILE,
-	        NM_SETTING_IP4_CONFIG_SETTING_NAME,
-	        NM_SETTING_IP4_CONFIG_ADDRESSES);
-	
-	/* Address #2 */
-	ip4_addr = nm_setting_ip4_config_get_address (s_ip4, 1);
-	ASSERT (ip4_addr,
-	        "connection-verify-wired", "failed to verify %s: missing IP4 address #2",
-	        TEST_WIRED_FILE,
-	        NM_SETTING_IP4_CONFIG_SETTING_NAME,
-	        NM_SETTING_IP4_CONFIG_ADDRESSES);
+	/* IPv4 addresses */
+	g_assert (nm_setting_ip4_config_get_num_addresses (s_ip4) == 4);
+	check_ip4_address (s_ip4, 0, "2.3.4.5", 24, "2.3.4.6");
+	check_ip4_address (s_ip4, 1, "192.168.0.5", 24, "192.168.0.1");
+	check_ip4_address (s_ip4, 2, "1.2.3.4", 16, "1.2.1.1");
+	check_ip4_address (s_ip4, 3, "3.4.5.6", 16, "0.0.0.0");
 
-	ASSERT (nm_ip4_address_get_prefix (ip4_addr) == 16,
-	        "connection-verify-wired", "failed to verify %s: unexpected IP4 address #2 prefix",
-	        TEST_WIRED_FILE,
-	        NM_SETTING_IP4_CONFIG_SETTING_NAME,
-	        NM_SETTING_IP4_CONFIG_ADDRESSES);
-
-	ASSERT (inet_pton (AF_INET, expected_address2, &addr) > 0,
-	        "connection-verify-wired", "failed to verify %s: couldn't convert IP address #2",
-	        TEST_WIRED_FILE,
-	        NM_SETTING_IP4_CONFIG_SETTING_NAME,
-	        NM_SETTING_IP4_CONFIG_DNS);
-	ASSERT (nm_ip4_address_get_address (ip4_addr) == addr.s_addr,
-	        "connection-verify-wired", "failed to verify %s: unexpected IP4 address #2",
-	        TEST_WIRED_FILE,
-	        NM_SETTING_IP4_CONFIG_SETTING_NAME,
-	        NM_SETTING_IP4_CONFIG_ADDRESSES);
-
-	ASSERT (inet_pton (AF_INET, expected_address2_gw, &addr) > 0,
-	        "connection-verify-wired", "failed to verify %s: couldn't convert IP address #2 gateway",
-	        TEST_WIRED_FILE,
-	        NM_SETTING_IP4_CONFIG_SETTING_NAME,
-	        NM_SETTING_IP4_CONFIG_ADDRESSES);
-	ASSERT (nm_ip4_address_get_gateway (ip4_addr) == addr.s_addr,
-	        "connection-verify-wired", "failed to verify %s: unexpected IP4 address #2 gateway",
-	        TEST_WIRED_FILE,
-	        NM_SETTING_IP4_CONFIG_SETTING_NAME,
-	        NM_SETTING_IP4_CONFIG_ADDRESSES);
+	/* IPv4 routes */
+	g_assert (nm_setting_ip4_config_get_num_routes (s_ip4) == 2);
+	check_ip4_route (s_ip4, 0, "5.6.7.8", 32, "0.0.0.0", 0);
+	check_ip4_route (s_ip4, 1, "1.2.3.0", 24, "2.3.4.8", 99);
 
 	/* ===== IPv6 SETTING ===== */
 
@@ -342,12 +333,6 @@ test_read_valid_wired_connection (void)
 	        NM_SETTING_IP6_CONFIG_SETTING_NAME,
 	        NM_SETTING_IP6_CONFIG_DNS);
 
-	ASSERT (nm_setting_ip6_config_get_num_addresses (s_ip6) == 2,
-	        "connection-verify-wired", "failed to verify %s: unexpected %s / %s key value",
-	        TEST_WIRED_FILE,
-	        NM_SETTING_IP6_CONFIG_SETTING_NAME,
-	        NM_SETTING_IP6_CONFIG_DNS);
-
 	/* DNS Searches */
 	ASSERT (nm_setting_ip6_config_get_num_dns_searches (s_ip6) == 3,
 	        "connection-verify-wired", "failed to verify %s: unexpected %s / %s key value",
@@ -371,98 +356,18 @@ test_read_valid_wired_connection (void)
 	        NM_SETTING_IP6_CONFIG_SETTING_NAME,
 	        NM_SETTING_IP6_CONFIG_DNS_SEARCH);
 
-	/* Address #1 */
-	ip6_addr = nm_setting_ip6_config_get_address (s_ip6, 0);
-	ASSERT (ip6_addr,
-	        "connection-verify-wired", "failed to verify %s: missing IP6 address #1",
-	        TEST_WIRED_FILE,
-	        NM_SETTING_IP6_CONFIG_SETTING_NAME,
-	        NM_SETTING_IP6_CONFIG_ADDRESSES);
-
-	ASSERT (nm_ip6_address_get_prefix (ip6_addr) == 64,
-	        "connection-verify-wired", "failed to verify %s: unexpected IP6 address #1 prefix",
-	        TEST_WIRED_FILE,
-	        NM_SETTING_IP6_CONFIG_SETTING_NAME,
-	        NM_SETTING_IP6_CONFIG_ADDRESSES);
-
-	ASSERT (inet_pton (AF_INET6, expected6_address1, &addr6) > 0,
-	        "connection-verify-wired", "failed to verify %s: couldn't convert IP address #1",
-	        TEST_WIRED_FILE,
-	        NM_SETTING_IP6_CONFIG_SETTING_NAME,
-	        NM_SETTING_IP6_CONFIG_DNS);
-	ASSERT (IN6_ARE_ADDR_EQUAL (nm_ip6_address_get_address (ip6_addr), &addr6),
-	        "connection-verify-wired", "failed to verify %s: unexpected IP4 address #1",
-	        TEST_WIRED_FILE,
-	        NM_SETTING_IP6_CONFIG_SETTING_NAME,
-	        NM_SETTING_IP6_CONFIG_ADDRESSES);
-
-	/* Address #2 */
-	ip6_addr = nm_setting_ip6_config_get_address (s_ip6, 1);
-	ASSERT (ip6_addr,
-	        "connection-verify-wired", "failed to verify %s: missing IP6 address #2",
-	        TEST_WIRED_FILE,
-	        NM_SETTING_IP6_CONFIG_SETTING_NAME,
-	        NM_SETTING_IP6_CONFIG_ADDRESSES);
-
-	ASSERT (nm_ip6_address_get_prefix (ip6_addr) == 96,
-	        "connection-verify-wired", "failed to verify %s: unexpected IP6 address #2 prefix",
-	        TEST_WIRED_FILE,
-	        NM_SETTING_IP6_CONFIG_SETTING_NAME,
-	        NM_SETTING_IP6_CONFIG_ADDRESSES);
-
-	ASSERT (inet_pton (AF_INET6, expected6_address2, &addr6) > 0,
-	        "connection-verify-wired", "failed to verify %s: couldn't convert IP address #2",
-	        TEST_WIRED_FILE,
-	        NM_SETTING_IP6_CONFIG_SETTING_NAME,
-	        NM_SETTING_IP6_CONFIG_DNS);
-	ASSERT (IN6_ARE_ADDR_EQUAL (nm_ip6_address_get_address (ip6_addr), &addr6),
-	        "connection-verify-wired", "failed to verify %s: unexpected IP6 address #2",
-	        TEST_WIRED_FILE,
-	        NM_SETTING_IP6_CONFIG_SETTING_NAME,
-	        NM_SETTING_IP6_CONFIG_ADDRESSES);
+	/* IPv6 addresses */
+	g_assert (nm_setting_ip6_config_get_num_addresses (s_ip6) == 4);
+	check_ip6_address (s_ip6, 0, "2:3:4:5:6:7:8:9", 64, "2:3:4:5:1:2:3:4");
+	check_ip6_address (s_ip6, 1, "abcd:1234:ffff::cdde", 64, "::");
+	check_ip6_address (s_ip6, 2, "1:2:3:4:5:6:7:8", 96, "::");
+	check_ip6_address (s_ip6, 3, "3:4:5:6:7:8:9:0", 128, "::");
 
 	/* Route #1 */
-	ip6_route = nm_setting_ip6_config_get_route (s_ip6, 0);
-	ASSERT (ip6_route,
-	        "connection-verify-wired", "failed to verify %s: missing IP6 route #1",
-	        TEST_WIRED_FILE,
-	        NM_SETTING_IP6_CONFIG_SETTING_NAME,
-	        NM_SETTING_IP6_CONFIG_ROUTES);
-
-	ASSERT (inet_pton (AF_INET6, expected6_route_dest, &addr6) > 0,
-	        "connection-verify-wired", "failed to verify %s: couldn't convert IP route dest #1",
-	        TEST_WIRED_FILE,
-	        NM_SETTING_IP6_CONFIG_SETTING_NAME,
-	        NM_SETTING_IP6_CONFIG_DNS);
-	ASSERT (IN6_ARE_ADDR_EQUAL (nm_ip6_route_get_dest (ip6_route), &addr6),
-	        "connection-verify-wired", "failed to verify %s: unexpected IP4 route dest #1",
-	        TEST_WIRED_FILE,
-	        NM_SETTING_IP6_CONFIG_SETTING_NAME,
-	        NM_SETTING_IP6_CONFIG_ROUTES);
-
-	ASSERT (nm_ip6_route_get_prefix (ip6_route) == 64,
-	        "connection-verify-wired", "failed to verify %s: unexpected IP6 route #1 prefix",
-	        TEST_WIRED_FILE,
-	        NM_SETTING_IP6_CONFIG_SETTING_NAME,
-	        NM_SETTING_IP6_CONFIG_ROUTES);
-
-	ASSERT (inet_pton (AF_INET6, expected6_route_nh, &addr6) > 0,
-	        "connection-verify-wired", "failed to verify %s: couldn't convert IP route next hop #1",
-	        TEST_WIRED_FILE,
-	        NM_SETTING_IP6_CONFIG_SETTING_NAME,
-	        NM_SETTING_IP6_CONFIG_DNS);
-	ASSERT (IN6_ARE_ADDR_EQUAL (nm_ip6_route_get_next_hop (ip6_route), &addr6),
-	        "connection-verify-wired", "failed to verify %s: unexpected IP4 route dest #1",
-	        TEST_WIRED_FILE,
-	        NM_SETTING_IP6_CONFIG_SETTING_NAME,
-	        NM_SETTING_IP6_CONFIG_ROUTES);
-
-	ASSERT (nm_ip6_route_get_metric (ip6_route) == 99,
-	        "connection-verify-wired", "failed to verify %s: unexpected IP6 route #1 metric",
-	        TEST_WIRED_FILE,
-	        NM_SETTING_IP6_CONFIG_SETTING_NAME,
-	        NM_SETTING_IP6_CONFIG_ROUTES);
-
+	g_assert (nm_setting_ip6_config_get_num_routes (s_ip6) == 3);
+	check_ip6_route (s_ip6, 0, "d:e:f:0:1:2:3:4", 64, "f:e:d:c:1:2:3:4", 0);
+	check_ip6_route (s_ip6, 1, "a:b:c:d::", 64, "f:e:d:c:1:2:3:4", 99);
+	check_ip6_route (s_ip6, 2, "8:7:6:5:4:3:2:1", 128, "::", 0);
 	g_object_unref (connection);
 }
 
@@ -733,10 +638,6 @@ test_read_ip6_wired_connection (void)
 	const char *tmp;
 	const char *expected_id = "Test Wired Connection IP6";
 	const char *expected_uuid = "4e80a56d-c99f-4aad-a6dd-b449bc398c57";
-	struct in6_addr addr6;
-	const char *expected6_address1 = "abcd:1234:ffff::cdde";
-	const char *expected6_gw1 = "abcd:1234:ffff::cdd1";
-	NMIP6Address *ip6_addr;
 
 	connection = nm_keyfile_plugin_connection_from_file (TEST_WIRED_IP6_FILE, NULL);
 	ASSERT (connection != NULL,
@@ -825,47 +726,9 @@ test_read_ip6_wired_connection (void)
 	        NM_SETTING_IP6_CONFIG_SETTING_NAME,
 	        NM_SETTING_IP6_CONFIG_METHOD);
 
-	ASSERT (nm_setting_ip6_config_get_num_addresses (s_ip6) == 1,
-	        "connection-verify-wired", "failed to verify %s: unexpected %s / %s key value",
-	        TEST_WIRED_IP6_FILE,
-	        NM_SETTING_IP6_CONFIG_SETTING_NAME,
-	        NM_SETTING_IP6_CONFIG_DNS);
-
-	/* Address #1 */
-	ip6_addr = nm_setting_ip6_config_get_address (s_ip6, 0);
-	ASSERT (ip6_addr,
-	        "connection-verify-wired", "failed to verify %s: missing IP6 address #1",
-	        TEST_WIRED_IP6_FILE,
-	        NM_SETTING_IP6_CONFIG_SETTING_NAME,
-	        NM_SETTING_IP6_CONFIG_ADDRESSES);
-
-	ASSERT (nm_ip6_address_get_prefix (ip6_addr) == 64,
-	        "connection-verify-wired", "failed to verify %s: unexpected IP6 address #1 prefix",
-	        TEST_WIRED_IP6_FILE,
-	        NM_SETTING_IP6_CONFIG_SETTING_NAME,
-	        NM_SETTING_IP6_CONFIG_ADDRESSES);
-
-	ASSERT (inet_pton (AF_INET6, expected6_address1, &addr6) > 0,
-	        "connection-verify-wired", "failed to verify %s: couldn't convert IP address #1",
-	        TEST_WIRED_IP6_FILE,
-	        NM_SETTING_IP6_CONFIG_SETTING_NAME,
-	        NM_SETTING_IP6_CONFIG_ADDRESSES);
-	ASSERT (IN6_ARE_ADDR_EQUAL (nm_ip6_address_get_address (ip6_addr), &addr6),
-	        "connection-verify-wired", "failed to verify %s: unexpected IP4 address #1",
-	        TEST_WIRED_IP6_FILE,
-	        NM_SETTING_IP6_CONFIG_SETTING_NAME,
-	        NM_SETTING_IP6_CONFIG_ADDRESSES);
-
-	ASSERT (inet_pton (AF_INET6, expected6_gw1, &addr6) > 0,
-	        "connection-verify-wired", "failed to verify %s: couldn't convert GW address #1",
-	        TEST_WIRED_IP6_FILE,
-	        NM_SETTING_IP6_CONFIG_SETTING_NAME,
-	        NM_SETTING_IP6_CONFIG_ADDRESSES);
-	ASSERT (IN6_ARE_ADDR_EQUAL (nm_ip6_address_get_gateway (ip6_addr), &addr6),
-	        "connection-verify-wired", "failed to verify %s: unexpected IP4 address #1",
-	        TEST_WIRED_IP6_FILE,
-	        NM_SETTING_IP6_CONFIG_SETTING_NAME,
-	        NM_SETTING_IP6_CONFIG_ADDRESSES);
+	/* IPv6 address */
+	g_assert (nm_setting_ip6_config_get_num_addresses (s_ip6) == 1);
+	check_ip6_address (s_ip6, 0, "abcd:1234:ffff::cdde", 64, "abcd:1234:ffff::cdd1");
 
 	g_object_unref (connection);
 }
@@ -2958,6 +2821,264 @@ test_write_infiniband_connection (void)
 	g_object_unref (connection);
 }
 
+#define TEST_BRIDGE_MAIN_FILE TEST_KEYFILES_DIR"/Test_Bridge_Main"
+
+static void
+test_read_bridge_main (void)
+{
+	NMConnection *connection;
+	NMSettingConnection *s_con;
+	NMSettingIP4Config *s_ip4;
+	NMSettingBridge *s_bridge;
+	GError *error = NULL;
+	const char *expected_id = "Test Bridge Main";
+	const char *expected_uuid = "8f061643-fe41-4d4c-a8d9-097d26e2ad3a";
+	gboolean success;
+
+	connection = nm_keyfile_plugin_connection_from_file (TEST_BRIDGE_MAIN_FILE, &error);
+	g_assert_no_error (error);
+	g_assert (connection);
+	success = nm_connection_verify (connection, &error);
+	g_assert_no_error (error);
+	g_assert (success);
+
+	/* Connection setting */
+	s_con = nm_connection_get_setting_connection (connection);
+	g_assert (s_con);
+	g_assert_cmpstr (nm_setting_connection_get_id (s_con), ==, expected_id);
+	g_assert_cmpstr (nm_setting_connection_get_uuid (s_con), ==, expected_uuid);
+
+	/* IPv4 setting */
+	s_ip4 = nm_connection_get_setting_ip4_config (connection);
+	g_assert (s_ip4);
+	g_assert_cmpstr (nm_setting_ip4_config_get_method (s_ip4), ==, NM_SETTING_IP4_CONFIG_METHOD_AUTO);
+
+	/* Bridge setting */
+	s_bridge = nm_connection_get_setting_bridge (connection);
+	g_assert (s_bridge);
+	g_assert_cmpstr (nm_setting_bridge_get_interface_name (s_bridge), ==, "br0");
+	g_assert_cmpuint (nm_setting_bridge_get_forward_delay (s_bridge), ==, 0);
+	g_assert_cmpuint (nm_setting_bridge_get_stp (s_bridge), ==, TRUE);
+	g_assert_cmpuint (nm_setting_bridge_get_priority (s_bridge), ==, 32744);
+	g_assert_cmpuint (nm_setting_bridge_get_hello_time (s_bridge), ==, 7);
+	g_assert_cmpuint (nm_setting_bridge_get_max_age (s_bridge), ==, 39);
+	g_assert_cmpuint (nm_setting_bridge_get_ageing_time (s_bridge), ==, 235352);
+
+	g_object_unref (connection);
+}
+
+static void
+test_write_bridge_main (void)
+{
+	NMConnection *connection;
+	NMSettingConnection *s_con;
+	NMSettingBridge *s_bridge;
+	NMSettingIP4Config *s_ip4;
+	NMSettingIP6Config *s_ip6;
+	char *uuid;
+	gboolean success;
+	NMConnection *reread;
+	char *testfile = NULL;
+	GError *error = NULL;
+	pid_t owner_grp;
+	uid_t owner_uid;
+
+	connection = nm_connection_new ();
+	g_assert (connection);
+
+	/* Connection setting */
+	s_con = (NMSettingConnection *) nm_setting_connection_new ();
+	g_assert (s_con);
+	nm_connection_add_setting (connection, NM_SETTING (s_con));
+
+	uuid = nm_utils_uuid_generate ();
+	g_object_set (s_con,
+	              NM_SETTING_CONNECTION_ID, "Test Write Bridge Main",
+	              NM_SETTING_CONNECTION_UUID, uuid,
+	              NM_SETTING_CONNECTION_AUTOCONNECT, TRUE,
+	              NM_SETTING_CONNECTION_TYPE, NM_SETTING_BRIDGE_SETTING_NAME,
+	              NULL);
+	g_free (uuid);
+
+	/* Bridge setting */
+	s_bridge = (NMSettingBridge *) nm_setting_bridge_new ();
+	g_assert (s_bridge);
+	nm_connection_add_setting (connection, NM_SETTING (s_bridge));
+
+	g_object_set (s_bridge,
+	              NM_SETTING_BRIDGE_INTERFACE_NAME, "br0",
+	              NULL);
+
+	/* IP4 setting */
+	s_ip4 = (NMSettingIP4Config *) nm_setting_ip4_config_new ();
+	g_assert (s_ip4);
+	nm_connection_add_setting (connection, NM_SETTING (s_ip4));
+	g_object_set (s_ip4,
+	              NM_SETTING_IP4_CONFIG_METHOD, NM_SETTING_IP4_CONFIG_METHOD_MANUAL,
+	              NM_SETTING_IP4_CONFIG_MAY_FAIL, TRUE,
+	              NULL);
+
+	add_one_ip4_address (s_ip4, "1.2.3.4", "1.1.1.1", 24);
+
+	/* IP6 setting */
+	s_ip6 = (NMSettingIP6Config *) nm_setting_ip6_config_new ();
+	g_assert (s_ip6);
+	nm_connection_add_setting (connection, NM_SETTING (s_ip6));
+	g_object_set (s_ip6, NM_SETTING_IP6_CONFIG_METHOD, NM_SETTING_IP6_CONFIG_METHOD_AUTO, NULL);
+
+	/* Write out the connection */
+	owner_uid = geteuid ();
+	owner_grp = getegid ();
+	success = nm_keyfile_plugin_write_test_connection (connection, TEST_SCRATCH_DIR, owner_uid, owner_grp, &testfile, &error);
+	g_assert_no_error (error);
+	g_assert (success);
+	g_assert (testfile);
+
+	/* Read the connection back in and compare it to the one we just wrote out */
+	reread = nm_keyfile_plugin_connection_from_file (testfile, &error);
+	g_assert_no_error (error);
+	g_assert (reread);
+
+	g_assert (nm_connection_compare (connection, reread, NM_SETTING_COMPARE_FLAG_EXACT));
+
+	unlink (testfile);
+	g_free (testfile);
+
+	g_object_unref (reread);
+	g_object_unref (connection);
+}
+
+#define TEST_BRIDGE_COMPONENT_FILE TEST_KEYFILES_DIR"/Test_Bridge_Component"
+
+static void
+test_read_bridge_component (void)
+{
+	NMConnection *connection;
+	NMSettingConnection *s_con;
+	NMSettingBridgePort *s_port;
+	NMSettingWired *s_wired;
+	const GByteArray *array;
+	guint8 expected_mac[ETH_ALEN] = { 0x00, 0x22, 0x15, 0x59, 0x62, 0x97 };
+	GError *error = NULL;
+	const char *expected_id = "Test Bridge Component";
+	const char *expected_uuid = "d7b4f96c-c45e-4298-bef8-f48574f8c1c0";
+	gboolean success;
+
+	connection = nm_keyfile_plugin_connection_from_file (TEST_BRIDGE_COMPONENT_FILE, &error);
+	g_assert_no_error (error);
+	g_assert (connection);
+	success = nm_connection_verify (connection, &error);
+	g_assert_no_error (error);
+	g_assert (success);
+
+	/* Connection setting */
+	s_con = nm_connection_get_setting_connection (connection);
+	g_assert (s_con);
+	g_assert_cmpstr (nm_setting_connection_get_id (s_con), ==, expected_id);
+	g_assert_cmpstr (nm_setting_connection_get_uuid (s_con), ==, expected_uuid);
+	g_assert_cmpstr (nm_setting_connection_get_master (s_con), ==, "br0");
+	g_assert (nm_setting_connection_is_slave_type (s_con, NM_SETTING_BRIDGE_SETTING_NAME));
+
+	/* Wired setting */
+	s_wired = nm_connection_get_setting_wired (connection);
+	g_assert (s_wired);
+	array = nm_setting_wired_get_mac_address (s_wired);
+	g_assert (array);
+	g_assert_cmpint (array->len, ==, ETH_ALEN);
+	g_assert_cmpint (memcmp (array->data, expected_mac, sizeof (expected_mac)), ==, 0);
+
+	/* BridgePort setting */
+	s_port = nm_connection_get_setting_bridge_port (connection);
+	g_assert (s_port);
+	g_assert (nm_setting_bridge_port_get_hairpin_mode (s_port));
+	g_assert_cmpuint (nm_setting_bridge_port_get_priority (s_port), ==, 28);
+	g_assert_cmpuint (nm_setting_bridge_port_get_path_cost (s_port), ==, 100);
+
+	g_object_unref (connection);
+}
+
+static void
+test_write_bridge_component (void)
+{
+	NMConnection *connection;
+	NMSettingConnection *s_con;
+	NMSettingBridgePort *s_port;
+	NMSettingWired *s_wired;
+	char *uuid;
+	GByteArray *mac;
+	guint8 tmpmac[] = { 0x99, 0x88, 0x77, 0x66, 0x55, 0x44 };
+	gboolean success;
+	NMConnection *reread;
+	char *testfile = NULL;
+	GError *error = NULL;
+	pid_t owner_grp;
+	uid_t owner_uid;
+
+	connection = nm_connection_new ();
+	g_assert (connection);
+
+	/* Connection setting */
+	s_con = (NMSettingConnection *) nm_setting_connection_new ();
+	g_assert (s_con);
+	nm_connection_add_setting (connection, NM_SETTING (s_con));
+
+	uuid = nm_utils_uuid_generate ();
+	g_object_set (s_con,
+	              NM_SETTING_CONNECTION_ID, "Test Write Bridge Component",
+	              NM_SETTING_CONNECTION_UUID, uuid,
+	              NM_SETTING_CONNECTION_AUTOCONNECT, TRUE,
+	              NM_SETTING_CONNECTION_TYPE, NM_SETTING_WIRED_SETTING_NAME,
+	              NM_SETTING_CONNECTION_MASTER, "br0",
+	              NM_SETTING_CONNECTION_SLAVE_TYPE, NM_SETTING_BRIDGE_SETTING_NAME,
+	              NULL);
+	g_free (uuid);
+
+	/* Wired setting */
+	s_wired = NM_SETTING_WIRED (nm_setting_wired_new ());
+	g_assert (s_wired);
+	nm_connection_add_setting (connection, NM_SETTING (s_wired));
+
+	mac = g_byte_array_sized_new (ETH_ALEN);
+	g_byte_array_append (mac, &tmpmac[0], sizeof (tmpmac));
+	g_object_set (s_wired,
+	              NM_SETTING_WIRED_MAC_ADDRESS, mac,
+	              NM_SETTING_WIRED_MTU, 1300,
+	              NULL);
+	g_byte_array_free (mac, TRUE);
+
+	/* BridgePort setting */
+	s_port = (NMSettingBridgePort *) nm_setting_bridge_port_new ();
+	g_assert (s_port);
+	nm_connection_add_setting (connection, NM_SETTING (s_port));
+
+	g_object_set (s_port,
+	              NM_SETTING_BRIDGE_PORT_PRIORITY, 3,
+	              NM_SETTING_BRIDGE_PORT_PATH_COST, 99,
+	              NULL);
+
+	/* Write out the connection */
+	owner_uid = geteuid ();
+	owner_grp = getegid ();
+	success = nm_keyfile_plugin_write_test_connection (connection, TEST_SCRATCH_DIR, owner_uid, owner_grp, &testfile, &error);
+	g_assert_no_error (error);
+	g_assert (success);
+	g_assert (testfile);
+
+	/* Read the connection back in and compare it to the one we just wrote out */
+	reread = nm_keyfile_plugin_connection_from_file (testfile, &error);
+	g_assert_no_error (error);
+	g_assert (reread);
+
+	g_assert (nm_connection_compare (connection, reread, NM_SETTING_COMPARE_FLAG_EXACT));
+
+	unlink (testfile);
+	g_free (testfile);
+
+	g_object_unref (reread);
+	g_object_unref (connection);
+}
+
+
 int main (int argc, char **argv)
 {
 	GError *error = NULL;
@@ -3009,6 +3130,11 @@ int main (int argc, char **argv)
 	test_read_infiniband_connection ();
 	test_write_infiniband_connection ();
 
+	test_read_bridge_main ();
+	test_write_bridge_main ();
+	test_read_bridge_component ();
+	test_write_bridge_component ();
+
 	base = g_path_get_basename (argv[0]);
 	fprintf (stdout, "%s: SUCCESS\n", base);
 	g_free (base);
diff --git a/src/settings/plugins/keyfile/writer.c b/src/settings/plugins/keyfile/writer.c
index bbd6a7c3..0b8c1592 100644
--- a/src/settings/plugins/keyfile/writer.c
+++ b/src/settings/plugins/keyfile/writer.c
@@ -16,7 +16,7 @@
  * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
  *
  * Copyright (C) 2008 Novell, Inc.
- * Copyright (C) 2008 - 2011 Red Hat, Inc.
+ * Copyright (C) 2008 - 2012 Red Hat, Inc.
  */
 
 #include <config.h>
@@ -41,7 +41,6 @@
 #include <string.h>
 #include <arpa/inet.h>
 #include <netinet/ether.h>
-#include <ctype.h>
 
 #include "nm-dbus-glib-types.h"
 #include "nm-glib-compat.h"
@@ -116,18 +115,16 @@ write_ip4_values (GKeyFile *file,
                   guint32 addr1_pos,
                   guint32 addr2_pos)
 {
-	char **list = NULL;
+	GString *output;
 	int i, j;
 
-	list = g_new (char *, tuple_len);
-
 	for (i = 0, j = 0; i < array->len; i++, j++) {
 		GArray *tuple = g_ptr_array_index (array, i);
 		gboolean success = TRUE;
 		char *key_name;
 		int k;
 
-		memset (list, 0, tuple_len * sizeof (char *));
+		output = g_string_new ("");
 
 		for (k = 0; k < tuple_len; k++) {
 			if (k == addr1_pos || k == addr2_pos) {
@@ -142,24 +139,23 @@ write_ip4_values (GKeyFile *file,
 					success = FALSE;
 					break;
 				} else {
-					list[k] = g_strdup (buf);
+					g_string_append_printf (output, "%s%s", k == 0 ? "" : ",", buf);
 				}
 			} else {
 				/* prefix, metric */
-				list[k] = g_strdup_printf ("%d", g_array_index (tuple, guint32, k));
+				g_string_append_printf (output, "%c%d", k == 1 ? '/' : ',', g_array_index (tuple, guint32, k));
 			}
 		}
 
 		if (success) {
 			key_name = g_strdup_printf ("%s%d", key, j + 1);
-			g_key_file_set_string_list (file, setting_name, key_name, (const char **) list, tuple_len);
+			g_key_file_set_string (file, setting_name, key_name, output->str);
 			g_free (key_name);
 		}
 
-		for (k = 0; k < tuple_len; k++)
-			g_free (list[k]);
+		g_string_free (output, TRUE);
+
 	}
-	g_free (list);
 }
 
 static void
@@ -177,7 +173,7 @@ ip4_addr_writer (GKeyFile *file,
 
 	array = (GPtrArray *) g_value_get_boxed (value);
 	if (array && array->len)
-		write_ip4_values (file, setting_name, key, array, 3, 0, 2);
+		write_ip4_values (file, setting_name, "address", array, 3, 0, 2);
 }
 
 static void
@@ -195,7 +191,7 @@ ip4_route_writer (GKeyFile *file,
 
 	array = (GPtrArray *) g_value_get_boxed (value);
 	if (array && array->len)
-		write_ip4_values (file, setting_name, key, array, 4, 0, 2);
+		write_ip4_values (file, setting_name, "route", array, 4, 0, 2);
 }
 
 static void
@@ -340,7 +336,7 @@ ip6_addr_writer (GKeyFile *file,
 		ip6_addr = ip6_array_to_addr_prefix (values);
 		if (ip6_addr) {
 			/* Write it out */
-			key_name = g_strdup_printf ("%s%d", key, j++);
+			key_name = g_strdup_printf ("address%d", j++);
 			g_key_file_set_string (file, setting_name, key_name, ip6_addr);
 			g_free (key_name);
 			g_free (ip6_addr);
@@ -358,7 +354,7 @@ ip6_route_writer (GKeyFile *file,
 {
 	GPtrArray *array;
 	const char *setting_name = nm_setting_get_name (setting);
-	char *list[3];
+	GString *output;
 	int i, j;
 
 	g_return_if_fail (G_VALUE_HOLDS (value, DBUS_TYPE_G_ARRAY_OF_IP6_ROUTE));
@@ -371,36 +367,23 @@ ip6_route_writer (GKeyFile *file,
 		GValueArray *values = g_ptr_array_index (array, i);
 		char *key_name;
 		guint32 int_val;
-		char buf[INET6_ADDRSTRLEN + 1];
-		gboolean is_unspec = FALSE;
 
-		memset (list, 0, sizeof (list));
+		output = g_string_new ("");
 
-		/* Address and prefix */
-		list[0] = ip6_array_to_addr_prefix (values);
-		if (!list[0])
-			continue;
-
-		/* Next Hop */
-		if (!ip6_array_to_addr (values, 2, buf, sizeof (buf), &is_unspec))
-			continue;
-		if (is_unspec)
-			continue;
-		list[1] = g_strdup (buf);
+		/* Address, prefix and next hop*/
+		g_string_append (output, ip6_array_to_addr_prefix (values));
 
 		/* Metric */
 		value = g_value_array_get_nth (values, 3);
 		int_val = g_value_get_uint (value);
-		list[2] = g_strdup_printf ("%d", int_val);
+		g_string_append_printf (output, ",%d", int_val);
 
 		/* Write it out */
-		key_name = g_strdup_printf ("%s%d", key, j++);
-		g_key_file_set_string_list (file, setting_name, key_name, (const char **) list, 3);
+		key_name = g_strdup_printf ("route%d", j++);
+		g_key_file_set_string (file, setting_name, key_name, output->str);
 		g_free (key_name);
 
-		g_free (list[0]);
-		g_free (list[1]);
-		g_free (list[2]);
+		g_string_free (output, TRUE);
 	}
 }
 
@@ -500,7 +483,7 @@ ssid_writer (GKeyFile *file,
 	 */
 	for (i = 0; i < array->len; i++) {
 		char c = array->data[i] & 0xFF;
-		if (!isprint (c)) {
+		if (!g_ascii_isprint (c)) {
 			new_format = FALSE;
 			break;
 		}
@@ -816,6 +799,9 @@ static KeyWriter key_writers[] = {
 	{ NM_SETTING_INFINIBAND_SETTING_NAME,
 	  NM_SETTING_INFINIBAND_MAC_ADDRESS,
 	  mac_address_writer },
+	{ NM_SETTING_WIMAX_SETTING_NAME,
+	  NM_SETTING_WIMAX_MAC_ADDRESS,
+	  mac_address_writer },
 	{ NM_SETTING_WIRELESS_SETTING_NAME,
 	  NM_SETTING_WIRELESS_SSID,
 	  ssid_writer },
@@ -1024,8 +1010,15 @@ _internal_write_connection (NMConnection *connection,
 	if (!data)
 		goto out;
 
-	filename = _writer_id_to_filename (id);
-	path = g_build_filename (keyfile_dir, filename, NULL);
+	/* If we have existing file path, use it. Else generate one from
+	 * connection's ID.
+	 */
+	if (existing_path != NULL) {
+		path = g_strdup (existing_path);
+	} else {
+		filename = _writer_id_to_filename (id);
+		path = g_build_filename (keyfile_dir, filename, NULL);
+	}
 
 	/* If a file with this path already exists (but isn't the existing path
 	 * of the connection) then we need another name.  Multiple connections