summary refs log tree commit diff
path: root/libnm-core
diff options
context:
space:
mode:
Diffstat (limited to 'libnm-core')
-rw-r--r--libnm-core/Makefile.in54
-rw-r--r--libnm-core/Makefile.libnm-core2
-rw-r--r--libnm-core/nm-connection.c90
-rw-r--r--libnm-core/nm-core-internal.h21
-rw-r--r--libnm-core/nm-dbus-interface.h2
-rw-r--r--libnm-core/nm-setting-8021x.c140
-rw-r--r--libnm-core/nm-setting-8021x.h6
-rw-r--r--libnm-core/nm-setting-connection.c15
-rw-r--r--libnm-core/nm-setting-ip-config.c14
-rw-r--r--libnm-core/nm-setting-ip-tunnel.c1
-rw-r--r--libnm-core/nm-setting-ip4-config.c44
-rw-r--r--libnm-core/nm-setting-ip6-config.c44
-rw-r--r--libnm-core/nm-setting-private.h13
-rw-r--r--libnm-core/nm-setting-vlan.c9
-rw-r--r--libnm-core/nm-setting.c128
-rw-r--r--libnm-core/nm-simple-connection.c34
-rw-r--r--libnm-core/nm-utils.c83
-rw-r--r--libnm-core/tests/test-general.c58
18 files changed, 536 insertions, 222 deletions
diff --git a/libnm-core/Makefile.in b/libnm-core/Makefile.in
index 7ca647e2..0661fc1e 100644
--- a/libnm-core/Makefile.in
+++ b/libnm-core/Makefile.in
@@ -129,19 +129,20 @@ am__DEPENDENCIES_1 =
 libnm_core_la_DEPENDENCIES = $(am__DEPENDENCIES_1) \
 	$(am__DEPENDENCIES_1) $(am__DEPENDENCIES_2) \
 	$(am__DEPENDENCIES_3)
-am__libnm_core_la_SOURCES_DIST = $(core_build)/nm-core-enum-types.c \
-	$(core)/crypto.c $(core)/nm-connection.c \
-	$(core)/nm-dbus-utils.c $(core)/nm-errors.c \
-	$(core)/nm-keyfile-reader.c $(core)/nm-keyfile-utils.c \
-	$(core)/nm-keyfile-writer.c $(core)/nm-property-compare.c \
-	$(core)/nm-setting-8021x.c $(core)/nm-setting-adsl.c \
-	$(core)/nm-setting-bluetooth.c $(core)/nm-setting-bond.c \
-	$(core)/nm-setting-bridge-port.c $(core)/nm-setting-bridge.c \
-	$(core)/nm-setting-cdma.c $(core)/nm-setting-connection.c \
-	$(core)/nm-setting-dcb.c $(core)/nm-setting-generic.c \
-	$(core)/nm-setting-gsm.c $(core)/nm-setting-infiniband.c \
-	$(core)/nm-setting-ip-config.c $(core)/nm-setting-ip-tunnel.c \
-	$(core)/nm-setting-ip4-config.c \
+am__libnm_core_la_SOURCES_DIST =  \
+	$(top_builddir)/shared/nm-shared-utils.c \
+	$(core_build)/nm-core-enum-types.c $(core)/crypto.c \
+	$(core)/nm-connection.c $(core)/nm-dbus-utils.c \
+	$(core)/nm-errors.c $(core)/nm-keyfile-reader.c \
+	$(core)/nm-keyfile-utils.c $(core)/nm-keyfile-writer.c \
+	$(core)/nm-property-compare.c $(core)/nm-setting-8021x.c \
+	$(core)/nm-setting-adsl.c $(core)/nm-setting-bluetooth.c \
+	$(core)/nm-setting-bond.c $(core)/nm-setting-bridge-port.c \
+	$(core)/nm-setting-bridge.c $(core)/nm-setting-cdma.c \
+	$(core)/nm-setting-connection.c $(core)/nm-setting-dcb.c \
+	$(core)/nm-setting-generic.c $(core)/nm-setting-gsm.c \
+	$(core)/nm-setting-infiniband.c $(core)/nm-setting-ip-config.c \
+	$(core)/nm-setting-ip-tunnel.c $(core)/nm-setting-ip4-config.c \
 	$(core)/nm-setting-ip6-config.c $(core)/nm-setting-macvlan.c \
 	$(core)/nm-setting-olpc-mesh.c $(core)/nm-setting-ppp.c \
 	$(core)/nm-setting-pppoe.c $(core)/nm-setting-serial.c \
@@ -153,14 +154,15 @@ am__libnm_core_la_SOURCES_DIST = $(core_build)/nm-core-enum-types.c \
 	$(core)/nm-setting-wireless.c $(core)/nm-setting.c \
 	$(core)/nm-simple-connection.c $(core)/nm-utils.c \
 	$(core)/nm-vpn-editor-plugin.c $(core)/nm-vpn-plugin-info.c \
-	$(core)/crypto.h $(core)/nm-connection-private.h \
-	$(core)/nm-core-internal.h $(core)/nm-core-types-internal.h \
-	$(core)/nm-keyfile-internal.h $(core)/nm-keyfile-utils.h \
-	$(core)/nm-property-compare.h $(core)/nm-setting-private.h \
-	$(core)/nm-utils-private.h crypto_gnutls.c crypto_nss.c
-am__objects_1 = nm-core-enum-types.lo crypto.lo nm-connection.lo \
-	nm-dbus-utils.lo nm-errors.lo nm-keyfile-reader.lo \
-	nm-keyfile-utils.lo nm-keyfile-writer.lo \
+	$(top_builddir)/shared/nm-shared-utils.h $(core)/crypto.h \
+	$(core)/nm-connection-private.h $(core)/nm-core-internal.h \
+	$(core)/nm-core-types-internal.h $(core)/nm-keyfile-internal.h \
+	$(core)/nm-keyfile-utils.h $(core)/nm-property-compare.h \
+	$(core)/nm-setting-private.h $(core)/nm-utils-private.h \
+	crypto_gnutls.c crypto_nss.c
+am__objects_1 = nm-shared-utils.lo nm-core-enum-types.lo crypto.lo \
+	nm-connection.lo nm-dbus-utils.lo nm-errors.lo \
+	nm-keyfile-reader.lo nm-keyfile-utils.lo nm-keyfile-writer.lo \
 	nm-property-compare.lo nm-setting-8021x.lo nm-setting-adsl.lo \
 	nm-setting-bluetooth.lo nm-setting-bond.lo \
 	nm-setting-bridge-port.lo nm-setting-bridge.lo \
@@ -640,6 +642,7 @@ libnm_core_headers = \
 	$(core)/nm-vpn-plugin-info.h
 
 libnm_core_private_headers = \
+	$(top_builddir)/shared/nm-shared-utils.h \
 	$(core)/crypto.h			\
 	$(core)/nm-connection-private.h		\
 	$(core)/nm-core-internal.h		\
@@ -651,6 +654,7 @@ libnm_core_private_headers = \
 	$(core)/nm-utils-private.h
 
 libnm_core_sources = \
+	$(top_builddir)/shared/nm-shared-utils.c \
 	$(core_build)/nm-core-enum-types.c	\
 	$(core)/crypto.c			\
 	$(core)/nm-connection.c			\
@@ -811,6 +815,7 @@ distclean-compile:
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/nm-setting-wireless-security.Plo@am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/nm-setting-wireless.Plo@am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/nm-setting.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/nm-shared-utils.Plo@am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/nm-simple-connection.Plo@am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/nm-utils.Plo@am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/nm-vpn-editor-plugin.Plo@am__quote@
@@ -837,6 +842,13 @@ distclean-compile:
 @AMDEP_TRUE@@am__fastdepCC_FALSE@	DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
 @am__fastdepCC_FALSE@	$(AM_V_CC@am__nodep@)$(LTCOMPILE) -c -o $@ $<
 
+nm-shared-utils.lo: $(top_builddir)/shared/nm-shared-utils.c
+@am__fastdepCC_TRUE@	$(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT nm-shared-utils.lo -MD -MP -MF $(DEPDIR)/nm-shared-utils.Tpo -c -o nm-shared-utils.lo `test -f '$(top_builddir)/shared/nm-shared-utils.c' || echo '$(srcdir)/'`$(top_builddir)/shared/nm-shared-utils.c
+@am__fastdepCC_TRUE@	$(AM_V_at)$(am__mv) $(DEPDIR)/nm-shared-utils.Tpo $(DEPDIR)/nm-shared-utils.Plo
+@AMDEP_TRUE@@am__fastdepCC_FALSE@	$(AM_V_CC)source='$(top_builddir)/shared/nm-shared-utils.c' object='nm-shared-utils.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@	DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@	$(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o nm-shared-utils.lo `test -f '$(top_builddir)/shared/nm-shared-utils.c' || echo '$(srcdir)/'`$(top_builddir)/shared/nm-shared-utils.c
+
 nm-core-enum-types.lo: $(core_build)/nm-core-enum-types.c
 @am__fastdepCC_TRUE@	$(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT nm-core-enum-types.lo -MD -MP -MF $(DEPDIR)/nm-core-enum-types.Tpo -c -o nm-core-enum-types.lo `test -f '$(core_build)/nm-core-enum-types.c' || echo '$(srcdir)/'`$(core_build)/nm-core-enum-types.c
 @am__fastdepCC_TRUE@	$(AM_V_at)$(am__mv) $(DEPDIR)/nm-core-enum-types.Tpo $(DEPDIR)/nm-core-enum-types.Plo
diff --git a/libnm-core/Makefile.libnm-core b/libnm-core/Makefile.libnm-core
index fe8cc8a6..0038ce23 100644
--- a/libnm-core/Makefile.libnm-core
+++ b/libnm-core/Makefile.libnm-core
@@ -52,6 +52,7 @@ libnm_core_headers =				\
 	$(core)/nm-vpn-plugin-info.h
 
 libnm_core_private_headers =			\
+	$(top_builddir)/shared/nm-shared-utils.h \
 	$(core)/crypto.h			\
 	$(core)/nm-connection-private.h		\
 	$(core)/nm-core-internal.h		\
@@ -63,6 +64,7 @@ libnm_core_private_headers =			\
 	$(core)/nm-utils-private.h
 
 libnm_core_sources =				\
+	$(top_builddir)/shared/nm-shared-utils.c \
 	$(core_build)/nm-core-enum-types.c	\
 	$(core)/crypto.c			\
 	$(core)/nm-connection.c			\
diff --git a/libnm-core/nm-connection.c b/libnm-core/nm-connection.c
index 04e601ce..c03e6265 100644
--- a/libnm-core/nm-connection.c
+++ b/libnm-core/nm-connection.c
@@ -233,9 +233,10 @@ validate_permissions_type (GVariant *variant, GError **error)
 }
 
 /**
- * nm_connection_replace_settings:
+ * _nm_connection_replace_settings:
  * @connection: a #NMConnection
  * @new_settings: a #GVariant of type %NM_VARIANT_TYPE_CONNECTION, with the new settings
+ * @parse_flags: flags.
  * @error: location to store error, or %NULL
  *
  * Replaces @connection's settings with @new_settings (which must be
@@ -244,49 +245,82 @@ validate_permissions_type (GVariant *variant, GError **error)
  *
  * Returns: %TRUE if connection was updated, %FALSE if @new_settings could not
  *   be deserialized (in which case @connection will be unchanged).
+ *   Only exception is the NM_SETTING_PARSE_FLAGS_NORMALIZE flag: if normalization
+ *   fails, the input @connection is already modified and the original settings
+ *   are lost.
  **/
 gboolean
-nm_connection_replace_settings (NMConnection *connection,
-                                GVariant *new_settings,
-                                GError **error)
+_nm_connection_replace_settings (NMConnection *connection,
+                                 GVariant *new_settings,
+                                 NMSettingParseFlags parse_flags,
+                                 GError **error)
 {
 	NMConnectionPrivate *priv;
 	GVariantIter iter;
 	const char *setting_name;
 	GVariant *setting_dict;
 	GSList *settings = NULL, *s;
-	gboolean changed;
+	gboolean changed, success;
 
 	g_return_val_if_fail (NM_IS_CONNECTION (connection), FALSE);
 	g_return_val_if_fail (g_variant_is_of_type (new_settings, NM_VARIANT_TYPE_CONNECTION), FALSE);
 	g_return_val_if_fail (error == NULL || *error == NULL, FALSE);
 
+	nm_assert (!NM_FLAGS_ANY (parse_flags, ~NM_SETTING_PARSE_FLAGS_ALL));
+	nm_assert (!NM_FLAGS_ALL (parse_flags, NM_SETTING_PARSE_FLAGS_STRICT | NM_SETTING_PARSE_FLAGS_BEST_EFFORT));
+
 	priv = NM_CONNECTION_GET_PRIVATE (connection);
 
-	if (!validate_permissions_type (new_settings, error))
+	if (   !NM_FLAGS_HAS (parse_flags, NM_SETTING_PARSE_FLAGS_BEST_EFFORT)
+	    && !validate_permissions_type (new_settings, error))
 		return FALSE;
 
 	g_variant_iter_init (&iter, new_settings);
 	while (g_variant_iter_next (&iter, "{&s@a{sv}}", &setting_name, &setting_dict)) {
+		gs_unref_variant GVariant *setting_dict_free = NULL;
+		GError *local = NULL;
 		NMSetting *setting;
 		GType type;
 
+		setting_dict_free = setting_dict;
+
 		type = nm_setting_lookup_type (setting_name);
 		if (type == G_TYPE_INVALID) {
+			if (NM_FLAGS_HAS (parse_flags, NM_SETTING_PARSE_FLAGS_BEST_EFFORT))
+				continue;
 			g_set_error_literal (error,
 			                     NM_CONNECTION_ERROR,
 			                     NM_CONNECTION_ERROR_INVALID_SETTING,
 			                     _("unknown setting name"));
 			g_prefix_error (error, "%s: ", setting_name);
-			g_variant_unref (setting_dict);
 			g_slist_free_full (settings, g_object_unref);
 			return FALSE;
 		}
 
-		setting = _nm_setting_new_from_dbus (type, setting_dict, new_settings, error);
-		g_variant_unref (setting_dict);
+		for (s = settings; s; s = s->next) {
+			if (G_OBJECT_TYPE (s->data) == type) {
+				if (NM_FLAGS_HAS (parse_flags, NM_SETTING_PARSE_FLAGS_STRICT)) {
+					g_set_error_literal (error,
+					                     NM_CONNECTION_ERROR,
+					                     NM_CONNECTION_ERROR_INVALID_SETTING,
+					                     _("duplicate setting name"));
+					g_prefix_error (error, "%s: ", setting_name);
+					g_slist_free_full (settings, g_object_unref);
+					return FALSE;
+				}
+				/* last wins. */
+				g_object_unref (s->data);
+				settings = g_slist_delete_link (settings, s);
+				break;
+			}
+		}
+
+		setting = _nm_setting_new_from_dbus (type, setting_dict, new_settings, parse_flags, &local);
 
 		if (!setting) {
+			if (NM_FLAGS_HAS (parse_flags, NM_SETTING_PARSE_FLAGS_BEST_EFFORT))
+				continue;
+			g_propagate_error (error, local);
 			g_slist_free_full (settings, g_object_unref);
 			return FALSE;
 		}
@@ -300,14 +334,50 @@ nm_connection_replace_settings (NMConnection *connection,
 	} else
 		changed = (settings != NULL);
 
+	/* Note: @settings might be empty in which case the connection
+	 * has no NMSetting instances... which is fine, just something
+	 * to be aware of. */
 	for (s = settings; s; s = s->next)
 		_nm_connection_add_setting (connection, s->data);
 
 	g_slist_free (settings);
 
+	/* If verification/normalization fails, the original connection
+	 * is already lost. From an API point of view, it would be nicer
+	 * not to touch the input argument if we fail at the end.
+	 * However, that would require creating a temporary connection
+	 * to validate it first. As none of the caller cares about the
+	 * state of the @connection when normalization fails, just do it
+	 * this way. */
+	if (NM_FLAGS_HAS (parse_flags, NM_SETTING_PARSE_FLAGS_NORMALIZE))
+		success = nm_connection_normalize (connection, NULL, NULL, error);
+	else
+		success = TRUE;
+
 	if (changed)
 		g_signal_emit (connection, signals[CHANGED], 0);
-	return TRUE;
+	return success;
+}
+
+/**
+ * nm_connection_replace_settings:
+ * @connection: a #NMConnection
+ * @new_settings: a #GVariant of type %NM_VARIANT_TYPE_CONNECTION, with the new settings
+ * @error: location to store error, or %NULL
+ *
+ * Replaces @connection's settings with @new_settings (which must be
+ * syntactically valid, and describe a known type of connection, but does not
+ * need to result in a connection that passes nm_connection_verify()).
+ *
+ * Returns: %TRUE if connection was updated, %FALSE if @new_settings could not
+ *   be deserialized (in which case @connection will be unchanged).
+ **/
+gboolean
+nm_connection_replace_settings (NMConnection *connection,
+                                GVariant *new_settings,
+                                GError **error)
+{
+	return _nm_connection_replace_settings (connection, new_settings, NM_SETTING_PARSE_FLAGS_NONE, error);
 }
 
 /**
diff --git a/libnm-core/nm-core-internal.h b/libnm-core/nm-core-internal.h
index 3e1236b9..9512ee56 100644
--- a/libnm-core/nm-core-internal.h
+++ b/libnm-core/nm-core-internal.h
@@ -100,6 +100,25 @@
 	 NM_SETTING_SECRET_FLAG_NOT_SAVED | \
 	 NM_SETTING_SECRET_FLAG_NOT_REQUIRED)
 
+typedef enum { /*< skip >*/
+	NM_SETTING_PARSE_FLAGS_NONE                     = 0,
+	NM_SETTING_PARSE_FLAGS_STRICT                   = 1LL << 0,
+	NM_SETTING_PARSE_FLAGS_BEST_EFFORT              = 1LL << 1,
+	NM_SETTING_PARSE_FLAGS_NORMALIZE                = 1LL << 2,
+
+	_NM_SETTING_PARSE_FLAGS_LAST,
+	NM_SETTING_PARSE_FLAGS_ALL                      = ((_NM_SETTING_PARSE_FLAGS_LAST - 1) << 1) - 1,
+} NMSettingParseFlags;
+
+gboolean _nm_connection_replace_settings (NMConnection *connection,
+                                          GVariant *new_settings,
+                                          NMSettingParseFlags parse_flags,
+                                          GError **error);
+
+NMConnection *_nm_simple_connection_new_from_dbus (GVariant      *dict,
+                                                   NMSettingParseFlags parse_flags,
+                                                   GError       **error);
+
 guint32 _nm_setting_get_setting_priority (NMSetting *setting);
 
 gboolean _nm_setting_get_property (NMSetting *setting, const char *name, GValue *value);
@@ -179,8 +198,6 @@ GByteArray *nm_utils_rsa_key_encrypt (const guint8 *data,
                                       char **out_password,
                                       GError **error);
 
-gint64 _nm_utils_ascii_str_to_int64 (const char *str, guint base, gint64 min, gint64 max, gint64 fallback);
-
 gulong _nm_dbus_signal_connect_data (GDBusProxy *proxy,
                                      const char *signal_name,
                                      const GVariantType *signature,
diff --git a/libnm-core/nm-dbus-interface.h b/libnm-core/nm-dbus-interface.h
index 1b16cce5..d76c5640 100644
--- a/libnm-core/nm-dbus-interface.h
+++ b/libnm-core/nm-dbus-interface.h
@@ -669,7 +669,7 @@ typedef enum /*< flags >*/ {
 #define NM_LLDP_ATTR_IEEE_802_1_PVID "ieee-802-1-pvid"
 #define NM_LLDP_ATTR_IEEE_802_1_PPVID "ieee-802-1-ppvid"
 #define NM_LLDP_ATTR_IEEE_802_1_PPVID_FLAGS "ieee-802-1-ppvid-flags"
-#define NM_LLDP_ATTR_IEEE_802_1_VID "ieee-802-1-pvid"
+#define NM_LLDP_ATTR_IEEE_802_1_VID "ieee-802-1-vid"
 #define NM_LLDP_ATTR_IEEE_802_1_VLAN_NAME "ieee-802-1-vlan-name"
 
 #define NM_LLDP_DEST_NEAREST_BRIDGE "nearest-bridge"
diff --git a/libnm-core/nm-setting-8021x.c b/libnm-core/nm-setting-8021x.c
index 0ecb988a..4db420de 100644
--- a/libnm-core/nm-setting-8021x.c
+++ b/libnm-core/nm-setting-8021x.c
@@ -80,6 +80,7 @@ typedef struct {
 	char *ca_path;
 	char *subject_match;
 	GSList *altsubject_matches;
+	char *domain_suffix_match;
 	GBytes *client_cert;
 	char *phase1_peapver;
 	char *phase1_peaplabel;
@@ -90,6 +91,7 @@ typedef struct {
 	char *phase2_ca_path;
 	char *phase2_subject_match;
 	GSList *phase2_altsubject_matches;
+	char *phase2_domain_suffix_match;
 	GBytes *phase2_client_cert;
 	char *password;
 	NMSettingSecretFlags password_flags;
@@ -116,6 +118,7 @@ enum {
 	PROP_CA_PATH,
 	PROP_SUBJECT_MATCH,
 	PROP_ALTSUBJECT_MATCHES,
+	PROP_DOMAIN_SUFFIX_MATCH,
 	PROP_CLIENT_CERT,
 	PROP_PHASE1_PEAPVER,
 	PROP_PHASE1_PEAPLABEL,
@@ -126,6 +129,7 @@ enum {
 	PROP_PHASE2_CA_PATH,
 	PROP_PHASE2_SUBJECT_MATCH,
 	PROP_PHASE2_ALTSUBJECT_MATCHES,
+	PROP_PHASE2_DOMAIN_SUFFIX_MATCH,
 	PROP_PHASE2_CLIENT_CERT,
 	PROP_PASSWORD,
 	PROP_PASSWORD_FLAGS,
@@ -850,6 +854,22 @@ nm_setting_802_1x_clear_altsubject_matches (NMSetting8021x *setting)
 }
 
 /**
+ * nm_setting_802_1x_get_domain_suffix_match:
+ * @setting: the #NMSetting8021x
+ *
+ * Returns: the #NMSetting8021x:domain-suffix-match property.
+ *
+ * Since: 1.2
+ **/
+const char *
+nm_setting_802_1x_get_domain_suffix_match (NMSetting8021x *setting)
+{
+	g_return_val_if_fail (NM_IS_SETTING_802_1X (setting), NULL);
+
+	return NM_SETTING_802_1X_GET_PRIVATE (setting)->domain_suffix_match;
+}
+
+/**
  * nm_setting_802_1x_get_client_cert_scheme:
  * @setting: the #NMSetting8021x
  *
@@ -1299,6 +1319,22 @@ nm_setting_802_1x_get_num_phase2_altsubject_matches (NMSetting8021x *setting)
 }
 
 /**
+ * nm_setting_802_1x_get_phase2_domain_suffix_match:
+ * @setting: the #NMSetting8021x
+ *
+ * Returns: the #NMSetting8021x:phase2-domain-suffix-match property.
+ *
+ * Since: 1.2
+ **/
+const char *
+nm_setting_802_1x_get_phase2_domain_suffix_match (NMSetting8021x *setting)
+{
+	g_return_val_if_fail (NM_IS_SETTING_802_1X (setting), NULL);
+
+	return NM_SETTING_802_1X_GET_PRIVATE (setting)->phase2_domain_suffix_match;
+}
+
+/**
  * nm_setting_802_1x_get_phase2_altsubject_match:
  * @setting: the #NMSettingConnection
  * @i: the zero-based index of the array of "phase 2" altSubjectName matches
@@ -2827,6 +2863,7 @@ finalize (GObject *object)
 	g_free (priv->anonymous_identity);
 	g_free (priv->ca_path);
 	g_free (priv->subject_match);
+	g_free (priv->domain_suffix_match);
 	g_free (priv->phase1_peapver);
 	g_free (priv->phase1_peaplabel);
 	g_free (priv->phase1_fast_provisioning);
@@ -2834,6 +2871,7 @@ finalize (GObject *object)
 	g_free (priv->phase2_autheap);
 	g_free (priv->phase2_ca_path);
 	g_free (priv->phase2_subject_match);
+	g_free (priv->phase2_domain_suffix_match);
 	g_free (priv->password);
 	if (priv->password_raw)
 		g_bytes_unref (priv->password_raw);
@@ -2877,6 +2915,15 @@ set_cert_prop_helper (const GValue *value, const char *prop_name, GError **error
 	return bytes;
 }
 
+static char *
+_g_value_dup_string_not_empty (const GValue *value)
+{
+	const gchar *str;
+
+	str = g_value_get_string (value);
+	return str && str[0] ? g_strdup (str) : NULL;
+}
+
 static void
 set_property (GObject *object, guint prop_id,
               const GValue *value, GParamSpec *pspec)
@@ -2907,8 +2954,7 @@ set_property (GObject *object, guint prop_id,
 			g_bytes_unref (priv->ca_cert);
 		priv->ca_cert = set_cert_prop_helper (value, NM_SETTING_802_1X_CA_CERT, &error);
 		if (error) {
-			g_warning ("Error setting certificate (invalid data): (%d) %s",
-			           error->code, error->message);
+			g_warning ("Error setting certificate (invalid data): %s", error->message);
 			g_error_free (error);
 		}
 		break;
@@ -2918,19 +2964,22 @@ set_property (GObject *object, guint prop_id,
 		break;
 	case PROP_SUBJECT_MATCH:
 		g_free (priv->subject_match);
-		priv->subject_match = g_value_dup_string (value);
+		priv->subject_match = _g_value_dup_string_not_empty (value);
 		break;
 	case PROP_ALTSUBJECT_MATCHES:
 		g_slist_free_full (priv->altsubject_matches, g_free);
 		priv->altsubject_matches = _nm_utils_strv_to_slist (g_value_get_boxed (value), TRUE);
 		break;
+	case PROP_DOMAIN_SUFFIX_MATCH:
+		g_free (priv->domain_suffix_match);
+		priv->domain_suffix_match = _g_value_dup_string_not_empty (value);
+		break;
 	case PROP_CLIENT_CERT:
 		if (priv->client_cert)
 			g_bytes_unref (priv->client_cert);
 		priv->client_cert = set_cert_prop_helper (value, NM_SETTING_802_1X_CLIENT_CERT, &error);
 		if (error) {
-			g_warning ("Error setting certificate (invalid data): (%d) %s",
-			           error->code, error->message);
+			g_warning ("Error setting certificate (invalid data): %s", error->message);
 			g_error_free (error);
 		}
 		break;
@@ -2959,8 +3008,7 @@ set_property (GObject *object, guint prop_id,
 			g_bytes_unref (priv->phase2_ca_cert);
 		priv->phase2_ca_cert = set_cert_prop_helper (value, NM_SETTING_802_1X_PHASE2_CA_CERT, &error);
 		if (error) {
-			g_warning ("Error setting certificate (invalid data): (%d) %s",
-			           error->code, error->message);
+			g_warning ("Error setting certificate (invalid data): %s", error->message);
 			g_error_free (error);
 		}
 		break;
@@ -2970,19 +3018,22 @@ set_property (GObject *object, guint prop_id,
 		break;
 	case PROP_PHASE2_SUBJECT_MATCH:
 		g_free (priv->phase2_subject_match);
-		priv->phase2_subject_match = g_value_dup_string (value);
+		priv->phase2_subject_match = _g_value_dup_string_not_empty (value);
 		break;
 	case PROP_PHASE2_ALTSUBJECT_MATCHES:
 		g_slist_free_full (priv->phase2_altsubject_matches, g_free);
 		priv->phase2_altsubject_matches = _nm_utils_strv_to_slist (g_value_get_boxed (value), TRUE);
 		break;
+	case PROP_PHASE2_DOMAIN_SUFFIX_MATCH:
+		g_free (priv->phase2_domain_suffix_match);
+		priv->phase2_domain_suffix_match = _g_value_dup_string_not_empty (value);
+		break;
 	case PROP_PHASE2_CLIENT_CERT:
 		if (priv->phase2_client_cert)
 			g_bytes_unref (priv->phase2_client_cert);
 		priv->phase2_client_cert = set_cert_prop_helper (value, NM_SETTING_802_1X_PHASE2_CLIENT_CERT, &error);
 		if (error) {
-			g_warning ("Error setting certificate (invalid data): (%d) %s",
-			           error->code, error->message);
+			g_warning ("Error setting certificate (invalid data): %s", error->message);
 			g_error_free (error);
 		}
 		break;
@@ -3006,8 +3057,7 @@ set_property (GObject *object, guint prop_id,
 			g_bytes_unref (priv->private_key);
 		priv->private_key = set_cert_prop_helper (value, NM_SETTING_802_1X_PRIVATE_KEY, &error);
 		if (error) {
-			g_warning ("Error setting private key (invalid data): (%d) %s",
-			           error->code, error->message);
+			g_warning ("Error setting private key (invalid data): %s", error->message);
 			g_error_free (error);
 		}
 		break;
@@ -3023,8 +3073,7 @@ set_property (GObject *object, guint prop_id,
 			g_bytes_unref (priv->phase2_private_key);
 		priv->phase2_private_key = set_cert_prop_helper (value, NM_SETTING_802_1X_PHASE2_PRIVATE_KEY, &error);
 		if (error) {
-			g_warning ("Error setting private key (invalid data): (%d) %s",
-			           error->code, error->message);
+			g_warning ("Error setting private key (invalid data): %s", error->message);
 			g_error_free (error);
 		}
 		break;
@@ -3083,6 +3132,9 @@ get_property (GObject *object, guint prop_id,
 	case PROP_ALTSUBJECT_MATCHES:
 		g_value_take_boxed (value, _nm_utils_slist_to_strv (priv->altsubject_matches, TRUE));
 		break;
+	case PROP_DOMAIN_SUFFIX_MATCH:
+		g_value_set_string (value, priv->domain_suffix_match);
+		break;
 	case PROP_CLIENT_CERT:
 		g_value_set_boxed (value, priv->client_cert);
 		break;
@@ -3113,6 +3165,9 @@ get_property (GObject *object, guint prop_id,
 	case PROP_PHASE2_ALTSUBJECT_MATCHES:
 		g_value_take_boxed (value, _nm_utils_slist_to_strv (priv->phase2_altsubject_matches, TRUE));
 		break;
+	case PROP_PHASE2_DOMAIN_SUFFIX_MATCH:
+		g_value_set_string (value, priv->phase2_domain_suffix_match);
+		break;
 	case PROP_PHASE2_CLIENT_CERT:
 		g_value_set_boxed (value, priv->phase2_client_cert);
 		break;
@@ -3319,7 +3374,9 @@ nm_setting_802_1x_class_init (NMSetting8021xClass *setting_class)
 	 *
 	 * Substring to be matched against the subject of the certificate presented
 	 * by the authentication server. When unset, no verification of the
-	 * authentication server certificate's subject is performed.
+	 * authentication server certificate's subject is performed.  This property
+	 * provides little security, if any, and its use is deprecated in favor of
+	 * NMSetting8021x:domain-suffix-match.
 	 **/
 	/* ---ifcfg-rh---
 	 * property: subject-match
@@ -3357,6 +3414,30 @@ nm_setting_802_1x_class_init (NMSetting8021xClass *setting_class)
 		                     G_PARAM_STATIC_STRINGS));
 
 	/**
+	 * NMSetting8021x:domain-suffix-match:
+	 *
+	 * Constraint for server domain name. If set, this FQDN is used as a suffix
+	 * match requirement for dNSName element(s) of the certificate presented by
+	 * the authentication server.  If a matching dNSName is found, this
+	 * constraint is met.  If no dNSName values are present, this constraint is
+	 * matched against SubjectName CN using same suffix match comparison.
+	 *
+	 * Since: 1.2
+	 **/
+	/* ---ifcfg-rh---
+	 * property: domain-suffix-match
+	 * description: Suffix to match domain of server certificate against.
+	 * variable: IEEE_8021X_DOMAIN_SUFFIX_MATCH(+)
+	 * ---end---
+	 */
+	g_object_class_install_property
+		(object_class, PROP_DOMAIN_SUFFIX_MATCH,
+		 g_param_spec_string (NM_SETTING_802_1X_DOMAIN_SUFFIX_MATCH, "", "",
+		                      NULL,
+		                      G_PARAM_READWRITE |
+		                      G_PARAM_STATIC_STRINGS));
+
+	/**
 	 * NMSetting8021x:client-cert:
 	 *
 	 * Contains the client certificate if used by the EAP method specified in
@@ -3556,7 +3637,9 @@ nm_setting_802_1x_class_init (NMSetting8021xClass *setting_class)
 	 * Substring to be matched against the subject of the certificate presented
 	 * by the authentication server during the inner "phase 2"
 	 * authentication. When unset, no verification of the authentication server
-	 * certificate's subject is performed.
+	 * certificate's subject is performed.  This property provides little security,
+	 * if any, and its use is deprecated in favor of
+	 * NMSetting8021x:phase2-domain-suffix-match.
 	 **/
 	/* ---ifcfg-rh---
 	 * property: phase2-subject-match
@@ -3593,6 +3676,31 @@ nm_setting_802_1x_class_init (NMSetting8021xClass *setting_class)
 		                     G_PARAM_STATIC_STRINGS));
 
 	/**
+	 * NMSetting8021x:phase2-domain-suffix-match:
+	 *
+	 * Constraint for server domain name. If set, this FQDN is used as a suffix
+	 * match requirement for dNSName element(s) of the certificate presented by
+	 * the authentication server during the inner "phase 2" authentication.  If
+	 * a matching dNSName is found, this constraint is met.  If no dNSName
+	 * values are present, this constraint is matched against SubjectName CN
+	 * using same suffix match comparison.
+	 *
+	 * Since: 1.2
+	 **/
+	/* ---ifcfg-rh---
+	 * property: phase2-domain-suffix-match
+	 * description: Suffix to match domain of server certificate for phase 2 against.
+	 * variable: IEEE_8021X_PHASE2_DOMAIN_SUFFIX_MATCH(+)
+	 * ---end---
+	 */
+	g_object_class_install_property
+		(object_class, PROP_PHASE2_DOMAIN_SUFFIX_MATCH,
+		 g_param_spec_string (NM_SETTING_802_1X_PHASE2_DOMAIN_SUFFIX_MATCH, "", "",
+		                      NULL,
+		                      G_PARAM_READWRITE |
+		                      G_PARAM_STATIC_STRINGS));
+
+	/**
 	 * NMSetting8021x:phase2-client-cert:
 	 *
 	 * Contains the "phase 2" client certificate if used by the EAP method
diff --git a/libnm-core/nm-setting-8021x.h b/libnm-core/nm-setting-8021x.h
index da86071a..d8867b92 100644
--- a/libnm-core/nm-setting-8021x.h
+++ b/libnm-core/nm-setting-8021x.h
@@ -89,6 +89,7 @@ typedef enum { /*< underscore_name=nm_setting_802_1x_ck_scheme >*/
 #define NM_SETTING_802_1X_CA_PATH "ca-path"
 #define NM_SETTING_802_1X_SUBJECT_MATCH "subject-match"
 #define NM_SETTING_802_1X_ALTSUBJECT_MATCHES "altsubject-matches"
+#define NM_SETTING_802_1X_DOMAIN_SUFFIX_MATCH "domain-suffix-match"
 #define NM_SETTING_802_1X_CLIENT_CERT "client-cert"
 #define NM_SETTING_802_1X_PHASE1_PEAPVER "phase1-peapver"
 #define NM_SETTING_802_1X_PHASE1_PEAPLABEL "phase1-peaplabel"
@@ -99,6 +100,7 @@ typedef enum { /*< underscore_name=nm_setting_802_1x_ck_scheme >*/
 #define NM_SETTING_802_1X_PHASE2_CA_PATH "phase2-ca-path"
 #define NM_SETTING_802_1X_PHASE2_SUBJECT_MATCH "phase2-subject-match"
 #define NM_SETTING_802_1X_PHASE2_ALTSUBJECT_MATCHES "phase2-altsubject-matches"
+#define NM_SETTING_802_1X_PHASE2_DOMAIN_SUFFIX_MATCH "phase2-domain-suffix-match"
 #define NM_SETTING_802_1X_PHASE2_CLIENT_CERT "phase2-client-cert"
 #define NM_SETTING_802_1X_PASSWORD "password"
 #define NM_SETTING_802_1X_PASSWORD_FLAGS "password-flags"
@@ -190,6 +192,8 @@ void              nm_setting_802_1x_remove_altsubject_match          (NMSetting8
 gboolean          nm_setting_802_1x_remove_altsubject_match_by_value (NMSetting8021x *setting,
                                                                       const char *altsubject_match);
 void              nm_setting_802_1x_clear_altsubject_matches         (NMSetting8021x *setting);
+NM_AVAILABLE_IN_1_2
+const char *      nm_setting_802_1x_get_domain_suffix_match          (NMSetting8021x *setting);
 
 NMSetting8021xCKScheme nm_setting_802_1x_get_client_cert_scheme      (NMSetting8021x *setting);
 GBytes *               nm_setting_802_1x_get_client_cert_blob        (NMSetting8021x *setting);
@@ -231,6 +235,8 @@ void              nm_setting_802_1x_remove_phase2_altsubject_match          (NMS
 gboolean          nm_setting_802_1x_remove_phase2_altsubject_match_by_value (NMSetting8021x *setting,
                                                                              const char *phase2_altsubject_match);
 void              nm_setting_802_1x_clear_phase2_altsubject_matches         (NMSetting8021x *setting);
+NM_AVAILABLE_IN_1_2
+const char *      nm_setting_802_1x_get_phase2_domain_suffix_match          (NMSetting8021x *setting);
 
 NMSetting8021xCKScheme nm_setting_802_1x_get_phase2_client_cert_scheme   (NMSetting8021x *setting);
 GBytes *               nm_setting_802_1x_get_phase2_client_cert_blob     (NMSetting8021x *setting);
diff --git a/libnm-core/nm-setting-connection.c b/libnm-core/nm-setting-connection.c
index 44237d98..e1cd913a 100644
--- a/libnm-core/nm-setting-connection.c
+++ b/libnm-core/nm-setting-connection.c
@@ -1055,11 +1055,13 @@ find_virtual_interface_name (GVariant *connection_dict)
 	return interface_name;
 }
 
-static void
+static gboolean
 nm_setting_connection_set_interface_name (NMSetting *setting,
                                           GVariant *connection_dict,
                                           const char *property,
-                                          GVariant *value)
+                                          GVariant *value,
+                                          NMSettingParseFlags parse_flags,
+                                          GError **error)
 {
 	const char *interface_name;
 
@@ -1074,12 +1076,16 @@ nm_setting_connection_set_interface_name (NMSetting *setting,
 	g_object_set (G_OBJECT (setting),
 	              NM_SETTING_CONNECTION_INTERFACE_NAME, interface_name,
 	              NULL);
+
+	return TRUE;
 }
 
-static void
+static gboolean
 nm_setting_connection_no_interface_name (NMSetting *setting,
                                          GVariant *connection_dict,
-                                         const char *property)
+                                         const char *property,
+                                         NMSettingParseFlags parse_flags,
+                                         GError **error)
 {
 	const char *virtual_interface_name;
 
@@ -1087,6 +1093,7 @@ nm_setting_connection_no_interface_name (NMSetting *setting,
 	g_object_set (G_OBJECT (setting),
 	              NM_SETTING_CONNECTION_INTERFACE_NAME, virtual_interface_name,
 	              NULL);
+	return TRUE;
 }
 
 static gboolean
diff --git a/libnm-core/nm-setting-ip-config.c b/libnm-core/nm-setting-ip-config.c
index bbdb19ff..a69045b3 100644
--- a/libnm-core/nm-setting-ip-config.c
+++ b/libnm-core/nm-setting-ip-config.c
@@ -2464,17 +2464,22 @@ get_property (GObject *object, guint prop_id,
 	}
 }
 
-static void
+static gboolean
 ip_gateway_set (NMSetting  *setting,
                 GVariant   *connection_dict,
                 const char *property,
-                GVariant   *value)
+                GVariant   *value,
+                NMSettingParseFlags parse_flags,
+                GError    **error)
 {
+	/* FIXME: properly handle errors */
+
 	/* Don't set from 'gateway' if we're going to use the gateway in 'addresses' */
 	if (_nm_setting_use_legacy_property (setting, connection_dict, "addresses", "gateway"))
-		return;
+		return TRUE;
 
 	g_object_set (setting, property, g_variant_get_string (value, NULL), NULL);
+	return TRUE;
 }
 
 static void
@@ -2510,6 +2515,9 @@ nm_setting_ip_config_class_init (NMSettingIPConfigClass *setting_class)
 	 *
 	 * For methods that imply no upstream network, such as "shared" or
 	 * "link-local", these properties must be empty.
+	 *
+	 * For IPv4 method "shared", the IP subnet can be configured by adding one
+	 * manual IPv4 address or otherwise 10.42.x.0/24 is chosen.
 	 **/
 	g_object_class_install_property
 		(object_class, PROP_METHOD,
diff --git a/libnm-core/nm-setting-ip-tunnel.c b/libnm-core/nm-setting-ip-tunnel.c
index fa193d75..f75a51b6 100644
--- a/libnm-core/nm-setting-ip-tunnel.c
+++ b/libnm-core/nm-setting-ip-tunnel.c
@@ -544,6 +544,7 @@ finalize (GObject *object)
 	NMSettingIPTunnel *setting = NM_SETTING_IP_TUNNEL (object);
 	NMSettingIPTunnelPrivate *priv = NM_SETTING_IP_TUNNEL_GET_PRIVATE (setting);
 
+	g_free (priv->parent);
 	g_free (priv->local);
 	g_free (priv->remote);
 	g_free (priv->input_key);
diff --git a/libnm-core/nm-setting-ip4-config.c b/libnm-core/nm-setting-ip4-config.c
index b0308e71..9b479a08 100644
--- a/libnm-core/nm-setting-ip4-config.c
+++ b/libnm-core/nm-setting-ip4-config.c
@@ -313,19 +313,23 @@ ip4_addresses_get (NMSetting  *setting,
 	return ret;
 }
 
-static void
+static gboolean
 ip4_addresses_set (NMSetting  *setting,
                    GVariant   *connection_dict,
                    const char *property,
-                   GVariant   *value)
+                   GVariant   *value,
+                   NMSettingParseFlags parse_flags,
+                   GError    **error)
 {
 	GPtrArray *addrs;
 	GVariant *s_ip4;
 	char **labels, *gateway = NULL;
 	int i;
 
+	/* FIXME: properly handle errors */
+
 	if (!_nm_setting_use_legacy_property (setting, connection_dict, "addresses", "address-data"))
-		return;
+		return TRUE;
 
 	addrs = nm_utils_ip4_addresses_from_variant (value, &gateway);
 
@@ -344,6 +348,7 @@ ip4_addresses_set (NMSetting  *setting,
 	              NULL);
 	g_ptr_array_unref (addrs);
 	g_free (gateway);
+	return TRUE;
 }
 
 static GVariant *
@@ -399,21 +404,26 @@ ip4_address_data_get (NMSetting    *setting,
 	return ret;
 }
 
-static void
+static gboolean
 ip4_address_data_set (NMSetting  *setting,
                       GVariant   *connection_dict,
                       const char *property,
-                      GVariant   *value)
+                      GVariant   *value,
+                      NMSettingParseFlags parse_flags,
+                      GError    **error)
 {
 	GPtrArray *addrs;
 
+	/* FIXME: properly handle errors */
+
 	/* Ignore 'address-data' if we're going to process 'addresses' */
 	if (_nm_setting_use_legacy_property (setting, connection_dict, "addresses", "address-data"))
-		return;
+		return TRUE;
 
 	addrs = nm_utils_ip_addresses_from_variant (value, AF_INET);
 	g_object_set (setting, NM_SETTING_IP_CONFIG_ADDRESSES, addrs, NULL);
 	g_ptr_array_unref (addrs);
+	return TRUE;
 }
 
 static GVariant *
@@ -430,20 +440,25 @@ ip4_routes_get (NMSetting  *setting,
 	return ret;
 }
 
-static void
+static gboolean
 ip4_routes_set (NMSetting  *setting,
                 GVariant   *connection_dict,
                 const char *property,
-                GVariant   *value)
+                GVariant   *value,
+                NMSettingParseFlags parse_flags,
+                GError    **error)
 {
 	GPtrArray *routes;
 
+	/* FIXME: properly handle errors */
+
 	if (!_nm_setting_use_legacy_property (setting, connection_dict, "routes", "route-data"))
-		return;
+		return TRUE;
 
 	routes = nm_utils_ip4_routes_from_variant (value);
 	g_object_set (setting, property, routes, NULL);
 	g_ptr_array_unref (routes);
+	return TRUE;
 }
 
 static GVariant *
@@ -461,21 +476,26 @@ ip4_route_data_get (NMSetting    *setting,
 	return ret;
 }
 
-static void
+static gboolean
 ip4_route_data_set (NMSetting  *setting,
                     GVariant   *connection_dict,
                     const char *property,
-                    GVariant   *value)
+                    GVariant   *value,
+                    NMSettingParseFlags parse_flags,
+                    GError    **error)
 {
 	GPtrArray *routes;
 
+	/* FIXME: properly handle errors */
+
 	/* Ignore 'route-data' if we're going to process 'routes' */
 	if (_nm_setting_use_legacy_property (setting, connection_dict, "routes", "route-data"))
-		return;
+		return TRUE;
 
 	routes = nm_utils_ip_routes_from_variant (value, AF_INET);
 	g_object_set (setting, NM_SETTING_IP_CONFIG_ROUTES, routes, NULL);
 	g_ptr_array_unref (routes);
+	return TRUE;
 }
 
 
diff --git a/libnm-core/nm-setting-ip6-config.c b/libnm-core/nm-setting-ip6-config.c
index f2d85084..bab8c535 100644
--- a/libnm-core/nm-setting-ip6-config.c
+++ b/libnm-core/nm-setting-ip6-config.c
@@ -239,17 +239,21 @@ ip6_addresses_get (NMSetting  *setting,
 	return ret;
 }
 
-static void
+static gboolean
 ip6_addresses_set (NMSetting  *setting,
                    GVariant   *connection_dict,
                    const char *property,
-                   GVariant   *value)
+                   GVariant   *value,
+                   NMSettingParseFlags parse_flags,
+                   GError    **error)
 {
 	GPtrArray *addrs;
 	char *gateway = NULL;
 
+	/* FIXME: properly handle errors */
+
 	if (!_nm_setting_use_legacy_property (setting, connection_dict, "addresses", "address-data"))
-		return;
+		return TRUE;
 
 	addrs = nm_utils_ip6_addresses_from_variant (value, &gateway);
 
@@ -259,6 +263,7 @@ ip6_addresses_set (NMSetting  *setting,
 	              NULL);
 	g_ptr_array_unref (addrs);
 	g_free (gateway);
+	return TRUE;
 }
 
 static GVariant *
@@ -276,21 +281,26 @@ ip6_address_data_get (NMSetting    *setting,
 	return ret;
 }
 
-static void
+static gboolean
 ip6_address_data_set (NMSetting  *setting,
                       GVariant   *connection_dict,
                       const char *property,
-                      GVariant   *value)
+                      GVariant   *value,
+                      NMSettingParseFlags parse_flags,
+                      GError    **error)
 {
 	GPtrArray *addrs;
 
+	/* FIXME: properly handle errors */
+
 	/* Ignore 'address-data' if we're going to process 'addresses' */
 	if (_nm_setting_use_legacy_property (setting, connection_dict, "addresses", "address-data"))
-		return;
+		return TRUE;
 
 	addrs = nm_utils_ip_addresses_from_variant (value, AF_INET6);
 	g_object_set (setting, NM_SETTING_IP_CONFIG_ADDRESSES, addrs, NULL);
 	g_ptr_array_unref (addrs);
+	return TRUE;
 }
 
 static GVariant *
@@ -307,20 +317,25 @@ ip6_routes_get (NMSetting  *setting,
 	return ret;
 }
 
-static void
+static gboolean
 ip6_routes_set (NMSetting  *setting,
                 GVariant   *connection_dict,
                 const char *property,
-                GVariant   *value)
+                GVariant   *value,
+                NMSettingParseFlags parse_flags,
+                GError    **error)
 {
 	GPtrArray *routes;
 
+	/* FIXME: properly handle errors */
+
 	if (!_nm_setting_use_legacy_property (setting, connection_dict, "routes", "route-data"))
-		return;
+		return TRUE;
 
 	routes = nm_utils_ip6_routes_from_variant (value);
 	g_object_set (setting, property, routes, NULL);
 	g_ptr_array_unref (routes);
+	return TRUE;
 }
 
 static GVariant *
@@ -338,21 +353,26 @@ ip6_route_data_get (NMSetting    *setting,
 	return ret;
 }
 
-static void
+static gboolean
 ip6_route_data_set (NMSetting  *setting,
                     GVariant   *connection_dict,
                     const char *property,
-                    GVariant   *value)
+                    GVariant   *value,
+                    NMSettingParseFlags parse_flags,
+                    GError    **error)
 {
 	GPtrArray *routes;
 
+	/* FIXME: properly handle errors */
+
 	/* Ignore 'route-data' if we're going to process 'routes' */
 	if (_nm_setting_use_legacy_property (setting, connection_dict, "routes", "route-data"))
-		return;
+		return TRUE;
 
 	routes = nm_utils_ip_routes_from_variant (value, AF_INET6);
 	g_object_set (setting, NM_SETTING_IP_CONFIG_ROUTES, routes, NULL);
 	g_ptr_array_unref (routes);
+	return TRUE;
 }
 
 static void
diff --git a/libnm-core/nm-setting-private.h b/libnm-core/nm-setting-private.h
index cb7ca52e..6560c4a2 100644
--- a/libnm-core/nm-setting-private.h
+++ b/libnm-core/nm-setting-private.h
@@ -126,6 +126,7 @@ GVariant   *_nm_setting_to_dbus       (NMSetting *setting,
 NMSetting  *_nm_setting_new_from_dbus (GType setting_type,
                                        GVariant *setting_dict,
                                        GVariant *connection_dict,
+                                       NMSettingParseFlags parse_flags,
                                        GError **error);
 
 typedef GVariant * (*NMSettingPropertyGetFunc)    (NMSetting     *setting,
@@ -133,13 +134,17 @@ typedef GVariant * (*NMSettingPropertyGetFunc)    (NMSetting     *setting,
 typedef GVariant * (*NMSettingPropertySynthFunc)  (NMSetting     *setting,
                                                    NMConnection  *connection,
                                                    const char    *property);
-typedef void       (*NMSettingPropertySetFunc)    (NMSetting     *setting,
+typedef gboolean   (*NMSettingPropertySetFunc)    (NMSetting     *setting,
                                                    GVariant      *connection_dict,
                                                    const char    *property,
-                                                   GVariant      *value);
-typedef void       (*NMSettingPropertyNotSetFunc) (NMSetting     *setting,
+                                                   GVariant      *value,
+                                                   NMSettingParseFlags parse_flags,
+                                                   GError       **error);
+typedef gboolean   (*NMSettingPropertyNotSetFunc) (NMSetting     *setting,
                                                    GVariant      *connection_dict,
-                                                   const char    *property);
+                                                   const char    *property,
+                                                   NMSettingParseFlags parse_flags,
+                                                   GError       **error);
 
 void _nm_setting_class_add_dbus_only_property (NMSettingClass *setting_class,
                                                const char *property_name,
diff --git a/libnm-core/nm-setting-vlan.c b/libnm-core/nm-setting-vlan.c
index 39587d59..827a47af 100644
--- a/libnm-core/nm-setting-vlan.c
+++ b/libnm-core/nm-setting-vlan.c
@@ -692,16 +692,19 @@ _override_flags_get (NMSetting *setting, const char *property)
 	return g_variant_new_uint32 (nm_setting_vlan_get_flags ((NMSettingVlan *) setting));
 }
 
-static void
+static gboolean
 _override_flags_not_set (NMSetting *setting,
-                          GVariant *connection_dict,
-                          const char *property)
+                         GVariant *connection_dict,
+                         const char *property,
+                         NMSettingParseFlags parse_flags,
+                         GError **error)
 {
 	/* we changed the default value for FLAGS. When an older client
 	 * doesn't serialize the property, we assume it is the old default. */
 	g_object_set (G_OBJECT (setting),
 	              NM_SETTING_VLAN_FLAGS, (NMVlanFlags) 0,
 	              NULL);
+	return TRUE;
 }
 
 static GSList *
diff --git a/libnm-core/nm-setting.c b/libnm-core/nm-setting.c
index fec645b2..0c41bd84 100644
--- a/libnm-core/nm-setting.c
+++ b/libnm-core/nm-setting.c
@@ -774,6 +774,7 @@ _nm_setting_to_dbus (NMSetting *setting, NMConnection *connection, NMConnectionS
  *   mapping property names to values
  * @connection_dict: the #GVariant containing an %NM_VARIANT_TYPE_CONNECTION
  *   dictionary mapping setting names to dictionaries.
+ * @parse_flags: flags to determine behavior during parsing.
  * @error: location to store error, or %NULL
  *
  * Creates a new #NMSetting object and populates that object with the properties
@@ -790,16 +791,20 @@ NMSetting *
 _nm_setting_new_from_dbus (GType setting_type,
                            GVariant *setting_dict,
                            GVariant *connection_dict,
+                           NMSettingParseFlags parse_flags,
                            GError **error)
 {
-	NMSetting *setting;
+	gs_unref_object NMSetting *setting = NULL;
+	gs_unref_hashtable GHashTable *keys = NULL;
 	const NMSettingProperty *properties;
-	guint n_properties;
-	guint i;
+	guint i, n_properties;
 
 	g_return_val_if_fail (G_TYPE_IS_INSTANTIATABLE (setting_type), NULL);
 	g_return_val_if_fail (g_variant_is_of_type (setting_dict, NM_VARIANT_TYPE_SETTING), NULL);
 
+	nm_assert (!NM_FLAGS_ANY (parse_flags, ~NM_SETTING_PARSE_FLAGS_ALL));
+	nm_assert (!NM_FLAGS_ALL (parse_flags, NM_SETTING_PARSE_FLAGS_STRICT | NM_SETTING_PARSE_FLAGS_BEST_EFFORT));
+
 	/* connection_dict is not technically optional, but some tests in test-general
 	 * don't bother with it in cases where they know it's not needed.
 	 */
@@ -813,19 +818,49 @@ _nm_setting_new_from_dbus (GType setting_type,
 	 */
 	setting = (NMSetting *) g_object_new (setting_type, NULL);
 
+	if (NM_FLAGS_HAS (parse_flags, NM_SETTING_PARSE_FLAGS_STRICT)) {
+		GVariantIter iter;
+		GVariant *entry, *entry_key;
+		char *key;
+
+		keys = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, NULL);
+
+		g_variant_iter_init (&iter, setting_dict);
+		while ((entry = g_variant_iter_next_value (&iter))) {
+			entry_key = g_variant_get_child_value (entry, 0);
+			key = g_strdup (g_variant_get_string (entry_key, NULL));
+			g_variant_unref (entry_key);
+			g_variant_unref (entry);
+
+			if (!nm_g_hash_table_add (keys, key)) {
+				g_set_error (error, NM_CONNECTION_ERROR, NM_CONNECTION_ERROR_INVALID_SETTING,
+				             _("duplicate property"));
+				g_prefix_error (error, "%s.%s: ", nm_setting_get_name (setting), key);
+				return NULL;
+			}
+		}
+	}
+
 	properties = nm_setting_class_get_properties (NM_SETTING_GET_CLASS (setting), &n_properties);
 	for (i = 0; i < n_properties; i++) {
 		const NMSettingProperty *property = &properties[i];
-		GVariant *value;
+		gs_unref_variant GVariant *value = NULL;
+		gs_free_error GError *local = NULL;
 
 		if (property->param_spec && !(property->param_spec->flags & G_PARAM_WRITABLE))
 			continue;
 
 		value = g_variant_lookup_value (setting_dict, property->name, NULL);
 
+		if (value && keys)
+			g_hash_table_remove (keys, property->name);
+
 		if (value && property->set_func) {
+
 			if (!g_variant_type_equal (g_variant_get_type (value), property->dbus_type)) {
-			property_type_error:
+				/* for backward behavior, fail unless best-effort is chosen. */
+				if (NM_FLAGS_HAS (parse_flags, NM_SETTING_PARSE_FLAGS_BEST_EFFORT))
+					continue;
 				g_set_error (error, NM_CONNECTION_ERROR, NM_CONNECTION_ERROR_INVALID_PROPERTY,
 				             _("can't set property of type '%s' from value of type '%s'"),
 				             property->dbus_type ?
@@ -834,36 +869,83 @@ _nm_setting_new_from_dbus (GType setting_type,
 				                     g_type_name (property->param_spec->value_type) : "(unknown)",
 				             g_variant_get_type_string (value));
 				g_prefix_error (error, "%s.%s: ", nm_setting_get_name (setting), property->name);
-
-				g_variant_unref (value);
-				g_object_unref (setting);
 				return NULL;
 			}
 
-			property->set_func (setting,
-			                    connection_dict,
-			                    property->name,
-			                    value);
+			if (!property->set_func (setting,
+			                         connection_dict,
+			                         property->name,
+			                         value,
+			                         parse_flags,
+			                         &local)) {
+				if (!NM_FLAGS_HAS (parse_flags, NM_SETTING_PARSE_FLAGS_STRICT))
+					continue;
+				g_set_error (error, NM_CONNECTION_ERROR, NM_CONNECTION_ERROR_INVALID_PROPERTY,
+				             _("failed to set property: %s"),
+				             local->message);
+				g_prefix_error (error, "%s.%s: ", nm_setting_get_name (setting), property->name);
+				return NULL;
+			}
 		} else if (!value && property->not_set_func) {
-			property->not_set_func (setting,
-			                        connection_dict,
-			                        property->name);
+			if (!property->not_set_func (setting,
+			                             connection_dict,
+			                             property->name,
+			                             parse_flags,
+			                             &local)) {
+				if (!NM_FLAGS_HAS (parse_flags, NM_SETTING_PARSE_FLAGS_STRICT))
+					continue;
+				g_set_error (error, NM_CONNECTION_ERROR, NM_CONNECTION_ERROR_INVALID_PROPERTY,
+				             _("failed to set property: %s"),
+				             local->message);
+				g_prefix_error (error, "%s.%s: ", nm_setting_get_name (setting), property->name);
+				return NULL;
+			}
 		} else if (value && property->param_spec) {
-			GValue object_value = { 0, };
+			nm_auto_unset_gvalue GValue object_value = G_VALUE_INIT;
 
 			g_value_init (&object_value, property->param_spec->value_type);
-			if (!set_property_from_dbus (property, value, &object_value))
-				goto property_type_error;
+			if (!set_property_from_dbus (property, value, &object_value)) {
+				/* for backward behavior, fail unless best-effort is chosen. */
+				if (NM_FLAGS_HAS (parse_flags, NM_SETTING_PARSE_FLAGS_BEST_EFFORT))
+					continue;
+				g_set_error (error, NM_CONNECTION_ERROR, NM_CONNECTION_ERROR_INVALID_PROPERTY,
+				             _("can't set property of type '%s' from value of type '%s'"),
+				             property->dbus_type ?
+				                 g_variant_type_peek_string (property->dbus_type) :
+				                 property->param_spec ?
+				                     g_type_name (property->param_spec->value_type) : "(unknown)",
+				             g_variant_get_type_string (value));
+				g_prefix_error (error, "%s.%s: ", nm_setting_get_name (setting), property->name);
+				return NULL;
+			}
 
-			g_object_set_property (G_OBJECT (setting), property->param_spec->name, &object_value);
-			g_value_unset (&object_value);
+			if (!nm_g_object_set_property (G_OBJECT (setting), property->param_spec->name, &object_value, &local)) {
+				if (!NM_FLAGS_HAS (parse_flags, NM_SETTING_PARSE_FLAGS_STRICT))
+					continue;
+				g_set_error (error, NM_CONNECTION_ERROR, NM_CONNECTION_ERROR_INVALID_PROPERTY,
+				             _("can not set property: %s"),
+				             local->message);
+				g_prefix_error (error, "%s.%s: ", nm_setting_get_name (setting), property->name);
+				return NULL;
+			}
 		}
+	}
 
-		if (value)
-			g_variant_unref (value);
+	if (   NM_FLAGS_HAS (parse_flags, NM_SETTING_PARSE_FLAGS_STRICT)
+	    && g_hash_table_size (keys) > 0) {
+		GHashTableIter iter;
+		const char *key;
+
+		g_hash_table_iter_init (&iter, keys);
+		if (g_hash_table_iter_next (&iter, (gpointer *) &key, NULL)) {
+			g_set_error (error, NM_CONNECTION_ERROR, NM_CONNECTION_ERROR_INVALID_PROPERTY,
+			             _("unknown property"));
+			g_prefix_error (error, "%s.%s: ", nm_setting_get_name (setting), key);
+			return NULL;
+		}
 	}
 
-	return setting;
+	return nm_unauto (&setting);
 }
 
 /**
diff --git a/libnm-core/nm-simple-connection.c b/libnm-core/nm-simple-connection.c
index 1036c8ec..11700666 100644
--- a/libnm-core/nm-simple-connection.c
+++ b/libnm-core/nm-simple-connection.c
@@ -51,7 +51,7 @@ nm_simple_connection_new (void)
 }
 
 /**
- * nm_simple_connection_new_from_dbus:
+ * _nm_simple_connection_new_from_dbus:
  * @dict: a #GVariant of type %NM_VARIANT_TYPE_CONNECTION describing the connection
  * @error: on unsuccessful return, an error
  *
@@ -60,25 +60,47 @@ nm_simple_connection_new (void)
  * hash table.
  *
  * Returns: (transfer full): the new #NMSimpleConnection object, populated with
- * settings created from the values in the hash table, or %NULL if the
- * connection failed to validate
+ * settings created from the values in the hash table, or %NULL if there was
+ * an error.
  **/
 NMConnection *
-nm_simple_connection_new_from_dbus (GVariant *dict, GError **error)
+_nm_simple_connection_new_from_dbus (GVariant *dict, NMSettingParseFlags parse_flags, GError **error)
 {
 	NMConnection *connection;
 
 	g_return_val_if_fail (dict != NULL, NULL);
 	g_return_val_if_fail (g_variant_is_of_type (dict, NM_VARIANT_TYPE_CONNECTION), NULL);
+	g_return_val_if_fail (!NM_FLAGS_ANY (parse_flags, ~NM_SETTING_PARSE_FLAGS_ALL), NULL);
+	g_return_val_if_fail (!NM_FLAGS_ALL (parse_flags, NM_SETTING_PARSE_FLAGS_STRICT | NM_SETTING_PARSE_FLAGS_BEST_EFFORT), NULL);
 
 	connection = nm_simple_connection_new ();
-	if (   !nm_connection_replace_settings (connection, dict, error)
-	    || !nm_connection_normalize (connection, NULL, NULL, error))
+	if (!_nm_connection_replace_settings (connection, dict, parse_flags, error))
 		g_clear_object (&connection);
 	return connection;
 }
 
 /**
+ * nm_simple_connection_new_from_dbus:
+ * @dict: a #GVariant of type %NM_VARIANT_TYPE_CONNECTION describing the connection
+ * @error: on unsuccessful return, an error
+ *
+ * Creates a new #NMSimpleConnection from a hash table describing the
+ * connection and normalize the connection.  See nm_connection_to_dbus() for a
+ * description of the expected hash table.
+ *
+ * Returns: (transfer full): the new #NMSimpleConnection object, populated with
+ * settings created from the values in the hash table, or %NULL if the
+ * connection failed to normalize.
+ **/
+NMConnection *
+nm_simple_connection_new_from_dbus (GVariant *dict, GError **error)
+{
+	return _nm_simple_connection_new_from_dbus (dict,
+	                                            NM_SETTING_PARSE_FLAGS_NORMALIZE,
+	                                            error);
+}
+
+/**
  * nm_simple_connection_new_clone:
  * @connection: the #NMConnection to clone
  *
diff --git a/libnm-core/nm-utils.c b/libnm-core/nm-utils.c
index 52d4e8b8..a8467081 100644
--- a/libnm-core/nm-utils.c
+++ b/libnm-core/nm-utils.c
@@ -2084,8 +2084,7 @@ nm_utils_ip_routes_from_variant (GVariant *value,
 		if (   !g_variant_lookup (route_var, "dest", "&s", &dest)
 		    || !g_variant_lookup (route_var, "prefix", "u", &prefix)) {
 			g_warning ("Ignoring invalid address");
-			g_variant_unref (route_var);
-			continue;
+			goto next;
 		}
 		if (!g_variant_lookup (route_var, "next-hop", "&s", &next_hop))
 			next_hop = NULL;
@@ -2098,8 +2097,7 @@ nm_utils_ip_routes_from_variant (GVariant *value,
 		if (!route) {
 			g_warning ("Ignoring invalid route: %s", error->message);
 			g_clear_error (&error);
-			g_variant_unref (route_var);
-			continue;
+			goto next;
 		}
 
 		g_variant_iter_init (&attrs_iter, route_var);
@@ -2113,6 +2111,8 @@ nm_utils_ip_routes_from_variant (GVariant *value,
 		}
 
 		g_ptr_array_add (routes, route);
+next:
+		g_variant_unref (route_var);
 	}
 
 	return routes;
@@ -3789,81 +3789,6 @@ _nm_utils_strstrdictkey_create (const char *v1, const char *v2)
 	return k;
 }
 
-/**********************************************************************************************/
-
-/* _nm_utils_ascii_str_to_int64:
- *
- * A wrapper for g_ascii_strtoll, that checks whether the whole string
- * can be successfully converted to a number and is within a given
- * range. On any error, @fallback will be returned and %errno will be set
- * to a non-zero value. On success, %errno will be set to zero, check %errno
- * for errors. Any trailing or leading (ascii) white space is ignored and the
- * functions is locale independent.
- *
- * The function is guaranteed to return a value between @min and @max
- * (inclusive) or @fallback. Also, the parsing is rather strict, it does
- * not allow for any unrecognized characters, except leading and trailing
- * white space.
- **/
-gint64
-_nm_utils_ascii_str_to_int64 (const char *str, guint base, gint64 min, gint64 max, gint64 fallback)
-{
-	gint64 v;
-	size_t len;
-	char buf[64], *s, *str_free = NULL;
-
-	if (str) {
-		while (g_ascii_isspace (str[0]))
-			str++;
-	}
-	if (!str || !str[0]) {
-		errno = EINVAL;
-		return fallback;
-	}
-
-	len = strlen (str);
-	if (g_ascii_isspace (str[--len])) {
-		/* backward search the first non-ws character.
-		 * We already know that str[0] is non-ws. */
-		while (g_ascii_isspace (str[--len]))
-			;
-
-		/* str[len] is now the last non-ws character... */
-		len++;
-
-		if (len >= sizeof (buf))
-			s = str_free = g_malloc (len + 1);
-		else
-			s = buf;
-
-		memcpy (s, str, len);
-		s[len] = 0;
-
-		nm_assert (len > 0 && len < strlen (str) && len == strlen (s));
-		nm_assert (!g_ascii_isspace (str[len-1]) && g_ascii_isspace (str[len]));
-		nm_assert (strncmp (str, s, len) == 0);
-
-		str = s;
-	}
-
-	errno = 0;
-	v = g_ascii_strtoll (str, &s, base);
-
-	if (errno != 0)
-		v = fallback;
-	else if (s[0] != 0) {
-		errno = EINVAL;
-		v = fallback;
-	} else if (v > max || v < min) {
-		errno = ERANGE;
-		v = fallback;
-	}
-
-	if (G_UNLIKELY (str_free))
-		g_free (str_free);
-	return v;
-}
-
 static gboolean
 validate_dns_option (const char *name, gboolean numeric, gboolean ipv6,
                      const NMUtilsDNSOptionDesc *option_descs)
diff --git a/libnm-core/tests/test-general.c b/libnm-core/tests/test-general.c
index 82af4140..dcbcb880 100644
--- a/libnm-core/tests/test-general.c
+++ b/libnm-core/tests/test-general.c
@@ -74,6 +74,12 @@ G_STATIC_ASSERT (sizeof (bool) <= sizeof (int));
 
 /*****************************************************************************/
 
+static NMConnection *
+_connection_new_from_dbus (GVariant *dict, GError **error)
+{
+	return _nm_simple_connection_new_from_dbus (dict, NM_SETTING_PARSE_FLAGS_NORMALIZE, error);
+}
+
 static void
 vpn_check_func (const char *key, const char *value, gpointer user_data)
 {
@@ -450,7 +456,7 @@ test_setting_ip4_config_labels (void)
 	                      NMTST_VARIANT_DROP_PROPERTY (NM_SETTING_IP4_CONFIG_SETTING_NAME,
 	                                                   "address-data");
 	                      );
-	conn = nm_simple_connection_new_from_dbus (dict, &error);
+	conn = _connection_new_from_dbus (dict, &error);
 	g_assert_no_error (error);
 	g_variant_unref (dict);
 
@@ -473,7 +479,7 @@ test_setting_ip4_config_labels (void)
 	                      NMTST_VARIANT_DROP_PROPERTY (NM_SETTING_IP4_CONFIG_SETTING_NAME,
 	                                                   "address-labels");
 	                      );
-	conn = nm_simple_connection_new_from_dbus (dict2, &error);
+	conn = _connection_new_from_dbus (dict2, &error);
 	g_assert_no_error (error);
 	g_variant_unref (dict2);
 
@@ -603,7 +609,7 @@ test_setting_ip4_config_address_data (void)
 	g_object_unref (conn);
 
 	/* When we reserialize that dictionary as a client, 'address-data' will be preferred. */
-	conn = nm_simple_connection_new_from_dbus (dict, &error);
+	conn = _connection_new_from_dbus (dict, &error);
 	g_assert_no_error (error);
 
 	s_ip4 = nm_connection_get_setting_ip4_config (conn);
@@ -619,7 +625,7 @@ test_setting_ip4_config_address_data (void)
 
 	/* But on the server side, 'addresses' will have precedence. */
 	_nm_utils_is_manager_process = TRUE;
-	conn = nm_simple_connection_new_from_dbus (dict, &error);
+	conn = _connection_new_from_dbus (dict, &error);
 	_nm_utils_is_manager_process = FALSE;
 	g_assert_no_error (error);
 	g_variant_unref (dict);
@@ -1025,7 +1031,7 @@ test_setting_new_from_dbus (void)
 	dict = _nm_setting_to_dbus (NM_SETTING (s_wsec), NULL, NM_CONNECTION_SERIALIZE_ALL);
 	g_object_unref (s_wsec);
 
-	s_wsec = (NMSettingWirelessSecurity *) _nm_setting_new_from_dbus (NM_TYPE_SETTING_WIRELESS_SECURITY, dict, NULL, NULL);
+	s_wsec = (NMSettingWirelessSecurity *) _nm_setting_new_from_dbus (NM_TYPE_SETTING_WIRELESS_SECURITY, dict, NULL, NM_SETTING_PARSE_FLAGS_NONE, NULL);
 	g_variant_unref (dict);
 
 	g_assert (s_wsec);
@@ -1054,7 +1060,7 @@ test_setting_new_from_dbus_transform (void)
 	                                                  dbus_mac_address, ETH_ALEN, 1));
 	dict = g_variant_builder_end (&builder);
 
-	s_wired = _nm_setting_new_from_dbus (NM_TYPE_SETTING_WIRED, dict, NULL, &error);
+	s_wired = _nm_setting_new_from_dbus (NM_TYPE_SETTING_WIRED, dict, NULL, NM_SETTING_PARSE_FLAGS_NONE, &error);
 	g_assert_no_error (error);
 
 	g_assert_cmpstr (nm_setting_wired_get_mac_address (NM_SETTING_WIRED (s_wired)), ==, test_mac_address);
@@ -1080,7 +1086,7 @@ test_setting_new_from_dbus_enum (void)
 	                       g_variant_new_int32 (NM_SETTING_IP6_CONFIG_PRIVACY_PREFER_TEMP_ADDR));
 	dict = g_variant_builder_end (&builder);
 
-	s_ip6 = (NMSettingIP6Config *) _nm_setting_new_from_dbus (NM_TYPE_SETTING_IP6_CONFIG, dict, NULL, &error);
+	s_ip6 = (NMSettingIP6Config *) _nm_setting_new_from_dbus (NM_TYPE_SETTING_IP6_CONFIG, dict, NULL, NM_SETTING_PARSE_FLAGS_NONE, &error);
 	g_assert_no_error (error);
 
 	g_assert_cmpint (nm_setting_ip6_config_get_ip6_privacy (s_ip6), ==, NM_SETTING_IP6_CONFIG_PRIVACY_PREFER_TEMP_ADDR);
@@ -1099,7 +1105,7 @@ test_setting_new_from_dbus_enum (void)
 	                                             NM_SETTING_SECRET_FLAG_NOT_SAVED));
 	dict = g_variant_builder_end (&builder);
 
-	s_wsec = (NMSettingWirelessSecurity *) _nm_setting_new_from_dbus (NM_TYPE_SETTING_WIRELESS_SECURITY, dict, NULL, &error);
+	s_wsec = (NMSettingWirelessSecurity *) _nm_setting_new_from_dbus (NM_TYPE_SETTING_WIRELESS_SECURITY, dict, NULL, NM_SETTING_PARSE_FLAGS_NONE, &error);
 	g_assert_no_error (error);
 
 	g_assert_cmpint (nm_setting_wireless_security_get_wep_key_type (s_wsec), ==, NM_WEP_KEY_TYPE_KEY);
@@ -1116,7 +1122,7 @@ test_setting_new_from_dbus_enum (void)
 	                       g_variant_new_byte ('E'));
 	dict = g_variant_builder_end (&builder);
 
-	s_serial = (NMSettingSerial *) _nm_setting_new_from_dbus (NM_TYPE_SETTING_SERIAL, dict, NULL, &error);
+	s_serial = (NMSettingSerial *) _nm_setting_new_from_dbus (NM_TYPE_SETTING_SERIAL, dict, NULL, NM_SETTING_PARSE_FLAGS_NONE, &error);
 	g_assert_no_error (error);
 
 	g_assert_cmpint (nm_setting_serial_get_parity (s_serial), ==, NM_SETTING_SERIAL_PARITY_EVEN);
@@ -1188,7 +1194,7 @@ test_setting_new_from_dbus_bad (void)
 	g_object_unref (conn);
 
 	/* sanity-check */
-	conn = nm_simple_connection_new_from_dbus (orig_dict, &error);
+	conn = _connection_new_from_dbus (orig_dict, &error);
 	g_assert_no_error (error);
 	g_assert (conn);
 	g_object_unref (conn);
@@ -1201,7 +1207,7 @@ test_setting_new_from_dbus_bad (void)
 	                                                     NM_SETTING_WIRELESS_RATE,
 	                                                     "i", 10);
 	                      );
-	conn = nm_simple_connection_new_from_dbus (dict, &error);
+	conn = _connection_new_from_dbus (dict, &error);
 	g_assert (conn);
 	g_assert_no_error (error);
 	setting = nm_connection_get_setting (conn, NM_TYPE_SETTING_WIRELESS);
@@ -1216,7 +1222,7 @@ test_setting_new_from_dbus_bad (void)
 	                                                     NM_SETTING_IP6_CONFIG_IP6_PRIVACY,
 	                                                     "i", NM_SETTING_IP6_CONFIG_PRIVACY_PREFER_TEMP_ADDR);
 	                      );
-	conn = nm_simple_connection_new_from_dbus (dict, &error);
+	conn = _connection_new_from_dbus (dict, &error);
 	g_assert (conn);
 	g_assert_no_error (error);
 	setting = nm_connection_get_setting (conn, NM_TYPE_SETTING_IP6_CONFIG);
@@ -1233,7 +1239,7 @@ test_setting_new_from_dbus_bad (void)
 	                                                     NM_SETTING_WIRELESS_RATE,
 	                                                     "s", "ten");
 	                      );
-	conn = nm_simple_connection_new_from_dbus (dict, &error);
+	conn = _connection_new_from_dbus (dict, &error);
 	g_assert_error (error, NM_CONNECTION_ERROR, NM_CONNECTION_ERROR_INVALID_PROPERTY);
 	g_assert (g_str_has_prefix (error->message, "802-11-wireless.rate:"));
 	g_clear_error (&error);
@@ -1245,7 +1251,7 @@ test_setting_new_from_dbus_bad (void)
 	                                                     NM_SETTING_WIRELESS_MODE,
 	                                                     "b", FALSE);
 	                      );
-	conn = nm_simple_connection_new_from_dbus (dict, &error);
+	conn = _connection_new_from_dbus (dict, &error);
 	g_assert_error (error, NM_CONNECTION_ERROR, NM_CONNECTION_ERROR_INVALID_PROPERTY);
 	g_assert (g_str_has_prefix (error->message, "802-11-wireless.mode:"));
 	g_clear_error (&error);
@@ -1257,7 +1263,7 @@ test_setting_new_from_dbus_bad (void)
 	                                                     NM_SETTING_WIRELESS_SSID,
 	                                                     "s", "fred");
 	                      );
-	conn = nm_simple_connection_new_from_dbus (dict, &error);
+	conn = _connection_new_from_dbus (dict, &error);
 	g_assert_error (error, NM_CONNECTION_ERROR, NM_CONNECTION_ERROR_INVALID_PROPERTY);
 	g_assert (g_str_has_prefix (error->message, "802-11-wireless.ssid:"));
 	g_clear_error (&error);
@@ -1269,7 +1275,7 @@ test_setting_new_from_dbus_bad (void)
 	                                                     NM_SETTING_WIRELESS_BSSID,
 	                                                     "i", 42);
 	                      );
-	conn = nm_simple_connection_new_from_dbus (dict, &error);
+	conn = _connection_new_from_dbus (dict, &error);
 	g_assert_error (error, NM_CONNECTION_ERROR, NM_CONNECTION_ERROR_INVALID_PROPERTY);
 	g_assert (g_str_has_prefix (error->message, "802-11-wireless.bssid:"));
 	g_clear_error (&error);
@@ -1281,7 +1287,7 @@ test_setting_new_from_dbus_bad (void)
 	                                                     NM_SETTING_IP6_CONFIG_IP6_PRIVACY,
 	                                                     "s", "private");
 	                      );
-	conn = nm_simple_connection_new_from_dbus (dict, &error);
+	conn = _connection_new_from_dbus (dict, &error);
 	g_assert_error (error, NM_CONNECTION_ERROR, NM_CONNECTION_ERROR_INVALID_PROPERTY);
 	g_assert (g_str_has_prefix (error->message, "ipv6.ip6-privacy:"));
 	g_clear_error (&error);
@@ -1293,7 +1299,7 @@ test_setting_new_from_dbus_bad (void)
 	                                                     NM_SETTING_IP_CONFIG_ADDRESSES,
 	                                                     "s", "1234::5678");
 	                      );
-	conn = nm_simple_connection_new_from_dbus (dict, &error);
+	conn = _connection_new_from_dbus (dict, &error);
 	g_assert_error (error, NM_CONNECTION_ERROR, NM_CONNECTION_ERROR_INVALID_PROPERTY);
 	g_assert (g_str_has_prefix (error->message, "ipv6.addresses:"));
 	g_clear_error (&error);
@@ -1561,7 +1567,7 @@ test_connection_new_from_dbus (void)
 	g_assert (new_settings);
 
 	/* Replace settings and test */
-	connection = nm_simple_connection_new_from_dbus (new_settings, &error);
+	connection = _connection_new_from_dbus (new_settings, &error);
 	g_assert_no_error (error);
 	g_assert (connection);
 
@@ -3241,7 +3247,7 @@ test_connection_normalize_virtual_iface_name (void)
 	                                                     ":::this-is-not-a-valid-interface-name:::");
 	                      );
 
-	con = nm_simple_connection_new_from_dbus (connection_dict, &error);
+	con = _connection_new_from_dbus (connection_dict, &error);
 	g_assert_error (error, NM_CONNECTION_ERROR, NM_CONNECTION_ERROR_INVALID_PROPERTY);
 	g_clear_error (&error);
 
@@ -3253,7 +3259,7 @@ test_connection_normalize_virtual_iface_name (void)
 	                                                     IFACE_VIRT);
 	                      );
 
-	con = nm_simple_connection_new_from_dbus (connection_dict, &error);
+	con = _connection_new_from_dbus (connection_dict, &error);
 	g_assert_no_error (error);
 
 	g_assert_cmpstr (nm_connection_get_interface_name (con), ==, IFACE_NAME);
@@ -3269,7 +3275,7 @@ test_connection_normalize_virtual_iface_name (void)
 	                                                   NM_SETTING_CONNECTION_INTERFACE_NAME);
 	                      );
 
-	con = nm_simple_connection_new_from_dbus (connection_dict, &error);
+	con = _connection_new_from_dbus (connection_dict, &error);
 	g_assert_no_error (error);
 
 	g_assert_cmpstr (nm_connection_get_interface_name (con), ==, IFACE_VIRT);
@@ -3783,7 +3789,7 @@ test_setting_ip4_gateway (void)
 	                                                   "address-data");
 	                      );
 
-	conn = nm_simple_connection_new_from_dbus (conn_dict, &error);
+	conn = _connection_new_from_dbus (conn_dict, &error);
 	g_assert_no_error (error);
 
 	s_ip4 = (NMSettingIPConfig *) nm_connection_get_setting_ip4_config (conn);
@@ -3805,7 +3811,7 @@ test_setting_ip4_gateway (void)
 	                                                     "addresses", "aau", &addrs_builder);
 	                      );
 
-	conn = nm_simple_connection_new_from_dbus (conn_dict, &error);
+	conn = _connection_new_from_dbus (conn_dict, &error);
 	g_assert_no_error (error);
 	g_variant_unref (conn_dict);
 
@@ -3890,7 +3896,7 @@ test_setting_ip6_gateway (void)
 	                                                   "address-data");
 	                      );
 
-	conn = nm_simple_connection_new_from_dbus (conn_dict, &error);
+	conn = _connection_new_from_dbus (conn_dict, &error);
 	g_assert_no_error (error);
 
 	s_ip6 = (NMSettingIPConfig *) nm_connection_get_setting_ip6_config (conn);
@@ -3918,7 +3924,7 @@ test_setting_ip6_gateway (void)
 	                                                     "addresses", "a(ayuay)", &addrs_builder);
 	                      );
 
-	conn = nm_simple_connection_new_from_dbus (conn_dict, &error);
+	conn = _connection_new_from_dbus (conn_dict, &error);
 	g_assert_no_error (error);
 	g_variant_unref (conn_dict);