about summary refs log tree commit diff
path: root/libnm-core
diff options
context:
space:
mode:
authorSebastien Bacher <seb128@ubuntu.com>2019-01-25 11:24:41 +0100
committerSebastien Bacher <seb128@ubuntu.com>2019-01-25 11:24:41 +0100
commitbbae86d3d2997a853ca0365e8eb7a3ca7489ee09 (patch)
tree1f7fa49b47ab13aea3effbe839559d221f6323b4 /libnm-core
parent404ebe62622150e77e311777dff8617eb974e834 (diff)
New upstream version 1.15.2
Diffstat (limited to 'libnm-core')
-rw-r--r--libnm-core/meson.build19
-rw-r--r--libnm-core/nm-connection.c281
-rw-r--r--libnm-core/nm-connection.h4
-rw-r--r--libnm-core/nm-core-internal.h172
-rw-r--r--libnm-core/nm-crypto.c15
-rw-r--r--libnm-core/nm-dbus-interface.h29
-rw-r--r--libnm-core/nm-dbus-types.xml15
-rw-r--r--libnm-core/nm-dbus-utils.c89
-rw-r--r--libnm-core/nm-keyfile-internal.h15
-rw-r--r--libnm-core/nm-keyfile-utils.c57
-rw-r--r--libnm-core/nm-keyfile-utils.h12
-rw-r--r--libnm-core/nm-keyfile.c902
-rw-r--r--libnm-core/nm-setting-6lowpan.c80
-rw-r--r--libnm-core/nm-setting-8021x.c6
-rw-r--r--libnm-core/nm-setting-adsl.c225
-rw-r--r--libnm-core/nm-setting-bluetooth.c127
-rw-r--r--libnm-core/nm-setting-bond.c87
-rw-r--r--libnm-core/nm-setting-bridge-port.c131
-rw-r--r--libnm-core/nm-setting-bridge.c281
-rw-r--r--libnm-core/nm-setting-cdma.c189
-rw-r--r--libnm-core/nm-setting-connection.c652
-rw-r--r--libnm-core/nm-setting-dcb.c428
-rw-r--r--libnm-core/nm-setting-dummy.c34
-rw-r--r--libnm-core/nm-setting-generic.c19
-rw-r--r--libnm-core/nm-setting-gsm.c367
-rw-r--r--libnm-core/nm-setting-gsm.h8
-rw-r--r--libnm-core/nm-setting-infiniband.c204
-rw-r--r--libnm-core/nm-setting-ip-config.c615
-rw-r--r--libnm-core/nm-setting-ip-tunnel.c336
-rw-r--r--libnm-core/nm-setting-ip4-config.c240
-rw-r--r--libnm-core/nm-setting-ip6-config.c182
-rw-r--r--libnm-core/nm-setting-macsec.c159
-rw-r--r--libnm-core/nm-setting-macvlan.c157
-rw-r--r--libnm-core/nm-setting-match.c17
-rw-r--r--libnm-core/nm-setting-olpc-mesh.c154
-rw-r--r--libnm-core/nm-setting-ovs-bridge.c66
-rw-r--r--libnm-core/nm-setting-ovs-interface.c27
-rw-r--r--libnm-core/nm-setting-ovs-patch.c25
-rw-r--r--libnm-core/nm-setting-ovs-port.c102
-rw-r--r--libnm-core/nm-setting-ppp.c420
-rw-r--r--libnm-core/nm-setting-pppoe.c169
-rw-r--r--libnm-core/nm-setting-private.h30
-rw-r--r--libnm-core/nm-setting-proxy.c136
-rw-r--r--libnm-core/nm-setting-serial.c170
-rw-r--r--libnm-core/nm-setting-sriov.c210
-rw-r--r--libnm-core/nm-setting-tc-config.c267
-rw-r--r--libnm-core/nm-setting-team-port.c320
-rw-r--r--libnm-core/nm-setting-team.c621
-rw-r--r--libnm-core/nm-setting-team.h11
-rw-r--r--libnm-core/nm-setting-tun.c191
-rw-r--r--libnm-core/nm-setting-user.c46
-rw-r--r--libnm-core/nm-setting-vlan.c220
-rw-r--r--libnm-core/nm-setting-vpn.c484
-rw-r--r--libnm-core/nm-setting-vxlan.c416
-rw-r--r--libnm-core/nm-setting-wimax.c129
-rw-r--r--libnm-core/nm-setting-wired.c453
-rw-r--r--libnm-core/nm-setting-wireless-security.c626
-rw-r--r--libnm-core/nm-setting-wireless-security.h9
-rw-r--r--libnm-core/nm-setting-wireless.c509
-rw-r--r--libnm-core/nm-setting-wireless.h2
-rw-r--r--libnm-core/nm-setting-wpan.c191
-rw-r--r--libnm-core/nm-setting-wpan.h9
-rw-r--r--libnm-core/nm-setting.c1069
-rw-r--r--libnm-core/nm-setting.h41
-rw-r--r--libnm-core/nm-simple-connection.c5
-rw-r--r--libnm-core/nm-utils-private.h6
-rw-r--r--libnm-core/nm-utils.c477
-rw-r--r--libnm-core/nm-version.h14
-rw-r--r--libnm-core/nm-vpn-editor-plugin.c36
-rw-r--r--libnm-core/nm-vpn-plugin-info.c162
-rw-r--r--libnm-core/tests/meson.build13
-rw-r--r--libnm-core/tests/test-general.c453
-rw-r--r--libnm-core/tests/test-keyfile.c4
-rw-r--r--libnm-core/tests/test-setting.c262
74 files changed, 8378 insertions, 6331 deletions
diff --git a/libnm-core/meson.build b/libnm-core/meson.build
index ac13a1be..812f12bb 100644
--- a/libnm-core/meson.build
+++ b/libnm-core/meson.build
@@ -56,7 +56,7 @@ libnm_core_headers = files(
   'nm-version.h',
   'nm-vpn-dbus-interface.h',
   'nm-vpn-editor-plugin.h',
-  'nm-vpn-plugin-info.h'
+  'nm-vpn-plugin-info.h',
 )
 
 libnm_core_settings_sources = files(
@@ -104,7 +104,7 @@ libnm_core_settings_sources = files(
   'nm-setting-wired.c',
   'nm-setting-wireless-security.c',
   'nm-setting-wireless.c',
-  'nm-setting-wpan.c'
+  'nm-setting-wpan.c',
 )
 
 libnm_core_sources = libnm_core_settings_sources + files(
@@ -119,7 +119,7 @@ libnm_core_sources = libnm_core_settings_sources + files(
   'nm-simple-connection.c',
   'nm-utils.c',
   'nm-vpn-editor-plugin.c',
-  'nm-vpn-plugin-info.c'
+  'nm-vpn-plugin-info.c',
 )
 
 enum_headers = libnm_core_headers + [version_header]
@@ -132,7 +132,7 @@ libnm_core_enum = gnome.mkenums(
   c_template: enum_types + '.c.template',
   h_template: enum_types + '.h.template',
   install_header: true,
-  install_dir: libnm_pkgincludedir
+  install_dir: libnm_pkgincludedir,
 )
 
 deps = [
@@ -158,7 +158,7 @@ if (crypto_gnutls_dep.found())
     'nm-crypto-gnutls',
     sources: [ 'nm-crypto-gnutls.c' ],
     dependencies: deps + [ crypto_gnutls_dep ],
-    c_args: cflags
+    c_args: cflags,
   )
 endif
 
@@ -167,7 +167,7 @@ if (crypto_nss_dep.found())
     'nm-crypto-nss',
     sources: [ 'nm-crypto-nss.c' ],
     dependencies: deps + [ crypto_nss_dep ],
-    c_args: cflags
+    c_args: cflags,
   )
 endif
 
@@ -191,7 +191,7 @@ libnm_core = static_library(
   sources: libnm_core_sources_all,
   dependencies: deps,
   link_with: libnm_crypto,
-  c_args: cflags
+  c_args: cflags,
 )
 
 nm_core_dep = declare_dependency(
@@ -200,6 +200,7 @@ nm_core_dep = declare_dependency(
   dependencies: [
     shared_dep,
     shared_c_siphash_dep,
+    libnm_systemd_shared_dep,
   ],
 )
 
@@ -207,7 +208,7 @@ enums_to_docbook = join_paths(meson.source_root(), 'tools', 'enums-to-docbook.pl
 
 docbooks = [
   ['nm-dbus-types', 'nm-dbus-interface.h', 'NetworkManager D-Bus API Types'],
-  ['nm-vpn-dbus-types', 'nm-vpn-dbus-interface.h', 'VPN Plugin D-Bus API Types']
+  ['nm-vpn-dbus-types', 'nm-vpn-dbus-interface.h', 'VPN Plugin D-Bus API Types'],
 ]
 
 foreach docbook: docbooks
@@ -221,7 +222,7 @@ foreach docbook: docbooks
     command: [perl, enums_to_docbook, docbook[0], docbook[2], '@INPUT@'],
     # FIXME: gtkdoc does not depend directly on this.
     #        https://github.com/mesonbuild/meson/pull/2806
-    build_by_default: true
+    build_by_default: true,
   )
 
   content_files += xml.full_path()
diff --git a/libnm-core/nm-connection.c b/libnm-core/nm-connection.c
index 172f9c99..724e8557 100644
--- a/libnm-core/nm-connection.c
+++ b/libnm-core/nm-connection.c
@@ -22,10 +22,11 @@
 
 #include "nm-default.h"
 
+#include "nm-connection.h"
+
 #include <string.h>
 #include <arpa/inet.h>
 
-#include "nm-connection.h"
 #include "nm-connection-private.h"
 #include "nm-utils.h"
 #include "nm-setting-private.h"
@@ -50,6 +51,17 @@
  *
  */
 
+/*****************************************************************************/
+
+enum {
+	SECRETS_UPDATED,
+	SECRETS_CLEARED,
+	CHANGED,
+	LAST_SIGNAL
+};
+
+static guint signals[LAST_SIGNAL] = { 0 };
+
 typedef struct {
 	NMConnection *self;
 
@@ -59,19 +71,26 @@ typedef struct {
 	char *path;
 } NMConnectionPrivate;
 
+G_DEFINE_INTERFACE (NMConnection, nm_connection, G_TYPE_OBJECT)
+
 static NMConnectionPrivate *nm_connection_get_private (NMConnection *connection);
 #define NM_CONNECTION_GET_PRIVATE(o) (nm_connection_get_private ((NMConnection *)o))
 
-G_DEFINE_INTERFACE (NMConnection, nm_connection, G_TYPE_OBJECT)
+/*****************************************************************************/
 
-enum {
-	SECRETS_UPDATED,
-	SECRETS_CLEARED,
-	CHANGED,
-	LAST_SIGNAL
-};
+static gpointer
+_gtype_to_hash_key (GType gtype)
+{
+#if NM_MORE_ASSERTS
+	_nm_unused const gsize *const test_gtype_typedef = &gtype;
 
-static guint signals[LAST_SIGNAL] = { 0 };
+	nm_assert ((GType) (GPOINTER_TO_SIZE (GSIZE_TO_POINTER (gtype))) == gtype);
+	G_STATIC_ASSERT_EXPR (sizeof (gpointer) >= sizeof (gsize));
+	G_STATIC_ASSERT_EXPR (sizeof (gsize) == sizeof (GType));
+#endif
+
+	return GSIZE_TO_POINTER (gtype);
+}
 
 /*****************************************************************************/
 
@@ -83,10 +102,16 @@ setting_changed_cb (NMSetting *setting,
 	g_signal_emit (self, signals[CHANGED], 0);
 }
 
+static void
+_setting_release (NMConnection *connection, NMSetting *setting)
+{
+	g_signal_handlers_disconnect_by_func (setting, setting_changed_cb, connection);
+}
+
 static gboolean
-_setting_release (gpointer key, gpointer value, gpointer user_data)
+_setting_release_hfr (gpointer key, gpointer value, gpointer user_data)
 {
-	g_signal_handlers_disconnect_by_func (user_data, setting_changed_cb, value);
+	_setting_release (user_data, value);
 	return TRUE;
 }
 
@@ -94,19 +119,20 @@ static void
 _nm_connection_add_setting (NMConnection *connection, NMSetting *setting)
 {
 	NMConnectionPrivate *priv;
-	const char *name;
+	GType setting_type;
 	NMSetting *s_old;
 
 	nm_assert (NM_IS_CONNECTION (connection));
 	nm_assert (NM_IS_SETTING (setting));
 
 	priv = NM_CONNECTION_GET_PRIVATE (connection);
-	name = G_OBJECT_TYPE_NAME (setting);
+	setting_type = G_OBJECT_TYPE (setting);
+
+	if ((s_old = g_hash_table_lookup (priv->settings, _gtype_to_hash_key (setting_type))))
+		_setting_release (connection, s_old);
+
+	g_hash_table_insert (priv->settings, _gtype_to_hash_key (setting_type), setting);
 
-	if ((s_old = g_hash_table_lookup (priv->settings, (gpointer) name)))
-		g_signal_handlers_disconnect_by_func (s_old, setting_changed_cb, connection);
-	g_hash_table_insert (priv->settings, (gpointer) name, setting);
-	/* Listen for property changes so we can emit the 'changed' signal */
 	g_signal_connect (setting, "notify", (GCallback) setting_changed_cb, connection);
 }
 
@@ -135,17 +161,15 @@ _nm_connection_remove_setting (NMConnection *connection, GType setting_type)
 {
 	NMConnectionPrivate *priv;
 	NMSetting *setting;
-	const char *setting_name;
 
 	g_return_val_if_fail (NM_IS_CONNECTION (connection), FALSE);
 	g_return_val_if_fail (g_type_is_a (setting_type, NM_TYPE_SETTING), FALSE);
 
 	priv = NM_CONNECTION_GET_PRIVATE (connection);
-	setting_name = g_type_name (setting_type);
-	setting = g_hash_table_lookup (priv->settings, setting_name);
+	setting = g_hash_table_lookup (priv->settings, _gtype_to_hash_key (setting_type));
 	if (setting) {
 		g_signal_handlers_disconnect_by_func (setting, setting_changed_cb, connection);
-		g_hash_table_remove (priv->settings, setting_name);
+		g_hash_table_remove (priv->settings, _gtype_to_hash_key (setting_type));
 		g_signal_emit (connection, signals[CHANGED], 0);
 		return TRUE;
 	}
@@ -169,11 +193,15 @@ nm_connection_remove_setting (NMConnection *connection, GType setting_type)
 static gpointer
 _connection_get_setting (NMConnection *connection, GType setting_type)
 {
+	NMSetting *setting;
+
 	nm_assert (NM_IS_CONNECTION (connection));
 	nm_assert (g_type_is_a (setting_type, NM_TYPE_SETTING));
 
-	return g_hash_table_lookup (NM_CONNECTION_GET_PRIVATE (connection)->settings,
-	                            g_type_name (setting_type));
+	setting = g_hash_table_lookup (NM_CONNECTION_GET_PRIVATE (connection)->settings,
+	                               _gtype_to_hash_key (setting_type));
+	nm_assert (!setting || G_TYPE_CHECK_INSTANCE_TYPE (setting, setting_type));
+	return setting;
 }
 
 static gpointer
@@ -388,7 +416,7 @@ _nm_connection_replace_settings (NMConnection *connection,
 	}
 
 	if (g_hash_table_size (priv->settings) > 0) {
-		g_hash_table_foreach_remove (priv->settings, _setting_release, connection);
+		g_hash_table_foreach_remove (priv->settings, _setting_release_hfr, connection);
 		changed = TRUE;
 	} else
 		changed = (settings != NULL);
@@ -473,7 +501,7 @@ nm_connection_replace_settings_from_connection (NMConnection *connection,
 	new_priv = NM_CONNECTION_GET_PRIVATE (new_connection);
 
 	if ((changed = g_hash_table_size (priv->settings) > 0))
-		g_hash_table_foreach_remove (priv->settings, _setting_release, connection);
+		g_hash_table_foreach_remove (priv->settings, _setting_release_hfr, connection);
 
 	if (g_hash_table_size (new_priv->settings)) {
 		g_hash_table_iter_init (&iter, new_priv->settings);
@@ -502,7 +530,7 @@ nm_connection_clear_settings (NMConnection *connection)
 	priv = NM_CONNECTION_GET_PRIVATE (connection);
 
 	if (g_hash_table_size (priv->settings) > 0) {
-		g_hash_table_foreach_remove (priv->settings, _setting_release, connection);
+		g_hash_table_foreach_remove (priv->settings, _setting_release_hfr, connection);
 		g_signal_emit (connection, signals[CHANGED], 0);
 	}
 }
@@ -1125,6 +1153,29 @@ _normalize_wireless_mac_address_randomization (NMConnection *self, GHashTable *p
 }
 
 static gboolean
+_normalize_macsec (NMConnection *self, GHashTable *parameters)
+{
+	NMSettingMacsec *s_macsec = nm_connection_get_setting_macsec (self);
+	gboolean changed = FALSE;
+
+	if (!s_macsec)
+		return FALSE;
+
+	if (nm_setting_macsec_get_mode (s_macsec) != NM_SETTING_MACSEC_MODE_PSK) {
+		if (nm_setting_macsec_get_mka_cak (s_macsec)) {
+			g_object_set (s_macsec, NM_SETTING_MACSEC_MKA_CAK, NULL, NULL);
+			changed = TRUE;
+		}
+		if (nm_setting_macsec_get_mka_ckn (s_macsec)) {
+			g_object_set (s_macsec, NM_SETTING_MACSEC_MKA_CKN, NULL, NULL);
+			changed = TRUE;
+		}
+	}
+
+	return changed;
+}
+
+static gboolean
 _normalize_team_config (NMConnection *self, GHashTable *parameters)
 {
 	NMSettingTeam *s_team = nm_connection_get_setting_team (self);
@@ -1564,6 +1615,7 @@ nm_connection_normalize (NMConnection *connection,
 	was_modified |= _normalize_bond_mode (connection, parameters);
 	was_modified |= _normalize_bond_options (connection, parameters);
 	was_modified |= _normalize_wireless_mac_address_randomization (connection, parameters);
+	was_modified |= _normalize_macsec (connection, parameters);
 	was_modified |= _normalize_team_config (connection, parameters);
 	was_modified |= _normalize_team_port_config (connection, parameters);
 	was_modified |= _normalize_bluetooth_type (connection, parameters);
@@ -1787,26 +1839,14 @@ nm_connection_need_secrets (NMConnection *connection,
 void
 nm_connection_clear_secrets (NMConnection *connection)
 {
-	GHashTableIter iter;
-	NMSetting *setting;
-
-	g_return_if_fail (NM_IS_CONNECTION (connection));
-
-	g_hash_table_iter_init (&iter, NM_CONNECTION_GET_PRIVATE (connection)->settings);
-	while (g_hash_table_iter_next (&iter, NULL, (gpointer) &setting)) {
-		g_signal_handlers_block_by_func (setting, (GCallback) setting_changed_cb, connection);
-		_nm_setting_clear_secrets (setting);
-		g_signal_handlers_unblock_by_func (setting, (GCallback) setting_changed_cb, connection);
-	}
-
-	g_signal_emit (connection, signals[SECRETS_CLEARED], 0);
+	return nm_connection_clear_secrets_with_flags (connection, NULL, NULL);
 }
 
 /**
  * nm_connection_clear_secrets_with_flags:
  * @connection: the #NMConnection
- * @func: (scope call): function to be called to determine whether a
- *     specific secret should be cleared or not
+ * @func: (scope call): (allow-none): function to be called to determine whether a
+ *     specific secret should be cleared or not. If %NULL, all secrets are cleared.
  * @user_data: caller-supplied data passed to @func
  *
  * Clears and frees secrets determined by @func.
@@ -1824,7 +1864,7 @@ nm_connection_clear_secrets_with_flags (NMConnection *connection,
 	g_hash_table_iter_init (&iter, NM_CONNECTION_GET_PRIVATE (connection)->settings);
 	while (g_hash_table_iter_next (&iter, NULL, (gpointer) &setting)) {
 		g_signal_handlers_block_by_func (setting, (GCallback) setting_changed_cb, connection);
-		_nm_setting_clear_secrets_with_flags (setting, func, user_data);
+		_nm_setting_clear_secrets (setting, func, user_data);
 		g_signal_handlers_unblock_by_func (setting, (GCallback) setting_changed_cb, connection);
 	}
 
@@ -1850,7 +1890,7 @@ nm_connection_to_dbus (NMConnection *connection,
 	NMConnectionPrivate *priv;
 	GVariantBuilder builder;
 	GHashTableIter iter;
-	gpointer key, data;
+	gpointer data;
 	GVariant *setting_dict, *ret;
 
 	g_return_val_if_fail (NM_IS_CONNECTION (connection), NULL);
@@ -1860,7 +1900,7 @@ nm_connection_to_dbus (NMConnection *connection,
 
 	/* Add each setting's hash to the main hash */
 	g_hash_table_iter_init (&iter, priv->settings);
-	while (g_hash_table_iter_next (&iter, &key, &data)) {
+	while (g_hash_table_iter_next (&iter, NULL, &data)) {
 		NMSetting *setting = NM_SETTING (data);
 
 		setting_dict = _nm_setting_to_dbus (setting, connection, flags);
@@ -1992,6 +2032,73 @@ nm_connection_for_each_setting_value (NMConnection *connection,
 }
 
 /**
+ * _nm_connection_aggregate:
+ * @connecition: the #NMConnection for which values are to be aggregated.
+ * @type: one of the supported aggrate types.
+ * @arg: the input/output argument that depends on @type.
+ *
+ * For example, with %NM_CONNECTION_AGGREGATE_ANY_SECRETS and
+ * %NM_CONNECTION_AGGREGATE_ANY_SYSTEM_SECRET_FLAGS @arg is a boolean
+ * output argument. It is either %NULL or a pointer to an gboolean
+ * out-argument. The function will always set @arg if given.
+ * Also, the return value of the function is likewise the result
+ * that is set to @arg.
+ *
+ * Returns: a boolean result with the meaning depending on the aggregation
+ *   type @type.
+ */
+gboolean
+_nm_connection_aggregate (NMConnection *connection,
+                          NMConnectionAggregateType type,
+                          gpointer arg)
+{
+	NMConnectionPrivate *priv;
+	GHashTableIter iter;
+	NMSetting *setting;
+	gboolean arg_boolean;
+	gboolean completed_early;
+	gpointer my_arg;
+
+	g_return_val_if_fail (NM_IS_CONNECTION (connection), FALSE);
+
+	switch (type) {
+	case NM_CONNECTION_AGGREGATE_ANY_SECRETS:
+		arg_boolean = FALSE;
+		my_arg = &arg_boolean;
+		goto good;
+	case NM_CONNECTION_AGGREGATE_ANY_SYSTEM_SECRET_FLAGS:
+		arg_boolean = FALSE;
+		my_arg = &arg_boolean;
+		goto good;
+	}
+	g_return_val_if_reached (FALSE);
+
+good:
+	priv = NM_CONNECTION_GET_PRIVATE (connection);
+
+	completed_early = FALSE;
+	g_hash_table_iter_init (&iter, priv->settings);
+	while (g_hash_table_iter_next (&iter, NULL, (gpointer) &setting)) {
+		if (_nm_setting_aggregate (setting, type, my_arg)) {
+			completed_early = TRUE;
+			break;
+		}
+		nm_assert (   my_arg != &arg_boolean
+		           || !arg_boolean);
+	}
+
+	if (my_arg == &arg_boolean) {
+		nm_assert (completed_early == arg_boolean);
+		if (arg)
+			*((gboolean *) arg) = arg_boolean;
+		return arg_boolean;
+	}
+
+	nm_assert_not_reached ();
+	return FALSE;
+}
+
+/**
  * nm_connection_dump:
  * @connection: the #NMConnection
  *
@@ -2005,14 +2112,13 @@ nm_connection_dump (NMConnection *connection)
 {
 	GHashTableIter iter;
 	NMSetting *setting;
-	const char *setting_name;
 	char *str;
 
 	if (!connection)
 		return;
 
 	g_hash_table_iter_init (&iter, NM_CONNECTION_GET_PRIVATE (connection)->settings);
-	while (g_hash_table_iter_next (&iter, (gpointer) &setting_name, (gpointer) &setting)) {
+	while (g_hash_table_iter_next (&iter, NULL, (gpointer) &setting)) {
 		str = nm_setting_to_string (setting);
 		g_print ("%s\n", str);
 		g_free (str);
@@ -2197,23 +2303,23 @@ nm_connection_is_virtual (NMConnection *connection)
 	if (!type)
 		return FALSE;
 
-	if (   !strcmp (type, NM_SETTING_6LOWPAN_SETTING_NAME)
-	    || !strcmp (type, NM_SETTING_BOND_SETTING_NAME)
-	    || !strcmp (type, NM_SETTING_DUMMY_SETTING_NAME)
-	    || !strcmp (type, NM_SETTING_TEAM_SETTING_NAME)
-	    || !strcmp (type, NM_SETTING_BRIDGE_SETTING_NAME)
-	    || !strcmp (type, NM_SETTING_VLAN_SETTING_NAME)
-	    || !strcmp (type, NM_SETTING_TUN_SETTING_NAME)
-	    || !strcmp (type, NM_SETTING_IP_TUNNEL_SETTING_NAME)
-	    || !strcmp (type, NM_SETTING_MACSEC_SETTING_NAME)
-	    || !strcmp (type, NM_SETTING_MACVLAN_SETTING_NAME)
-	    || !strcmp (type, NM_SETTING_OVS_BRIDGE_SETTING_NAME)
-	    || !strcmp (type, NM_SETTING_OVS_INTERFACE_SETTING_NAME)
-	    || !strcmp (type, NM_SETTING_OVS_PORT_SETTING_NAME)
-	    || !strcmp (type, NM_SETTING_VXLAN_SETTING_NAME))
+	if (NM_IN_STRSET (type, NM_SETTING_6LOWPAN_SETTING_NAME,
+	                        NM_SETTING_BOND_SETTING_NAME,
+	                        NM_SETTING_BRIDGE_SETTING_NAME,
+	                        NM_SETTING_DUMMY_SETTING_NAME,
+	                        NM_SETTING_IP_TUNNEL_SETTING_NAME,
+	                        NM_SETTING_MACSEC_SETTING_NAME,
+	                        NM_SETTING_MACVLAN_SETTING_NAME,
+	                        NM_SETTING_OVS_BRIDGE_SETTING_NAME,
+	                        NM_SETTING_OVS_INTERFACE_SETTING_NAME,
+	                        NM_SETTING_OVS_PORT_SETTING_NAME,
+	                        NM_SETTING_TEAM_SETTING_NAME,
+	                        NM_SETTING_TUN_SETTING_NAME,
+	                        NM_SETTING_VLAN_SETTING_NAME,
+	                        NM_SETTING_VXLAN_SETTING_NAME))
 		return TRUE;
 
-	if (!strcmp (type, NM_SETTING_INFINIBAND_SETTING_NAME)) {
+	if (nm_streq (type, NM_SETTING_INFINIBAND_SETTING_NAME)) {
 		NMSettingInfiniband *s_ib;
 
 		s_ib = nm_connection_get_setting_infiniband (connection);
@@ -2862,7 +2968,7 @@ nm_connection_private_free (NMConnectionPrivate *priv)
 {
 	NMConnection *self = priv->self;
 
-	g_hash_table_foreach_remove (priv->settings, _setting_release, self);
+	g_hash_table_foreach_remove (priv->settings, _setting_release_hfr, self);
 	g_hash_table_destroy (priv->settings);
 	g_free (priv->path);
 
@@ -2886,7 +2992,10 @@ nm_connection_get_private (NMConnection *connection)
 		                         priv, (GDestroyNotify) nm_connection_private_free);
 
 		priv->self = connection;
-		priv->settings = g_hash_table_new_full (nm_str_hash, g_str_equal, NULL, g_object_unref);
+		priv->settings = g_hash_table_new_full (nm_direct_hash,
+		                                        NULL,
+		                                        NULL,
+		                                        g_object_unref);
 	}
 
 	return priv;
@@ -2895,8 +3004,6 @@ nm_connection_get_private (NMConnection *connection)
 static void
 nm_connection_default_init (NMConnectionInterface *iface)
 {
-	/* Signals */
-
 	/**
 	 * NMConnection::secrets-updated:
 	 * @connection: the object on which the signal is emitted
@@ -2907,14 +3014,14 @@ nm_connection_default_init (NMConnectionInterface *iface)
 	 * have been changed.
 	 */
 	signals[SECRETS_UPDATED] =
-		g_signal_new (NM_CONNECTION_SECRETS_UPDATED,
-		              NM_TYPE_CONNECTION,
-		              G_SIGNAL_RUN_FIRST,
-		              G_STRUCT_OFFSET (NMConnectionInterface, secrets_updated),
-		              NULL, NULL,
-		              g_cclosure_marshal_VOID__STRING,
-		              G_TYPE_NONE, 1,
-		              G_TYPE_STRING);
+	    g_signal_new (NM_CONNECTION_SECRETS_UPDATED,
+	                 NM_TYPE_CONNECTION,
+	                 G_SIGNAL_RUN_FIRST,
+	                 G_STRUCT_OFFSET (NMConnectionInterface, secrets_updated),
+	                 NULL, NULL,
+	                 g_cclosure_marshal_VOID__STRING,
+	                 G_TYPE_NONE, 1,
+	                 G_TYPE_STRING);
 
 	/**
 	 * NMConnection::secrets-cleared:
@@ -2924,13 +3031,13 @@ nm_connection_default_init (NMConnectionInterface *iface)
 	 * are cleared.
 	 */
 	signals[SECRETS_CLEARED] =
-		g_signal_new (NM_CONNECTION_SECRETS_CLEARED,
-		              NM_TYPE_CONNECTION,
-		              G_SIGNAL_RUN_FIRST,
-		              G_STRUCT_OFFSET (NMConnectionInterface, secrets_cleared),
-		              NULL, NULL,
-		              g_cclosure_marshal_VOID__VOID,
-		              G_TYPE_NONE, 0);
+	    g_signal_new (NM_CONNECTION_SECRETS_CLEARED,
+	                 NM_TYPE_CONNECTION,
+	                 G_SIGNAL_RUN_FIRST,
+	                 G_STRUCT_OFFSET (NMConnectionInterface, secrets_cleared),
+	                 NULL, NULL,
+	                 g_cclosure_marshal_VOID__VOID,
+	                 G_TYPE_NONE, 0);
 
 	/**
 	 * NMConnection::changed:
@@ -2941,11 +3048,11 @@ nm_connection_default_init (NMConnectionInterface *iface)
 	 * or when settings are added or removed.
 	 */
 	signals[CHANGED] =
-		g_signal_new (NM_CONNECTION_CHANGED,
-		              NM_TYPE_CONNECTION,
-		              G_SIGNAL_RUN_FIRST,
-		              G_STRUCT_OFFSET (NMConnectionInterface, changed),
-		              NULL, NULL,
-		              g_cclosure_marshal_VOID__VOID,
-		              G_TYPE_NONE, 0);
+	    g_signal_new (NM_CONNECTION_CHANGED,
+	                 NM_TYPE_CONNECTION,
+	                 G_SIGNAL_RUN_FIRST,
+	                 G_STRUCT_OFFSET (NMConnectionInterface, changed),
+	                 NULL, NULL,
+	                 g_cclosure_marshal_VOID__VOID,
+	                 G_TYPE_NONE, 0);
 }
diff --git a/libnm-core/nm-connection.h b/libnm-core/nm-connection.h
index 802f68ba..8d64a4ce 100644
--- a/libnm-core/nm-connection.h
+++ b/libnm-core/nm-connection.h
@@ -45,7 +45,7 @@ G_BEGIN_DECLS
 
 /*
  * NM_CONNECTION_NORMALIZE_PARAM_IP6_CONFIG_METHOD: overwrite the ip6 method
- * when normalizing ip6 configuration. If omited, this defaults to
+ * when normalizing ip6 configuration. If omitted, this defaults to
  * @NM_SETTING_IP6_CONFIG_METHOD_AUTO.
  */
 #define NM_CONNECTION_NORMALIZE_PARAM_IP6_CONFIG_METHOD "ip6-config-method"
@@ -59,7 +59,7 @@ G_BEGIN_DECLS
 
 /**
  * NMConnectionInterface:
- * @parent: the parent interace struct
+ * @parent: the parent interface struct
  * @secrets_updated: emitted when the connection's secrets are updated
  * @secrets_cleared: emitted when the connection's secrets are cleared
  * @changed: emitted when any change to the connection's settings occurs
diff --git a/libnm-core/nm-core-internal.h b/libnm-core/nm-core-internal.h
index f0d4e40f..6af293a0 100644
--- a/libnm-core/nm-core-internal.h
+++ b/libnm-core/nm-core-internal.h
@@ -101,6 +101,11 @@
 #define NM_BR_MIN_AGEING_TIME   0
 #define NM_BR_MAX_AGEING_TIME   1000000
 
+#define NM_BR_PORT_MAX_PRIORITY 63
+#define NM_BR_PORT_DEF_PRIORITY 32
+
+#define NM_BR_PORT_MAX_PATH_COST 65535
+
 /* NM_SETTING_COMPARE_FLAG_INFERRABLE: check whether a device-generated
  * connection can be replaced by a already-defined connection. This flag only
  * takes into account properties marked with the %NM_SETTING_PARAM_INFERRABLE
@@ -121,11 +126,21 @@
  */
 #define NM_SETTING_COMPARE_FLAG_NONE ((NMSettingCompareFlags) 0)
 
+/*****************************************************************************/
+
 #define NM_SETTING_SECRET_FLAGS_ALL \
-	(NM_SETTING_SECRET_FLAG_NONE | \
-	 NM_SETTING_SECRET_FLAG_AGENT_OWNED | \
-	 NM_SETTING_SECRET_FLAG_NOT_SAVED | \
-	 NM_SETTING_SECRET_FLAG_NOT_REQUIRED)
+	((NMSettingSecretFlags) (  NM_SETTING_SECRET_FLAG_NONE \
+	                         | NM_SETTING_SECRET_FLAG_AGENT_OWNED \
+	                         | NM_SETTING_SECRET_FLAG_NOT_SAVED \
+	                         | NM_SETTING_SECRET_FLAG_NOT_REQUIRED))
+
+static inline gboolean
+_nm_setting_secret_flags_valid (NMSettingSecretFlags flags)
+{
+	return !NM_FLAGS_ANY (flags, ~NM_SETTING_SECRET_FLAGS_ALL);
+}
+
+/*****************************************************************************/
 
 typedef enum { /*< skip >*/
 	NM_SETTING_PARSE_FLAGS_NONE                     = 0,
@@ -146,6 +161,26 @@ gpointer _nm_connection_check_main_setting (NMConnection *connection,
                                             const char *setting_name,
                                             GError **error);
 
+typedef enum {
+	/* whether the connection has any secrets.
+	 *
+	 * @arg may be %NULL or a pointer to a gboolean for the result. The return
+	 *   value of _nm_connection_aggregate() is likewise the boolean result. */
+	NM_CONNECTION_AGGREGATE_ANY_SECRETS,
+
+	/* whether the connection has any secret with flags NM_SETTING_SECRET_FLAG_NONE.
+	 * Note that this only cares about the flags, not whether the secret is actually
+	 * present.
+	 *
+	 * @arg may be %NULL or a pointer to a gboolean for the result. The return
+	 *   value of _nm_connection_aggregate() is likewise the boolean result. */
+	NM_CONNECTION_AGGREGATE_ANY_SYSTEM_SECRET_FLAGS,
+} NMConnectionAggregateType;
+
+gboolean _nm_connection_aggregate (NMConnection *connection,
+                                   NMConnectionAggregateType type,
+                                   gpointer arg);
+
 /**
  * NMSettingVerifyResult:
  * @NM_SETTING_VERIFY_SUCCESS: the setting verifies successfully
@@ -212,15 +247,26 @@ guint nm_setting_ethtool_init_features (NMSettingEthtool *setting,
 guint8 *_nm_utils_hwaddr_aton (const char *asc, gpointer buffer, gsize buffer_length, gsize *out_length);
 const char *nm_utils_hwaddr_ntoa_buf (gconstpointer addr, gsize addr_len, gboolean upper_case, char *buf, gsize buf_len);
 
-char *_nm_utils_bin2str (gconstpointer addr, gsize length, gboolean upper_case);
-void _nm_utils_bin2str_full (gconstpointer addr, gsize length, const char delimiter, gboolean upper_case, char *out);
+char *_nm_utils_bin2hexstr_full (gconstpointer addr, gsize length, const char delimiter, gboolean upper_case, char *out);
+
+guint8 *_nm_utils_hexstr2bin_full (const char *hexstr,
+                                   gboolean allow_0x_prefix,
+                                   gboolean delimiter_required,
+                                   const char *delimiter_candidates,
+                                   gsize required_len,
+                                   guint8 *buffer,
+                                   gsize buffer_len,
+                                   gsize *out_len);
+
+#define _nm_utils_hexstr2bin_buf(hexstr, allow_0x_prefix, delimiter_required, delimiter_candidates, buffer) \
+    _nm_utils_hexstr2bin_full ((hexstr), (allow_0x_prefix), (delimiter_required), (delimiter_candidates), G_N_ELEMENTS (buffer), (buffer), G_N_ELEMENTS (buffer), NULL)
 
-guint8 *_nm_utils_str2bin_full (const char *asc,
-                                gboolean delimiter_required,
-                                const char *delimiter_candidates,
-                                guint8 *buffer,
-                                gsize buffer_length,
-                                gsize *out_len);
+guint8 *_nm_utils_hexstr2bin_alloc (const char *hexstr,
+                                    gboolean allow_0x_prefix,
+                                    gboolean delimiter_required,
+                                    const char *delimiter_candidates,
+                                    gsize required_len,
+                                    gsize *out_len);
 
 GSList *    _nm_utils_hash_values_to_slist (GHashTable *hash);
 
@@ -234,7 +280,7 @@ gboolean _nm_ip_route_attribute_validate_all (const NMIPRoute *route);
 const char **_nm_ip_route_get_attribute_names (const NMIPRoute *route, gboolean sorted, guint *out_length);
 GHashTable *_nm_ip_route_get_attributes_direct (NMIPRoute *route);
 
-NMSriovVF *_nm_utils_sriov_vf_from_strparts (const char *index, const char *detail, GError **error);
+NMSriovVF *_nm_utils_sriov_vf_from_strparts (const char *index, const char *detail, gboolean ignore_unknown, GError **error);
 gboolean _nm_sriov_vf_attribute_validate_all (const NMSriovVF *vf, GError **error);
 
 static inline void
@@ -272,8 +318,25 @@ gboolean _nm_utils_check_module_file (const char *name,
                                       gpointer user_data,
                                       GError **error);
 
+/*****************************************************************************/
+
+typedef struct _NMUuid {
+	guchar uuid[16];
+} NMUuid;
+
+NMUuid *_nm_utils_uuid_parse (const char *str,
+                              NMUuid *uuid);
+char *_nm_utils_uuid_unparse (const NMUuid *uuid,
+                              char *out_str /*[37]*/);
+NMUuid *_nm_utils_uuid_generate_random (NMUuid *out_uuid);
+
+gboolean nm_utils_uuid_is_null (const NMUuid *uuid);
+
 #define NM_UTILS_UUID_TYPE_LEGACY            0
-#define NM_UTILS_UUID_TYPE_VARIANT3          1
+#define NM_UTILS_UUID_TYPE_VERSION3          3
+#define NM_UTILS_UUID_TYPE_VERSION5          5
+
+NMUuid *nm_utils_uuid_generate_from_string_bin (NMUuid *uuid, const char *s, gssize slen, int uuid_type, gpointer type_args);
 
 char *nm_utils_uuid_generate_from_string (const char *s, gssize slen, int uuid_type, gpointer type_args);
 
@@ -294,6 +357,10 @@ void _nm_dbus_errors_init (void);
 
 extern gboolean _nm_utils_is_manager_process;
 
+gboolean _nm_dbus_typecheck_response (GVariant *response,
+                                      const GVariantType *reply_type,
+                                      GError **error);
+
 gulong _nm_dbus_signal_connect_data (GDBusProxy *proxy,
                                      const char *signal_name,
                                      const GVariantType *signature,
@@ -318,6 +385,11 @@ GVariant *_nm_dbus_proxy_call_sync   (GDBusProxy           *proxy,
                                       GCancellable         *cancellable,
                                       GError              **error);
 
+GVariant * _nm_dbus_connection_call_finish (GDBusConnection *dbus_connection,
+                                            GAsyncResult *result,
+                                            const GVariantType *reply_type,
+                                            GError **error);
+
 gboolean _nm_dbus_error_has_name (GError     *error,
                                   const char *dbus_error_name);
 
@@ -452,6 +524,30 @@ NMSettingBluetooth *_nm_connection_get_setting_bluetooth_for_nap (NMConnection *
 
 const char *nm_utils_inet_ntop (int addr_family, gconstpointer addr, char *dst);
 
+static inline char *
+nm_utils_inet4_ntop_dup (in_addr_t addr)
+{
+	char buf[NM_UTILS_INET_ADDRSTRLEN];
+
+	return g_strdup (nm_utils_inet4_ntop (addr, buf));
+}
+
+static inline char *
+nm_utils_inet6_ntop_dup (const struct in6_addr *addr)
+{
+	char buf[NM_UTILS_INET_ADDRSTRLEN];
+
+	return g_strdup (nm_utils_inet6_ntop (addr, buf));
+}
+
+static inline char *
+nm_utils_inet_ntop_dup (int addr_family, const struct in6_addr *addr)
+{
+	char buf[NM_UTILS_INET_ADDRSTRLEN];
+
+	return g_strdup (nm_utils_inet_ntop (addr_family, addr, buf));
+}
+
 gboolean _nm_utils_inet6_is_token (const struct in6_addr *in6addr);
 
 /*****************************************************************************/
@@ -521,9 +617,11 @@ typedef struct _NMSettInfoSetting NMSettInfoSetting;
 
 typedef GVariant *(*NMSettingPropertyGetFunc)           (NMSetting     *setting,
                                                          const char    *property);
-typedef GVariant *(*NMSettingPropertySynthFunc)         (NMSetting     *setting,
+typedef GVariant *(*NMSettingPropertySynthFunc)         (const NMSettInfoSetting *sett_info,
+                                                         guint property_idx,
                                                          NMConnection  *connection,
-                                                         const char    *property);
+                                                         NMSetting     *setting,
+                                                         NMConnectionSerializationFlags flags);
 typedef gboolean  (*NMSettingPropertySetFunc)           (NMSetting     *setting,
                                                          GVariant      *connection_dict,
                                                          const char    *property,
@@ -576,15 +674,51 @@ typedef struct {
 
 struct _NMSettInfoSetting {
 	NMSettingClass *setting_class;
+
+	/* the properties, sorted by property name. */
 	const NMSettInfoProperty *property_infos;
+
+	/* the @property_infos list is sorted by property name. For some uses we need
+	 * a different sort order. If @property_infos_sorted is set, this is the order
+	 * instead. It is used for:
+	 *
+	 *   - nm_setting_enumerate_values()
+	 *   - keyfile writer adding keys to the group.
+	 *
+	 * Note that currently only NMSettingConnection implements here a sort order
+	 * that differs from alphabetical sort of the property names.
+	 */
+	const NMSettInfoProperty *const*property_infos_sorted;
+
 	guint property_infos_len;
 	NMSettInfoSettDetail detail;
 };
 
-const NMSettInfoSetting *_nm_sett_info_setting_get (NMSettingClass *setting_class);
+static inline const NMSettInfoProperty *
+_nm_sett_info_property_info_get_sorted (const NMSettInfoSetting *sett_info,
+                                        guint idx)
+{
+	nm_assert (sett_info);
+	nm_assert (idx < sett_info->property_infos_len);
+	nm_assert (!sett_info->property_infos_sorted || sett_info->property_infos_sorted[idx]);
 
-const NMSettInfoProperty *_nm_sett_info_property_get (NMSettingClass *setting_class,
-                                                      const char *property_name);
+	return   sett_info->property_infos_sorted
+	       ? sett_info->property_infos_sorted[idx]
+	       : &sett_info->property_infos[idx];
+}
+
+const NMSettInfoProperty *_nm_sett_info_setting_get_property_info (const NMSettInfoSetting *sett_info,
+                                                                   const char *property_name);
+
+const NMSettInfoSetting *_nm_setting_class_get_sett_info (NMSettingClass *setting_class);
+
+static inline const NMSettInfoProperty *
+_nm_setting_class_get_property_info (NMSettingClass *setting_class,
+                                     const char *property_name)
+{
+	return _nm_sett_info_setting_get_property_info (_nm_setting_class_get_sett_info (setting_class),
+	                                                property_name);
+}
 
 /*****************************************************************************/
 
diff --git a/libnm-core/nm-crypto.c b/libnm-core/nm-crypto.c
index dc8f1c15..1af2ea28 100644
--- a/libnm-core/nm-crypto.c
+++ b/libnm-core/nm-crypto.c
@@ -879,13 +879,10 @@ nm_crypto_md5_hash (const guint8 *salt,
                     gsize buflen)
 {
 	nm_auto_free_checksum GChecksum *ctx = NULL;
-#define MD5_DIGEST_LEN 16
-	nm_auto_clear_static_secret_ptr const NMSecretPtr digest = NM_SECRET_PTR_STATIC (MD5_DIGEST_LEN);
+	nm_auto_clear_static_secret_ptr const NMSecretPtr digest = NM_SECRET_PTR_STATIC (NM_UTILS_CHECKSUM_LENGTH_MD5);
 	gsize bufidx = 0;
 	int i;
 
-	nm_assert (g_checksum_type_get_length (G_CHECKSUM_MD5) == MD5_DIGEST_LEN);
-
 	g_return_if_fail (password_len == 0 || password);
 	g_return_if_fail (buffer);
 	g_return_if_fail (buflen > 0);
@@ -894,25 +891,21 @@ nm_crypto_md5_hash (const guint8 *salt,
 	ctx = g_checksum_new (G_CHECKSUM_MD5);
 
 	for (;;) {
-		gsize digest_len;
-
 		if (password_len > 0)
 			g_checksum_update (ctx, (const guchar *) password, password_len);
 		if (salt_len > 0)
 			g_checksum_update (ctx, (const guchar *) salt, salt_len);
 
-		digest_len = MD5_DIGEST_LEN;
-		g_checksum_get_digest (ctx, digest.bin, &digest_len);
-		nm_assert (digest_len == MD5_DIGEST_LEN);
+		nm_utils_checksum_get_digest_len (ctx, digest.bin, NM_UTILS_CHECKSUM_LENGTH_MD5);
 
-		for (i = 0; i < MD5_DIGEST_LEN; i++) {
+		for (i = 0; i < NM_UTILS_CHECKSUM_LENGTH_MD5; i++) {
 			if (bufidx >= buflen)
 				return;
 			buffer[bufidx++] = digest.bin[i];
 		}
 
 		g_checksum_reset (ctx);
-		g_checksum_update (ctx, digest.ptr, MD5_DIGEST_LEN);
+		g_checksum_update (ctx, digest.ptr, NM_UTILS_CHECKSUM_LENGTH_MD5);
 	}
 }
 
diff --git a/libnm-core/nm-dbus-interface.h b/libnm-core/nm-dbus-interface.h
index 4e12dc63..aac4d7ea 100644
--- a/libnm-core/nm-dbus-interface.h
+++ b/libnm-core/nm-dbus-interface.h
@@ -168,7 +168,7 @@ typedef enum {
  * @NM_CONNECTIVITY_PORTAL: The Internet connection is hijacked by a captive
  *   portal gateway. The graphical shell may open a sandboxed web browser window
  *   (because the captive portals typically attempt a man-in-the-middle attacks
- *   agains the https connections) for the purpose of authenticating to a gateway
+ *   against the https connections) for the purpose of authenticating to a gateway
  *   and retrigger the connectivity check with CheckConnectivity() when the
  *   browser window is dismissed.
  * @NM_CONNECTIVITY_LIMITED: The host is connected to a network, does not appear
@@ -190,7 +190,7 @@ typedef enum {
  * @NM_DEVICE_TYPE_UNKNOWN: unknown device
  * @NM_DEVICE_TYPE_GENERIC: generic support for unrecognized device types
  * @NM_DEVICE_TYPE_ETHERNET: a wired ethernet device
- * @NM_DEVICE_TYPE_WIFI: an 802.11 WiFi device
+ * @NM_DEVICE_TYPE_WIFI: an 802.11 Wi-Fi device
  * @NM_DEVICE_TYPE_UNUSED1: not used
  * @NM_DEVICE_TYPE_UNUSED2: not used
  * @NM_DEVICE_TYPE_BT: a Bluetooth device supporting PAN or DUN access protocols
@@ -456,7 +456,7 @@ typedef enum {
  *   setting physical link properties, and anything else required to connect
  *   to the requested network.
  * @NM_DEVICE_STATE_CONFIG: the device is connecting to the requested network.
- *   This may include operations like associating with the WiFi AP, dialing
+ *   This may include operations like associating with the Wi-Fi AP, dialing
  *   the modem, connecting to the remote Bluetooth device, etc.
  * @NM_DEVICE_STATE_NEED_AUTH: the device requires more information to continue
  *   connecting to the requested network.  This includes secrets like WiFi
@@ -549,7 +549,7 @@ typedef enum {
  * @NM_DEVICE_STATE_REASON_DEPENDENCY_FAILED: A dependency of the connection failed
  * @NM_DEVICE_STATE_REASON_BR2684_FAILED: Problem with the RFC 2684 Ethernet over ADSL bridge
  * @NM_DEVICE_STATE_REASON_MODEM_MANAGER_UNAVAILABLE: ModemManager not running
- * @NM_DEVICE_STATE_REASON_SSID_NOT_FOUND: The WiFi network could not be found
+ * @NM_DEVICE_STATE_REASON_SSID_NOT_FOUND: The Wi-Fi network could not be found
  * @NM_DEVICE_STATE_REASON_SECONDARY_CONNECTION_FAILED: A secondary connection of the base connection failed
  * @NM_DEVICE_STATE_REASON_DCB_FCOE_FAILED: DCB or FCoE setup failed
  * @NM_DEVICE_STATE_REASON_TEAMD_CONTROL_FAILED: teamd control failed
@@ -960,20 +960,25 @@ typedef enum { /*< flags >*/
  * @NM_ACTIVATION_STATE_FLAG_IP6_READY: IPv6 setting is completed.
  * @NM_ACTIVATION_STATE_FLAG_MASTER_HAS_SLAVES: The master has any slave devices attached.
  *   This only makes sense if the device is a master.
+ * @NM_ACTIVATION_STATE_FLAG_LIFETIME_BOUND_TO_PROFILE_VISIBILITY: the lifetime
+ *   of the activation is bound to the visilibity of the connection profile,
+ *   which in turn depends on "connection.permissions" and whether a session
+ *   for the user exists. Since: 1.16
  *
  * Flags describing the current activation state.
  *
  * Since: 1.10
  **/
 typedef enum { /*< flags >*/
-	NM_ACTIVATION_STATE_FLAG_NONE                       = 0,
+	NM_ACTIVATION_STATE_FLAG_NONE                                 = 0,
 
-	NM_ACTIVATION_STATE_FLAG_IS_MASTER                  = (1LL <<  0),
-	NM_ACTIVATION_STATE_FLAG_IS_SLAVE                   = (1LL <<  1),
-	NM_ACTIVATION_STATE_FLAG_LAYER2_READY               = (1LL <<  2),
-	NM_ACTIVATION_STATE_FLAG_IP4_READY                  = (1LL <<  3),
-	NM_ACTIVATION_STATE_FLAG_IP6_READY                  = (1LL <<  4),
-	NM_ACTIVATION_STATE_FLAG_MASTER_HAS_SLAVES          = (1LL <<  5),
+	NM_ACTIVATION_STATE_FLAG_IS_MASTER                            = (1LL <<  0),
+	NM_ACTIVATION_STATE_FLAG_IS_SLAVE                             = (1LL <<  1),
+	NM_ACTIVATION_STATE_FLAG_LAYER2_READY                         = (1LL <<  2),
+	NM_ACTIVATION_STATE_FLAG_IP4_READY                            = (1LL <<  3),
+	NM_ACTIVATION_STATE_FLAG_IP6_READY                            = (1LL <<  4),
+	NM_ACTIVATION_STATE_FLAG_MASTER_HAS_SLAVES                    = (1LL <<  5),
+	NM_ACTIVATION_STATE_FLAG_LIFETIME_BOUND_TO_PROFILE_VISIBILITY = (1LL <<  6),
 } NMActivationStateFlags;
 
 /**
@@ -1004,7 +1009,7 @@ typedef enum { /*< flags >*/
  *   again (because it's about to be deleted), but a manual activation will
  *   clear the volatile flag.
  * @NM_SETTINGS_UPDATE2_FLAG_BLOCK_AUTOCONNECT: usually, when the connection
- *   has autoconnect enabled and is modified, it becomes elegible to autoconnect
+ *   has autoconnect enabled and is modified, it becomes eligible to autoconnect
  *   right away. Setting this flag, disables autoconnect until the connection
  *   is manually activated.
  *
diff --git a/libnm-core/nm-dbus-types.xml b/libnm-core/nm-dbus-types.xml
index e3e9fca9..b824f78a 100644
--- a/libnm-core/nm-dbus-types.xml
+++ b/libnm-core/nm-dbus-types.xml
@@ -125,7 +125,7 @@
             <row role="constant">
               <entry role="enum_member_name"><para>NM_CONNECTIVITY_PORTAL</para><para></para></entry>
               <entry role="enum_member_value"><para>= <literal>2</literal></para><para></para></entry>
-              <entry role="enum_member_description"><para>The Internet connection is hijacked by a captive portal gateway. The graphical shell may open a sandboxed web browser window (because the captive portals typically attempt a man-in-the-middle attacks agains the https connections) for the purpose of authenticating to a gateway and retrigger the connectivity check with CheckConnectivity() when the browser window is dismissed.</para><para></para></entry>
+              <entry role="enum_member_description"><para>The Internet connection is hijacked by a captive portal gateway. The graphical shell may open a sandboxed web browser window (because the captive portals typically attempt a man-in-the-middle attacks against the https connections) for the purpose of authenticating to a gateway and retrigger the connectivity check with CheckConnectivity() when the browser window is dismissed.</para><para></para></entry>
             </row>
             <row role="constant">
               <entry role="enum_member_name"><para>NM_CONNECTIVITY_LIMITED</para><para></para></entry>
@@ -175,7 +175,7 @@
             <row role="constant">
               <entry role="enum_member_name"><para>NM_DEVICE_TYPE_WIFI</para><para></para></entry>
               <entry role="enum_member_value"><para>= <literal>2</literal></para><para></para></entry>
-              <entry role="enum_member_description"><para>an 802.11 WiFi device</para><para></para></entry>
+              <entry role="enum_member_description"><para>an 802.11 Wi-Fi device</para><para></para></entry>
             </row>
             <row role="constant">
               <entry role="enum_member_name"><para>NM_DEVICE_TYPE_UNUSED1</para><para></para></entry>
@@ -760,7 +760,7 @@
             <row role="constant">
               <entry role="enum_member_name"><para>NM_DEVICE_STATE_CONFIG</para><para></para></entry>
               <entry role="enum_member_value"><para>= <literal>50</literal></para><para></para></entry>
-              <entry role="enum_member_description"><para>the device is connecting to the requested network. This may include operations like associating with the WiFi AP, dialing the modem, connecting to the remote Bluetooth device, etc.</para><para></para></entry>
+              <entry role="enum_member_description"><para>the device is connecting to the requested network. This may include operations like associating with the Wi-Fi AP, dialing the modem, connecting to the remote Bluetooth device, etc.</para><para></para></entry>
             </row>
             <row role="constant">
               <entry role="enum_member_name"><para>NM_DEVICE_STATE_NEED_AUTH</para><para></para></entry>
@@ -1085,7 +1085,7 @@
             <row role="constant">
               <entry role="enum_member_name"><para>NM_DEVICE_STATE_REASON_SSID_NOT_FOUND</para><para></para></entry>
               <entry role="enum_member_value"><para>= <literal>53</literal></para><para></para></entry>
-              <entry role="enum_member_description"><para>The WiFi network could not be found</para><para></para></entry>
+              <entry role="enum_member_description"><para>The Wi-Fi network could not be found</para><para></para></entry>
             </row>
             <row role="constant">
               <entry role="enum_member_name"><para>NM_DEVICE_STATE_REASON_SECONDARY_CONNECTION_FAILED</para><para></para></entry>
@@ -1722,6 +1722,11 @@
               <entry role="enum_member_value"><para>= <literal>(1LL</literal></para><para></para></entry>
               <entry role="enum_member_description"><para>The master has any slave devices attached. This only makes sense if the device is a master.</para><para></para></entry>
             </row>
+            <row role="constant">
+              <entry role="enum_member_name"><para>NM_ACTIVATION_STATE_FLAG_LIFETIME_BOUND_TO_PROFILE_VISIBILITY</para><para></para></entry>
+              <entry role="enum_member_value"><para>= <literal>(1LL</literal></para><para></para></entry>
+              <entry role="enum_member_description"><para>the lifetime of the activation is bound to the visilibity of the connection profile, which in turn depends on "connection.permissions" and whether a session for the user exists. Since: 1.16</para><para></para></entry>
+            </row>
           </tbody>
         </tgroup>
       </informaltable>
@@ -1775,7 +1780,7 @@
             <row role="constant">
               <entry role="enum_member_name"><para>NM_SETTINGS_UPDATE2_FLAG_BLOCK_AUTOCONNECT</para><para></para></entry>
               <entry role="enum_member_value"><para>= <literal>(1LL</literal></para><para></para></entry>
-              <entry role="enum_member_description"><para>usually, when the connection has autoconnect enabled and is modified, it becomes elegible to autoconnect right away. Setting this flag, disables autoconnect until the connection is manually activated.</para><para></para></entry>
+              <entry role="enum_member_description"><para>usually, when the connection has autoconnect enabled and is modified, it becomes eligible to autoconnect right away. Setting this flag, disables autoconnect until the connection is manually activated.</para><para></para></entry>
             </row>
           </tbody>
         </tgroup>
diff --git a/libnm-core/nm-dbus-utils.c b/libnm-core/nm-dbus-utils.c
index 25af7c99..69f4bb2f 100644
--- a/libnm-core/nm-dbus-utils.c
+++ b/libnm-core/nm-dbus-utils.c
@@ -174,23 +174,35 @@ _nm_dbus_signal_connect_data (GDBusProxy *proxy,
  * Returns: the signal handler ID, as with _nm_signal_connect_data().
  */
 
-static void
-typecheck_response (GVariant **response,
-                    const GVariantType *reply_type,
-                    GError **error)
+/**
+ * _nm_dbus_typecheck_response:
+ * @response: the #GVariant response to check.
+ * @reply_type: the expected reply type. It may be %NULL to perform no
+ *   checking.
+ * @error: (allow-none): the error in case the @reply_type does not match.
+ *
+ * Returns: %TRUE, if @response is of the expected @reply_type.
+ */
+gboolean
+_nm_dbus_typecheck_response (GVariant *response,
+                             const GVariantType *reply_type,
+                             GError **error)
 {
-	if (   *response
-	    && reply_type
-	    && !g_variant_is_of_type (*response, reply_type)) {
-		/* This is the same error code that g_dbus_connection_call() returns if
-		 * @reply_type doesn't match.
-		 */
-		g_set_error (error, G_IO_ERROR, G_IO_ERROR_INVALID_ARGUMENT,
-		             _("Method returned type '%s', but expected '%s'"),
-		             g_variant_get_type_string (*response),
-		             g_variant_type_peek_string (reply_type));
-		g_clear_pointer (response, g_variant_unref);
-	}
+	g_return_val_if_fail (response, FALSE);
+
+	if (!reply_type)
+		return TRUE;
+	if (g_variant_is_of_type (response, reply_type))
+		return TRUE;
+
+	/* This is the same error code that g_dbus_connection_call() returns if
+	 * @reply_type doesn't match.
+	 */
+	g_set_error (error, G_IO_ERROR, G_IO_ERROR_INVALID_ARGUMENT,
+	             _("Method returned type '%s', but expected '%s'"),
+	             g_variant_get_type_string (response),
+	             g_variant_type_peek_string (reply_type));
+	return FALSE;
 }
 
 /**
@@ -215,11 +227,15 @@ _nm_dbus_proxy_call_finish (GDBusProxy          *proxy,
                             const GVariantType  *reply_type,
                             GError             **error)
 {
-	GVariant *ret;
+	GVariant *variant;
 
-	ret = g_dbus_proxy_call_finish (proxy, res, error);
-	typecheck_response (&ret, reply_type, error);
-	return ret;
+	variant = g_dbus_proxy_call_finish (proxy,
+	                                    res,
+	                                    error);
+	if (   variant
+	    && !_nm_dbus_typecheck_response (variant, reply_type, error))
+		nm_clear_pointer (&variant, g_variant_unref);
+	return variant;
 }
 
 /**
@@ -253,13 +269,34 @@ _nm_dbus_proxy_call_sync (GDBusProxy          *proxy,
                           GCancellable        *cancellable,
                           GError             **error)
 {
-	GVariant *ret;
+	GVariant *variant;
+
+	variant = g_dbus_proxy_call_sync (proxy,
+	                                  method_name,
+	                                  parameters,
+	                                  flags,
+	                                  timeout_msec,
+	                                  cancellable,
+	                                  error);
+	if (   variant
+	    && !_nm_dbus_typecheck_response (variant, reply_type, error))
+		nm_clear_pointer (&variant, g_variant_unref);
+	return variant;
+}
+
+GVariant *
+_nm_dbus_connection_call_finish (GDBusConnection *dbus_connection,
+                                 GAsyncResult *result,
+                                 const GVariantType *reply_type,
+                                 GError **error)
+{
+	GVariant *variant;
 
-	ret = g_dbus_proxy_call_sync (proxy, method_name, parameters,
-	                              flags, timeout_msec,
-	                              cancellable, error);
-	typecheck_response (&ret, reply_type, error);
-	return ret;
+	variant = g_dbus_connection_call_finish (dbus_connection, result, error);
+	if (   variant
+	    && !_nm_dbus_typecheck_response (variant, reply_type, error))
+		nm_clear_pointer (&variant, g_variant_unref);
+	return variant;
 }
 
 /**
diff --git a/libnm-core/nm-keyfile-internal.h b/libnm-core/nm-keyfile-internal.h
index 94228d95..5487f59d 100644
--- a/libnm-core/nm-keyfile-internal.h
+++ b/libnm-core/nm-keyfile-internal.h
@@ -168,4 +168,19 @@ gboolean _nm_keyfile_a_contains_all_in_b (GKeyFile *kf_a, GKeyFile *kf_b);
 gboolean _nm_keyfile_equals (GKeyFile *kf_a, GKeyFile *kf_b, gboolean consider_order);
 gboolean _nm_keyfile_has_values (GKeyFile *keyfile);
 
+/*****************************************************************************/
+
+#define NM_KEYFILE_PATH_NAME_ETC_DEFAULT         NMCONFDIR "/system-connections"
+#define NM_KEYFILE_PATH_NAME_RUN                 NMRUNDIR "/system-connections"
+
+#define NM_KEYFILE_PATH_SUFFIX_NMCONNECTION      ".nmconnection"
+
+#define NM_KEYFILE_PATH_PREFIX_NMLOADED          ".loaded-"
+
+#define NM_KEYFILE_PATH_NMLOADED_NULL            "/dev/null"
+
+gboolean nm_keyfile_utils_ignore_filename (const char *filename, gboolean require_extension);
+
+char *nm_keyfile_utils_create_filename (const char *filename, gboolean with_extension);
+
 #endif /* __NM_KEYFILE_INTERNAL_H__ */
diff --git a/libnm-core/nm-keyfile-utils.c b/libnm-core/nm-keyfile-utils.c
index 21f8b07d..9543ebde 100644
--- a/libnm-core/nm-keyfile-utils.c
+++ b/libnm-core/nm-keyfile-utils.c
@@ -48,7 +48,7 @@ nm_keyfile_plugin_get_alias_for_setting_name (const char *setting_name)
 	g_return_val_if_fail (setting_name != NULL, NULL);
 
 	for (i = 0; i < G_N_ELEMENTS (alias_list); i++) {
-		if (strcmp (setting_name, alias_list[i].setting) == 0)
+		if (nm_streq (setting_name, alias_list[i].setting))
 			return alias_list[i].alias;
 	}
 	return NULL;
@@ -62,7 +62,7 @@ nm_keyfile_plugin_get_setting_name_for_alias (const char *alias)
 	g_return_val_if_fail (alias != NULL, NULL);
 
 	for (i = 0; i < G_N_ELEMENTS (alias_list); i++) {
-		if (strcmp (alias, alias_list[i].alias) == 0)
+		if (nm_streq (alias, alias_list[i].alias))
 			return alias_list[i].setting;
 	}
 	return NULL;
@@ -82,17 +82,22 @@ nm_keyfile_plugin_kf_get_##stype##_list (GKeyFile *kf, \
 	get_ctype list; \
 	const char *alias; \
 	GError *local = NULL; \
+	gsize l; \
  \
-	list = g_key_file_get_##stype##_list (kf, group, key, out_length, &local); \
+	list = g_key_file_get_##stype##_list (kf, group, key, &l, &local); \
 	if (g_error_matches (local, G_KEY_FILE_ERROR, G_KEY_FILE_ERROR_GROUP_NOT_FOUND)) { \
 		alias = nm_keyfile_plugin_get_alias_for_setting_name (group); \
 		if (alias) { \
 			g_clear_error (&local); \
-			list = g_key_file_get_##stype##_list (kf, alias, key, out_length, &local); \
+			list = g_key_file_get_##stype##_list (kf, alias, key, &l, &local); \
 		} \
 	} \
+	nm_assert ((!local) != (!list)); \
 	if (local) \
 		g_propagate_error (error, local); \
+	if (!list) \
+		l = 0; \
+	NM_SET_OUT (out_length, l); \
 	return list; \
 } \
  \
@@ -174,11 +179,41 @@ nm_keyfile_plugin_kf_set_##stype (GKeyFile *kf, \
 }
 
 DEFINE_KF_WRAPPER(string, char*, const char*);
-DEFINE_KF_WRAPPER(integer, int, int);
-DEFINE_KF_WRAPPER(uint64, guint64, guint64);
 DEFINE_KF_WRAPPER(boolean, gboolean, gboolean);
 DEFINE_KF_WRAPPER(value, char*, const char*);
 
+gint64
+nm_keyfile_plugin_kf_get_int64 (GKeyFile *kf,
+                                const char *group,
+                                const char *key,
+                                guint base,
+                                gint64 min,
+                                gint64 max,
+                                gint64 fallback,
+                                GError **error)
+{
+	gs_free char *s = NULL;
+	int errsv;
+	gint64 v;
+
+	s = nm_keyfile_plugin_kf_get_value (kf, group, key, error);
+	if (!s) {
+		errno = ENODATA;
+		return fallback;
+	}
+
+	v = _nm_utils_ascii_str_to_int64 (s, base, min, max, fallback);
+	errsv = errno;
+	if (   errsv != 0
+	    && error) {
+		g_set_error (error, G_KEY_FILE_ERROR, G_KEY_FILE_ERROR_INVALID_VALUE,
+		             _("value is not an integer in range [%lld, %lld]"),
+		             (long long) min, (long long) max);
+		errno = errsv;
+	}
+	return v;
+}
+
 char **
 nm_keyfile_plugin_kf_get_keys (GKeyFile *kf,
                                const char *group,
@@ -188,15 +223,21 @@ nm_keyfile_plugin_kf_get_keys (GKeyFile *kf,
 	char **keys;
 	const char *alias;
 	GError *local = NULL;
+	gsize l;
 
-	keys = g_key_file_get_keys (kf, group, out_length, &local);
+	keys = g_key_file_get_keys (kf, group, &l, &local);
 	if (g_error_matches (local, G_KEY_FILE_ERROR, G_KEY_FILE_ERROR_GROUP_NOT_FOUND)) {
 		alias = nm_keyfile_plugin_get_alias_for_setting_name (group);
 		if (alias) {
 			g_clear_error (&local);
-			keys = g_key_file_get_keys (kf, alias, out_length, error ? &local : NULL);
+			keys = g_key_file_get_keys (kf, alias, &l, error ? &local : NULL);
 		}
 	}
+	nm_assert ((!local) != (!keys));
+	if (!keys)
+		l = 0;
+	nm_assert (l == NM_PTRARRAY_LEN (keys));
+	NM_SET_OUT (out_length, l);
 	if (local)
 		g_propagate_error (error, local);
 	return keys;
diff --git a/libnm-core/nm-keyfile-utils.h b/libnm-core/nm-keyfile-utils.h
index 46a6d564..0467230e 100644
--- a/libnm-core/nm-keyfile-utils.h
+++ b/libnm-core/nm-keyfile-utils.h
@@ -67,12 +67,19 @@ void nm_keyfile_plugin_kf_set_##stype (GKeyFile *kf, \
                                        const char *key, \
                                        set_ctype value);
 DEFINE_KF_WRAPPER_PROTO(string, char*, const char*)
-DEFINE_KF_WRAPPER_PROTO(integer, int, int)
-DEFINE_KF_WRAPPER_PROTO(uint64, guint64, guint64)
 DEFINE_KF_WRAPPER_PROTO(boolean, gboolean, gboolean)
 DEFINE_KF_WRAPPER_PROTO(value, char*, const char*)
 
 /* Misc */
+gint64 nm_keyfile_plugin_kf_get_int64 (GKeyFile *kf,
+                                       const char *group,
+                                       const char *key,
+                                       guint base,
+                                       gint64 min,
+                                       gint64 max,
+                                       gint64 fallback,
+                                       GError **error);
+
 char ** nm_keyfile_plugin_kf_get_keys    (GKeyFile *kf,
                                            const char *group,
                                            gsize *out_length,
@@ -90,4 +97,3 @@ const char *nm_keyfile_key_decode (const char *key,
                                    char **out_to_free);
 
 #endif  /* __NM_KEYFILE_UTILS_H__ */
-
diff --git a/libnm-core/nm-keyfile.c b/libnm-core/nm-keyfile.c
index e4ed1899..e2068130 100644
--- a/libnm-core/nm-keyfile.c
+++ b/libnm-core/nm-keyfile.c
@@ -96,6 +96,15 @@ _handle_warn (KeyfileReaderInfo *info,
 		_info->error == NULL; \
 	})
 
+/*****************************************************************************/
+
+static gboolean
+_secret_flags_persist_secret (NMSettingSecretFlags flags)
+{
+	return flags == NM_SETTING_SECRET_FLAG_NONE;
+}
+
+/*****************************************************************************/
 /* Some setting properties also contain setting names, such as
  * NMSettingConnection's 'type' property (which specifies the base type of the
  * connection, e.g. ethernet or wifi) or 'slave-type' (specifies type of slave
@@ -106,17 +115,18 @@ static void
 setting_alias_parser (KeyfileReaderInfo *info, NMSetting *setting, const char *key)
 {
 	const char *setting_name = nm_setting_get_name (setting);
-	char *s;
 	const char *key_setting_name;
+	gs_free char *s = NULL;
 
 	s = nm_keyfile_plugin_kf_get_string (info->keyfile, setting_name, key, NULL);
-	if (s) {
-		key_setting_name = nm_keyfile_plugin_get_setting_name_for_alias (s);
-		g_object_set (G_OBJECT (setting),
-		              key, key_setting_name ?: s,
-		              NULL);
-		g_free (s);
-	}
+	if (!s)
+		return;
+
+	key_setting_name = nm_keyfile_plugin_get_setting_name_for_alias (s);
+	g_object_set (G_OBJECT (setting),
+	              key,
+	              key_setting_name ?: s,
+	              NULL);
 }
 
 static void
@@ -129,7 +139,7 @@ sriov_vfs_parser (KeyfileReaderInfo *info, NMSetting *setting, const char *key)
 	int i;
 
 	keys = nm_keyfile_plugin_kf_get_keys (info->keyfile, setting_name, &n_keys, NULL);
-	if (!keys || n_keys == 0)
+	if (n_keys == 0)
 		return;
 
 	vfs = g_ptr_array_new_with_free_func ((GDestroyNotify) nm_sriov_vf_unref);
@@ -152,7 +162,7 @@ sriov_vfs_parser (KeyfileReaderInfo *info, NMSetting *setting, const char *key)
 		                                         keys[i],
 		                                         NULL);
 
-		vf = _nm_utils_sriov_vf_from_strparts (rest, value, NULL);
+		vf = _nm_utils_sriov_vf_from_strparts (rest, value, TRUE, NULL);
 		if (vf)
 			g_ptr_array_add (vfs, vf);
 	}
@@ -372,7 +382,7 @@ read_field (char **current, const char **out_err_str, const char *characters, co
  * address/plen,gateway,metric (NETWORK via GATEWAY dev DEVICE metric METRIC)
  *
  * For backward, forward and sideward compatibility, slash (/),
- * semicolon (;) and comma (,) are interchangable. The choice of
+ * semicolon (;) and comma (,) are interchangeable. The choice of
  * separator in the above examples is therefore not significant.
  *
  * Leaving out the prefix length is discouraged and DEPRECATED. The
@@ -622,17 +632,16 @@ ip_address_or_route_parser (KeyfileReaderInfo *info, NMSetting *setting, const c
 	gs_free char *gateway = NULL;
 	gs_unref_ptrarray GPtrArray *list = NULL;
 	gs_strfreev char **keys = NULL;
-	gsize i_keys, keys_len;
+	gsize i_keys, n_keys;
 	gs_free IPAddrRouteBuildListData *build_list = NULL;
 	gsize i_build_list, build_list_len = 0;
 
-	keys = nm_keyfile_plugin_kf_get_keys (info->keyfile, setting_name, &keys_len, NULL);
-
-	if (keys_len == 0)
+	keys = nm_keyfile_plugin_kf_get_keys (info->keyfile, setting_name, &n_keys, NULL);
+	if (n_keys == 0)
 		return;
 
 	/* first create a list of all relevant keys, and sort them. */
-	for (i_keys = 0; i_keys < keys_len; i_keys++) {
+	for (i_keys = 0; i_keys < n_keys; i_keys++) {
 		const char *s_key = keys[i_keys];
 		gint32 key_idx;
 		gint8 key_type;
@@ -641,7 +650,7 @@ ip_address_or_route_parser (KeyfileReaderInfo *info, NMSetting *setting, const c
 			continue;
 
 		if (G_UNLIKELY (!build_list))
-			build_list = g_new (IPAddrRouteBuildListData, keys_len - i_keys);
+			build_list = g_new (IPAddrRouteBuildListData, n_keys - i_keys);
 
 		build_list[build_list_len].s_key = s_key;
 		build_list[build_list_len].key_idx = key_idx;
@@ -786,7 +795,6 @@ mac_address_parser (KeyfileReaderInfo *info, NMSetting *setting, const char *key
 	const char *p, *mac_str;
 	gs_free guint8 *buf_arr = NULL;
 	guint buf_len = 0;
-	gsize length;
 
 	tmp_string = nm_keyfile_plugin_kf_get_string (info->keyfile, setting_name, key, NULL);
 
@@ -819,6 +827,7 @@ mac_address_parser (KeyfileReaderInfo *info, NMSetting *setting, const char *key
 
 	if (!buf_arr) {
 		gs_free int *tmp_list = NULL;
+		gsize length;
 
 		/* Old format; list of ints */
 		tmp_list = nm_keyfile_plugin_kf_get_integer_list (info->keyfile, setting_name, key, &length, NULL);
@@ -879,9 +888,10 @@ read_hash_of_string (GKeyFile *file, NMSetting *setting, const char *key)
 	const char *const*iter;
 	const char *setting_name = nm_setting_get_name (setting);
 	gboolean is_vpn;
+	gsize n_keys;
 
-	keys = nm_keyfile_plugin_kf_get_keys (file, setting_name, NULL, NULL);
-	if (!keys || !*keys)
+	keys = nm_keyfile_plugin_kf_get_keys (file, setting_name, &n_keys, NULL);
+	if (n_keys == 0)
 		return;
 
 	if (   (is_vpn = NM_IS_SETTING_VPN (setting))
@@ -902,7 +912,7 @@ read_hash_of_string (GKeyFile *file, NMSetting *setting, const char *key)
 				if (!g_object_class_find_property (G_OBJECT_GET_CLASS (setting), name))
 					nm_setting_vpn_add_data_item (NM_SETTING_VPN (setting), name, value);
 			} else {
-				if (strcmp (name, "interface-name"))
+				if (!nm_streq (name, "interface-name"))
 					nm_setting_bond_add_option (NM_SETTING_BOND (setting), name, value);
 			}
 		}
@@ -1374,55 +1384,119 @@ cert_parser (KeyfileReaderInfo *info, NMSetting *setting, const char *key)
 	g_object_set (setting, key, bytes, NULL);
 }
 
+static int
+_parity_from_char (int ch)
+{
+#if NM_MORE_ASSERTS > 5
+	{
+		static char check = 0;
+
+		if (check == 0) {
+			nm_auto_unref_gtypeclass GEnumClass *klass = g_type_class_ref (NM_TYPE_SETTING_SERIAL_PARITY);
+			guint i;
+
+			check = 1;
+
+			/* In older versions, parity was G_TYPE_CHAR/gint8, and the character
+			 * value was stored as integer.
+			 * For example parity=69 equals parity=E, meaning NM_SETTING_SERIAL_PARITY_EVEN.
+			 *
+			 * That means, certain values are reserved. Assert that these numbers
+			 * are not reused when we extend NMSettingSerialParity enum.
+			 * Actually, since NM_SETTING_SERIAL_PARITY is g_param_spec_enum(),
+			 * we anyway cannot extend the enum without breaking API...
+			 *
+			 * [1] commit "a91e60902e libnm-core: make NMSettingSerial:parity an enum"
+			 * [2] https://cgit.freedesktop.org/NetworkManager/NetworkManager/commit/?id=a91e60902eabae1de93d61323dae6ac894b5d40f
+			 */
+			g_assert (G_IS_ENUM_CLASS (klass));
+			for (i = 0; i < klass->n_values; i++) {
+				const GEnumValue *v = &klass->values[i];
+				int num = v->value;
+
+				g_assert (_parity_from_char (num) == -1);
+				g_assert (!NM_IN_SET (num, 'e', 'E', 'o', 'O', 'n', 'N'));
+			}
+		}
+	}
+#endif
+
+	switch (ch) {
+	case 'E':
+	case 'e':
+		return NM_SETTING_SERIAL_PARITY_EVEN;
+	case 'O':
+	case 'o':
+		return NM_SETTING_SERIAL_PARITY_ODD;
+	case 'N':
+	case 'n':
+		return NM_SETTING_SERIAL_PARITY_NONE;
+	}
+
+	return -1;
+}
+
 static void
 parity_parser (KeyfileReaderInfo *info, NMSetting *setting, const char *key)
 {
 	const char *setting_name = nm_setting_get_name (setting);
-	NMSettingSerialParity parity;
-	int int_val;
-	gs_free char *str_val = NULL;
+	gs_free_error GError *err = NULL;
+	int parity;
+	gs_free char *tmp_str = NULL;
+	gint64 i64;
 
 	/* Keyfile traditionally stored this as the ASCII value for 'E', 'o', or 'n'.
 	 * We now accept either that or the (case-insensitive) character itself (but
 	 * still always write it the old way, for backward compatibility).
 	 */
-	int_val = nm_keyfile_plugin_kf_get_integer (info->keyfile, setting_name, key, NULL);
-	if (!int_val) {
-		str_val = nm_keyfile_plugin_kf_get_string (info->keyfile, setting_name, key, NULL);
-		if (str_val) {
-			if (str_val[0] && !str_val[1])
-				int_val = str_val[0];
-			else {
-				/* This will hit the warning below */
-				int_val = 'X';
-			}
+	tmp_str = nm_keyfile_plugin_kf_get_value (info->keyfile, setting_name, key, &err);
+	if (err)
+		goto out_err;
+
+	if (   tmp_str
+	    && tmp_str[0] != '\0'
+	    && tmp_str[1] == '\0') {
+		/* the ASCII characters like 'E' are taken directly... */
+		parity = _parity_from_char (tmp_str[0]);
+		if (parity >= 0)
+			goto parity_good;
+	}
+
+	i64 = _nm_utils_ascii_str_to_int64 (tmp_str, 0, G_MININT, G_MAXINT, G_MININT64);
+	if (   i64 != G_MININT64
+	    && errno == 0) {
+
+		if ((parity = _parity_from_char (i64)) >= 0) {
+			/* another oddity: the string is a valid number. However, if the numeric values
+			 * is one of the supported ASCII codes, accept it (like 69 for 'E').
+			 */
+			goto parity_good;
 		}
+
+		/* Finally, take the numeric value as is. */
+		parity = i64;
+		goto parity_good;
 	}
 
-	if (!int_val)
-		return;
+	handle_warn (info, key, NM_KEYFILE_WARN_SEVERITY_WARN,
+	             _("invalid parity value '%s'"),
+	             tmp_str ?: "");
+	return;
 
-	switch (int_val) {
-	case 'E':
-	case 'e':
-		parity = NM_SETTING_SERIAL_PARITY_EVEN;
-		break;
-	case 'O':
-	case 'o':
-		parity = NM_SETTING_SERIAL_PARITY_ODD;
-		break;
-	case 'N':
-	case 'n':
-		parity = NM_SETTING_SERIAL_PARITY_NONE;
-		break;
-	default:
-		handle_warn (info, key, NM_KEYFILE_WARN_SEVERITY_WARN,
-		             _("invalid parity value '%s'"),
-		             str_val ?: "");
+parity_good:
+	nm_g_object_set_property_enum (G_OBJECT (setting), key, NM_TYPE_SETTING_SERIAL_PARITY, parity, &err);
+
+out_err:
+	if (!err)
+		return;
+	if (   err->domain == G_KEY_FILE_ERROR
+	    && NM_IN_SET (err->code, G_KEY_FILE_ERROR_GROUP_NOT_FOUND,
+	                             G_KEY_FILE_ERROR_KEY_NOT_FOUND)) {
+		/* ignore such errors. The key is not present. */
 		return;
 	}
-
-	g_object_set (setting, key, parity, NULL);
+	handle_warn (info, key, NM_KEYFILE_WARN_SEVERITY_WARN,
+	             _("invalid setting: %s"), err->message);
 }
 
 static void
@@ -1433,7 +1507,9 @@ team_config_parser (KeyfileReaderInfo *info, NMSetting *setting, const char *key
 	gs_free_error GError *error = NULL;
 
 	conf = nm_keyfile_plugin_kf_get_string (info->keyfile, setting_name, key, NULL);
-	if (conf && conf[0] && !nm_utils_is_json_object (conf, &error)) {
+	if (   conf
+	    && conf[0]
+	    && !nm_utils_is_json_object (conf, &error)) {
 		handle_warn (info, key, NM_KEYFILE_WARN_SEVERITY_WARN,
 		             _("ignoring invalid team configuration: %s"),
 		             error->message);
@@ -1455,7 +1531,7 @@ qdisc_parser (KeyfileReaderInfo *info, NMSetting *setting, const char *key)
 	qdiscs = g_ptr_array_new_with_free_func ((GDestroyNotify) nm_tc_qdisc_unref);
 
 	keys = nm_keyfile_plugin_kf_get_keys (info->keyfile, setting_name, &n_keys, NULL);
-	if (!keys || n_keys == 0)
+	if (n_keys == 0)
 		return;
 
 	for (i = 0; i < n_keys; i++) {
@@ -1503,7 +1579,7 @@ tfilter_parser (KeyfileReaderInfo *info, NMSetting *setting, const char *key)
 	tfilters = g_ptr_array_new_with_free_func ((GDestroyNotify) nm_tc_tfilter_unref);
 
 	keys = nm_keyfile_plugin_kf_get_keys (info->keyfile, setting_name, &n_keys, NULL);
-	if (!keys || n_keys == 0)
+	if (n_keys == 0)
 		return;
 
 	for (i = 0; i < n_keys; i++) {
@@ -1663,16 +1739,21 @@ write_ip_values (GKeyFile *file,
                  const char *gateway,
                  gboolean is_route)
 {
-	GString *output;
-	int family, i;
-	const char *addr, *gw;
+	nm_auto_free_gstring GString *output = NULL;
+	int addr_family;
+	guint i;
+	const char *addr;
+	const char *gw;
 	guint32 plen;
-	char key_name[64], *key_name_idx;
+	char key_name[64];
+	char *key_name_idx;
 
 	if (!array->len)
 		return;
 
-	family = !strcmp (setting_name, NM_SETTING_IP4_CONFIG_SETTING_NAME) ? AF_INET : AF_INET6;
+	addr_family =   nm_streq (setting_name, NM_SETTING_IP4_CONFIG_SETTING_NAME)
+	              ? AF_INET
+	              : AF_INET6;
 
 	strcpy (key_name, is_route ? "route" : "address");
 	key_name_idx = key_name + strlen (key_name);
@@ -1693,7 +1774,9 @@ write_ip_values (GKeyFile *file,
 
 			addr = nm_ip_address_get_address (address);
 			plen = nm_ip_address_get_prefix (address);
-			gw = i == 0 ? gateway : NULL;
+			gw =   (i == 0)
+			     ? gateway
+			     : NULL;
 		}
 
 		g_string_set_size (output, 0);
@@ -1706,18 +1789,19 @@ write_ip_values (GKeyFile *file,
 			 * The current version supports reading of the above form.
 			 */
 			if (!gw) {
-				if (family == AF_INET)
+				if (addr_family == AF_INET)
 					gw = "0.0.0.0";
 				else
 					gw = "::";
 			}
 
 			g_string_append_printf (output, ",%s", gw);
-			if (is_route && metric != -1)
+			if (   is_route
+			    && metric != -1)
 				g_string_append_printf (output, ",%lu", (unsigned long) metric);
 		}
 
-		sprintf (key_name_idx, "%d", i + 1);
+		sprintf (key_name_idx, "%u", i + 1);
 		nm_keyfile_plugin_kf_set_string (file, setting_name, key_name, output->str);
 
 		if (is_route) {
@@ -1732,7 +1816,6 @@ write_ip_values (GKeyFile *file,
 			}
 		}
 	}
-	g_string_free (output, TRUE);
 }
 
 static void
@@ -1843,7 +1926,8 @@ write_hash_of_string (GKeyFile *file,
 	guint i, l;
 
 	/* Write VPN secrets out to a different group to keep them separate */
-	if (NM_IS_SETTING_VPN (setting) && !strcmp (key, NM_SETTING_VPN_SECRETS)) {
+	if (   NM_IS_SETTING_VPN (setting)
+	    && nm_streq (key, NM_SETTING_VPN_SECRETS)) {
 		group_name = NM_KEYFILE_GROUP_VPN_SECRETS;
 		vpn_secrets = TRUE;
 	}
@@ -1852,8 +1936,8 @@ write_hash_of_string (GKeyFile *file,
 
 	keys = nm_utils_strdict_get_keys (hash, TRUE, &l);
 	for (i = 0; i < l; i++) {
+		gs_free char *to_free = NULL;
 		const char *property, *data;
-		gboolean write_item = TRUE;
 
 		property = keys[i];
 
@@ -1864,19 +1948,16 @@ write_hash_of_string (GKeyFile *file,
 		if (vpn_secrets) {
 			NMSettingSecretFlags secret_flags = NM_SETTING_SECRET_FLAG_NONE;
 
-			nm_setting_get_secret_flags (setting, property, &secret_flags, NULL);
-			if (secret_flags != NM_SETTING_SECRET_FLAG_NONE)
-				write_item = FALSE;
+			if (!nm_setting_get_secret_flags (setting, property, &secret_flags, NULL))
+				nm_assert_not_reached ();
+			if (!_secret_flags_persist_secret (secret_flags))
+				continue;
 		}
 
-		if (write_item) {
-			gs_free char *to_free = NULL;
-
-			data = g_hash_table_lookup (hash, property);
-			nm_keyfile_plugin_kf_set_string (file, group_name,
-			                                 nm_keyfile_key_encode (property, &to_free),
-			                                 data);
-		}
+		data = g_hash_table_lookup (hash, property);
+		nm_keyfile_plugin_kf_set_string (file, group_name,
+		                                 nm_keyfile_key_encode (property, &to_free),
+		                                 data);
 	}
 }
 
@@ -1976,9 +2057,10 @@ cert_writer_default (NMConnection *connection,
 
 	scheme = cert_data->vtable->scheme_func (cert_data->setting);
 	if (scheme == NM_SETTING_802_1X_CK_SCHEME_PATH) {
-		const char *path;
-		char *path_free = NULL, *tmp;
+		gs_free char *path_free = NULL;
 		gs_free char *base_dir = NULL;
+		gs_free char *tmp = NULL;
+		const char *path;
 
 		path = cert_data->vtable->path_func (cert_data->setting);
 		g_assert (path);
@@ -1988,7 +2070,8 @@ cert_writer_default (NMConnection *connection,
 		 * context. */
 		if (path[0] && path[0] != '/') {
 			base_dir = g_get_current_dir ();
-			path = path_free = g_strconcat (base_dir, "/", path, NULL);
+			path_free = g_strconcat (base_dir, "/", path, NULL);
+			path = path_free;
 		} else
 			base_dir = g_path_get_dirname (path);
 
@@ -1998,20 +2081,21 @@ cert_writer_default (NMConnection *connection,
 		tmp = nm_keyfile_detect_unqualified_path_scheme (base_dir, path, -1, FALSE, NULL);
 		if (tmp)
 			g_clear_pointer (&tmp, g_free);
-		else
-			path = tmp = g_strconcat (NM_KEYFILE_CERT_SCHEME_PREFIX_PATH, path, NULL);
+		else {
+			tmp = g_strconcat (NM_KEYFILE_CERT_SCHEME_PREFIX_PATH, path, NULL);
+			path = tmp;
+		}
 
 		/* Path contains at least a '/', hence it cannot be recognized as the old
 		 * binary format consisting of a list of integers. */
 
 		nm_keyfile_plugin_kf_set_string (file, setting_name, cert_data->vtable->setting_key, path);
-		g_free (tmp);
-		g_free (path_free);
 	} else if (scheme == NM_SETTING_802_1X_CK_SCHEME_BLOB) {
 		GBytes *blob;
 		const guint8 *blob_data;
 		gsize blob_len;
-		char *blob_base64, *val;
+		gs_free char *blob_base64 = NULL;
+		gs_free char *val = NULL;
 
 		blob = cert_data->vtable->blob_func (cert_data->setting);
 		g_assert (blob);
@@ -2021,8 +2105,6 @@ cert_writer_default (NMConnection *connection,
 		val = g_strconcat (NM_KEYFILE_CERT_SCHEME_PREFIX_BLOB, blob_base64, NULL);
 
 		nm_keyfile_plugin_kf_set_string (file, setting_name, cert_data->vtable->setting_key, val);
-		g_free (val);
-		g_free (blob_base64);
 	} else if (scheme == NM_SETTING_802_1X_CK_SCHEME_PKCS11) {
 		nm_keyfile_plugin_kf_set_string (file, setting_name, cert_data->vtable->setting_key,
 		                                 cert_data->vtable->uri_func (cert_data->setting));
@@ -2048,7 +2130,7 @@ cert_writer (KeyfileWriterInfo *info,
 	NMKeyfileWriteTypeDataCert type_data = { 0 };
 
 	for (i = 0; nm_setting_8021x_scheme_vtable[i].setting_key; i++) {
-		if (g_strcmp0 (nm_setting_8021x_scheme_vtable[i].setting_key, key) == 0) {
+		if (nm_streq0 (nm_setting_8021x_scheme_vtable[i].setting_key, key)) {
 			objtype = &nm_setting_8021x_scheme_vtable[i];
 			break;
 		}
@@ -2506,26 +2588,28 @@ _parse_info_find (NMSetting *setting,
 /*****************************************************************************/
 
 static void
-read_one_setting_value (NMSetting *setting,
-                        const char *key,
-                        const GValue *value,
-                        GParamFlags flags,
-                        gpointer user_data)
+read_one_setting_value (KeyfileReaderInfo *info,
+                        NMSetting *setting,
+                        const NMSettInfoProperty *property_info)
 {
-	KeyfileReaderInfo *info = user_data;
 	GKeyFile *keyfile = info->keyfile;
-	const char *setting_name;
-	int errsv;
-	GType type;
 	gs_free_error GError *err = NULL;
 	const ParseInfoProperty *pip;
+	gs_free char *tmp_str = NULL;
+	const char *setting_name;
+	const char *key;
+	GType type;
+	guint64 u64;
+	gint64 i64;
 
-	if (info->error)
-		return;
+	nm_assert (!info->error);
+	nm_assert (property_info->param_spec);
 
-	if (!(flags & G_PARAM_WRITABLE))
+	if ((property_info->param_spec->flags & (G_PARAM_WRITABLE | G_PARAM_CONSTRUCT_ONLY)) != G_PARAM_WRITABLE)
 		return;
 
+	key = property_info->param_spec->name;
+
 	pip = _parse_info_find (setting, key, &setting_name);
 
 	nm_assert (setting_name);
@@ -2544,7 +2628,7 @@ read_one_setting_value (NMSetting *setting,
 	 */
 	if (   (!pip || !pip->parser_no_check_key)
 	    && !nm_keyfile_plugin_kf_has_key (keyfile, setting_name, key, &err)) {
-		/* Key doesn't exist or an error ocurred, thus nothing to do. */
+		/* Key doesn't exist or an error occurred, thus nothing to do. */
 		if (err) {
 			if (!handle_warn (info, key, NM_KEYFILE_WARN_SEVERITY_WARN,
 			                  _("error loading setting value: %s"),
@@ -2559,69 +2643,78 @@ read_one_setting_value (NMSetting *setting,
 		return;
 	}
 
-	type = G_VALUE_TYPE (value);
+	type = G_PARAM_SPEC_VALUE_TYPE (property_info->param_spec);
 
 	if (type == G_TYPE_STRING) {
 		gs_free char *str_val = NULL;
 
-		str_val = nm_keyfile_plugin_kf_get_string (keyfile, setting_name, key, NULL);
-		g_object_set (setting, key, str_val, NULL);
+		str_val = nm_keyfile_plugin_kf_get_string (keyfile, setting_name, key, &err);
+		if (!err)
+			nm_g_object_set_property_string_take (G_OBJECT (setting), key, g_steal_pointer (&str_val), &err);
 	} else if (type == G_TYPE_UINT) {
-		int int_val;
-
-		int_val = nm_keyfile_plugin_kf_get_integer (keyfile, setting_name, key, NULL);
-		if (int_val < 0) {
-			if (!handle_warn (info, key, NM_KEYFILE_WARN_SEVERITY_WARN,
-			                  _("invalid negative value (%i)"),
-			                  int_val))
-				return;
+		tmp_str = nm_keyfile_plugin_kf_get_value (keyfile, setting_name, key, &err);
+		if (!err) {
+			u64 = _nm_utils_ascii_str_to_uint64 (tmp_str, 0, 0, G_MAXUINT, G_MAXUINT64);
+			if (   u64 == G_MAXUINT64
+			    && errno != 0) {
+				g_set_error_literal (&err, G_KEY_FILE_ERROR, G_KEY_FILE_ERROR_INVALID_VALUE,
+				                     _("value cannot be interpreted as integer"));
+			} else
+				nm_g_object_set_property_uint (G_OBJECT (setting), key, u64, &err);
 		}
-		g_object_set (setting, key, int_val, NULL);
 	} else if (type == G_TYPE_INT) {
-		int int_val;
-
-		int_val = nm_keyfile_plugin_kf_get_integer (keyfile, setting_name, key, NULL);
-		g_object_set (setting, key, int_val, NULL);
+		tmp_str = nm_keyfile_plugin_kf_get_value (keyfile, setting_name, key, &err);
+		if (!err) {
+			i64 = _nm_utils_ascii_str_to_int64 (tmp_str, 0, G_MININT, G_MAXINT, G_MININT64);
+			if (   i64 == G_MININT64
+			    && errno != 0) {
+				g_set_error_literal (&err, G_KEY_FILE_ERROR, G_KEY_FILE_ERROR_INVALID_VALUE,
+				                     _("value cannot be interpreted as integer"));
+			} else
+				nm_g_object_set_property_int (G_OBJECT (setting), key, i64, &err);
+		}
 	} else if (type == G_TYPE_BOOLEAN) {
 		gboolean bool_val;
 
-		bool_val = nm_keyfile_plugin_kf_get_boolean (keyfile, setting_name, key, NULL);
-		g_object_set (setting, key, bool_val, NULL);
+		bool_val = nm_keyfile_plugin_kf_get_boolean (keyfile, setting_name, key, &err);
+		if (!err)
+			nm_g_object_set_property_boolean (G_OBJECT (setting), key, bool_val, &err);
 	} else if (type == G_TYPE_CHAR) {
-		int int_val;
-
-		int_val = nm_keyfile_plugin_kf_get_integer (keyfile, setting_name, key, NULL);
-		if (int_val < G_MININT8 || int_val > G_MAXINT8) {
-			if (!handle_warn (info, key, NM_KEYFILE_WARN_SEVERITY_WARN,
-			                  _("invalid char value (%i)"),
-			                  int_val))
-				return;
+		tmp_str = nm_keyfile_plugin_kf_get_value (keyfile, setting_name, key, &err);
+		if (!err) {
+			/* As documented by glib, G_TYPE_CHAR is really a (signed!) gint8. */
+			i64 = _nm_utils_ascii_str_to_int64 (tmp_str, 0, G_MININT8, G_MAXINT8, G_MININT64);
+			if (   i64 == G_MININT64
+			    && errno != 0) {
+				g_set_error_literal (&err, G_KEY_FILE_ERROR, G_KEY_FILE_ERROR_INVALID_VALUE,
+				                     _("value cannot be interpreted as integer"));
+			} else
+				nm_g_object_set_property_char (G_OBJECT (setting), key, i64, &err);
 		}
-
-		g_object_set (setting, key, int_val, NULL);
 	} else if (type == G_TYPE_UINT64) {
-		gs_free char *tmp_str = NULL;
-		guint64 uint_val;
-
-		tmp_str = nm_keyfile_plugin_kf_get_value (keyfile, setting_name, key, NULL);
-		uint_val = g_ascii_strtoull (tmp_str, NULL, 10);
-		g_object_set (setting, key, uint_val, NULL);
+		tmp_str = nm_keyfile_plugin_kf_get_value (keyfile, setting_name, key, &err);
+		if (!err) {
+			u64 = _nm_utils_ascii_str_to_uint64 (tmp_str, 0, 0, G_MAXUINT64, G_MAXUINT64);
+			if (   u64 == G_MAXUINT64
+			    && errno != 0) {
+				g_set_error_literal (&err, G_KEY_FILE_ERROR, G_KEY_FILE_ERROR_INVALID_VALUE,
+				                     _("value cannot be interpreted as integer"));
+			} else
+				nm_g_object_set_property_uint64 (G_OBJECT (setting), key, u64, &err);
+		}
 	} else if (type == G_TYPE_INT64) {
-		gs_free char *tmp_str = NULL;
-		gint64 int_val;
-
-		tmp_str = nm_keyfile_plugin_kf_get_value (keyfile, setting_name, key, NULL);
-		int_val = _nm_utils_ascii_str_to_int64 (tmp_str, 10, G_MININT64, G_MAXINT64, 0);
-		errsv = errno;
-		if (errsv) {
-			if (!handle_warn (info, key, NM_KEYFILE_WARN_SEVERITY_WARN,
-			                  _("invalid int64 value (%s)"),
-			                  tmp_str))
-				return;
-		} else
-			g_object_set (setting, key, int_val, NULL);
+		tmp_str = nm_keyfile_plugin_kf_get_value (keyfile, setting_name, key, &err);
+		if (!err) {
+			i64 = _nm_utils_ascii_str_to_int64 (tmp_str, 0, G_MININT64, G_MAXINT64, G_MAXINT64);
+			if (   i64 == G_MAXINT64
+			    && errno != 0) {
+				g_set_error_literal (&err, G_KEY_FILE_ERROR, G_KEY_FILE_ERROR_INVALID_VALUE,
+				                     _("value cannot be interpreted as integer"));
+			} else
+				nm_g_object_set_property_int64 (G_OBJECT (setting), key, i64, &err);
+		}
 	} else if (type == G_TYPE_BYTES) {
-		int *tmp;
+		gs_free int *tmp = NULL;
 		GByteArray *array;
 		GBytes *bytes;
 		gsize length;
@@ -2632,7 +2725,7 @@ read_one_setting_value (NMSetting *setting,
 
 		array = g_byte_array_sized_new (length);
 		for (i = 0; i < length; i++) {
-			int val = tmp[i];
+			const int val = tmp[i];
 			unsigned char v = (unsigned char) (val & 0xFF);
 
 			if (val < 0 || val > 255) {
@@ -2641,7 +2734,6 @@ read_one_setting_value (NMSetting *setting,
 				                     _("ignoring invalid byte element '%d' (not between 0 and 255 inclusive)"),
 				                     val)) {
 					g_byte_array_unref (array);
-					g_free (tmp);
 					return;
 				}
 				already_warned = TRUE;
@@ -2652,54 +2744,61 @@ read_one_setting_value (NMSetting *setting,
 		bytes = g_byte_array_free_to_bytes (array);
 		g_object_set (setting, key, bytes, NULL);
 		g_bytes_unref (bytes);
-		g_free (tmp);
 	} else if (type == G_TYPE_STRV) {
-		char **sa;
+		gs_strfreev char **sa = NULL;
 		gsize length;
 
 		sa = nm_keyfile_plugin_kf_get_string_list (keyfile, setting_name, key, &length, NULL);
 		g_object_set (setting, key, sa, NULL);
-		g_strfreev (sa);
 	} else if (type == G_TYPE_HASH_TABLE) {
 		read_hash_of_string (keyfile, setting, key);
 	} else if (type == G_TYPE_ARRAY) {
 		read_array_of_uint (keyfile, setting, key);
-	} else if (G_VALUE_HOLDS_FLAGS (value)) {
-		guint64 uint_val;
-
-		/* Flags are guint but GKeyFile has no uint reader, just uint64 */
-		uint_val = nm_keyfile_plugin_kf_get_uint64 (keyfile, setting_name, key, &err);
+	} else if (G_TYPE_IS_FLAGS (type)) {
+		tmp_str = nm_keyfile_plugin_kf_get_value (keyfile, setting_name, key, &err);
 		if (!err) {
-			if (uint_val <= G_MAXUINT)
-				g_object_set (setting, key, (guint) uint_val, NULL);
-			else {
-				if (!handle_warn (info, key, NM_KEYFILE_WARN_SEVERITY_WARN,
-				                  _("too large FLAGS property '%s' (%llu)"),
-				                  G_VALUE_TYPE_NAME (value), (unsigned long long) uint_val))
-					return;
-			}
+			u64 = _nm_utils_ascii_str_to_uint64 (tmp_str, 0, 0, G_MAXUINT, G_MAXUINT64);
+			if (   u64 == G_MAXUINT64
+			    && errno != 0) {
+				g_set_error_literal (&err, G_KEY_FILE_ERROR, G_KEY_FILE_ERROR_INVALID_VALUE,
+				                     _("value cannot be interpreted as integer"));
+			} else
+				nm_g_object_set_property_flags (G_OBJECT (setting), key, type, u64, &err);
+		}
+	} else if (G_TYPE_IS_ENUM (type)) {
+		tmp_str = nm_keyfile_plugin_kf_get_value (keyfile, setting_name, key, &err);
+		if (!err) {
+			i64 = _nm_utils_ascii_str_to_int64 (tmp_str, 0, G_MININT, G_MAXINT, G_MAXINT64);
+			if (   i64 == G_MAXINT64
+			    && errno != 0) {
+				g_set_error_literal (&err, G_KEY_FILE_ERROR, G_KEY_FILE_ERROR_INVALID_VALUE,
+				                     _("value cannot be interpreted as integer"));
+			} else
+				nm_g_object_set_property_enum (G_OBJECT (setting), key, type, i64, &err);
 		}
-	} else if (G_VALUE_HOLDS_ENUM (value)) {
-		int int_val;
+	} else
+		g_return_if_reached ();
 
-		int_val = nm_keyfile_plugin_kf_get_integer (keyfile, setting_name, key, &err);
-		if (!err)
-			g_object_set (setting, key, (int) int_val, NULL);
-	} else {
-		if (!handle_warn (info, key, NM_KEYFILE_WARN_SEVERITY_WARN,
-		                 _("unhandled setting property type '%s'"),
-		                 G_VALUE_TYPE_NAME (value)))
-			return;
+	if (err) {
+		if (   err->domain == G_KEY_FILE_ERROR
+		    && NM_IN_SET (err->code, G_KEY_FILE_ERROR_GROUP_NOT_FOUND,
+		                             G_KEY_FILE_ERROR_KEY_NOT_FOUND)) {
+			/* ignore such errors. The key is not present. */
+		} else {
+			handle_warn (info, key, NM_KEYFILE_WARN_SEVERITY_WARN,
+			             _("invalid setting: %s"), err->message);
+		}
 	}
 }
 
-static NMSetting *
-read_setting (KeyfileReaderInfo *info)
+static void
+_read_setting (KeyfileReaderInfo *info)
 {
 	const NMSettInfoSetting *sett_info;
 	gs_unref_object NMSetting *setting = NULL;
 	const char *alias;
 	GType type;
+	guint i;
 
 	alias = nm_keyfile_plugin_get_setting_name_for_alias (info->group);
 	if (!alias)
@@ -2709,34 +2808,36 @@ read_setting (KeyfileReaderInfo *info)
 	if (!type) {
 		handle_warn (info, NULL, NM_KEYFILE_WARN_SEVERITY_WARN,
 		             _("invalid setting name '%s'"), info->group);
-		return NULL;
+		return;
 	}
 
 	setting = g_object_new (type, NULL);
 
 	info->setting = setting;
 
-	sett_info = _nm_sett_info_setting_get (NM_SETTING_GET_CLASS (setting));
+	sett_info = _nm_setting_class_get_sett_info (NM_SETTING_GET_CLASS (setting));
 
 	if (sett_info->detail.gendata_info) {
 		gs_free char **keys = NULL;
-		gsize i, n_keys;
+		gsize k, n_keys;
 
 		keys = g_key_file_get_keys (info->keyfile, info->group, &n_keys, NULL);
+		if (!keys)
+			n_keys = 0;
 		if (n_keys > 0) {
 			GHashTable *h = _nm_setting_gendata_hash (setting, TRUE);
 
 			nm_utils_strv_sort (keys, n_keys);
-			for (i = 0; i < n_keys; i++) {
-				gs_free char *key = keys[i];
+			for (k = 0; k < n_keys; k++) {
+				gs_free char *key = keys[k];
 				gs_free_error GError *local = NULL;
 				const GVariantType *variant_type;
 				GVariant *variant;
 
-				/* a GKeyfile can return duplicate keys, there is just no API to make sense
+				/* a GKeyFile can return duplicate keys, there is just no API to make sense
 				 * of them. Skip them. */
-				if (   i + 1 < n_keys
-				    && nm_streq (key, keys[i + 1]))
+				if (   k + 1 < n_keys
+				    && nm_streq (key, keys[k + 1]))
 					continue;
 
 				/* currently, the API is very simple. The setting class just returns
@@ -2781,34 +2882,49 @@ read_setting (KeyfileReaderInfo *info)
 				                     g_steal_pointer (&key),
 				                     g_variant_take_ref (variant));
 			}
-			for (; i < n_keys; i++)
-				g_free (keys[i]);
+			for (; k < n_keys; k++)
+				g_free (keys[k]);
 		}
-	} else
-		nm_setting_enumerate_values (setting, read_one_setting_value, info);
+	}
 
-	info->setting = NULL;
+	for (i = 0; i < sett_info->property_infos_len; i++) {
+		const NMSettInfoProperty *property_info = &sett_info->property_infos[i];
 
-	if (info->error)
-		return NULL;
-	return g_steal_pointer (&setting);
+		if (property_info->param_spec) {
+			read_one_setting_value (info, setting, property_info);
+			if (info->error)
+				goto out;
+		}
+	}
+
+out:
+	info->setting = NULL;
+	if (!info->error)
+		nm_connection_add_setting (info->connection, g_steal_pointer (&setting));
 }
 
 static void
-read_vpn_secrets (KeyfileReaderInfo *info, NMSettingVpn *s_vpn)
+_read_setting_vpn_secrets (KeyfileReaderInfo *info)
 {
 	gs_strfreev char **keys = NULL;
-	char **iter;
+	gsize i, n_keys;
+	NMSettingVpn *s_vpn;
+
+	s_vpn = nm_connection_get_setting_vpn (info->connection);
+	if (!s_vpn) {
+		/* if we don't also have a [vpn] section (which must be parsed earlier),
+		 * we don't do anything. */
+		nm_assert (!g_key_file_has_group (info->keyfile, "vpn"));
+		return;
+	}
 
-	keys = nm_keyfile_plugin_kf_get_keys (info->keyfile, NM_KEYFILE_GROUP_VPN_SECRETS, NULL, NULL);
-	for (iter = keys; *iter; iter++) {
-		char *secret;
+	keys = nm_keyfile_plugin_kf_get_keys (info->keyfile, NM_KEYFILE_GROUP_VPN_SECRETS, &n_keys, NULL);
+	for (i = 0; i < n_keys; i++) {
+		gs_free char *secret = NULL;
 
-		secret = nm_keyfile_plugin_kf_get_string (info->keyfile, NM_KEYFILE_GROUP_VPN_SECRETS, *iter, NULL);
-		if (secret) {
-			nm_setting_vpn_add_secret (s_vpn, *iter, secret);
-			g_free (secret);
-		}
+		secret = nm_keyfile_plugin_kf_get_string (info->keyfile, NM_KEYFILE_GROUP_VPN_SECRETS, keys[i], NULL);
+		if (secret)
+			nm_setting_vpn_add_secret (s_vpn, keys[i], secret);
 	}
 }
 
@@ -2876,12 +2992,11 @@ nm_keyfile_read (GKeyFile *keyfile,
 {
 	gs_unref_object NMConnection *connection = NULL;
 	NMSettingConnection *s_con;
-	NMSetting *setting;
-	char **groups;
-	gsize length;
+	gs_strfreev char **groups = NULL;
+	gsize n_groups;
 	gsize i;
 	gboolean vpn_secrets = FALSE;
-	KeyfileReaderInfo info = { 0 };
+	KeyfileReaderInfo info;
 
 	g_return_val_if_fail (keyfile, NULL);
 	g_return_val_if_fail (!error || !*error, NULL);
@@ -2889,31 +3004,33 @@ nm_keyfile_read (GKeyFile *keyfile,
 
 	connection = nm_simple_connection_new ();
 
-	info.connection = connection;
-	info.keyfile = (GKeyFile *) keyfile;
-	info.base_dir = base_dir;
-	info.handler = handler;
-	info.user_data = user_data;
+	info = (KeyfileReaderInfo) {
+		.connection = connection,
+		.keyfile    = keyfile,
+		.base_dir   = base_dir,
+		.handler    = handler,
+		.user_data  = user_data,
+	};
 
-	groups = g_key_file_get_groups (keyfile, &length);
-	for (i = 0; i < length; i++) {
-		/* Only read out secrets when needed */
-		if (!strcmp (groups[i], NM_KEYFILE_GROUP_VPN_SECRETS)) {
-			vpn_secrets = TRUE;
-			continue;
-		}
+	groups = g_key_file_get_groups (keyfile, &n_groups);
+	if (!groups)
+		n_groups = 0;
+
+	for (i = 0; i < n_groups; i++) {
 
 		info.group = groups[i];
-		setting = read_setting (&info);
+
+		if (nm_streq (groups[i], NM_KEYFILE_GROUP_VPN_SECRETS)) {
+			/* Only read out secrets when needed */
+			vpn_secrets = TRUE;
+		} else
+			_read_setting (&info);
+
 		info.group = NULL;
-		if (info.error) {
-			g_propagate_error (error, info.error);
-			return NULL;
-		}
-		if (setting)
-			nm_connection_add_setting (connection, setting);
+
+		if (info.error)
+			goto out_with_info_error;
 	}
-	g_strfreev (groups);
 
 	s_con = nm_connection_get_setting_connection (connection);
 	if (!s_con) {
@@ -2926,55 +3043,51 @@ nm_keyfile_read (GKeyFile *keyfile,
 	 */
 	if (   !nm_setting_connection_get_interface_name (s_con)
 	    && nm_setting_connection_get_connection_type (s_con)) {
-		char *interface_name;
+		gs_free char *interface_name = NULL;
 
 		interface_name = g_key_file_get_string (keyfile,
 		                                        nm_setting_connection_get_connection_type (s_con),
 		                                        "interface-name",
 		                                        NULL);
-		if (interface_name) {
+		if (interface_name)
 			g_object_set (s_con, NM_SETTING_CONNECTION_INTERFACE_NAME, interface_name, NULL);
-			g_free (interface_name);
-		}
 	}
 
-	/* Handle vpn secrets after the 'vpn' setting was read */
 	if (vpn_secrets) {
-		NMSettingVpn *s_vpn;
-
-		s_vpn = nm_connection_get_setting_vpn (connection);
-		if (s_vpn) {
-			read_vpn_secrets (&info, s_vpn);
-			if (info.error) {
-				g_propagate_error (error, info.error);
-				return NULL;
-			}
-		}
+		info.group = NM_KEYFILE_GROUP_VPN_SECRETS;
+		_read_setting_vpn_secrets (&info);
+		info.group = NULL;;
+		if (info.error)
+			goto out_with_info_error;
 	}
 
 	return g_steal_pointer (&connection);
+
+out_with_info_error:
+	g_propagate_error (error, info.error);
+	return NULL;
 }
 
 /*****************************************************************************/
 
 static void
-write_setting_value (NMSetting *setting,
-                     const char *key,
-                     const GValue *value,
-                     GParamFlags flag,
-                     gpointer user_data)
+write_setting_value (KeyfileWriterInfo *info,
+                     NMSetting *setting,
+                     const NMSettInfoProperty *property_info)
 {
-	KeyfileWriterInfo *info = user_data;
+	const ParseInfoProperty *pip;
 	const char *setting_name;
+	const char *key;
+	char numstr[64];
+	GValue value;
 	GType type;
-	const ParseInfoProperty *pip;
-	GParamSpec *pspec;
 
-	if (info->error)
+	nm_assert (!info->error);
+
+	if (!property_info->param_spec)
 		return;
 
-	pspec = g_object_class_find_property (G_OBJECT_GET_CLASS (setting), key);
-	nm_assert (pspec);
+	key = property_info->param_spec->name;
 
 	pip = _parse_info_find (setting, key, &setting_name);
 
@@ -3002,58 +3115,65 @@ write_setting_value (NMSetting *setting,
 	 * the secret flags there are in a third-level hash in the 'secrets'
 	 * property.
 	 */
-	if (   (pspec->flags & NM_SETTING_PARAM_SECRET)
+	if (   (property_info->param_spec->flags & NM_SETTING_PARAM_SECRET)
 	    && !NM_IS_SETTING_VPN (setting)) {
 		NMSettingSecretFlags secret_flags = NM_SETTING_SECRET_FLAG_NONE;
 
 		if (!nm_setting_get_secret_flags (setting, key, &secret_flags, NULL))
-			g_assert_not_reached ();
-		if (secret_flags != NM_SETTING_SECRET_FLAG_NONE)
+			g_return_if_reached ();
+		if (!_secret_flags_persist_secret (secret_flags))
 			return;
 	}
 
+	value = (GValue) { 0 };
+
+	g_value_init (&value, G_PARAM_SPEC_VALUE_TYPE (property_info->param_spec));
+	g_object_get_property (G_OBJECT (setting), property_info->param_spec->name, &value);
+
 	if (   (!pip || !pip->writer_persist_default)
-	    && g_param_value_defaults (pspec, (GValue *) value)) {
+	    && g_param_value_defaults (property_info->param_spec, &value)) {
 		nm_assert (!g_key_file_has_key (info->keyfile, setting_name, key, NULL));
-		return;
+		goto out_unset_value;
 	}
 
 	if (pip && pip->writer) {
-		pip->writer (info, setting, key, value);
-		return;
+		pip->writer (info, setting, key, &value);
+		goto out_unset_value;
 	}
 
-	type = G_VALUE_TYPE (value);
+	type = G_VALUE_TYPE (&value);
 	if (type == G_TYPE_STRING) {
 		const char *str;
 
-		str = g_value_get_string (value);
+		str = g_value_get_string (&value);
 		if (str)
 			nm_keyfile_plugin_kf_set_string (info->keyfile, setting_name, key, str);
-	} else if (type == G_TYPE_UINT)
-		nm_keyfile_plugin_kf_set_integer (info->keyfile, setting_name, key, (int) g_value_get_uint (value));
-	else if (type == G_TYPE_INT)
-		nm_keyfile_plugin_kf_set_integer (info->keyfile, setting_name, key, g_value_get_int (value));
-	else if (type == G_TYPE_UINT64) {
-		char numstr[30];
-
-		nm_sprintf_buf (numstr, "%" G_GUINT64_FORMAT, g_value_get_uint64 (value));
+	} else if (type == G_TYPE_UINT) {
+		nm_sprintf_buf (numstr, "%u", g_value_get_uint (&value));
+		nm_keyfile_plugin_kf_set_value (info->keyfile, setting_name, key, numstr);
+	} else if (type == G_TYPE_INT) {
+		nm_sprintf_buf (numstr, "%d", g_value_get_int (&value));
+		nm_keyfile_plugin_kf_set_value (info->keyfile, setting_name, key, numstr);
+	} else if (type == G_TYPE_UINT64) {
+		nm_sprintf_buf (numstr, "%" G_GUINT64_FORMAT, g_value_get_uint64 (&value));
 		nm_keyfile_plugin_kf_set_value (info->keyfile, setting_name, key, numstr);
 	} else if (type == G_TYPE_INT64) {
-		char numstr[30];
-
-		nm_sprintf_buf (numstr, "%" G_GINT64_FORMAT, g_value_get_int64 (value));
+		nm_sprintf_buf (numstr, "%" G_GINT64_FORMAT, g_value_get_int64 (&value));
 		nm_keyfile_plugin_kf_set_value (info->keyfile, setting_name, key, numstr);
 	} else if (type == G_TYPE_BOOLEAN) {
-		nm_keyfile_plugin_kf_set_boolean (info->keyfile, setting_name, key, g_value_get_boolean (value));
+		nm_keyfile_plugin_kf_set_value (info->keyfile, setting_name, key,
+		                                  g_value_get_boolean (&value)
+		                                ? "true"
+		                                : "false");
 	} else if (type == G_TYPE_CHAR) {
-		nm_keyfile_plugin_kf_set_integer (info->keyfile, setting_name, key, (int) g_value_get_schar (value));
+		nm_sprintf_buf (numstr, "%d", (int) g_value_get_schar (&value));
+		nm_keyfile_plugin_kf_set_value (info->keyfile, setting_name, key, numstr);
 	} else if (type == G_TYPE_BYTES) {
 		GBytes *bytes;
 		const guint8 *data;
 		gsize len = 0;
 
-		bytes = g_value_get_boxed (value);
+		bytes = g_value_get_boxed (&value);
 		data = bytes ? g_bytes_get_data (bytes, &len) : NULL;
 
 		if (data != NULL && len > 0)
@@ -3061,19 +3181,23 @@ write_setting_value (NMSetting *setting,
 	} else if (type == G_TYPE_STRV) {
 		char **array;
 
-		array = (char **) g_value_get_boxed (value);
+		array = (char **) g_value_get_boxed (&value);
 		nm_keyfile_plugin_kf_set_string_list (info->keyfile, setting_name, key, (const char **const) array, g_strv_length (array));
 	} else if (type == G_TYPE_HASH_TABLE) {
-		write_hash_of_string (info->keyfile, setting, key, value);
+		write_hash_of_string (info->keyfile, setting, key, &value);
 	} else if (type == G_TYPE_ARRAY) {
-		write_array_of_uint (info->keyfile, setting, key, value);
-	} else if (G_VALUE_HOLDS_FLAGS (value)) {
-		/* Flags are guint but GKeyFile has no uint reader, just uint64 */
-		nm_keyfile_plugin_kf_set_uint64 (info->keyfile, setting_name, key, (guint64) g_value_get_flags (value));
-	} else if (G_VALUE_HOLDS_ENUM (value))
-		nm_keyfile_plugin_kf_set_integer (info->keyfile, setting_name, key, (int) g_value_get_enum (value));
-	else
-		g_warn_if_reached ();
+		write_array_of_uint (info->keyfile, setting, key, &value);
+	} else if (G_VALUE_HOLDS_FLAGS (&value)) {
+		nm_sprintf_buf (numstr, "%u", g_value_get_flags (&value));
+		nm_keyfile_plugin_kf_set_value (info->keyfile, setting_name, key, numstr);
+	} else if (G_VALUE_HOLDS_ENUM (&value)) {
+		nm_sprintf_buf (numstr, "%d", g_value_get_enum (&value));
+		nm_keyfile_plugin_kf_set_value (info->keyfile, setting_name, key, numstr);
+	} else
+		g_return_if_reached ();
+
+out_unset_value:
+	g_value_unset (&value);
 }
 
 GKeyFile *
@@ -3082,9 +3206,10 @@ nm_keyfile_write (NMConnection *connection,
                   void *user_data,
                   GError **error)
 {
-	KeyfileWriterInfo info = { 0 };
+	gs_unref_keyfile GKeyFile *keyfile = NULL;
+	KeyfileWriterInfo info;
 	gs_free NMSetting **settings = NULL;
-	guint i, length = 0;
+	guint i, j, n_settings = 0;
 
 	g_return_val_if_fail (NM_IS_CONNECTION (connection), NULL);
 	g_return_val_if_fail (!error || !*error, NULL);
@@ -3092,18 +3217,22 @@ nm_keyfile_write (NMConnection *connection,
 	if (!nm_connection_verify (connection, error))
 		return NULL;
 
-	info.connection = connection;
-	info.keyfile = g_key_file_new ();
-	info.error = NULL;
-	info.handler = handler;
-	info.user_data = user_data;
+	keyfile = g_key_file_new ();
 
-	settings = nm_connection_get_settings (connection, &length);
-	for (i = 0; i < length; i++) {
+	info = (KeyfileWriterInfo) {
+		.connection = connection,
+		.keyfile    = keyfile,
+		.error      = NULL,
+		.handler    = handler,
+		.user_data  = user_data,
+	};
+
+	settings = nm_connection_get_settings (connection, &n_settings);
+	for (i = 0; i < n_settings; i++) {
 		const NMSettInfoSetting *sett_info;
 		NMSetting *setting = settings[i];
 
-		sett_info = _nm_sett_info_setting_get (NM_SETTING_GET_CLASS (setting));
+		sett_info = _nm_setting_class_get_sett_info (NM_SETTING_GET_CLASS (setting));
 
 		if (sett_info->detail.gendata_info) {
 			guint k, n_keys;
@@ -3138,18 +3267,169 @@ nm_keyfile_write (NMConnection *connection,
 					}
 				}
 			}
-		} else
-			nm_setting_enumerate_values (setting, write_setting_value, &info);
+		}
 
-		if (info.error)
-			break;
+		for (j = 0; j < sett_info->property_infos_len; j++) {
+			const NMSettInfoProperty *property_info = _nm_sett_info_property_info_get_sorted (sett_info, j);
+
+			write_setting_value (&info, setting, property_info);
+			if (info.error)
+				goto out_with_info_error;
+		}
+
+		nm_assert (!info.error);
 	}
 
-	if (info.error) {
-		g_propagate_error (error, info.error);
-		g_key_file_unref (info.keyfile);
-		return NULL;
+	nm_assert (!info.error);
+
+	return g_steal_pointer (&keyfile);
+
+out_with_info_error:
+	g_propagate_error (error, info.error);
+	return NULL;
+}
+
+/*****************************************************************************/
+
+static const char temp_letters[] =
+"abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789";
+
+/*
+ * Check '.[a-zA-Z0-9]{6}' file suffix used for temporary files by g_file_set_contents() (mkstemp()).
+ */
+static gboolean
+check_mkstemp_suffix (const char *path)
+{
+	const char *ptr;
+
+	nm_assert (path);
+
+	/* Matches *.[a-zA-Z0-9]{6} suffix of mkstemp()'s temporary files */
+	ptr = strrchr (path, '.');
+	if (   ptr
+	    && strspn (&ptr[1], temp_letters) == 6
+	    && ptr[7] == '\0')
+		return TRUE;
+	return FALSE;
+}
+
+static gboolean
+_check_suffix_impl (const char *base, const char *tag, gsize tag_len)
+{
+	gsize len;
+
+	nm_assert (base);
+	nm_assert (tag);
+	nm_assert (strlen (tag) == tag_len);
+
+	len = strlen (base);
+	if (   len > tag_len
+	    && !g_ascii_strcasecmp (base + len - tag_len, tag))
+		return TRUE;
+	return FALSE;
+}
+#define check_suffix(base, tag) _check_suffix_impl ((base), ""tag"", NM_STRLEN (tag))
+
+#define SWP_TAG ".swp"
+#define SWPX_TAG ".swpx"
+#define PEM_TAG ".pem"
+#define DER_TAG ".der"
+
+gboolean
+nm_keyfile_utils_ignore_filename (const char *filename, gboolean require_extension)
+{
+	const char *base;
+	gsize l;
+
+	/* ignore_filename() must mirror nm_keyfile_utils_create_filename() */
+
+	g_return_val_if_fail (filename, TRUE);
+
+	base = strrchr (filename, '/');
+	if (base)
+		base++;
+	else
+		base = filename;
+
+	if (!base[0]) {
+		/* this check above with strrchr() also rejects "/some/path/with/trailing/slash/",
+		 * but that is fine, because such a path would name a directory, and we are not
+		 * interested in directories. */
+		return TRUE;
+	}
+
+	if (base[0] == '.') {
+		/* don't allow hidden files */
+		return TRUE;
+	}
+
+	l = strlen (base);
+
+	if (require_extension) {
+		if (   l <= NM_STRLEN (NM_KEYFILE_PATH_SUFFIX_NMCONNECTION)
+		    || !g_str_has_suffix (base, NM_KEYFILE_PATH_SUFFIX_NMCONNECTION))
+			return TRUE;
+		return FALSE;
+	}
+
+	/* Ignore backup files */
+	if (base[l - 1] == '~')
+		return TRUE;
+
+	/* Ignore temporary files */
+	if (check_mkstemp_suffix (base))
+		return TRUE;
+
+	/* Ignore 802.1x certificates and keys */
+	if (   check_suffix (base, PEM_TAG)
+	    || check_suffix (base, DER_TAG))
+		return TRUE;
+
+	return FALSE;
+}
+
+char *
+nm_keyfile_utils_create_filename (const char *name,
+                                  gboolean with_extension)
+{
+	GString *str;
+	const char *f = name;
+	/* keyfile used to escape with '*', do not change that behavior.
+	 *
+	 * But for newly added escapings, use '_' instead.
+	 * Also, @with_extension is new-style. */
+	const char ESCAPE_CHAR = with_extension ? '_' : '*';
+	const char ESCAPE_CHAR2 = '_';
+
+	g_return_val_if_fail (name && name[0], NULL);
+
+	str = g_string_sized_new (60);
+
+	/* Convert '/' to ESCAPE_CHAR */
+	for (f = name; f[0]; f++) {
+		if (f[0] == '/')
+			g_string_append_c (str, ESCAPE_CHAR);
+		else
+			g_string_append_c (str, f[0]);
 	}
 
-	return info.keyfile;
+	/* nm_keyfile_utils_create_filename() must avoid anything that ignore_filename() would reject.
+	 * We can escape here more aggressivly then what we would read back. */
+	if (str->str[0] == '.')
+		str->str[0] = ESCAPE_CHAR2;
+	if (str->str[str->len - 1] == '~')
+		str->str[str->len - 1] = ESCAPE_CHAR2;
+	if (   check_mkstemp_suffix (str->str)
+	    || check_suffix (str->str, PEM_TAG)
+	    || check_suffix (str->str, DER_TAG))
+		g_string_append_c (str, ESCAPE_CHAR2);
+
+	if (with_extension)
+		g_string_append (str, NM_KEYFILE_PATH_SUFFIX_NMCONNECTION);
+
+	/* nm_keyfile_utils_create_filename() must mirror ignore_filename() */
+	nm_assert (!strchr (str->str, '/'));
+	nm_assert (!nm_keyfile_utils_ignore_filename (str->str, with_extension));
+
+	return g_string_free (str, FALSE);;
 }
diff --git a/libnm-core/nm-setting-6lowpan.c b/libnm-core/nm-setting-6lowpan.c
index c0ce232d..3a2b084e 100644
--- a/libnm-core/nm-setting-6lowpan.c
+++ b/libnm-core/nm-setting-6lowpan.c
@@ -19,9 +19,20 @@
 
 #include "nm-default.h"
 
-#include "nm-setting-private.h"
 #include "nm-setting-6lowpan.h"
 
+#include "nm-setting-private.h"
+
+/**
+ * SECTION:nm-setting-6lowpan
+ * @short_description: Describes connection properties for 6LoWPAN interfaces
+ *
+ * The #NMSetting6Lowpan object is a #NMSetting subclass that describes properties
+ * necessary for connection to 6LoWPAN interfaces.
+ **/
+
+/*****************************************************************************/
+
 NM_GOBJECT_PROPERTIES_DEFINE_BASE (
 	PROP_PARENT,
 );
@@ -43,33 +54,11 @@ struct _NMSetting6LowpanClass {
 	NMSettingClass parent;
 };
 
-/**
- * SECTION:nm-setting-6lowpan
- * @short_description: Describes connection properties for 6LoWPAN interfaces
- *
- * The #NMSetting6Lowpan object is a #NMSetting subclass that describes properties
- * necessary for connection to 6LoWPAN interfaces.
- **/
-
 G_DEFINE_TYPE (NMSetting6Lowpan, nm_setting_6lowpan, NM_TYPE_SETTING)
 
 #define NM_SETTING_6LOWPAN_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), NM_TYPE_SETTING_6LOWPAN, NMSetting6LowpanPrivate))
 
-
-/**
- * nm_setting_6lowpan_new:
- *
- * Creates a new #NMSetting6Lowpan object with default values.
- *
- * Returns: (transfer full): the new empty #NMSetting6Lowpan object
- *
- * Since: 1.14
- **/
-NMSetting *
-nm_setting_6lowpan_new (void)
-{
-	return (NMSetting *) g_object_new (NM_TYPE_SETTING_6LOWPAN, NULL);
-}
+/*****************************************************************************/
 
 /**
  * nm_setting_6lowpan_get_parent:
@@ -143,22 +132,18 @@ verify (NMSetting *setting, NMConnection *connection, GError **error)
 	return TRUE;
 }
 
-static void
-nm_setting_6lowpan_init (NMSetting6Lowpan *setting)
-{
-}
+/*****************************************************************************/
 
 static void
-set_property (GObject *object, guint prop_id,
-              const GValue *value, GParamSpec *pspec)
+get_property (GObject *object, guint prop_id,
+              GValue *value, GParamSpec *pspec)
 {
 	NMSetting6Lowpan *setting = NM_SETTING_6LOWPAN (object);
 	NMSetting6LowpanPrivate *priv = NM_SETTING_6LOWPAN_GET_PRIVATE (setting);
 
 	switch (prop_id) {
 	case PROP_PARENT:
-		g_free (priv->parent);
-		priv->parent = g_value_dup_string (value);
+		g_value_set_string (value, priv->parent);
 		break;
 	default:
 		G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
@@ -167,15 +152,16 @@ set_property (GObject *object, guint prop_id,
 }
 
 static void
-get_property (GObject *object, guint prop_id,
-              GValue *value, GParamSpec *pspec)
+set_property (GObject *object, guint prop_id,
+              const GValue *value, GParamSpec *pspec)
 {
 	NMSetting6Lowpan *setting = NM_SETTING_6LOWPAN (object);
 	NMSetting6LowpanPrivate *priv = NM_SETTING_6LOWPAN_GET_PRIVATE (setting);
 
 	switch (prop_id) {
 	case PROP_PARENT:
-		g_value_set_string (value, priv->parent);
+		g_free (priv->parent);
+		priv->parent = g_value_dup_string (value);
 		break;
 	default:
 		G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
@@ -183,6 +169,28 @@ get_property (GObject *object, guint prop_id,
 	}
 }
 
+/*****************************************************************************/
+
+static void
+nm_setting_6lowpan_init (NMSetting6Lowpan *setting)
+{
+}
+
+/**
+ * nm_setting_6lowpan_new:
+ *
+ * Creates a new #NMSetting6Lowpan object with default values.
+ *
+ * Returns: (transfer full): the new empty #NMSetting6Lowpan object
+ *
+ * Since: 1.14
+ **/
+NMSetting *
+nm_setting_6lowpan_new (void)
+{
+	return (NMSetting *) g_object_new (NM_TYPE_SETTING_6LOWPAN, NULL);
+}
+
 static void
 finalize (GObject *object)
 {
@@ -202,8 +210,8 @@ nm_setting_6lowpan_class_init (NMSetting6LowpanClass *klass)
 
 	g_type_class_add_private (klass, sizeof (NMSetting6LowpanPrivate));
 
-	object_class->set_property = set_property;
 	object_class->get_property = get_property;
+	object_class->set_property = set_property;
 	object_class->finalize     = finalize;
 
 	setting_class->verify = verify;
diff --git a/libnm-core/nm-setting-8021x.c b/libnm-core/nm-setting-8021x.c
index 7e004c90..19741fdf 100644
--- a/libnm-core/nm-setting-8021x.c
+++ b/libnm-core/nm-setting-8021x.c
@@ -246,7 +246,7 @@ nm_setting_802_1x_check_cert_scheme (gconstpointer pdata, gsize length, GError *
 	if (scheme != NM_SETTING_802_1X_CK_SCHEME_BLOB) {
 		/* An actual URI must be NUL terminated, contain at least
 		 * one non-NUL character, and contain only one trailing NUL
-		 * chracter.
+		 * character.
 		 * And ensure it's UTF-8 valid too so we can pass it through
 		 * D-Bus and stuff like that. */
 
@@ -3369,8 +3369,6 @@ finalize (GObject *object)
 	NMSetting8021x *self = NM_SETTING_802_1X (object);
 	NMSetting8021xPrivate *priv = NM_SETTING_802_1X_GET_PRIVATE (self);
 
-	/* Strings first. g_free() already checks for NULLs so we don't have to */
-
 	g_free (priv->identity);
 	g_free (priv->anonymous_identity);
 	g_free (priv->ca_path);
@@ -3416,8 +3414,8 @@ nm_setting_802_1x_class_init (NMSetting8021xClass *klass)
 
 	g_type_class_add_private (klass, sizeof (NMSetting8021xPrivate));
 
-	object_class->set_property = set_property;
 	object_class->get_property = get_property;
+	object_class->set_property = set_property;
 	object_class->finalize     = finalize;
 
 	setting_class->verify       = verify;
diff --git a/libnm-core/nm-setting-adsl.c b/libnm-core/nm-setting-adsl.c
index 9ffff927..b7f7d746 100644
--- a/libnm-core/nm-setting-adsl.c
+++ b/libnm-core/nm-setting-adsl.c
@@ -21,9 +21,10 @@
 
 #include "nm-default.h"
 
+#include "nm-setting-adsl.h"
+
 #include <string.h>
 
-#include "nm-setting-adsl.h"
 #include "nm-setting-ppp.h"
 #include "nm-setting-private.h"
 #include "nm-utils.h"
@@ -37,9 +38,17 @@
  * properties of ADSL connections.
  */
 
-G_DEFINE_TYPE (NMSettingAdsl, nm_setting_adsl, NM_TYPE_SETTING)
+/*****************************************************************************/
 
-#define NM_SETTING_ADSL_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), NM_TYPE_SETTING_ADSL, NMSettingAdslPrivate))
+NM_GOBJECT_PROPERTIES_DEFINE_BASE (
+	PROP_USERNAME,
+	PROP_PASSWORD,
+	PROP_PASSWORD_FLAGS,
+	PROP_PROTOCOL,
+	PROP_ENCAPSULATION,
+	PROP_VPI,
+	PROP_VCI,
+);
 
 typedef struct {
 	char *  username;
@@ -51,31 +60,11 @@ typedef struct {
 	guint32 vci;
 } NMSettingAdslPrivate;
 
-enum {
-	PROP_0,
-	PROP_USERNAME,
-	PROP_PASSWORD,
-	PROP_PASSWORD_FLAGS,
-	PROP_PROTOCOL,
-	PROP_ENCAPSULATION,
-	PROP_VPI,
-	PROP_VCI,
+G_DEFINE_TYPE (NMSettingAdsl, nm_setting_adsl, NM_TYPE_SETTING)
 
-	LAST_PROP
-};
+#define NM_SETTING_ADSL_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), NM_TYPE_SETTING_ADSL, NMSettingAdslPrivate))
 
-/**
- * nm_setting_adsl_new:
- *
- * Creates a new #NMSettingAdsl object with default values.
- *
- * Returns: the new empty #NMSettingAdsl object
- **/
-NMSetting *
-nm_setting_adsl_new (void)
-{
-	return (NMSetting *) g_object_new (NM_TYPE_SETTING_ADSL, NULL);
-}
+/*****************************************************************************/
 
 /**
  * nm_setting_adsl_get_username:
@@ -250,22 +239,40 @@ need_secrets (NMSetting *setting)
 	return secrets;
 }
 
-static void
-nm_setting_adsl_init (NMSettingAdsl *setting)
-{
-}
+/*****************************************************************************/
 
 static void
-finalize (GObject *object)
+get_property (GObject *object, guint prop_id,
+              GValue *value, GParamSpec *pspec)
 {
-	NMSettingAdslPrivate *priv = NM_SETTING_ADSL_GET_PRIVATE (object);
-
-	g_free (priv->username);
-	g_free (priv->password);
-	g_free (priv->protocol);
-	g_free (priv->encapsulation);
+	NMSettingAdsl *setting = NM_SETTING_ADSL (object);
 
-	G_OBJECT_CLASS (nm_setting_adsl_parent_class)->finalize (object);
+	switch (prop_id) {
+	case PROP_USERNAME:
+		g_value_set_string (value, nm_setting_adsl_get_username (setting));
+		break;
+	case PROP_PASSWORD:
+		g_value_set_string (value, nm_setting_adsl_get_password (setting));
+		break;
+	case PROP_PASSWORD_FLAGS:
+		g_value_set_flags (value, nm_setting_adsl_get_password_flags (setting));
+		break;
+	case PROP_PROTOCOL:
+		g_value_set_string (value, nm_setting_adsl_get_protocol (setting));
+		break;
+	case PROP_ENCAPSULATION:
+		g_value_set_string (value, nm_setting_adsl_get_encapsulation (setting));
+		break;
+	case PROP_VPI:
+		g_value_set_uint (value, nm_setting_adsl_get_vpi (setting));
+		break;
+	case PROP_VCI:
+		g_value_set_uint (value, nm_setting_adsl_get_vci (setting));
+		break;
+	default:
+		G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+		break;
+	}
 }
 
 static void
@@ -309,38 +316,37 @@ set_property (GObject *object, guint prop_id,
 	}
 }
 
+/*****************************************************************************/
+
 static void
-get_property (GObject *object, guint prop_id,
-              GValue *value, GParamSpec *pspec)
+nm_setting_adsl_init (NMSettingAdsl *setting)
 {
-	NMSettingAdsl *setting = NM_SETTING_ADSL (object);
+}
 
-	switch (prop_id) {
-	case PROP_USERNAME:
-		g_value_set_string (value, nm_setting_adsl_get_username (setting));
-		break;
-	case PROP_PASSWORD:
-		g_value_set_string (value, nm_setting_adsl_get_password (setting));
-		break;
-	case PROP_PASSWORD_FLAGS:
-		g_value_set_flags (value, nm_setting_adsl_get_password_flags (setting));
-		break;
-	case PROP_PROTOCOL:
-		g_value_set_string (value, nm_setting_adsl_get_protocol (setting));
-		break;
-	case PROP_ENCAPSULATION:
-		g_value_set_string (value, nm_setting_adsl_get_encapsulation (setting));
-		break;
-	case PROP_VPI:
-		g_value_set_uint (value, nm_setting_adsl_get_vpi (setting));
-		break;
-	case PROP_VCI:
-		g_value_set_uint (value, nm_setting_adsl_get_vci (setting));
-		break;
-	default:
-		G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
-		break;
-	}
+/**
+ * nm_setting_adsl_new:
+ *
+ * Creates a new #NMSettingAdsl object with default values.
+ *
+ * Returns: the new empty #NMSettingAdsl object
+ **/
+NMSetting *
+nm_setting_adsl_new (void)
+{
+	return (NMSetting *) g_object_new (NM_TYPE_SETTING_ADSL, NULL);
+}
+
+static void
+finalize (GObject *object)
+{
+	NMSettingAdslPrivate *priv = NM_SETTING_ADSL_GET_PRIVATE (object);
+
+	g_free (priv->username);
+	g_free (priv->password);
+	g_free (priv->protocol);
+	g_free (priv->encapsulation);
+
+	G_OBJECT_CLASS (nm_setting_adsl_parent_class)->finalize (object);
 }
 
 static void
@@ -351,8 +357,8 @@ nm_setting_adsl_class_init (NMSettingAdslClass *klass)
 
 	g_type_class_add_private (klass, sizeof (NMSettingAdslPrivate));
 
-	object_class->set_property = set_property;
 	object_class->get_property = get_property;
+	object_class->set_property = set_property;
 	object_class->finalize     = finalize;
 
 	setting_class->verify         = verify;
@@ -364,86 +370,81 @@ nm_setting_adsl_class_init (NMSettingAdslClass *klass)
 	 *
 	 * Username used to authenticate with the ADSL service.
 	 **/
-	g_object_class_install_property
-		(object_class, PROP_USERNAME,
-		 g_param_spec_string (NM_SETTING_ADSL_USERNAME, "", "",
-		                      NULL,
-		                      G_PARAM_READWRITE |
-		                      G_PARAM_STATIC_STRINGS));
+	obj_properties[PROP_USERNAME] =
+	    g_param_spec_string (NM_SETTING_ADSL_USERNAME, "", "",
+	                         NULL,
+	                         G_PARAM_READWRITE |
+	                         G_PARAM_STATIC_STRINGS);
 
 	/**
 	 * NMSettingAdsl:password:
 	 *
 	 * Password used to authenticate with the ADSL service.
 	 **/
-	g_object_class_install_property
-		(object_class, PROP_PASSWORD,
-		 g_param_spec_string (NM_SETTING_ADSL_PASSWORD, "", "",
-		                      NULL,
-		                      G_PARAM_READWRITE |
-		                      NM_SETTING_PARAM_SECRET |
-		                      G_PARAM_STATIC_STRINGS));
+	obj_properties[PROP_PASSWORD] =
+	    g_param_spec_string (NM_SETTING_ADSL_PASSWORD, "", "",
+	                         NULL,
+	                         G_PARAM_READWRITE |
+	                         NM_SETTING_PARAM_SECRET |
+	                         G_PARAM_STATIC_STRINGS);
 
 	/**
 	 * NMSettingAdsl:password-flags:
 	 *
 	 * Flags indicating how to handle the #NMSettingAdsl:password property.
 	 **/
-	g_object_class_install_property
-		(object_class, PROP_PASSWORD_FLAGS,
-		 g_param_spec_flags (NM_SETTING_ADSL_PASSWORD_FLAGS, "", "",
-		                     NM_TYPE_SETTING_SECRET_FLAGS,
-		                     NM_SETTING_SECRET_FLAG_NONE,
-		                     G_PARAM_READWRITE |
-		                     G_PARAM_STATIC_STRINGS));
+	obj_properties[PROP_PASSWORD_FLAGS] =
+	    g_param_spec_flags (NM_SETTING_ADSL_PASSWORD_FLAGS, "", "",
+	                        NM_TYPE_SETTING_SECRET_FLAGS,
+	                        NM_SETTING_SECRET_FLAG_NONE,
+	                        G_PARAM_READWRITE |
+	                        G_PARAM_STATIC_STRINGS);
 
 	/**
 	 * NMSettingAdsl:protocol:
 	 *
 	 * ADSL connection protocol.  Can be "pppoa", "pppoe" or "ipoatm".
 	 **/
-	g_object_class_install_property
-		(object_class, PROP_PROTOCOL,
-		 g_param_spec_string (NM_SETTING_ADSL_PROTOCOL, "", "",
-		                      NULL,
-		                      G_PARAM_READWRITE |
-		                      G_PARAM_STATIC_STRINGS));
+	obj_properties[PROP_PROTOCOL] =
+	    g_param_spec_string (NM_SETTING_ADSL_PROTOCOL, "", "",
+	                         NULL,
+	                         G_PARAM_READWRITE |
+	                         G_PARAM_STATIC_STRINGS);
 
 	/**
 	 * NMSettingAdsl:encapsulation:
 	 *
 	 * Encapsulation of ADSL connection.  Can be "vcmux" or "llc".
 	 **/
-	g_object_class_install_property
-		(object_class, PROP_ENCAPSULATION,
-		 g_param_spec_string (NM_SETTING_ADSL_ENCAPSULATION, "", "",
-		                      NULL,
-		                      G_PARAM_READWRITE |
-		                      G_PARAM_STATIC_STRINGS));
+	obj_properties[PROP_ENCAPSULATION] =
+	    g_param_spec_string (NM_SETTING_ADSL_ENCAPSULATION, "", "",
+	                         NULL,
+	                         G_PARAM_READWRITE |
+	                         G_PARAM_STATIC_STRINGS);
 
 	/**
 	 * NMSettingAdsl:vpi:
 	 *
 	 * VPI of ADSL connection
 	 **/
-	g_object_class_install_property
-		(object_class, PROP_VPI,
-		 g_param_spec_uint (NM_SETTING_ADSL_VPI, "", "",
-		                    0, 65536, 0,
-		                    G_PARAM_READWRITE |
-		                    G_PARAM_STATIC_STRINGS));
+	obj_properties[PROP_VPI] =
+	    g_param_spec_uint (NM_SETTING_ADSL_VPI, "", "",
+	                       0, 65536, 0,
+	                       G_PARAM_READWRITE |
+	                       G_PARAM_STATIC_STRINGS);
 
 	/**
 	 * NMSettingAdsl:vci:
 	 *
 	 * VCI of ADSL connection
 	 **/
-	g_object_class_install_property
-		(object_class, PROP_VCI,
-		 g_param_spec_uint (NM_SETTING_ADSL_VCI, "", "",
-		                    0, 65536, 0,
-		                    G_PARAM_READWRITE |
-		                    G_PARAM_STATIC_STRINGS));
+	obj_properties[PROP_VCI] =
+	    g_param_spec_uint (NM_SETTING_ADSL_VCI, "", "",
+	                       0, 65536, 0,
+	                       G_PARAM_READWRITE |
+	                       G_PARAM_STATIC_STRINGS);
+
+	g_object_class_install_properties (object_class, _PROPERTY_ENUMS_LAST, obj_properties);
 
 	_nm_setting_class_commit (setting_class, NM_META_SETTING_TYPE_ADSL);
 }
diff --git a/libnm-core/nm-setting-bluetooth.c b/libnm-core/nm-setting-bluetooth.c
index bbc6a83d..a3192840 100644
--- a/libnm-core/nm-setting-bluetooth.c
+++ b/libnm-core/nm-setting-bluetooth.c
@@ -22,11 +22,12 @@
 
 #include "nm-default.h"
 
+#include "nm-setting-bluetooth.h"
+
 #include <string.h>
 #include <net/ethernet.h>
 
 #include "nm-connection-private.h"
-#include "nm-setting-bluetooth.h"
 #include "nm-setting-cdma.h"
 #include "nm-setting-gsm.h"
 #include "nm-setting-private.h"
@@ -43,34 +44,23 @@
  * Point (NAP) profiles.
  **/
 
-G_DEFINE_TYPE (NMSettingBluetooth, nm_setting_bluetooth, NM_TYPE_SETTING)
+/*****************************************************************************/
 
-#define NM_SETTING_BLUETOOTH_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), NM_TYPE_SETTING_BLUETOOTH, NMSettingBluetoothPrivate))
+NM_GOBJECT_PROPERTIES_DEFINE_BASE (
+	PROP_BDADDR,
+	PROP_TYPE,
+);
 
 typedef struct {
 	char *bdaddr;
 	char *type;
 } NMSettingBluetoothPrivate;
 
-enum {
-	PROP_0,
-	PROP_BDADDR,
-	PROP_TYPE,
+G_DEFINE_TYPE (NMSettingBluetooth, nm_setting_bluetooth, NM_TYPE_SETTING)
 
-	LAST_PROP
-};
+#define NM_SETTING_BLUETOOTH_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), NM_TYPE_SETTING_BLUETOOTH, NMSettingBluetoothPrivate))
 
-/**
- * nm_setting_bluetooth_new:
- *
- * Creates a new #NMSettingBluetooth object with default values.
- *
- * Returns: (transfer full): the new empty #NMSettingBluetooth object
- **/
-NMSetting *nm_setting_bluetooth_new (void)
-{
-	return (NMSetting *) g_object_new (NM_TYPE_SETTING_BLUETOOTH, NULL);
-}
+/*****************************************************************************/
 
 /**
  * nm_setting_bluetooth_get_connection_type:
@@ -224,20 +214,25 @@ verify (NMSetting *setting, NMConnection *connection, GError **error)
 	return TRUE;
 }
 
-static void
-nm_setting_bluetooth_init (NMSettingBluetooth *setting)
-{
-}
+/*****************************************************************************/
 
 static void
-finalize (GObject *object)
+get_property (GObject *object, guint prop_id,
+              GValue *value, GParamSpec *pspec)
 {
-	NMSettingBluetoothPrivate *priv = NM_SETTING_BLUETOOTH_GET_PRIVATE (object);
-
-	g_free (priv->bdaddr);
-	g_free (priv->type);
+	NMSettingBluetooth *setting = NM_SETTING_BLUETOOTH (object);
 
-	G_OBJECT_CLASS (nm_setting_bluetooth_parent_class)->finalize (object);
+	switch (prop_id) {
+	case PROP_BDADDR:
+		g_value_set_string (value, nm_setting_bluetooth_get_bdaddr (setting));
+		break;
+	case PROP_TYPE:
+		g_value_set_string (value, nm_setting_bluetooth_get_connection_type (setting));
+		break;
+	default:
+		G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+		break;
+	}
 }
 
 static void
@@ -261,23 +256,34 @@ set_property (GObject *object, guint prop_id,
 	}
 }
 
+/*****************************************************************************/
+
 static void
-get_property (GObject *object, guint prop_id,
-              GValue *value, GParamSpec *pspec)
+nm_setting_bluetooth_init (NMSettingBluetooth *setting)
 {
-	NMSettingBluetooth *setting = NM_SETTING_BLUETOOTH (object);
+}
 
-	switch (prop_id) {
-	case PROP_BDADDR:
-		g_value_set_string (value, nm_setting_bluetooth_get_bdaddr (setting));
-		break;
-	case PROP_TYPE:
-		g_value_set_string (value, nm_setting_bluetooth_get_connection_type (setting));
-		break;
-	default:
-		G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
-		break;
-	}
+/**
+ * nm_setting_bluetooth_new:
+ *
+ * Creates a new #NMSettingBluetooth object with default values.
+ *
+ * Returns: (transfer full): the new empty #NMSettingBluetooth object
+ **/
+NMSetting *nm_setting_bluetooth_new (void)
+{
+	return (NMSetting *) g_object_new (NM_TYPE_SETTING_BLUETOOTH, NULL);
+}
+
+static void
+finalize (GObject *object)
+{
+	NMSettingBluetoothPrivate *priv = NM_SETTING_BLUETOOTH_GET_PRIVATE (object);
+
+	g_free (priv->bdaddr);
+	g_free (priv->type);
+
+	G_OBJECT_CLASS (nm_setting_bluetooth_parent_class)->finalize (object);
 }
 
 static void
@@ -289,8 +295,8 @@ nm_setting_bluetooth_class_init (NMSettingBluetoothClass *klass)
 
 	g_type_class_add_private (klass, sizeof (NMSettingBluetoothPrivate));
 
-	object_class->set_property = set_property;
 	object_class->get_property = get_property;
+	object_class->set_property = set_property;
 	object_class->finalize     = finalize;
 
 	setting_class->verify       = verify;
@@ -300,17 +306,15 @@ nm_setting_bluetooth_class_init (NMSettingBluetoothClass *klass)
 	 *
 	 * The Bluetooth address of the device.
 	 **/
-	g_object_class_install_property
-		(object_class, PROP_BDADDR,
-		 g_param_spec_string (NM_SETTING_BLUETOOTH_BDADDR, "", "",
-		                      NULL,
-		                      G_PARAM_READWRITE |
-		                      NM_SETTING_PARAM_INFERRABLE |
-		                      G_PARAM_STATIC_STRINGS));
+	obj_properties[PROP_BDADDR] =
+	    g_param_spec_string (NM_SETTING_BLUETOOTH_BDADDR, "", "",
+	                         NULL,
+	                         G_PARAM_READWRITE |
+	                         NM_SETTING_PARAM_INFERRABLE |
+	                         G_PARAM_STATIC_STRINGS);
 
 	_properties_override_add_transform (properties_override,
-	                                    g_object_class_find_property (G_OBJECT_CLASS (setting_class),
-	                                                                  NM_SETTING_BLUETOOTH_BDADDR),
+	                                    obj_properties[PROP_BDADDR],
 	                                    G_VARIANT_TYPE_BYTESTRING,
 	                                    _nm_utils_hwaddr_to_dbus,
 	                                    _nm_utils_hwaddr_from_dbus);
@@ -321,13 +325,14 @@ nm_setting_bluetooth_class_init (NMSettingBluetoothClass *klass)
 	 * Either "dun" for Dial-Up Networking connections or "panu" for Personal
 	 * Area Networking connections to devices supporting the NAP profile.
 	 **/
-	g_object_class_install_property
-		(object_class, PROP_TYPE,
-		 g_param_spec_string (NM_SETTING_BLUETOOTH_TYPE, "", "",
-		                      NULL,
-		                      G_PARAM_READWRITE |
-		                      NM_SETTING_PARAM_INFERRABLE |
-		                      G_PARAM_STATIC_STRINGS));
+	obj_properties[PROP_TYPE] =
+	    g_param_spec_string (NM_SETTING_BLUETOOTH_TYPE, "", "",
+	                         NULL,
+	                         G_PARAM_READWRITE |
+	                         NM_SETTING_PARAM_INFERRABLE |
+	                         G_PARAM_STATIC_STRINGS);
+
+	g_object_class_install_properties (object_class, _PROPERTY_ENUMS_LAST, obj_properties);
 
 	_nm_setting_class_commit_full (setting_class, NM_META_SETTING_TYPE_BLUETOOTH,
 	                               NULL, properties_override);
diff --git a/libnm-core/nm-setting-bond.c b/libnm-core/nm-setting-bond.c
index 0c84b3a0..fa55c06f 100644
--- a/libnm-core/nm-setting-bond.c
+++ b/libnm-core/nm-setting-bond.c
@@ -21,13 +21,14 @@
 
 #include "nm-default.h"
 
+#include "nm-setting-bond.h"
+
 #include <string.h>
 #include <stdlib.h>
 #include <errno.h>
 #include <netinet/in.h>
 #include <arpa/inet.h>
 
-#include "nm-setting-bond.h"
 #include "nm-utils.h"
 #include "nm-utils-private.h"
 #include "nm-connection-private.h"
@@ -46,11 +47,9 @@
 
 /*****************************************************************************/
 
-enum {
-	PROP_0,
+NM_GOBJECT_PROPERTIES_DEFINE (NMSettingBond,
 	PROP_OPTIONS,
-	LAST_PROP
-};
+);
 
 typedef struct {
 	GHashTable *options;
@@ -365,7 +364,7 @@ nm_setting_bond_add_option (NMSettingBond *setting,
 		g_hash_table_remove (priv->options, NM_SETTING_BOND_OPTION_UPDELAY);
 	}
 
-	g_object_notify (G_OBJECT (setting), NM_SETTING_BOND_OPTIONS);
+	_notify (setting, PROP_OPTIONS);
 
 	return TRUE;
 }
@@ -398,7 +397,7 @@ nm_setting_bond_remove_option (NMSettingBond *setting,
 	nm_clear_g_free (&priv->options_idx_cache);
 	found = g_hash_table_remove (priv->options, name);
 	if (found)
-		g_object_notify (G_OBJECT (setting), NM_SETTING_BOND_OPTIONS);
+		_notify (setting, PROP_OPTIONS);
 	return found;
 }
 
@@ -811,15 +810,15 @@ verify (NMSetting *setting, NMConnection *connection, GError **error)
 /*****************************************************************************/
 
 static gboolean
-options_hash_match (NMSettingBond *s_bond,
-                    GHashTable *options1,
-                    GHashTable *options2,
+options_equal_asym (NMSettingBond *s_bond,
+                    NMSettingBond *s_bond2,
                     NMSettingCompareFlags flags)
 {
+	GHashTable *options2 = NM_SETTING_BOND_GET_PRIVATE (s_bond2)->options;
 	GHashTableIter iter;
 	const char *key, *value, *value2;
 
-	g_hash_table_iter_init (&iter, options1);
+	g_hash_table_iter_init (&iter, NM_SETTING_BOND_GET_PRIVATE (s_bond)->options);
 	while (g_hash_table_iter_next (&iter, (gpointer *) &key, (gpointer *) &value)) {
 
 		if (NM_FLAGS_HAS (flags, NM_SETTING_COMPARE_FLAG_INFERRABLE)) {
@@ -841,15 +840,10 @@ options_hash_match (NMSettingBond *s_bond,
 				value2 = g_hash_table_lookup (options2, "num_grat_arp");
 		}
 
-		if (value2) {
-			if (nm_streq (value, value2))
-				continue;
-		} else {
-			if (nm_streq (value, nm_setting_bond_get_option_default (s_bond, key)))
-				continue;
-		}
-
-		return FALSE;
+		if (!value2)
+			value2 = nm_setting_bond_get_option_default (s_bond2, key);
+		if (!nm_streq (value, value2))
+			return FALSE;
 	}
 
 	return TRUE;
@@ -857,31 +851,32 @@ options_hash_match (NMSettingBond *s_bond,
 
 static gboolean
 options_equal (NMSettingBond *s_bond,
-               GHashTable *options1,
-               GHashTable *options2,
+               NMSettingBond *s_bond2,
                NMSettingCompareFlags flags)
 {
-	return    options_hash_match (s_bond, options1, options2, flags)
-	       && options_hash_match (s_bond, options2, options1, flags);
+	return    options_equal_asym (s_bond, s_bond2, flags)
+	       && options_equal_asym (s_bond2, s_bond, flags);
 }
 
-static gboolean
-compare_property (NMSetting *setting,
+static NMTernary
+compare_property (const NMSettInfoSetting *sett_info,
+                  guint property_idx,
+                  NMSetting *setting,
                   NMSetting *other,
-                  const GParamSpec *prop_spec,
                   NMSettingCompareFlags flags)
 {
-	NMSettingClass *setting_class;
-
-	if (nm_streq0 (prop_spec->name, NM_SETTING_BOND_OPTIONS)) {
-		return options_equal (NM_SETTING_BOND (setting),
-		                      NM_SETTING_BOND_GET_PRIVATE (setting)->options,
-		                      NM_SETTING_BOND_GET_PRIVATE (other)->options,
-		                      flags);
+	if (nm_streq (sett_info->property_infos[property_idx].name, NM_SETTING_BOND_OPTIONS)) {
+		return (   !other
+		        || options_equal (NM_SETTING_BOND (setting),
+		                          NM_SETTING_BOND (other),
+		                          flags));
 	}
 
-	setting_class = NM_SETTING_CLASS (nm_setting_bond_parent_class);
-	return setting_class->compare_property (setting, other, prop_spec, flags);
+	return NM_SETTING_CLASS (nm_setting_bond_parent_class)->compare_property (sett_info,
+	                                                                          property_idx,
+	                                                                          setting,
+	                                                                          other,
+	                                                                          flags);
 }
 
 /*****************************************************************************/
@@ -966,8 +961,8 @@ nm_setting_bond_class_init (NMSettingBondClass *klass)
 
 	g_type_class_add_private (klass, sizeof (NMSettingBondPrivate));
 
-	object_class->set_property     = set_property;
 	object_class->get_property     = get_property;
+	object_class->set_property     = set_property;
 	object_class->finalize         = finalize;
 
 	setting_class->verify           = verify;
@@ -987,17 +982,15 @@ nm_setting_bond_class_init (NMSettingBondClass *klass)
 	 * example: BONDING_OPTS="miimon=100 mode=broadcast"
 	 * ---end---
 	 */
-	 g_object_class_install_property
-		 (object_class, PROP_OPTIONS,
-		 g_param_spec_boxed (NM_SETTING_BOND_OPTIONS, "", "",
-		                     G_TYPE_HASH_TABLE,
-		                     G_PARAM_READWRITE |
-		                     NM_SETTING_PARAM_INFERRABLE |
-		                     G_PARAM_STATIC_STRINGS));
+	obj_properties[PROP_OPTIONS] =
+	    g_param_spec_boxed (NM_SETTING_BOND_OPTIONS, "", "",
+	                        G_TYPE_HASH_TABLE,
+	                        G_PARAM_READWRITE |
+	                        NM_SETTING_PARAM_INFERRABLE |
+	                        G_PARAM_STATIC_STRINGS);
 
 	_properties_override_add_transform (properties_override,
-	                                    g_object_class_find_property (G_OBJECT_CLASS (setting_class),
-	                                                                  NM_SETTING_BOND_OPTIONS),
+	                                    obj_properties[PROP_OPTIONS],
 	                                    G_VARIANT_TYPE ("a{ss}"),
 	                                    _nm_utils_strdict_to_dbus,
 	                                    _nm_utils_strdict_from_dbus);
@@ -1016,6 +1009,8 @@ nm_setting_bond_class_init (NMSettingBondClass *klass)
 	                                    _nm_setting_get_deprecated_virtual_interface_name,
 	                                    NULL);
 
+	g_object_class_install_properties (object_class, _PROPERTY_ENUMS_LAST, obj_properties);
+
 	_nm_setting_class_commit_full (setting_class, NM_META_SETTING_TYPE_BOND,
 	                               NULL, properties_override);
 }
diff --git a/libnm-core/nm-setting-bridge-port.c b/libnm-core/nm-setting-bridge-port.c
index 4104f8c5..b8670afd 100644
--- a/libnm-core/nm-setting-bridge-port.c
+++ b/libnm-core/nm-setting-bridge-port.c
@@ -21,11 +21,12 @@
 
 #include "nm-default.h"
 
+#include "nm-setting-bridge-port.h"
+
 #include <string.h>
 #include <ctype.h>
 #include <stdlib.h>
 
-#include "nm-setting-bridge-port.h"
 #include "nm-utils.h"
 #include "nm-utils-private.h"
 #include "nm-connection-private.h"
@@ -40,9 +41,13 @@
  * optional properties that apply to bridge ports.
  **/
 
-G_DEFINE_TYPE (NMSettingBridgePort, nm_setting_bridge_port, NM_TYPE_SETTING)
+/*****************************************************************************/
 
-#define NM_SETTING_BRIDGE_PORT_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), NM_TYPE_SETTING_BRIDGE_PORT, NMSettingBridgePortPrivate))
+NM_GOBJECT_PROPERTIES_DEFINE_BASE (
+	PROP_PRIORITY,
+	PROP_PATH_COST,
+	PROP_HAIRPIN_MODE,
+);
 
 typedef struct {
 	guint16 priority;
@@ -50,13 +55,9 @@ typedef struct {
 	gboolean hairpin_mode;
 } NMSettingBridgePortPrivate;
 
-enum {
-	PROP_0,
-	PROP_PRIORITY,
-	PROP_PATH_COST,
-	PROP_HAIRPIN_MODE,
-	LAST_PROP
-};
+G_DEFINE_TYPE (NMSettingBridgePort, nm_setting_bridge_port, NM_TYPE_SETTING)
+
+#define NM_SETTING_BRIDGE_PORT_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), NM_TYPE_SETTING_BRIDGE_PORT, NMSettingBridgePortPrivate))
 
 /*****************************************************************************/
 
@@ -104,12 +105,6 @@ nm_setting_bridge_port_get_hairpin_mode (NMSettingBridgePort *setting)
 
 /*****************************************************************************/
 
-#define BR_MAX_PORT_PRIORITY 63
-#define BR_DEF_PRIORITY      32
-
-#define BR_MIN_PATH_COST     1
-#define BR_MAX_PATH_COST     65535
-
 static gboolean
 verify (NMSetting *setting, NMConnection *connection, GError **error)
 {
@@ -147,39 +142,21 @@ verify (NMSetting *setting, NMConnection *connection, GError **error)
 
 /*****************************************************************************/
 
-/**
- * nm_setting_bridge_port_new:
- *
- * Creates a new #NMSettingBridgePort object with default values.
- *
- * Returns: (transfer full): the new empty #NMSettingBridgePort object
- **/
-NMSetting *
-nm_setting_bridge_port_new (void)
-{
-	return (NMSetting *) g_object_new (NM_TYPE_SETTING_BRIDGE_PORT, NULL);
-}
-
 static void
-nm_setting_bridge_port_init (NMSettingBridgePort *setting)
-{
-}
-
-static void
-set_property (GObject *object, guint prop_id,
-              const GValue *value, GParamSpec *pspec)
+get_property (GObject *object, guint prop_id,
+              GValue *value, GParamSpec *pspec)
 {
 	NMSettingBridgePortPrivate *priv = NM_SETTING_BRIDGE_PORT_GET_PRIVATE (object);
 
 	switch (prop_id) {
 	case PROP_PRIORITY:
-		priv->priority = g_value_get_uint (value);
+		g_value_set_uint (value, priv->priority);
 		break;
 	case PROP_PATH_COST:
-		priv->path_cost = g_value_get_uint (value);
+		g_value_set_uint (value, priv->path_cost);
 		break;
 	case PROP_HAIRPIN_MODE:
-		priv->hairpin_mode = g_value_get_boolean (value);
+		g_value_set_boolean (value, priv->hairpin_mode);
 		break;
 	default:
 		G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
@@ -188,20 +165,20 @@ set_property (GObject *object, guint prop_id,
 }
 
 static void
-get_property (GObject *object, guint prop_id,
-              GValue *value, GParamSpec *pspec)
+set_property (GObject *object, guint prop_id,
+              const GValue *value, GParamSpec *pspec)
 {
 	NMSettingBridgePortPrivate *priv = NM_SETTING_BRIDGE_PORT_GET_PRIVATE (object);
 
 	switch (prop_id) {
 	case PROP_PRIORITY:
-		g_value_set_uint (value, priv->priority);
+		priv->priority = g_value_get_uint (value);
 		break;
 	case PROP_PATH_COST:
-		g_value_set_uint (value, priv->path_cost);
+		priv->path_cost = g_value_get_uint (value);
 		break;
 	case PROP_HAIRPIN_MODE:
-		g_value_set_boolean (value, priv->hairpin_mode);
+		priv->hairpin_mode = g_value_get_boolean (value);
 		break;
 	default:
 		G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
@@ -209,6 +186,26 @@ get_property (GObject *object, guint prop_id,
 	}
 }
 
+/*****************************************************************************/
+
+static void
+nm_setting_bridge_port_init (NMSettingBridgePort *setting)
+{
+}
+
+/**
+ * nm_setting_bridge_port_new:
+ *
+ * Creates a new #NMSettingBridgePort object with default values.
+ *
+ * Returns: (transfer full): the new empty #NMSettingBridgePort object
+ **/
+NMSetting *
+nm_setting_bridge_port_new (void)
+{
+	return (NMSetting *) g_object_new (NM_TYPE_SETTING_BRIDGE_PORT, NULL);
+}
+
 static void
 nm_setting_bridge_port_class_init (NMSettingBridgePortClass *klass)
 {
@@ -217,8 +214,8 @@ nm_setting_bridge_port_class_init (NMSettingBridgePortClass *klass)
 
 	g_type_class_add_private (klass, sizeof (NMSettingBridgePortPrivate));
 
-	object_class->set_property = set_property;
 	object_class->get_property = get_property;
+	object_class->set_property = set_property;
 
 	setting_class->verify = verify;
 
@@ -235,14 +232,13 @@ nm_setting_bridge_port_class_init (NMSettingBridgePortClass *klass)
 	 * description: STP priority.
 	 * ---end---
 	 */
-	g_object_class_install_property
-		(object_class, PROP_PRIORITY,
-		 g_param_spec_uint (NM_SETTING_BRIDGE_PORT_PRIORITY, "", "",
-		                    0, BR_MAX_PORT_PRIORITY, BR_DEF_PRIORITY,
-		                    G_PARAM_READWRITE |
-		                    G_PARAM_CONSTRUCT |
-		                    NM_SETTING_PARAM_INFERRABLE |
-		                    G_PARAM_STATIC_STRINGS));
+	obj_properties[PROP_PRIORITY] =
+	    g_param_spec_uint (NM_SETTING_BRIDGE_PORT_PRIORITY, "", "",
+	                       0, NM_BR_PORT_MAX_PRIORITY, NM_BR_PORT_DEF_PRIORITY,
+	                       G_PARAM_READWRITE |
+	                       G_PARAM_CONSTRUCT |
+	                       NM_SETTING_PARAM_INFERRABLE |
+	                       G_PARAM_STATIC_STRINGS);
 
 	/**
 	 * NMSettingBridgePort:path-cost:
@@ -258,14 +254,12 @@ nm_setting_bridge_port_class_init (NMSettingBridgePortClass *klass)
 	 * description: STP cost.
 	 * ---end---
 	 */
-	g_object_class_install_property
-		(object_class, PROP_PATH_COST,
-		 g_param_spec_uint (NM_SETTING_BRIDGE_PORT_PATH_COST, "", "",
-		                    0, BR_MAX_PATH_COST, 100,
-		                    G_PARAM_READWRITE |
-		                    G_PARAM_CONSTRUCT |
-		                    NM_SETTING_PARAM_INFERRABLE |
-		                    G_PARAM_STATIC_STRINGS));
+	obj_properties[PROP_PATH_COST] =
+	    g_param_spec_uint (NM_SETTING_BRIDGE_PORT_PATH_COST, "", "",
+	                       0, NM_BR_PORT_MAX_PATH_COST, 100,
+	                       G_PARAM_READWRITE |
+	                       G_PARAM_CONSTRUCT |
+	                       G_PARAM_STATIC_STRINGS);
 
 	/**
 	 * NMSettingBridgePort:hairpin-mode:
@@ -280,13 +274,14 @@ nm_setting_bridge_port_class_init (NMSettingBridgePortClass *klass)
 	 * description: Hairpin mode of the bridge port.
 	 * ---end---
 	 */
-	g_object_class_install_property
-		(object_class, PROP_HAIRPIN_MODE,
-		 g_param_spec_boolean (NM_SETTING_BRIDGE_PORT_HAIRPIN_MODE, "", "",
-		                       FALSE,
-		                       G_PARAM_READWRITE |
-		                       NM_SETTING_PARAM_INFERRABLE |
-		                       G_PARAM_STATIC_STRINGS));
+	obj_properties[PROP_HAIRPIN_MODE] =
+	    g_param_spec_boolean (NM_SETTING_BRIDGE_PORT_HAIRPIN_MODE, "", "",
+	                          FALSE,
+	                          G_PARAM_READWRITE |
+	                          NM_SETTING_PARAM_INFERRABLE |
+	                          G_PARAM_STATIC_STRINGS);
+
+	g_object_class_install_properties (object_class, _PROPERTY_ENUMS_LAST, obj_properties);
 
 	_nm_setting_class_commit (setting_class, NM_META_SETTING_TYPE_BRIDGE_PORT);
 }
diff --git a/libnm-core/nm-setting-bridge.c b/libnm-core/nm-setting-bridge.c
index 71fe2ed2..328c1fd3 100644
--- a/libnm-core/nm-setting-bridge.c
+++ b/libnm-core/nm-setting-bridge.c
@@ -21,11 +21,12 @@
 
 #include "nm-default.h"
 
+#include "nm-setting-bridge.h"
+
 #include <string.h>
 #include <ctype.h>
 #include <stdlib.h>
 
-#include "nm-setting-bridge.h"
 #include "nm-connection-private.h"
 #include "nm-utils.h"
 #include "nm-utils-private.h"
@@ -38,9 +39,19 @@
  * necessary for bridging connections.
  **/
 
-G_DEFINE_TYPE (NMSettingBridge, nm_setting_bridge, NM_TYPE_SETTING)
+/*****************************************************************************/
 
-#define NM_SETTING_BRIDGE_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), NM_TYPE_SETTING_BRIDGE, NMSettingBridgePrivate))
+NM_GOBJECT_PROPERTIES_DEFINE_BASE (
+	PROP_MAC_ADDRESS,
+	PROP_STP,
+	PROP_PRIORITY,
+	PROP_FORWARD_DELAY,
+	PROP_HELLO_TIME,
+	PROP_MAX_AGE,
+	PROP_AGEING_TIME,
+	PROP_GROUP_FORWARD_MASK,
+	PROP_MULTICAST_SNOOPING,
+);
 
 typedef struct {
 	char *   mac_address;
@@ -54,32 +65,11 @@ typedef struct {
 	gboolean multicast_snooping;
 } NMSettingBridgePrivate;
 
-enum {
-	PROP_0,
-	PROP_MAC_ADDRESS,
-	PROP_STP,
-	PROP_PRIORITY,
-	PROP_FORWARD_DELAY,
-	PROP_HELLO_TIME,
-	PROP_MAX_AGE,
-	PROP_AGEING_TIME,
-	PROP_GROUP_FORWARD_MASK,
-	PROP_MULTICAST_SNOOPING,
-	LAST_PROP
-};
+G_DEFINE_TYPE (NMSettingBridge, nm_setting_bridge, NM_TYPE_SETTING)
 
-/**
- * nm_setting_bridge_new:
- *
- * Creates a new #NMSettingBridge object with default values.
- *
- * Returns: (transfer full): the new empty #NMSettingBridge object
- **/
-NMSetting *
-nm_setting_bridge_new (void)
-{
-	return (NMSetting *) g_object_new (NM_TYPE_SETTING_BRIDGE, NULL);
-}
+#define NM_SETTING_BRIDGE_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), NM_TYPE_SETTING_BRIDGE, NMSettingBridgePrivate))
+
+/*****************************************************************************/
 
 /**
  * nm_setting_bridge_get_mac_address:
@@ -292,56 +282,42 @@ verify (NMSetting *setting, NMConnection *connection, GError **error)
 	return _nm_connection_verify_required_interface_name (connection, error);
 }
 
-static void
-nm_setting_bridge_init (NMSettingBridge *setting)
-{
-}
+/*****************************************************************************/
 
 static void
-finalize (GObject *object)
-{
-	NMSettingBridgePrivate *priv = NM_SETTING_BRIDGE_GET_PRIVATE (object);
-
-	g_free (priv->mac_address);
-
-	G_OBJECT_CLASS (nm_setting_bridge_parent_class)->finalize (object);
-}
-
-static void
-set_property (GObject *object, guint prop_id,
-              const GValue *value, GParamSpec *pspec)
+get_property (GObject *object, guint prop_id,
+              GValue *value, GParamSpec *pspec)
 {
 	NMSettingBridgePrivate *priv = NM_SETTING_BRIDGE_GET_PRIVATE (object);
+	NMSettingBridge *setting = NM_SETTING_BRIDGE (object);
 
 	switch (prop_id) {
 	case PROP_MAC_ADDRESS:
-		g_free (priv->mac_address);
-		priv->mac_address = _nm_utils_hwaddr_canonical_or_invalid (g_value_get_string (value),
-		                                                           ETH_ALEN);
+		g_value_set_string (value, nm_setting_bridge_get_mac_address (setting));
 		break;
 	case PROP_STP:
-		priv->stp = g_value_get_boolean (value);
+		g_value_set_boolean (value, priv->stp);
 		break;
 	case PROP_PRIORITY:
-		priv->priority = (guint16) g_value_get_uint (value);
+		g_value_set_uint (value, priv->priority);
 		break;
 	case PROP_FORWARD_DELAY:
-		priv->forward_delay = (guint16) g_value_get_uint (value);
+		g_value_set_uint (value, priv->forward_delay);
 		break;
 	case PROP_HELLO_TIME:
-		priv->hello_time = (guint16) g_value_get_uint (value);
+		g_value_set_uint (value, priv->hello_time);
 		break;
 	case PROP_MAX_AGE:
-		priv->max_age = (guint16) g_value_get_uint (value);
+		g_value_set_uint (value, priv->max_age);
 		break;
 	case PROP_AGEING_TIME:
-		priv->ageing_time = g_value_get_uint (value);
+		g_value_set_uint (value, priv->ageing_time);
 		break;
 	case PROP_GROUP_FORWARD_MASK:
-		priv->group_forward_mask = (guint16) g_value_get_uint (value);
+		g_value_set_uint (value, priv->group_forward_mask);
 		break;
 	case PROP_MULTICAST_SNOOPING:
-		priv->multicast_snooping = g_value_get_boolean (value);
+		g_value_set_boolean (value, priv->multicast_snooping);
 		break;
 	default:
 		G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
@@ -350,39 +326,40 @@ set_property (GObject *object, guint prop_id,
 }
 
 static void
-get_property (GObject *object, guint prop_id,
-              GValue *value, GParamSpec *pspec)
+set_property (GObject *object, guint prop_id,
+              const GValue *value, GParamSpec *pspec)
 {
 	NMSettingBridgePrivate *priv = NM_SETTING_BRIDGE_GET_PRIVATE (object);
-	NMSettingBridge *setting = NM_SETTING_BRIDGE (object);
 
 	switch (prop_id) {
 	case PROP_MAC_ADDRESS:
-		g_value_set_string (value, nm_setting_bridge_get_mac_address (setting));
+		g_free (priv->mac_address);
+		priv->mac_address = _nm_utils_hwaddr_canonical_or_invalid (g_value_get_string (value),
+		                                                           ETH_ALEN);
 		break;
 	case PROP_STP:
-		g_value_set_boolean (value, priv->stp);
+		priv->stp = g_value_get_boolean (value);
 		break;
 	case PROP_PRIORITY:
-		g_value_set_uint (value, priv->priority);
+		priv->priority = (guint16) g_value_get_uint (value);
 		break;
 	case PROP_FORWARD_DELAY:
-		g_value_set_uint (value, priv->forward_delay);
+		priv->forward_delay = (guint16) g_value_get_uint (value);
 		break;
 	case PROP_HELLO_TIME:
-		g_value_set_uint (value, priv->hello_time);
+		priv->hello_time = (guint16) g_value_get_uint (value);
 		break;
 	case PROP_MAX_AGE:
-		g_value_set_uint (value, priv->max_age);
+		priv->max_age = (guint16) g_value_get_uint (value);
 		break;
 	case PROP_AGEING_TIME:
-		g_value_set_uint (value, priv->ageing_time);
+		priv->ageing_time = g_value_get_uint (value);
 		break;
 	case PROP_GROUP_FORWARD_MASK:
-		g_value_set_uint (value, priv->group_forward_mask);
+		priv->group_forward_mask = (guint16) g_value_get_uint (value);
 		break;
 	case PROP_MULTICAST_SNOOPING:
-		g_value_set_boolean (value, priv->multicast_snooping);
+		priv->multicast_snooping = g_value_get_boolean (value);
 		break;
 	default:
 		G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
@@ -390,6 +367,36 @@ get_property (GObject *object, guint prop_id,
 	}
 }
 
+/*****************************************************************************/
+
+static void
+nm_setting_bridge_init (NMSettingBridge *setting)
+{
+}
+
+/**
+ * nm_setting_bridge_new:
+ *
+ * Creates a new #NMSettingBridge object with default values.
+ *
+ * Returns: (transfer full): the new empty #NMSettingBridge object
+ **/
+NMSetting *
+nm_setting_bridge_new (void)
+{
+	return (NMSetting *) g_object_new (NM_TYPE_SETTING_BRIDGE, NULL);
+}
+
+static void
+finalize (GObject *object)
+{
+	NMSettingBridgePrivate *priv = NM_SETTING_BRIDGE_GET_PRIVATE (object);
+
+	g_free (priv->mac_address);
+
+	G_OBJECT_CLASS (nm_setting_bridge_parent_class)->finalize (object);
+}
+
 static void
 nm_setting_bridge_class_init (NMSettingBridgeClass *klass)
 {
@@ -399,8 +406,8 @@ nm_setting_bridge_class_init (NMSettingBridgeClass *klass)
 
 	g_type_class_add_private (klass, sizeof (NMSettingBridgePrivate));
 
-	object_class->set_property = set_property;
 	object_class->get_property = get_property;
+	object_class->set_property = set_property;
 	object_class->finalize     = finalize;
 
 	setting_class->verify = verify;
@@ -435,17 +442,15 @@ nm_setting_bridge_class_init (NMSettingBridgeClass *klass)
 	 *   BRIDGE_MACADDR for bridges is an NM extension.
 	 * ---end---
 	 */
-	g_object_class_install_property
-		(object_class, PROP_MAC_ADDRESS,
-		 g_param_spec_string (NM_SETTING_BRIDGE_MAC_ADDRESS, "", "",
-		                      NULL,
-		                      G_PARAM_READWRITE |
-		                      NM_SETTING_PARAM_INFERRABLE |
-		                      G_PARAM_STATIC_STRINGS));
+	obj_properties[PROP_MAC_ADDRESS] =
+	    g_param_spec_string (NM_SETTING_BRIDGE_MAC_ADDRESS, "", "",
+	                         NULL,
+	                         G_PARAM_READWRITE |
+	                         NM_SETTING_PARAM_INFERRABLE |
+	                         G_PARAM_STATIC_STRINGS);
 
 	_properties_override_add_transform (properties_override,
-	                                    g_object_class_find_property (G_OBJECT_CLASS (setting_class),
-	                                                                  NM_SETTING_BRIDGE_MAC_ADDRESS),
+	                                    obj_properties[PROP_MAC_ADDRESS],
 	                                    G_VARIANT_TYPE_BYTESTRING,
 	                                    _nm_utils_hwaddr_to_dbus,
 	                                    _nm_utils_hwaddr_from_dbus);
@@ -462,14 +467,13 @@ nm_setting_bridge_class_init (NMSettingBridgeClass *klass)
 	 * description: Span tree protocol participation.
 	 * ---end---
 	 */
-	g_object_class_install_property
-		(object_class, PROP_STP,
-		 g_param_spec_boolean (NM_SETTING_BRIDGE_STP, "", "",
-		                       TRUE,
-		                       G_PARAM_READWRITE |
-		                       G_PARAM_CONSTRUCT |
-		                       NM_SETTING_PARAM_INFERRABLE |
-		                       G_PARAM_STATIC_STRINGS));
+	obj_properties[PROP_STP] =
+	    g_param_spec_boolean (NM_SETTING_BRIDGE_STP, "", "",
+	                          TRUE,
+	                          G_PARAM_READWRITE |
+	                          G_PARAM_CONSTRUCT |
+	                          NM_SETTING_PARAM_INFERRABLE |
+	                          G_PARAM_STATIC_STRINGS);
 
 	/**
 	 * NMSettingBridge:priority:
@@ -486,14 +490,13 @@ nm_setting_bridge_class_init (NMSettingBridgeClass *klass)
 	 * description: STP priority.
 	 * ---end---
 	 */
-	g_object_class_install_property
-		(object_class, PROP_PRIORITY,
-		 g_param_spec_uint (NM_SETTING_BRIDGE_PRIORITY, "", "",
-		                    0, G_MAXUINT16, 0x8000,
-		                    G_PARAM_READWRITE |
-		                    G_PARAM_CONSTRUCT |
-		                    NM_SETTING_PARAM_INFERRABLE |
-		                    G_PARAM_STATIC_STRINGS));
+	obj_properties[PROP_PRIORITY] =
+	    g_param_spec_uint (NM_SETTING_BRIDGE_PRIORITY, "", "",
+	                       0, G_MAXUINT16, 0x8000,
+	                       G_PARAM_READWRITE |
+	                       G_PARAM_CONSTRUCT |
+	                       NM_SETTING_PARAM_INFERRABLE |
+	                       G_PARAM_STATIC_STRINGS);
 
 	/**
 	 * NMSettingBridge:forward-delay:
@@ -508,14 +511,13 @@ nm_setting_bridge_class_init (NMSettingBridgeClass *klass)
 	 * description: STP forwarding delay.
 	 * ---end---
 	 */
-	g_object_class_install_property
-		(object_class, PROP_FORWARD_DELAY,
-		 g_param_spec_uint (NM_SETTING_BRIDGE_FORWARD_DELAY, "", "",
-		                    0, NM_BR_MAX_FORWARD_DELAY, 15,
-		                    G_PARAM_READWRITE |
-		                    G_PARAM_CONSTRUCT |
-		                    NM_SETTING_PARAM_INFERRABLE |
-		                    G_PARAM_STATIC_STRINGS));
+	obj_properties[PROP_FORWARD_DELAY] =
+	    g_param_spec_uint (NM_SETTING_BRIDGE_FORWARD_DELAY, "", "",
+	                       0, NM_BR_MAX_FORWARD_DELAY, 15,
+	                       G_PARAM_READWRITE |
+	                       G_PARAM_CONSTRUCT |
+	                       NM_SETTING_PARAM_INFERRABLE |
+	                       G_PARAM_STATIC_STRINGS);
 
 	/**
 	 * NMSettingBridge:hello-time:
@@ -530,14 +532,13 @@ nm_setting_bridge_class_init (NMSettingBridgeClass *klass)
 	 * description: STP hello time.
 	 * ---end---
 	 */
-	g_object_class_install_property
-		(object_class, PROP_HELLO_TIME,
-		 g_param_spec_uint (NM_SETTING_BRIDGE_HELLO_TIME, "", "",
-		                    0, NM_BR_MAX_HELLO_TIME, 2,
-		                    G_PARAM_READWRITE |
-		                    G_PARAM_CONSTRUCT |
-		                    NM_SETTING_PARAM_INFERRABLE |
-		                    G_PARAM_STATIC_STRINGS));
+	obj_properties[PROP_HELLO_TIME] =
+	    g_param_spec_uint (NM_SETTING_BRIDGE_HELLO_TIME, "", "",
+	                       0, NM_BR_MAX_HELLO_TIME, 2,
+	                       G_PARAM_READWRITE |
+	                       G_PARAM_CONSTRUCT |
+	                       NM_SETTING_PARAM_INFERRABLE |
+	                       G_PARAM_STATIC_STRINGS);
 
 	/**
 	 * NMSettingBridge:max-age:
@@ -552,14 +553,13 @@ nm_setting_bridge_class_init (NMSettingBridgeClass *klass)
 	 * description: STP maximum message age.
 	 * ---end---
 	 */
-	g_object_class_install_property
-		(object_class, PROP_MAX_AGE,
-		 g_param_spec_uint (NM_SETTING_BRIDGE_MAX_AGE, "", "",
-		                    0, NM_BR_MAX_MAX_AGE, 20,
-		                    G_PARAM_READWRITE |
-		                    G_PARAM_CONSTRUCT |
-		                    NM_SETTING_PARAM_INFERRABLE |
-		                    G_PARAM_STATIC_STRINGS));
+	obj_properties[PROP_MAX_AGE] =
+	    g_param_spec_uint (NM_SETTING_BRIDGE_MAX_AGE, "", "",
+	                       0, NM_BR_MAX_MAX_AGE, 20,
+	                       G_PARAM_READWRITE |
+	                       G_PARAM_CONSTRUCT |
+	                       NM_SETTING_PARAM_INFERRABLE |
+	                       G_PARAM_STATIC_STRINGS);
 
 	/**
 	 * NMSettingBridge:ageing-time:
@@ -574,14 +574,13 @@ nm_setting_bridge_class_init (NMSettingBridgeClass *klass)
 	 * description: Ethernet MAC ageing time.
 	 * ---end---
 	 */
-	g_object_class_install_property
-		(object_class, PROP_AGEING_TIME,
-		 g_param_spec_uint (NM_SETTING_BRIDGE_AGEING_TIME, "", "",
-		                    NM_BR_MIN_AGEING_TIME, NM_BR_MAX_AGEING_TIME, 300,
-		                    G_PARAM_READWRITE |
-		                    G_PARAM_CONSTRUCT |
-		                    NM_SETTING_PARAM_INFERRABLE |
-		                    G_PARAM_STATIC_STRINGS));
+	obj_properties[PROP_AGEING_TIME] =
+	    g_param_spec_uint (NM_SETTING_BRIDGE_AGEING_TIME, "", "",
+	                       NM_BR_MIN_AGEING_TIME, NM_BR_MAX_AGEING_TIME, 300,
+	                       G_PARAM_READWRITE |
+	                       G_PARAM_CONSTRUCT |
+	                       NM_SETTING_PARAM_INFERRABLE |
+	                       G_PARAM_STATIC_STRINGS);
 
 	/**
 	 * NMSettingBridge:group-forward-mask:
@@ -595,14 +594,13 @@ nm_setting_bridge_class_init (NMSettingBridgeClass *klass)
 	 *
 	 * Since: 1.10
 	 **/
-	g_object_class_install_property
-		(object_class, PROP_GROUP_FORWARD_MASK,
-		 g_param_spec_uint (NM_SETTING_BRIDGE_GROUP_FORWARD_MASK, "", "",
-		                    0, 0xFFFF, 0,
-		                    G_PARAM_READWRITE |
-		                    G_PARAM_CONSTRUCT |
-		                    NM_SETTING_PARAM_INFERRABLE |
-		                    G_PARAM_STATIC_STRINGS));
+	obj_properties[PROP_GROUP_FORWARD_MASK] =
+	    g_param_spec_uint (NM_SETTING_BRIDGE_GROUP_FORWARD_MASK, "", "",
+	                       0, 0xFFFF, 0,
+	                       G_PARAM_READWRITE |
+	                       G_PARAM_CONSTRUCT |
+	                       NM_SETTING_PARAM_INFERRABLE |
+	                       G_PARAM_STATIC_STRINGS);
 
 	/**
 	 * NMSettingBridge:multicast-snooping:
@@ -622,14 +620,13 @@ nm_setting_bridge_class_init (NMSettingBridgeClass *klass)
 	 * description: IGMP snooping support.
 	 * ---end---
 	 */
-	g_object_class_install_property
-		(object_class, PROP_MULTICAST_SNOOPING,
-		 g_param_spec_boolean (NM_SETTING_BRIDGE_MULTICAST_SNOOPING, "", "",
-		                       TRUE,
-		                       G_PARAM_READWRITE |
-		                       G_PARAM_CONSTRUCT |
-		                       NM_SETTING_PARAM_INFERRABLE |
-		                       G_PARAM_STATIC_STRINGS));
+	obj_properties[PROP_MULTICAST_SNOOPING] =
+	    g_param_spec_boolean (NM_SETTING_BRIDGE_MULTICAST_SNOOPING, "", "",
+	                          TRUE,
+	                          G_PARAM_READWRITE |
+	                          G_PARAM_CONSTRUCT |
+	                          NM_SETTING_PARAM_INFERRABLE |
+	                          G_PARAM_STATIC_STRINGS);
 
 	/* ---dbus---
 	 * property: interface-name
@@ -645,6 +642,8 @@ nm_setting_bridge_class_init (NMSettingBridgeClass *klass)
 	                                    _nm_setting_get_deprecated_virtual_interface_name,
 	                                    NULL);
 
+	g_object_class_install_properties (object_class, _PROPERTY_ENUMS_LAST, obj_properties);
+
 	_nm_setting_class_commit_full (setting_class, NM_META_SETTING_TYPE_BRIDGE,
 	                               NULL, properties_override);
 }
diff --git a/libnm-core/nm-setting-cdma.c b/libnm-core/nm-setting-cdma.c
index a5d5428d..1e5cd81e 100644
--- a/libnm-core/nm-setting-cdma.c
+++ b/libnm-core/nm-setting-cdma.c
@@ -21,9 +21,10 @@
 
 #include "nm-default.h"
 
+#include "nm-setting-cdma.h"
+
 #include <string.h>
 
-#include "nm-setting-cdma.h"
 #include "nm-utils.h"
 #include "nm-setting-private.h"
 #include "nm-core-enum-types.h"
@@ -37,9 +38,15 @@
  * networks, including those using CDMA2000/EVDO technology.
  */
 
-G_DEFINE_TYPE (NMSettingCdma, nm_setting_cdma, NM_TYPE_SETTING)
+/*****************************************************************************/
 
-#define NM_SETTING_CDMA_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), NM_TYPE_SETTING_CDMA, NMSettingCdmaPrivate))
+NM_GOBJECT_PROPERTIES_DEFINE_BASE (
+	PROP_NUMBER,
+	PROP_USERNAME,
+	PROP_PASSWORD,
+	PROP_PASSWORD_FLAGS,
+	PROP_MTU,
+);
 
 typedef struct {
 	char *number; /* For dialing, duh */
@@ -49,29 +56,11 @@ typedef struct {
 	guint32 mtu;
 } NMSettingCdmaPrivate;
 
-enum {
-	PROP_0,
-	PROP_NUMBER,
-	PROP_USERNAME,
-	PROP_PASSWORD,
-	PROP_PASSWORD_FLAGS,
-	PROP_MTU,
+G_DEFINE_TYPE (NMSettingCdma, nm_setting_cdma, NM_TYPE_SETTING)
 
-	LAST_PROP
-};
+#define NM_SETTING_CDMA_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), NM_TYPE_SETTING_CDMA, NMSettingCdmaPrivate))
 
-/**
- * nm_setting_cdma_new:
- *
- * Creates a new #NMSettingCdma object with default values.
- *
- * Returns: the new empty #NMSettingCdma object
- **/
-NMSetting *
-nm_setting_cdma_new (void)
-{
-	return (NMSetting *) g_object_new (NM_TYPE_SETTING_CDMA, NULL);
-}
+/*****************************************************************************/
 
 /**
  * nm_setting_cdma_get_number:
@@ -206,21 +195,34 @@ need_secrets (NMSetting *setting)
 	return secrets;
 }
 
-static void
-nm_setting_cdma_init (NMSettingCdma *setting)
-{
-}
+/*****************************************************************************/
 
 static void
-finalize (GObject *object)
+get_property (GObject *object, guint prop_id,
+              GValue *value, GParamSpec *pspec)
 {
-	NMSettingCdmaPrivate *priv = NM_SETTING_CDMA_GET_PRIVATE (object);
-
-	g_free (priv->number);
-	g_free (priv->username);
-	g_free (priv->password);
+	NMSettingCdma *setting = NM_SETTING_CDMA (object);
 
-	G_OBJECT_CLASS (nm_setting_cdma_parent_class)->finalize (object);
+	switch (prop_id) {
+	case PROP_NUMBER:
+		g_value_set_string (value, nm_setting_cdma_get_number (setting));
+		break;
+	case PROP_USERNAME:
+		g_value_set_string (value, nm_setting_cdma_get_username (setting));
+		break;
+	case PROP_PASSWORD:
+		g_value_set_string (value, nm_setting_cdma_get_password (setting));
+		break;
+	case PROP_PASSWORD_FLAGS:
+		g_value_set_flags (value, nm_setting_cdma_get_password_flags (setting));
+		break;
+	case PROP_MTU:
+		g_value_set_uint (value, nm_setting_cdma_get_mtu (setting));
+		break;
+	default:
+		G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+		break;
+	}
 }
 
 static void
@@ -254,32 +256,36 @@ set_property (GObject *object, guint prop_id,
 	}
 }
 
+/*****************************************************************************/
+
 static void
-get_property (GObject *object, guint prop_id,
-              GValue *value, GParamSpec *pspec)
+nm_setting_cdma_init (NMSettingCdma *setting)
 {
-	NMSettingCdma *setting = NM_SETTING_CDMA (object);
+}
 
-	switch (prop_id) {
-	case PROP_NUMBER:
-		g_value_set_string (value, nm_setting_cdma_get_number (setting));
-		break;
-	case PROP_USERNAME:
-		g_value_set_string (value, nm_setting_cdma_get_username (setting));
-		break;
-	case PROP_PASSWORD:
-		g_value_set_string (value, nm_setting_cdma_get_password (setting));
-		break;
-	case PROP_PASSWORD_FLAGS:
-		g_value_set_flags (value, nm_setting_cdma_get_password_flags (setting));
-		break;
-	case PROP_MTU:
-		g_value_set_uint (value, nm_setting_cdma_get_mtu (setting));
-		break;
-	default:
-		G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
-		break;
-	}
+/**
+ * nm_setting_cdma_new:
+ *
+ * Creates a new #NMSettingCdma object with default values.
+ *
+ * Returns: the new empty #NMSettingCdma object
+ **/
+NMSetting *
+nm_setting_cdma_new (void)
+{
+	return (NMSetting *) g_object_new (NM_TYPE_SETTING_CDMA, NULL);
+}
+
+static void
+finalize (GObject *object)
+{
+	NMSettingCdmaPrivate *priv = NM_SETTING_CDMA_GET_PRIVATE (object);
+
+	g_free (priv->number);
+	g_free (priv->username);
+	g_free (priv->password);
+
+	G_OBJECT_CLASS (nm_setting_cdma_parent_class)->finalize (object);
 }
 
 static void
@@ -290,8 +296,8 @@ nm_setting_cdma_class_init (NMSettingCdmaClass *klass)
 
 	g_type_class_add_private (klass, sizeof (NMSettingCdmaPrivate));
 
-	object_class->set_property = set_property;
 	object_class->get_property = get_property;
+	object_class->set_property = set_property;
 	object_class->finalize     = finalize;
 
 	setting_class->verify         = verify;
@@ -305,12 +311,11 @@ nm_setting_cdma_class_init (NMSettingCdmaClass *klass)
 	 * broadband network, if any.  If not specified, the default number (#777)
 	 * is used when required.
 	 **/
-	g_object_class_install_property
-		(object_class, PROP_NUMBER,
-		 g_param_spec_string (NM_SETTING_CDMA_NUMBER, "", "",
-		                      NULL,
-		                      G_PARAM_READWRITE |
-		                      G_PARAM_STATIC_STRINGS));
+	obj_properties[PROP_NUMBER] =
+	    g_param_spec_string (NM_SETTING_CDMA_NUMBER, "", "",
+	                         NULL,
+	                         G_PARAM_READWRITE |
+	                         G_PARAM_STATIC_STRINGS);
 
 	/**
 	 * NMSettingCdma:username:
@@ -319,12 +324,11 @@ nm_setting_cdma_class_init (NMSettingCdmaClass *klass)
 	 * providers do not require a username, or accept any username.  But if a
 	 * username is required, it is specified here.
 	 **/
-	g_object_class_install_property
-		(object_class, PROP_USERNAME,
-		 g_param_spec_string (NM_SETTING_CDMA_USERNAME, "", "",
-		                      NULL,
-		                      G_PARAM_READWRITE |
-		                      G_PARAM_STATIC_STRINGS));
+	obj_properties[PROP_USERNAME] =
+	    g_param_spec_string (NM_SETTING_CDMA_USERNAME, "", "",
+	                         NULL,
+	                         G_PARAM_READWRITE |
+	                         G_PARAM_STATIC_STRINGS);
 
 	/**
 	 * NMSettingCdma:password:
@@ -333,26 +337,24 @@ nm_setting_cdma_class_init (NMSettingCdmaClass *klass)
 	 * providers do not require a password, or accept any password.  But if a
 	 * password is required, it is specified here.
 	 **/
-	g_object_class_install_property
-		(object_class, PROP_PASSWORD,
-		 g_param_spec_string (NM_SETTING_CDMA_PASSWORD, "", "",
-		                      NULL,
-		                      G_PARAM_READWRITE |
-		                      NM_SETTING_PARAM_SECRET |
-		                      G_PARAM_STATIC_STRINGS));
+	obj_properties[PROP_PASSWORD] =
+	    g_param_spec_string (NM_SETTING_CDMA_PASSWORD, "", "",
+	                         NULL,
+	                         G_PARAM_READWRITE |
+	                         NM_SETTING_PARAM_SECRET |
+	                         G_PARAM_STATIC_STRINGS);
 
 	/**
 	 * NMSettingCdma:password-flags:
 	 *
 	 * Flags indicating how to handle the #NMSettingCdma:password property.
 	 **/
-	g_object_class_install_property
-		(object_class, PROP_PASSWORD_FLAGS,
-		 g_param_spec_flags (NM_SETTING_CDMA_PASSWORD_FLAGS, "", "",
-		                     NM_TYPE_SETTING_SECRET_FLAGS,
-		                     NM_SETTING_SECRET_FLAG_NONE,
-		                     G_PARAM_READWRITE |
-		                     G_PARAM_STATIC_STRINGS));
+	obj_properties[PROP_PASSWORD_FLAGS] =
+	    g_param_spec_flags (NM_SETTING_CDMA_PASSWORD_FLAGS, "", "",
+	                        NM_TYPE_SETTING_SECRET_FLAGS,
+	                        NM_SETTING_SECRET_FLAG_NONE,
+	                        G_PARAM_READWRITE |
+	                        G_PARAM_STATIC_STRINGS);
 
 	/**
 	 * NMSettingCdma:mtu:
@@ -362,14 +364,15 @@ nm_setting_cdma_class_init (NMSettingCdmaClass *klass)
 	 *
 	 * Since: 1.8
 	 **/
-	g_object_class_install_property
-		(object_class, PROP_MTU,
-		 g_param_spec_uint (NM_SETTING_CDMA_MTU, "", "",
-		                    0, G_MAXUINT32, 0,
-		                    G_PARAM_READWRITE |
-		                    G_PARAM_CONSTRUCT |
-		                    NM_SETTING_PARAM_FUZZY_IGNORE |
-		                    G_PARAM_STATIC_STRINGS));
+	obj_properties[PROP_MTU] =
+	    g_param_spec_uint (NM_SETTING_CDMA_MTU, "", "",
+	                       0, G_MAXUINT32, 0,
+	                       G_PARAM_READWRITE |
+	                       G_PARAM_CONSTRUCT |
+	                       NM_SETTING_PARAM_FUZZY_IGNORE |
+	                       G_PARAM_STATIC_STRINGS);
+
+	g_object_class_install_properties (object_class, _PROPERTY_ENUMS_LAST, obj_properties);
 
 	_nm_setting_class_commit (setting_class, NM_META_SETTING_TYPE_CDMA);
 }
diff --git a/libnm-core/nm-setting-connection.c b/libnm-core/nm-setting-connection.c
index 50240bc9..a32044d2 100644
--- a/libnm-core/nm-setting-connection.c
+++ b/libnm-core/nm-setting-connection.c
@@ -45,9 +45,7 @@
  * a #NMSettingConnection setting.
  **/
 
-G_DEFINE_TYPE (NMSettingConnection, nm_setting_connection, NM_TYPE_SETTING)
-
-#define NM_SETTING_CONNECTION_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), NM_TYPE_SETTING_CONNECTION, NMSettingConnectionPrivate))
+/*****************************************************************************/
 
 typedef enum {
 	PERM_TYPE_USER = 0,
@@ -58,6 +56,32 @@ typedef struct {
 	char *item;
 } Permission;
 
+NM_GOBJECT_PROPERTIES_DEFINE (NMSettingConnection,
+	PROP_ID,
+	PROP_UUID,
+	PROP_INTERFACE_NAME,
+	PROP_TYPE,
+	PROP_PERMISSIONS,
+	PROP_AUTOCONNECT,
+	PROP_AUTOCONNECT_PRIORITY,
+	PROP_AUTOCONNECT_RETRIES,
+	PROP_MULTI_CONNECT,
+	PROP_TIMESTAMP,
+	PROP_READ_ONLY,
+	PROP_ZONE,
+	PROP_MASTER,
+	PROP_SLAVE_TYPE,
+	PROP_AUTOCONNECT_SLAVES,
+	PROP_SECONDARIES,
+	PROP_GATEWAY_PING_TIMEOUT,
+	PROP_METERED,
+	PROP_LLDP,
+	PROP_MDNS,
+	PROP_LLMNR,
+	PROP_STABLE_ID,
+	PROP_AUTH_RETRIES,
+);
+
 typedef struct {
 	char *id;
 	char *uuid;
@@ -84,34 +108,9 @@ typedef struct {
 	int llmnr;
 } NMSettingConnectionPrivate;
 
-enum {
-	PROP_0,
-	PROP_ID,
-	PROP_UUID,
-	PROP_INTERFACE_NAME,
-	PROP_TYPE,
-	PROP_PERMISSIONS,
-	PROP_AUTOCONNECT,
-	PROP_AUTOCONNECT_PRIORITY,
-	PROP_AUTOCONNECT_RETRIES,
-	PROP_MULTI_CONNECT,
-	PROP_TIMESTAMP,
-	PROP_READ_ONLY,
-	PROP_ZONE,
-	PROP_MASTER,
-	PROP_SLAVE_TYPE,
-	PROP_AUTOCONNECT_SLAVES,
-	PROP_SECONDARIES,
-	PROP_GATEWAY_PING_TIMEOUT,
-	PROP_METERED,
-	PROP_LLDP,
-	PROP_MDNS,
-	PROP_LLMNR,
-	PROP_STABLE_ID,
-	PROP_AUTH_RETRIES,
+G_DEFINE_TYPE (NMSettingConnection, nm_setting_connection, NM_TYPE_SETTING)
 
-	LAST_PROP
-};
+#define NM_SETTING_CONNECTION_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), NM_TYPE_SETTING_CONNECTION, NMSettingConnectionPrivate))
 
 /*****************************************************************************/
 
@@ -197,18 +196,6 @@ permission_free (Permission *p)
 /*****************************************************************************/
 
 /**
- * nm_setting_connection_new:
- *
- * Creates a new #NMSettingConnection object with default values.
- *
- * Returns: the new empty #NMSettingConnection object
- **/
-NMSetting *nm_setting_connection_new (void)
-{
-	return (NMSetting *) g_object_new (NM_TYPE_SETTING_CONNECTION, NULL);
-}
-
-/**
  * nm_setting_connection_get_id:
  * @setting: the #NMSettingConnection
  *
@@ -312,7 +299,7 @@ nm_setting_connection_get_num_permissions (NMSettingConnection *setting)
  * @setting: the #NMSettingConnection
  * @idx: the zero-based index of the permissions entry
  * @out_ptype: on return, the permission type (at this time, always "user")
- * @out_pitem: on return, the permission item (formatted accoring to @ptype, see
+ * @out_pitem: on return, the permission item (formatted according to @ptype, see
  * #NMSettingConnection:permissions for more detail
  * @out_detail: on return, the permission detail (at this time, always %NULL)
  *
@@ -431,7 +418,7 @@ nm_setting_connection_add_permission (NMSettingConnection *setting,
 	p = permission_new (pitem);
 	g_return_val_if_fail (p != NULL, FALSE);
 	priv->permissions = g_slist_append (priv->permissions, p);
-	g_object_notify (G_OBJECT (setting), NM_SETTING_CONNECTION_PERMISSIONS);
+	_notify (setting, PROP_PERMISSIONS);
 
 	return TRUE;
 }
@@ -458,7 +445,7 @@ nm_setting_connection_remove_permission (NMSettingConnection *setting,
 
 	permission_free ((Permission *) iter->data);
 	priv->permissions = g_slist_delete_link (priv->permissions, iter);
-	g_object_notify (G_OBJECT (setting), NM_SETTING_CONNECTION_PERMISSIONS);
+	_notify (setting, PROP_PERMISSIONS);
 }
 
 /**
@@ -498,7 +485,7 @@ nm_setting_connection_remove_permission_by_value (NMSettingConnection *setting,
 		if (strcmp (pitem, p->item) == 0) {
 			permission_free ((Permission *) iter->data);
 			priv->permissions = g_slist_delete_link (priv->permissions, iter);
-			g_object_notify (G_OBJECT (setting), NM_SETTING_CONNECTION_PERMISSIONS);
+			_notify (setting, PROP_PERMISSIONS);
 			return TRUE;
 		}
 	}
@@ -748,7 +735,7 @@ nm_setting_connection_get_secondary (NMSettingConnection *setting, guint32 idx)
  * @setting: the #NMSettingConnection
  * @sec_uuid: the secondary connection UUID to add
  *
- * Adds a new secondary connetion UUID to the setting.
+ * Adds a new secondary connection UUID to the setting.
  *
  * Returns: %TRUE if the secondary connection UUID was added; %FALSE if the UUID
  * was already present
@@ -771,7 +758,7 @@ nm_setting_connection_add_secondary (NMSettingConnection *setting,
 	}
 
 	priv->secondaries = g_slist_append (priv->secondaries, g_strdup (sec_uuid));
-	g_object_notify (G_OBJECT (setting), NM_SETTING_CONNECTION_SECONDARIES);
+	_notify (setting, PROP_SECONDARIES);
 	return TRUE;
 }
 
@@ -796,7 +783,7 @@ nm_setting_connection_remove_secondary (NMSettingConnection *setting, guint32 id
 
 	g_free (elt->data);
 	priv->secondaries = g_slist_delete_link (priv->secondaries, elt);
-	g_object_notify (G_OBJECT (setting), NM_SETTING_CONNECTION_SECONDARIES);
+	_notify (setting, PROP_SECONDARIES);
 }
 
 /**
@@ -823,7 +810,7 @@ nm_setting_connection_remove_secondary_by_value (NMSettingConnection *setting,
 	for (iter = priv->secondaries; iter; iter = g_slist_next (iter)) {
 		if (!strcmp (sec_uuid, (char *) iter->data)) {
 			priv->secondaries = g_slist_delete_link (priv->secondaries, iter);
-			g_object_notify (G_OBJECT (setting), NM_SETTING_CONNECTION_SECONDARIES);
+			_notify (setting, PROP_SECONDARIES);
 			return TRUE;
 		}
 	}
@@ -1281,51 +1268,26 @@ nm_setting_connection_no_interface_name (NMSetting *setting,
 	return TRUE;
 }
 
-static gboolean
-compare_property (NMSetting *setting,
+static NMTernary
+compare_property (const NMSettInfoSetting *sett_info,
+                  guint property_idx,
+                  NMSetting *setting,
                   NMSetting *other,
-                  const GParamSpec *prop_spec,
                   NMSettingCompareFlags flags)
 {
-	/* Handle ignore ID */
-	if (   (flags & NM_SETTING_COMPARE_FLAG_IGNORE_ID)
-	    && g_strcmp0 (prop_spec->name, NM_SETTING_CONNECTION_ID) == 0)
-		return TRUE;
-
-	/* Handle ignore timestamp */
-	if (   (flags & NM_SETTING_COMPARE_FLAG_IGNORE_TIMESTAMP)
-	    && g_strcmp0 (prop_spec->name, NM_SETTING_CONNECTION_TIMESTAMP) == 0)
-		return TRUE;
-
-	return NM_SETTING_CLASS (nm_setting_connection_parent_class)->compare_property (setting, other, prop_spec, flags);
-}
-
-static void
-nm_setting_connection_init (NMSettingConnection *setting)
-{
-	NMSettingConnectionPrivate *priv = NM_SETTING_CONNECTION_GET_PRIVATE (setting);
-
-	priv->mdns = NM_SETTING_CONNECTION_MDNS_DEFAULT;
-	priv->llmnr = NM_SETTING_CONNECTION_LLMNR_DEFAULT;
-}
-
-static void
-finalize (GObject *object)
-{
-	NMSettingConnectionPrivate *priv = NM_SETTING_CONNECTION_GET_PRIVATE (object);
-
-	g_free (priv->id);
-	g_free (priv->uuid);
-	g_free (priv->stable_id);
-	g_free (priv->interface_name);
-	g_free (priv->type);
-	g_free (priv->zone);
-	g_free (priv->master);
-	g_free (priv->slave_type);
-	g_slist_free_full (priv->permissions, (GDestroyNotify) permission_free);
-	g_slist_free_full (priv->secondaries, g_free);
-
-	G_OBJECT_CLASS (nm_setting_connection_parent_class)->finalize (object);
+	if (   NM_FLAGS_HAS (flags, NM_SETTING_COMPARE_FLAG_IGNORE_ID)
+	    && nm_streq (sett_info->property_infos[property_idx].name, NM_SETTING_CONNECTION_ID))
+		return NM_TERNARY_DEFAULT;
+
+	if (   NM_FLAGS_HAS(flags, NM_SETTING_COMPARE_FLAG_IGNORE_TIMESTAMP)
+	    && nm_streq (sett_info->property_infos[property_idx].name, NM_SETTING_CONNECTION_TIMESTAMP))
+		return NM_TERNARY_DEFAULT;
+
+	return NM_SETTING_CLASS (nm_setting_connection_parent_class)->compare_property (sett_info,
+	                                                                                property_idx,
+	                                                                                setting,
+	                                                                                other,
+	                                                                                flags);
 }
 
 static GSList *
@@ -1348,91 +1310,98 @@ perm_strv_to_permlist (char **strv)
 	return list;
 }
 
+static char **
+perm_permlist_to_strv (GSList *permlist)
+{
+	GPtrArray *strings;
+	GSList *iter;
+
+	strings = g_ptr_array_new ();
+	for (iter = permlist; iter; iter = g_slist_next (iter))
+		g_ptr_array_add (strings, permission_to_string ((Permission *) iter->data));
+	g_ptr_array_add (strings, NULL);
+
+	return (char **) g_ptr_array_free (strings, FALSE);
+}
+
+/*****************************************************************************/
+
 static void
-set_property (GObject *object, guint prop_id,
-              const GValue *value, GParamSpec *pspec)
+get_property (GObject *object, guint prop_id,
+              GValue *value, GParamSpec *pspec)
 {
-	NMSettingConnectionPrivate *priv = NM_SETTING_CONNECTION_GET_PRIVATE (object);
+	NMSettingConnection *setting = NM_SETTING_CONNECTION (object);
+	NMSettingConnectionPrivate *priv = NM_SETTING_CONNECTION_GET_PRIVATE (setting);
 
 	switch (prop_id) {
 	case PROP_ID:
-		g_free (priv->id);
-		priv->id = g_value_dup_string (value);
+		g_value_set_string (value, nm_setting_connection_get_id (setting));
 		break;
 	case PROP_UUID:
-		g_free (priv->uuid);
-		priv->uuid = g_value_dup_string (value);
+		g_value_set_string (value, nm_setting_connection_get_uuid (setting));
 		break;
 	case PROP_STABLE_ID:
-		g_free (priv->stable_id);
-		priv->stable_id = g_value_dup_string (value);
+		g_value_set_string (value, nm_setting_connection_get_stable_id (setting));
 		break;
 	case PROP_INTERFACE_NAME:
-		g_free (priv->interface_name);
-		priv->interface_name = g_value_dup_string (value);
+		g_value_set_string (value, nm_setting_connection_get_interface_name (setting));
 		break;
 	case PROP_TYPE:
-		g_free (priv->type);
-		priv->type = g_value_dup_string (value);
+		g_value_set_string (value, nm_setting_connection_get_connection_type (setting));
 		break;
 	case PROP_PERMISSIONS:
-		g_slist_free_full (priv->permissions, (GDestroyNotify) permission_free);
-		priv->permissions = perm_strv_to_permlist (g_value_get_boxed (value));
+		g_value_take_boxed (value, perm_permlist_to_strv (priv->permissions));
 		break;
 	case PROP_AUTOCONNECT:
-		priv->autoconnect = g_value_get_boolean (value);
+		g_value_set_boolean (value, nm_setting_connection_get_autoconnect (setting));
 		break;
 	case PROP_AUTOCONNECT_PRIORITY:
-		priv->autoconnect_priority = g_value_get_int (value);
+		g_value_set_int (value, nm_setting_connection_get_autoconnect_priority (setting));
 		break;
 	case PROP_AUTOCONNECT_RETRIES:
-		priv->autoconnect_retries = g_value_get_int (value);
+		g_value_set_int (value, nm_setting_connection_get_autoconnect_retries (setting));
 		break;
 	case PROP_MULTI_CONNECT:
-		priv->multi_connect = g_value_get_int (value);
+		g_value_set_int (value, priv->multi_connect);
 		break;
 	case PROP_TIMESTAMP:
-		priv->timestamp = g_value_get_uint64 (value);
+		g_value_set_uint64 (value, nm_setting_connection_get_timestamp (setting));
 		break;
 	case PROP_READ_ONLY:
-		priv->read_only = g_value_get_boolean (value);
+		g_value_set_boolean (value, nm_setting_connection_get_read_only (setting));
 		break;
 	case PROP_ZONE:
-		g_free (priv->zone);
-		priv->zone = g_value_dup_string (value);
+		g_value_set_string (value, nm_setting_connection_get_zone (setting));
 		break;
 	case PROP_MASTER:
-		g_free (priv->master);
-		priv->master = g_value_dup_string (value);
+		g_value_set_string (value, nm_setting_connection_get_master (setting));
 		break;
 	case PROP_SLAVE_TYPE:
-		g_free (priv->slave_type);
-		priv->slave_type = g_value_dup_string (value);
+		g_value_set_string (value, nm_setting_connection_get_slave_type (setting));
 		break;
 	case PROP_AUTOCONNECT_SLAVES:
-		priv->autoconnect_slaves = g_value_get_enum (value);
+		g_value_set_enum (value, nm_setting_connection_get_autoconnect_slaves (setting));
 		break;
 	case PROP_SECONDARIES:
-		g_slist_free_full (priv->secondaries, g_free);
-		priv->secondaries = _nm_utils_strv_to_slist (g_value_get_boxed (value), TRUE);
+		g_value_take_boxed (value, _nm_utils_slist_to_strv (priv->secondaries, TRUE));
 		break;
 	case PROP_GATEWAY_PING_TIMEOUT:
-		priv->gateway_ping_timeout = g_value_get_uint (value);
+		g_value_set_uint (value, priv->gateway_ping_timeout);
 		break;
 	case PROP_METERED:
-		priv->metered = g_value_get_enum (value);
+		g_value_set_enum (value, priv->metered);
 		break;
 	case PROP_LLDP:
-		priv->lldp = g_value_get_int (value);
+		g_value_set_int (value, priv->lldp);
 		break;
 	case PROP_AUTH_RETRIES:
-		priv->auth_retries = g_value_get_int (value);
+		g_value_set_int (value, priv->auth_retries);
 		break;
 	case PROP_MDNS:
-		priv->mdns = g_value_get_int (value);
+		g_value_set_int (value, priv->mdns);
 		break;
 	case PROP_LLMNR:
-		priv->llmnr = g_value_get_int (value);
+		g_value_set_int (value, priv->llmnr);
 		break;
 	default:
 		G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
@@ -1440,96 +1409,91 @@ set_property (GObject *object, guint prop_id,
 	}
 }
 
-static char **
-perm_permlist_to_strv (GSList *permlist)
-{
-	GPtrArray *strings;
-	GSList *iter;
-
-	strings = g_ptr_array_new ();
-	for (iter = permlist; iter; iter = g_slist_next (iter))
-		g_ptr_array_add (strings, permission_to_string ((Permission *) iter->data));
-	g_ptr_array_add (strings, NULL);
-
-	return (char **) g_ptr_array_free (strings, FALSE);
-}
-
 static void
-get_property (GObject *object, guint prop_id,
-              GValue *value, GParamSpec *pspec)
+set_property (GObject *object, guint prop_id,
+              const GValue *value, GParamSpec *pspec)
 {
-	NMSettingConnection *setting = NM_SETTING_CONNECTION (object);
-	NMSettingConnectionPrivate *priv = NM_SETTING_CONNECTION_GET_PRIVATE (setting);
+	NMSettingConnectionPrivate *priv = NM_SETTING_CONNECTION_GET_PRIVATE (object);
 
 	switch (prop_id) {
 	case PROP_ID:
-		g_value_set_string (value, nm_setting_connection_get_id (setting));
+		g_free (priv->id);
+		priv->id = g_value_dup_string (value);
 		break;
 	case PROP_UUID:
-		g_value_set_string (value, nm_setting_connection_get_uuid (setting));
+		g_free (priv->uuid);
+		priv->uuid = g_value_dup_string (value);
 		break;
 	case PROP_STABLE_ID:
-		g_value_set_string (value, nm_setting_connection_get_stable_id (setting));
+		g_free (priv->stable_id);
+		priv->stable_id = g_value_dup_string (value);
 		break;
 	case PROP_INTERFACE_NAME:
-		g_value_set_string (value, nm_setting_connection_get_interface_name (setting));
+		g_free (priv->interface_name);
+		priv->interface_name = g_value_dup_string (value);
 		break;
 	case PROP_TYPE:
-		g_value_set_string (value, nm_setting_connection_get_connection_type (setting));
+		g_free (priv->type);
+		priv->type = g_value_dup_string (value);
 		break;
 	case PROP_PERMISSIONS:
-		g_value_take_boxed (value, perm_permlist_to_strv (priv->permissions));
+		g_slist_free_full (priv->permissions, (GDestroyNotify) permission_free);
+		priv->permissions = perm_strv_to_permlist (g_value_get_boxed (value));
 		break;
 	case PROP_AUTOCONNECT:
-		g_value_set_boolean (value, nm_setting_connection_get_autoconnect (setting));
+		priv->autoconnect = g_value_get_boolean (value);
 		break;
 	case PROP_AUTOCONNECT_PRIORITY:
-		g_value_set_int (value, nm_setting_connection_get_autoconnect_priority (setting));
+		priv->autoconnect_priority = g_value_get_int (value);
 		break;
 	case PROP_AUTOCONNECT_RETRIES:
-		g_value_set_int (value, nm_setting_connection_get_autoconnect_retries (setting));
+		priv->autoconnect_retries = g_value_get_int (value);
 		break;
 	case PROP_MULTI_CONNECT:
-		g_value_set_int (value, priv->multi_connect);
+		priv->multi_connect = g_value_get_int (value);
 		break;
 	case PROP_TIMESTAMP:
-		g_value_set_uint64 (value, nm_setting_connection_get_timestamp (setting));
+		priv->timestamp = g_value_get_uint64 (value);
 		break;
 	case PROP_READ_ONLY:
-		g_value_set_boolean (value, nm_setting_connection_get_read_only (setting));
+		priv->read_only = g_value_get_boolean (value);
 		break;
 	case PROP_ZONE:
-		g_value_set_string (value, nm_setting_connection_get_zone (setting));
+		g_free (priv->zone);
+		priv->zone = g_value_dup_string (value);
 		break;
 	case PROP_MASTER:
-		g_value_set_string (value, nm_setting_connection_get_master (setting));
+		g_free (priv->master);
+		priv->master = g_value_dup_string (value);
 		break;
 	case PROP_SLAVE_TYPE:
-		g_value_set_string (value, nm_setting_connection_get_slave_type (setting));
+		g_free (priv->slave_type);
+		priv->slave_type = g_value_dup_string (value);
 		break;
 	case PROP_AUTOCONNECT_SLAVES:
-		g_value_set_enum (value, nm_setting_connection_get_autoconnect_slaves (setting));
+		priv->autoconnect_slaves = g_value_get_enum (value);
 		break;
 	case PROP_SECONDARIES:
-		g_value_take_boxed (value, _nm_utils_slist_to_strv (priv->secondaries, TRUE));
+		g_slist_free_full (priv->secondaries, g_free);
+		priv->secondaries = _nm_utils_strv_to_slist (g_value_get_boxed (value), TRUE);
 		break;
 	case PROP_GATEWAY_PING_TIMEOUT:
-		g_value_set_uint (value, priv->gateway_ping_timeout);
+		priv->gateway_ping_timeout = g_value_get_uint (value);
 		break;
 	case PROP_METERED:
-		g_value_set_enum (value, priv->metered);
+		priv->metered = g_value_get_enum (value);
 		break;
 	case PROP_LLDP:
-		g_value_set_int (value, priv->lldp);
+		priv->lldp = g_value_get_int (value);
 		break;
 	case PROP_AUTH_RETRIES:
-		g_value_set_int (value, priv->auth_retries);
+		priv->auth_retries = g_value_get_int (value);
 		break;
 	case PROP_MDNS:
-		g_value_set_int (value, priv->mdns);
+		priv->mdns = g_value_get_int (value);
 		break;
 	case PROP_LLMNR:
-		g_value_set_int (value, priv->llmnr);
+		priv->llmnr = g_value_get_int (value);
 		break;
 	default:
 		G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
@@ -1537,6 +1501,48 @@ get_property (GObject *object, guint prop_id,
 	}
 }
 
+/*****************************************************************************/
+
+static void
+nm_setting_connection_init (NMSettingConnection *setting)
+{
+	NMSettingConnectionPrivate *priv = NM_SETTING_CONNECTION_GET_PRIVATE (setting);
+
+	priv->mdns = NM_SETTING_CONNECTION_MDNS_DEFAULT;
+	priv->llmnr = NM_SETTING_CONNECTION_LLMNR_DEFAULT;
+}
+
+/**
+ * nm_setting_connection_new:
+ *
+ * Creates a new #NMSettingConnection object with default values.
+ *
+ * Returns: the new empty #NMSettingConnection object
+ **/
+NMSetting *nm_setting_connection_new (void)
+{
+	return (NMSetting *) g_object_new (NM_TYPE_SETTING_CONNECTION, NULL);
+}
+
+static void
+finalize (GObject *object)
+{
+	NMSettingConnectionPrivate *priv = NM_SETTING_CONNECTION_GET_PRIVATE (object);
+
+	g_free (priv->id);
+	g_free (priv->uuid);
+	g_free (priv->stable_id);
+	g_free (priv->interface_name);
+	g_free (priv->type);
+	g_free (priv->zone);
+	g_free (priv->master);
+	g_free (priv->slave_type);
+	g_slist_free_full (priv->permissions, (GDestroyNotify) permission_free);
+	g_slist_free_full (priv->secondaries, g_free);
+
+	G_OBJECT_CLASS (nm_setting_connection_parent_class)->finalize (object);
+}
+
 static void
 nm_setting_connection_class_init (NMSettingConnectionClass *klass)
 {
@@ -1546,8 +1552,8 @@ nm_setting_connection_class_init (NMSettingConnectionClass *klass)
 
 	g_type_class_add_private (klass, sizeof (NMSettingConnectionPrivate));
 
-	object_class->set_property = set_property;
 	object_class->get_property = get_property;
+	object_class->set_property = set_property;
 	object_class->finalize     = finalize;
 
 	setting_class->verify           = verify;
@@ -1565,13 +1571,12 @@ nm_setting_connection_class_init (NMSettingConnectionClass *klass)
 	 * description: User friendly name for the connection profile.
 	 * ---end---
 	 */
-	g_object_class_install_property
-		(object_class, PROP_ID,
-		 g_param_spec_string (NM_SETTING_CONNECTION_ID, "", "",
-		                      NULL,
-		                      G_PARAM_READWRITE |
-		                      NM_SETTING_PARAM_FUZZY_IGNORE |
-		                      G_PARAM_STATIC_STRINGS));
+	obj_properties[PROP_ID] =
+	    g_param_spec_string (NM_SETTING_CONNECTION_ID, "", "",
+	                         NULL,
+	                         G_PARAM_READWRITE |
+	                         NM_SETTING_PARAM_FUZZY_IGNORE |
+	                         G_PARAM_STATIC_STRINGS);
 
 	/**
 	 * NMSettingConnection:uuid:
@@ -1596,13 +1601,12 @@ nm_setting_connection_class_init (NMSettingConnectionClass *klass)
 	 *   creates the UUID itself (by hashing the filename).
 	 * ---end---
 	 */
-	g_object_class_install_property
-		(object_class, PROP_UUID,
-		 g_param_spec_string (NM_SETTING_CONNECTION_UUID, "", "",
-		                      NULL,
-		                      G_PARAM_READWRITE |
-		                      NM_SETTING_PARAM_FUZZY_IGNORE |
-		                      G_PARAM_STATIC_STRINGS));
+	obj_properties[PROP_UUID] =
+	    g_param_spec_string (NM_SETTING_CONNECTION_UUID, "", "",
+	                         NULL,
+	                         G_PARAM_READWRITE |
+	                         NM_SETTING_PARAM_FUZZY_IGNORE |
+	                         G_PARAM_STATIC_STRINGS);
 
 	/**
 	 * NMSettingConnection:stable-id:
@@ -1626,11 +1630,11 @@ nm_setting_connection_class_init (NMSettingConnectionClass *klass)
 	 * name is included, so that different interfaces yield different addresses.
 	 *
 	 * The '$' character is treated special to perform dynamic substitutions
-	 * at runtime. Currently supported are "${CONNECTION}", "${DEVICE}",
+	 * at runtime. Currently supported are "${CONNECTION}", "${DEVICE}", "${MAC}",
 	 * "${BOOT}", "${RANDOM}".
 	 * These effectively create unique IDs per-connection, per-device, per-boot,
 	 * or every time. Note that "${DEVICE}" corresponds the the interface name of the
-	 * device.
+	 * device and "${MAC}" is the permanent MAC address of the device.
 	 * Any unrecognized patterns following '$' are treated verbatim, however
 	 * are reserved for future use. You are thus advised to avoid '$' or
 	 * escape it as "$$".
@@ -1650,13 +1654,12 @@ nm_setting_connection_class_init (NMSettingConnectionClass *klass)
 	 * description: Token to generate stable IDs.
 	 * ---end---
 	 */
-	g_object_class_install_property
-		(object_class, PROP_STABLE_ID,
-		 g_param_spec_string (NM_SETTING_CONNECTION_STABLE_ID, "", "",
-		                      NULL,
-		                      G_PARAM_READWRITE |
-		                      NM_SETTING_PARAM_FUZZY_IGNORE |
-		                      G_PARAM_STATIC_STRINGS));
+	obj_properties[PROP_STABLE_ID] =
+	    g_param_spec_string (NM_SETTING_CONNECTION_STABLE_ID, "", "",
+	                         NULL,
+	                         G_PARAM_READWRITE |
+	                         NM_SETTING_PARAM_FUZZY_IGNORE |
+	                         G_PARAM_STATIC_STRINGS);
 
 	/**
 	 * NMSettingConnection:interface-name:
@@ -1681,17 +1684,15 @@ nm_setting_connection_class_init (NMSettingConnectionClass *klass)
 	 *   can be required for some connection types.
 	 * ---end---
 	 */
-	g_object_class_install_property
-		(object_class, PROP_INTERFACE_NAME,
-		 g_param_spec_string (NM_SETTING_CONNECTION_INTERFACE_NAME, "", "",
-		                      NULL,
-		                      G_PARAM_READWRITE |
-		                      NM_SETTING_PARAM_INFERRABLE |
-		                      G_PARAM_STATIC_STRINGS));
+	obj_properties[PROP_INTERFACE_NAME] =
+	    g_param_spec_string (NM_SETTING_CONNECTION_INTERFACE_NAME, "", "",
+	                         NULL,
+	                         G_PARAM_READWRITE |
+	                         NM_SETTING_PARAM_INFERRABLE |
+	                         G_PARAM_STATIC_STRINGS);
 
 	_properties_override_add_override (properties_override,
-	                                   g_object_class_find_property (G_OBJECT_CLASS (setting_class),
-	                                                                 NM_SETTING_CONNECTION_INTERFACE_NAME),
+	                                   obj_properties[PROP_INTERFACE_NAME],
 	                                   G_VARIANT_TYPE_STRING,
 	                                   NULL,
 	                                   nm_setting_connection_set_interface_name,
@@ -1715,13 +1716,12 @@ nm_setting_connection_class_init (NMSettingConnectionClass *klass)
 	 * example: TYPE=Ethernet; TYPE=Bond; TYPE=Bridge; DEVICETYPE=TeamPort
 	 * ---end---
 	 */
-	g_object_class_install_property
-		(object_class, PROP_TYPE,
-		 g_param_spec_string (NM_SETTING_CONNECTION_TYPE, "", "",
-		                      NULL,
-		                      G_PARAM_READWRITE |
-		                      NM_SETTING_PARAM_INFERRABLE |
-		                      G_PARAM_STATIC_STRINGS));
+	obj_properties[PROP_TYPE] =
+	    g_param_spec_string (NM_SETTING_CONNECTION_TYPE, "", "",
+	                         NULL,
+	                         G_PARAM_READWRITE |
+	                         NM_SETTING_PARAM_INFERRABLE |
+	                         G_PARAM_STATIC_STRINGS);
 
 	/**
 	 * NMSettingConnection:permissions:
@@ -1748,12 +1748,11 @@ nm_setting_connection_class_init (NMSettingConnectionClass *klass)
 	 * example: USERS="joe bob"
 	 * ---end---
 	 */
-	g_object_class_install_property
-		(object_class, PROP_PERMISSIONS,
-		 g_param_spec_boxed (NM_SETTING_CONNECTION_PERMISSIONS, "", "",
-		                     G_TYPE_STRV,
-		                     G_PARAM_READWRITE |
-		                     G_PARAM_STATIC_STRINGS));
+	obj_properties[PROP_PERMISSIONS] =
+	    g_param_spec_boxed (NM_SETTING_CONNECTION_PERMISSIONS, "", "",
+	                        G_TYPE_STRV,
+	                        G_PARAM_READWRITE |
+	                        G_PARAM_STATIC_STRINGS);
 
 	/**
 	 * NMSettingConnection:autoconnect:
@@ -1774,14 +1773,13 @@ nm_setting_connection_class_init (NMSettingConnectionClass *klass)
 	 * description: Whether the connection should be autoconnected (not only while booting).
 	 * ---end---
 	 */
-	g_object_class_install_property
-		(object_class, PROP_AUTOCONNECT,
-		 g_param_spec_boolean (NM_SETTING_CONNECTION_AUTOCONNECT, "", "",
-		                       TRUE,
-		                       G_PARAM_READWRITE |
-		                       G_PARAM_CONSTRUCT |
-		                       NM_SETTING_PARAM_FUZZY_IGNORE |
-		                       G_PARAM_STATIC_STRINGS));
+	obj_properties[PROP_AUTOCONNECT] =
+	    g_param_spec_boolean (NM_SETTING_CONNECTION_AUTOCONNECT, "", "",
+	                          TRUE,
+	                          G_PARAM_READWRITE |
+	                          G_PARAM_CONSTRUCT |
+	                          NM_SETTING_PARAM_FUZZY_IGNORE |
+	                          G_PARAM_STATIC_STRINGS);
 
 	/**
 	 * NMSettingConnection:autoconnect-priority:
@@ -1800,8 +1798,7 @@ nm_setting_connection_class_init (NMSettingConnectionClass *klass)
 	 * example: AUTOCONNECT_PRIORITY=20
 	 * ---end---
 	 */
-	g_object_class_install_property
-	    (object_class, PROP_AUTOCONNECT_PRIORITY,
+	obj_properties[PROP_AUTOCONNECT_PRIORITY] =
 	     g_param_spec_int (NM_SETTING_CONNECTION_AUTOCONNECT_PRIORITY, "", "",
 	                       NM_SETTING_CONNECTION_AUTOCONNECT_PRIORITY_MIN,
 	                       NM_SETTING_CONNECTION_AUTOCONNECT_PRIORITY_MAX,
@@ -1809,7 +1806,7 @@ nm_setting_connection_class_init (NMSettingConnectionClass *klass)
 	                       G_PARAM_READWRITE |
 	                       G_PARAM_CONSTRUCT |
 	                       NM_SETTING_PARAM_FUZZY_IGNORE |
-	                       G_PARAM_STATIC_STRINGS));
+	                       G_PARAM_STATIC_STRINGS);
 
 	/**
 	 * NMSettingConnection:autoconnect-retries:
@@ -1829,14 +1826,13 @@ nm_setting_connection_class_init (NMSettingConnectionClass *klass)
 	 * example: AUTOCONNECT_RETRIES=1
 	 * ---end---
 	 */
-	g_object_class_install_property
-	    (object_class, PROP_AUTOCONNECT_RETRIES,
+	obj_properties[PROP_AUTOCONNECT_RETRIES] =
 	     g_param_spec_int (NM_SETTING_CONNECTION_AUTOCONNECT_RETRIES, "", "",
 	                       -1, G_MAXINT32, -1,
 	                       G_PARAM_READWRITE |
 	                       G_PARAM_CONSTRUCT |
 	                       NM_SETTING_PARAM_FUZZY_IGNORE |
-	                       G_PARAM_STATIC_STRINGS));
+	                       G_PARAM_STATIC_STRINGS);
 
 	/**
 	 * NMSettingConnection:multi-connect:
@@ -1854,13 +1850,12 @@ nm_setting_connection_class_init (NMSettingConnectionClass *klass)
 	 * example: ZONE=3
 	 * ---end---
 	 */
-	g_object_class_install_property
-	    (object_class, PROP_MULTI_CONNECT,
+	obj_properties[PROP_MULTI_CONNECT] =
 	     g_param_spec_int (NM_SETTING_CONNECTION_MULTI_CONNECT, "", "",
 	                       G_MININT32, G_MAXINT32, NM_CONNECTION_MULTI_CONNECT_DEFAULT,
 	                       G_PARAM_READWRITE |
 	                       NM_SETTING_PARAM_FUZZY_IGNORE |
-	                       G_PARAM_STATIC_STRINGS));
+	                       G_PARAM_STATIC_STRINGS);
 
 	/**
 	 * NMSettingConnection:timestamp:
@@ -1873,14 +1868,13 @@ nm_setting_connection_class_init (NMSettingConnectionClass *klass)
 	 * timestamp. The property is only meant for reading (changes to this
 	 * property will not be preserved).
 	 **/
-	g_object_class_install_property
-		(object_class, PROP_TIMESTAMP,
-		 g_param_spec_uint64 (NM_SETTING_CONNECTION_TIMESTAMP, "", "",
-		                      0, G_MAXUINT64, 0,
-		                      G_PARAM_READWRITE |
-		                      G_PARAM_CONSTRUCT |
-		                      NM_SETTING_PARAM_FUZZY_IGNORE |
-		                      G_PARAM_STATIC_STRINGS));
+	obj_properties[PROP_TIMESTAMP] =
+	    g_param_spec_uint64 (NM_SETTING_CONNECTION_TIMESTAMP, "", "",
+	                         0, G_MAXUINT64, 0,
+	                         G_PARAM_READWRITE |
+	                         G_PARAM_CONSTRUCT |
+	                         NM_SETTING_PARAM_FUZZY_IGNORE |
+	                         G_PARAM_STATIC_STRINGS);
 
 	/**
 	 * NMSettingConnection:read-only:
@@ -1889,14 +1883,13 @@ nm_setting_connection_class_init (NMSettingConnectionClass *klass)
 	 * service's D-Bus interface with the right privileges, or %TRUE if the
 	 * connection is read-only and cannot be modified.
 	 **/
-	g_object_class_install_property
-		(object_class, PROP_READ_ONLY,
-		 g_param_spec_boolean (NM_SETTING_CONNECTION_READ_ONLY, "", "",
-		                       FALSE,
-		                       G_PARAM_READWRITE |
-		                       G_PARAM_CONSTRUCT |
-		                       NM_SETTING_PARAM_FUZZY_IGNORE |
-		                       G_PARAM_STATIC_STRINGS));
+	obj_properties[PROP_READ_ONLY] =
+	    g_param_spec_boolean (NM_SETTING_CONNECTION_READ_ONLY, "", "",
+	                          FALSE,
+	                          G_PARAM_READWRITE |
+	                          G_PARAM_CONSTRUCT |
+	                          NM_SETTING_PARAM_FUZZY_IGNORE |
+	                          G_PARAM_STATIC_STRINGS);
 
 	/**
 	 * NMSettingConnection:zone:
@@ -1917,15 +1910,14 @@ nm_setting_connection_class_init (NMSettingConnectionClass *klass)
 	 * example: ZONE=Work
 	 * ---end---
 	 */
-	g_object_class_install_property
-		(object_class, PROP_ZONE,
-		 g_param_spec_string (NM_SETTING_CONNECTION_ZONE, "", "",
-		                      NULL,
-		                      G_PARAM_READWRITE |
-		                      G_PARAM_CONSTRUCT |
-		                      NM_SETTING_PARAM_FUZZY_IGNORE |
-		                      NM_SETTING_PARAM_REAPPLY_IMMEDIATELY |
-		                      G_PARAM_STATIC_STRINGS));
+	obj_properties[PROP_ZONE] =
+	    g_param_spec_string (NM_SETTING_CONNECTION_ZONE, "", "",
+	                         NULL,
+	                         G_PARAM_READWRITE |
+	                         G_PARAM_CONSTRUCT |
+	                         NM_SETTING_PARAM_FUZZY_IGNORE |
+	                         NM_SETTING_PARAM_REAPPLY_IMMEDIATELY |
+	                         G_PARAM_STATIC_STRINGS);
 
 	/**
 	 * NMSettingConnection:master:
@@ -1941,14 +1933,13 @@ nm_setting_connection_class_init (NMSettingConnectionClass *klass)
 	 *   for compatibility with legacy tooling.
 	 * ---end---
 	 */
-	g_object_class_install_property
-		(object_class, PROP_MASTER,
-		 g_param_spec_string (NM_SETTING_CONNECTION_MASTER, "", "",
-		                      NULL,
-		                      G_PARAM_READWRITE |
-		                      NM_SETTING_PARAM_FUZZY_IGNORE |
-		                      NM_SETTING_PARAM_INFERRABLE |
-		                      G_PARAM_STATIC_STRINGS));
+	obj_properties[PROP_MASTER] =
+	    g_param_spec_string (NM_SETTING_CONNECTION_MASTER, "", "",
+	                         NULL,
+	                         G_PARAM_READWRITE |
+	                         NM_SETTING_PARAM_FUZZY_IGNORE |
+	                         NM_SETTING_PARAM_INFERRABLE |
+	                         G_PARAM_STATIC_STRINGS);
 
 	/**
 	 * NMSettingConnection:slave-type:
@@ -1967,14 +1958,13 @@ nm_setting_connection_class_init (NMSettingConnectionClass *klass)
 	 *   and BRIDGE_UUID for bridging.
 	 * ---end---
 	 */
-	g_object_class_install_property
-		(object_class, PROP_SLAVE_TYPE,
-		 g_param_spec_string (NM_SETTING_CONNECTION_SLAVE_TYPE, "", "",
-		                      NULL,
-		                      G_PARAM_READWRITE |
-		                      NM_SETTING_PARAM_FUZZY_IGNORE |
-		                      NM_SETTING_PARAM_INFERRABLE |
-		                      G_PARAM_STATIC_STRINGS));
+	obj_properties[PROP_SLAVE_TYPE] =
+	    g_param_spec_string (NM_SETTING_CONNECTION_SLAVE_TYPE, "", "",
+	                         NULL,
+	                         G_PARAM_READWRITE |
+	                         NM_SETTING_PARAM_FUZZY_IGNORE |
+	                         NM_SETTING_PARAM_INFERRABLE |
+	                         G_PARAM_STATIC_STRINGS);
 
 	/**
 	 * NMSettingConnection:autoconnect-slaves:
@@ -1999,15 +1989,14 @@ nm_setting_connection_class_init (NMSettingConnectionClass *klass)
 	 *   when this connection is activated.
 	 * ---end---
 	 */
-	g_object_class_install_property
-		(object_class, PROP_AUTOCONNECT_SLAVES,
-		 g_param_spec_enum (NM_SETTING_CONNECTION_AUTOCONNECT_SLAVES, "", "",
-		                    NM_TYPE_SETTING_CONNECTION_AUTOCONNECT_SLAVES,
-		                    NM_SETTING_CONNECTION_AUTOCONNECT_SLAVES_DEFAULT,
-		                    G_PARAM_READWRITE |
-		                    G_PARAM_CONSTRUCT |
-		                    NM_SETTING_PARAM_FUZZY_IGNORE |
-		                    G_PARAM_STATIC_STRINGS));
+	obj_properties[PROP_AUTOCONNECT_SLAVES] =
+	    g_param_spec_enum (NM_SETTING_CONNECTION_AUTOCONNECT_SLAVES, "", "",
+	                       NM_TYPE_SETTING_CONNECTION_AUTOCONNECT_SLAVES,
+	                       NM_SETTING_CONNECTION_AUTOCONNECT_SLAVES_DEFAULT,
+	                       G_PARAM_READWRITE |
+	                       G_PARAM_CONSTRUCT |
+	                       NM_SETTING_PARAM_FUZZY_IGNORE |
+	                       G_PARAM_STATIC_STRINGS);
 
 	/**
 	 * NMSettingConnection:secondaries:
@@ -2023,13 +2012,12 @@ nm_setting_connection_class_init (NMSettingConnectionClass *klass)
 	 *   together with this connection.
 	 * ---end---
 	 */
-	g_object_class_install_property
-		(object_class, PROP_SECONDARIES,
-		 g_param_spec_boxed (NM_SETTING_CONNECTION_SECONDARIES, "", "",
-		                     G_TYPE_STRV,
-		                     G_PARAM_READWRITE |
-		                     NM_SETTING_PARAM_FUZZY_IGNORE |
-		                     G_PARAM_STATIC_STRINGS));
+	obj_properties[PROP_SECONDARIES] =
+	    g_param_spec_boxed (NM_SETTING_CONNECTION_SECONDARIES, "", "",
+	                        G_TYPE_STRV,
+	                        G_PARAM_READWRITE |
+	                        NM_SETTING_PARAM_FUZZY_IGNORE |
+	                        G_PARAM_STATIC_STRINGS);
 
 	/**
 	 * NMSettingConnection:gateway-ping-timeout:
@@ -2046,13 +2034,12 @@ nm_setting_connection_class_init (NMSettingConnectionClass *klass)
 	 * example: GATEWAY_PING_TIMEOUT=5
 	 * ---end---
 	 */
-	g_object_class_install_property
-		(object_class, PROP_GATEWAY_PING_TIMEOUT,
-		 g_param_spec_uint (NM_SETTING_CONNECTION_GATEWAY_PING_TIMEOUT, "", "",
-		                    0, 600, 0,
-		                    G_PARAM_READWRITE |
-		                    G_PARAM_CONSTRUCT |
-		                    G_PARAM_STATIC_STRINGS));
+	obj_properties[PROP_GATEWAY_PING_TIMEOUT] =
+	    g_param_spec_uint (NM_SETTING_CONNECTION_GATEWAY_PING_TIMEOUT, "", "",
+	                       0, 600, 0,
+	                       G_PARAM_READWRITE |
+	                       G_PARAM_CONSTRUCT |
+	                       G_PARAM_STATIC_STRINGS);
 
 	/**
 	 * NMSettingConnection:metered:
@@ -2072,14 +2059,13 @@ nm_setting_connection_class_init (NMSettingConnectionClass *klass)
 	 * example: CONNECTION_METERED=yes
 	 * ---end---
 	 */
-	g_object_class_install_property
-		(object_class, PROP_METERED,
-		 g_param_spec_enum (NM_SETTING_CONNECTION_METERED, "", "",
-		                    NM_TYPE_METERED,
-		                    NM_METERED_UNKNOWN,
-		                    G_PARAM_READWRITE |
-		                    NM_SETTING_PARAM_REAPPLY_IMMEDIATELY |
-		                    G_PARAM_STATIC_STRINGS));
+	obj_properties[PROP_METERED] =
+	    g_param_spec_enum (NM_SETTING_CONNECTION_METERED, "", "",
+	                       NM_TYPE_METERED,
+	                       NM_METERED_UNKNOWN,
+	                       G_PARAM_READWRITE |
+	                       NM_SETTING_PARAM_REAPPLY_IMMEDIATELY |
+	                       G_PARAM_STATIC_STRINGS);
 
 	/**
 	 * NMSettingConnection:lldp:
@@ -2097,14 +2083,13 @@ nm_setting_connection_class_init (NMSettingConnectionClass *klass)
 	 * example: LLDP=no
 	 * ---end---
 	 */
-	g_object_class_install_property
-		(object_class, PROP_LLDP,
-		 g_param_spec_int (NM_SETTING_CONNECTION_LLDP, "", "",
-		                   G_MININT32, G_MAXINT32, NM_SETTING_CONNECTION_LLDP_DEFAULT,
-		                   NM_SETTING_PARAM_FUZZY_IGNORE |
-		                   G_PARAM_READWRITE |
-		                   G_PARAM_CONSTRUCT |
-		                   G_PARAM_STATIC_STRINGS));
+	obj_properties[PROP_LLDP] =
+	    g_param_spec_int (NM_SETTING_CONNECTION_LLDP, "", "",
+	                      G_MININT32, G_MAXINT32, NM_SETTING_CONNECTION_LLDP_DEFAULT,
+	                      NM_SETTING_PARAM_FUZZY_IGNORE |
+	                      G_PARAM_READWRITE |
+	                      G_PARAM_CONSTRUCT |
+	                      G_PARAM_STATIC_STRINGS);
 
 	/**
 	 * NMSettingConnection:auth-retries:
@@ -2124,14 +2109,13 @@ nm_setting_connection_class_init (NMSettingConnectionClass *klass)
 	 * description: Number of retries for authentication.
 	 * ---end---
 	 */
-	g_object_class_install_property
-		(object_class, PROP_AUTH_RETRIES,
-		 g_param_spec_int (NM_SETTING_CONNECTION_AUTH_RETRIES, "", "",
-		                   -1, G_MAXINT32, -1,
-		                   G_PARAM_READWRITE |
-		                   G_PARAM_CONSTRUCT |
-		                   NM_SETTING_PARAM_FUZZY_IGNORE |
-		                   G_PARAM_STATIC_STRINGS));
+	obj_properties[PROP_AUTH_RETRIES] =
+	    g_param_spec_int (NM_SETTING_CONNECTION_AUTH_RETRIES, "", "",
+	                      -1, G_MAXINT32, -1,
+	                      G_PARAM_READWRITE |
+	                      G_PARAM_CONSTRUCT |
+	                      NM_SETTING_PARAM_FUZZY_IGNORE |
+	                      G_PARAM_STATIC_STRINGS);
 
 	/**
 	 * NMSettingConnection:mdns:
@@ -2156,13 +2140,12 @@ nm_setting_connection_class_init (NMSettingConnectionClass *klass)
 	 * example: MDNS=yes
 	 * ---end---
 	 */
-	g_object_class_install_property
-		(object_class, PROP_MDNS,
-		 g_param_spec_int (NM_SETTING_CONNECTION_MDNS, "", "",
-		                   G_MININT32, G_MAXINT32,
-		                   NM_SETTING_CONNECTION_MDNS_DEFAULT,
-		                   G_PARAM_READWRITE |
-		                   G_PARAM_STATIC_STRINGS));
+	obj_properties[PROP_MDNS] =
+	    g_param_spec_int (NM_SETTING_CONNECTION_MDNS, "", "",
+	                      G_MININT32, G_MAXINT32,
+	                      NM_SETTING_CONNECTION_MDNS_DEFAULT,
+	                      G_PARAM_READWRITE |
+	                      G_PARAM_STATIC_STRINGS);
 
 	/**
 	 * NMSettingConnection:llmnr:
@@ -2190,13 +2173,14 @@ nm_setting_connection_class_init (NMSettingConnectionClass *klass)
 	 * example: LLMNR=yes
 	 * ---end---
 	 */
-	g_object_class_install_property
-		(object_class, PROP_LLMNR,
-		 g_param_spec_int (NM_SETTING_CONNECTION_LLMNR, "", "",
-		                   G_MININT32, G_MAXINT32,
-		                   NM_SETTING_CONNECTION_LLMNR_DEFAULT,
-		                   G_PARAM_READWRITE |
-		                   G_PARAM_STATIC_STRINGS));
+	obj_properties[PROP_LLMNR] =
+	    g_param_spec_int (NM_SETTING_CONNECTION_LLMNR, "", "",
+	                      G_MININT32, G_MAXINT32,
+	                      NM_SETTING_CONNECTION_LLMNR_DEFAULT,
+	                      G_PARAM_READWRITE |
+	                      G_PARAM_STATIC_STRINGS);
+
+	g_object_class_install_properties (object_class, _PROPERTY_ENUMS_LAST, obj_properties);
 
 	_nm_setting_class_commit_full (setting_class, NM_META_SETTING_TYPE_CONNECTION,
 	                               NULL, properties_override);
diff --git a/libnm-core/nm-setting-dcb.c b/libnm-core/nm-setting-dcb.c
index dabcbbaf..42c7d247 100644
--- a/libnm-core/nm-setting-dcb.c
+++ b/libnm-core/nm-setting-dcb.c
@@ -21,9 +21,10 @@
 
 #include "nm-default.h"
 
+#include "nm-setting-dcb.h"
+
 #include <string.h>
 
-#include "nm-setting-dcb.h"
 #include "nm-utils.h"
 #include "nm-utils-private.h"
 #include "nm-setting-private.h"
@@ -40,9 +41,30 @@
  * of storage technologies like Fibre Channel over Ethernet (FCoE) and iSCSI.
  **/
 
-G_DEFINE_TYPE (NMSettingDcb, nm_setting_dcb, NM_TYPE_SETTING)
+/*****************************************************************************/
 
-#define NM_SETTING_DCB_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), NM_TYPE_SETTING_DCB, NMSettingDcbPrivate))
+NM_GOBJECT_PROPERTIES_DEFINE (NMSettingDcb,
+
+	PROP_APP_FCOE_FLAGS,
+	PROP_APP_FCOE_PRIORITY,
+	PROP_APP_FCOE_MODE,
+
+	PROP_APP_ISCSI_FLAGS,
+	PROP_APP_ISCSI_PRIORITY,
+
+	PROP_APP_FIP_FLAGS,
+	PROP_APP_FIP_PRIORITY,
+
+	PROP_PFC_FLAGS,
+	PROP_PRIORITY_FLOW_CONTROL,
+
+	PROP_PRIORITY_GROUP_FLAGS,
+	PROP_PRIORITY_GROUP_ID,
+	PROP_PRIORITY_GROUP_BANDWIDTH,
+	PROP_PRIORITY_BANDWIDTH,
+	PROP_PRIORITY_STRICT_BANDWIDTH,
+	PROP_PRIORITY_TRAFFIC_CLASS,
+);
 
 typedef struct {
 	NMSettingDcbFlags app_fcoe_flags;
@@ -68,43 +90,11 @@ typedef struct {
 	guint             priority_traffic_class[8];
 } NMSettingDcbPrivate;
 
-enum {
-	PROP_0,
-	PROP_APP_FCOE_FLAGS,
-	PROP_APP_FCOE_PRIORITY,
-	PROP_APP_FCOE_MODE,
-
-	PROP_APP_ISCSI_FLAGS,
-	PROP_APP_ISCSI_PRIORITY,
-
-	PROP_APP_FIP_FLAGS,
-	PROP_APP_FIP_PRIORITY,
-
-	PROP_PFC_FLAGS,
-	PROP_PFC,
-
-	PROP_PRIORITY_GROUP_FLAGS,
-	PROP_PRIORITY_GROUP_ID,
-	PROP_PRIORITY_GROUP_BANDWIDTH,
-	PROP_PRIORITY_BANDWIDTH,
-	PROP_PRIORITY_STRICT,
-	PROP_PRIORITY_TRAFFIC_CLASS,
+G_DEFINE_TYPE (NMSettingDcb, nm_setting_dcb, NM_TYPE_SETTING)
 
-	LAST_PROP
-};
+#define NM_SETTING_DCB_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), NM_TYPE_SETTING_DCB, NMSettingDcbPrivate))
 
-/**
- * nm_setting_dcb_new:
- *
- * Creates a new #NMSettingDcb object with default values.
- *
- * Returns: (transfer full): the new empty #NMSettingDcb object
- **/
-NMSetting *
-nm_setting_dcb_new (void)
-{
-	return (NMSetting *) g_object_new (NM_TYPE_SETTING_DCB, NULL);
-}
+/*****************************************************************************/
 
 /**
  * nm_setting_dcb_get_app_fcoe_flags:
@@ -258,7 +248,7 @@ nm_setting_dcb_set_priority_flow_control (NMSettingDcb *setting,
 	priv = NM_SETTING_DCB_GET_PRIVATE (setting);
 	if (priv->pfc[user_priority] != uint_enabled) {
 		priv->pfc[user_priority] = uint_enabled;
-		g_object_notify (G_OBJECT (setting), NM_SETTING_DCB_PRIORITY_FLOW_CONTROL);
+		_notify (setting, PROP_PRIORITY_FLOW_CONTROL);
 	}
 }
 
@@ -318,7 +308,7 @@ nm_setting_dcb_set_priority_group_id (NMSettingDcb *setting,
 	priv = NM_SETTING_DCB_GET_PRIVATE (setting);
 	if (priv->priority_group_id[user_priority] != group_id) {
 		priv->priority_group_id[user_priority] = group_id;
-		g_object_notify (G_OBJECT (setting), NM_SETTING_DCB_PRIORITY_GROUP_ID);
+		_notify (setting, PROP_PRIORITY_GROUP_ID);
 	}
 }
 
@@ -363,7 +353,7 @@ nm_setting_dcb_set_priority_group_bandwidth (NMSettingDcb *setting,
 	priv = NM_SETTING_DCB_GET_PRIVATE (setting);
 	if (priv->priority_group_bandwidth[group_id] != bandwidth_percent) {
 		priv->priority_group_bandwidth[group_id] = bandwidth_percent;
-		g_object_notify (G_OBJECT (setting), NM_SETTING_DCB_PRIORITY_GROUP_BANDWIDTH);
+		_notify (setting, PROP_PRIORITY_GROUP_BANDWIDTH);
 	}
 }
 
@@ -409,7 +399,7 @@ nm_setting_dcb_set_priority_bandwidth (NMSettingDcb *setting,
 	priv = NM_SETTING_DCB_GET_PRIVATE (setting);
 	if (priv->priority_bandwidth[user_priority] != bandwidth_percent) {
 		priv->priority_bandwidth[user_priority] = bandwidth_percent;
-		g_object_notify (G_OBJECT (setting), NM_SETTING_DCB_PRIORITY_BANDWIDTH);
+		_notify (setting, PROP_PRIORITY_BANDWIDTH);
 	}
 }
 
@@ -455,7 +445,7 @@ nm_setting_dcb_set_priority_strict_bandwidth (NMSettingDcb *setting,
 	priv = NM_SETTING_DCB_GET_PRIVATE (setting);
 	if (priv->priority_strict[user_priority] != uint_strict) {
 		priv->priority_strict[user_priority] = uint_strict;
-		g_object_notify (G_OBJECT (setting), NM_SETTING_DCB_PRIORITY_STRICT_BANDWIDTH);
+		_notify (setting, PROP_PRIORITY_STRICT_BANDWIDTH);
 	}
 }
 
@@ -500,7 +490,7 @@ nm_setting_dcb_set_priority_traffic_class (NMSettingDcb *setting,
 	priv = NM_SETTING_DCB_GET_PRIVATE (setting);
 	if (priv->priority_traffic_class[user_priority] != traffic_class) {
 		priv->priority_traffic_class[user_priority] = traffic_class;
-		g_object_notify (G_OBJECT (setting), NM_SETTING_DCB_PRIORITY_TRAFFIC_CLASS);
+		_notify (setting, PROP_PRIORITY_TRAFFIC_CLASS);
 	}
 }
 
@@ -724,11 +714,6 @@ verify (NMSetting *setting, NMConnection *connection, GError **error)
 
 /*****************************************************************************/
 
-static void
-nm_setting_dcb_init (NMSettingDcb *setting)
-{
-}
-
 G_STATIC_ASSERT (sizeof (guint) == sizeof (gboolean));
 
 static inline void
@@ -776,58 +761,60 @@ _nm_setting_dcb_uint_array_from_dbus (GVariant *dbus_value,
 	set_gvalue_from_array (prop_value, (guint *) array, length);
 }
 
+/*****************************************************************************/
+
 static void
-set_property (GObject *object, guint prop_id,
-              const GValue *value, GParamSpec *pspec)
+get_property (GObject *object, guint prop_id,
+              GValue *value, GParamSpec *pspec)
 {
-	NMSettingDcbPrivate *priv = NM_SETTING_DCB_GET_PRIVATE (object);
+	NMSettingDcb *setting = NM_SETTING_DCB (object);
+	NMSettingDcbPrivate *priv = NM_SETTING_DCB_GET_PRIVATE (setting);
 
 	switch (prop_id) {
 	case PROP_APP_FCOE_FLAGS:
-		priv->app_fcoe_flags = g_value_get_flags (value);
+		g_value_set_flags (value, priv->app_fcoe_flags);
 		break;
 	case PROP_APP_FCOE_PRIORITY:
-		priv->app_fcoe_priority = g_value_get_int (value);
+		g_value_set_int (value, priv->app_fcoe_priority);
 		break;
 	case PROP_APP_FCOE_MODE:
-		g_free (priv->app_fcoe_mode);
-		priv->app_fcoe_mode = g_value_dup_string (value);
+		g_value_set_string (value, priv->app_fcoe_mode);
 		break;
 	case PROP_APP_ISCSI_FLAGS:
-		priv->app_iscsi_flags = g_value_get_flags (value);
+		g_value_set_flags (value, priv->app_iscsi_flags);
 		break;
 	case PROP_APP_ISCSI_PRIORITY:
-		priv->app_iscsi_priority = g_value_get_int (value);
+		g_value_set_int (value, priv->app_iscsi_priority);
 		break;
 	case PROP_APP_FIP_FLAGS:
-		priv->app_fip_flags = g_value_get_flags (value);
+		g_value_set_flags (value, priv->app_fip_flags);
 		break;
 	case PROP_APP_FIP_PRIORITY:
-		priv->app_fip_priority = g_value_get_int (value);
+		g_value_set_int (value, priv->app_fip_priority);
 		break;
 	case PROP_PFC_FLAGS:
-		priv->pfc_flags = g_value_get_flags (value);
+		g_value_set_flags (value, priv->pfc_flags);
 		break;
-	case PROP_PFC:
-		SET_ARRAY_FROM_GVALUE (value, priv->pfc);
+	case PROP_PRIORITY_FLOW_CONTROL:
+		SET_GVALUE_FROM_ARRAY (value, priv->pfc);
 		break;
 	case PROP_PRIORITY_GROUP_FLAGS:
-		priv->priority_group_flags = g_value_get_flags (value);
+		g_value_set_flags (value, priv->priority_group_flags);
 		break;
 	case PROP_PRIORITY_GROUP_ID:
-		SET_ARRAY_FROM_GVALUE (value, priv->priority_group_id);
+		SET_GVALUE_FROM_ARRAY (value, priv->priority_group_id);
 		break;
 	case PROP_PRIORITY_GROUP_BANDWIDTH:
-		SET_ARRAY_FROM_GVALUE (value, priv->priority_group_bandwidth);
+		SET_GVALUE_FROM_ARRAY (value, priv->priority_group_bandwidth);
 		break;
 	case PROP_PRIORITY_BANDWIDTH:
-		SET_ARRAY_FROM_GVALUE (value, priv->priority_bandwidth);
+		SET_GVALUE_FROM_ARRAY (value, priv->priority_bandwidth);
 		break;
-	case PROP_PRIORITY_STRICT:
-		SET_ARRAY_FROM_GVALUE (value, priv->priority_strict);
+	case PROP_PRIORITY_STRICT_BANDWIDTH:
+		SET_GVALUE_FROM_ARRAY (value, priv->priority_strict);
 		break;
 	case PROP_PRIORITY_TRAFFIC_CLASS:
-		SET_ARRAY_FROM_GVALUE (value, priv->priority_traffic_class);
+		SET_GVALUE_FROM_ARRAY (value, priv->priority_traffic_class);
 		break;
 	default:
 		G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
@@ -836,57 +823,57 @@ set_property (GObject *object, guint prop_id,
 }
 
 static void
-get_property (GObject *object, guint prop_id,
-              GValue *value, GParamSpec *pspec)
+set_property (GObject *object, guint prop_id,
+              const GValue *value, GParamSpec *pspec)
 {
-	NMSettingDcb *setting = NM_SETTING_DCB (object);
-	NMSettingDcbPrivate *priv = NM_SETTING_DCB_GET_PRIVATE (setting);
+	NMSettingDcbPrivate *priv = NM_SETTING_DCB_GET_PRIVATE (object);
 
 	switch (prop_id) {
 	case PROP_APP_FCOE_FLAGS:
-		g_value_set_flags (value, priv->app_fcoe_flags);
+		priv->app_fcoe_flags = g_value_get_flags (value);
 		break;
 	case PROP_APP_FCOE_PRIORITY:
-		g_value_set_int (value, priv->app_fcoe_priority);
+		priv->app_fcoe_priority = g_value_get_int (value);
 		break;
 	case PROP_APP_FCOE_MODE:
-		g_value_set_string (value, priv->app_fcoe_mode);
+		g_free (priv->app_fcoe_mode);
+		priv->app_fcoe_mode = g_value_dup_string (value);
 		break;
 	case PROP_APP_ISCSI_FLAGS:
-		g_value_set_flags (value, priv->app_iscsi_flags);
+		priv->app_iscsi_flags = g_value_get_flags (value);
 		break;
 	case PROP_APP_ISCSI_PRIORITY:
-		g_value_set_int (value, priv->app_iscsi_priority);
+		priv->app_iscsi_priority = g_value_get_int (value);
 		break;
 	case PROP_APP_FIP_FLAGS:
-		g_value_set_flags (value, priv->app_fip_flags);
+		priv->app_fip_flags = g_value_get_flags (value);
 		break;
 	case PROP_APP_FIP_PRIORITY:
-		g_value_set_int (value, priv->app_fip_priority);
+		priv->app_fip_priority = g_value_get_int (value);
 		break;
 	case PROP_PFC_FLAGS:
-		g_value_set_flags (value, priv->pfc_flags);
+		priv->pfc_flags = g_value_get_flags (value);
 		break;
-	case PROP_PFC:
-		SET_GVALUE_FROM_ARRAY (value, priv->pfc);
+	case PROP_PRIORITY_FLOW_CONTROL:
+		SET_ARRAY_FROM_GVALUE (value, priv->pfc);
 		break;
 	case PROP_PRIORITY_GROUP_FLAGS:
-		g_value_set_flags (value, priv->priority_group_flags);
+		priv->priority_group_flags = g_value_get_flags (value);
 		break;
 	case PROP_PRIORITY_GROUP_ID:
-		SET_GVALUE_FROM_ARRAY (value, priv->priority_group_id);
+		SET_ARRAY_FROM_GVALUE (value, priv->priority_group_id);
 		break;
 	case PROP_PRIORITY_GROUP_BANDWIDTH:
-		SET_GVALUE_FROM_ARRAY (value, priv->priority_group_bandwidth);
+		SET_ARRAY_FROM_GVALUE (value, priv->priority_group_bandwidth);
 		break;
 	case PROP_PRIORITY_BANDWIDTH:
-		SET_GVALUE_FROM_ARRAY (value, priv->priority_bandwidth);
+		SET_ARRAY_FROM_GVALUE (value, priv->priority_bandwidth);
 		break;
-	case PROP_PRIORITY_STRICT:
-		SET_GVALUE_FROM_ARRAY (value, priv->priority_strict);
+	case PROP_PRIORITY_STRICT_BANDWIDTH:
+		SET_ARRAY_FROM_GVALUE (value, priv->priority_strict);
 		break;
 	case PROP_PRIORITY_TRAFFIC_CLASS:
-		SET_GVALUE_FROM_ARRAY (value, priv->priority_traffic_class);
+		SET_ARRAY_FROM_GVALUE (value, priv->priority_traffic_class);
 		break;
 	default:
 		G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
@@ -894,6 +881,26 @@ get_property (GObject *object, guint prop_id,
 	}
 }
 
+/*****************************************************************************/
+
+static void
+nm_setting_dcb_init (NMSettingDcb *setting)
+{
+}
+
+/**
+ * nm_setting_dcb_new:
+ *
+ * Creates a new #NMSettingDcb object with default values.
+ *
+ * Returns: (transfer full): the new empty #NMSettingDcb object
+ **/
+NMSetting *
+nm_setting_dcb_new (void)
+{
+	return (NMSetting *) g_object_new (NM_TYPE_SETTING_DCB, NULL);
+}
+
 static void
 finalize (GObject *object)
 {
@@ -913,9 +920,9 @@ nm_setting_dcb_class_init (NMSettingDcbClass *klass)
 
 	g_type_class_add_private (klass, sizeof (NMSettingDcbPrivate));
 
-	object_class->set_property = set_property;
 	object_class->get_property = get_property;
-	object_class->finalize = finalize;
+	object_class->set_property = set_property;
+	object_class->finalize     = finalize;
 
 	setting_class->verify = verify;
 
@@ -934,13 +941,12 @@ nm_setting_dcb_class_init (NMSettingDcbClass *klass)
 	 * example: DCB_APP_FCOE_ENABLE=yes DCB_APP_FCOE_ADVERTISE=yes
 	 * ---end---
 	 */
-	g_object_class_install_property
-		(object_class, PROP_APP_FCOE_FLAGS,
-		 g_param_spec_flags (NM_SETTING_DCB_APP_FCOE_FLAGS, "", "",
-		                     NM_TYPE_SETTING_DCB_FLAGS,
-		                     NM_SETTING_DCB_FLAG_NONE,
-		                     G_PARAM_READWRITE |
-		                     G_PARAM_STATIC_STRINGS));
+	obj_properties[PROP_APP_FCOE_FLAGS] =
+	    g_param_spec_flags (NM_SETTING_DCB_APP_FCOE_FLAGS, "", "",
+	                        NM_TYPE_SETTING_DCB_FLAGS,
+	                        NM_SETTING_DCB_FLAG_NONE,
+	                        G_PARAM_READWRITE |
+	                        G_PARAM_STATIC_STRINGS);
 
 	/**
 	 * NMSettingDcb:app-fcoe-priority:
@@ -956,13 +962,12 @@ nm_setting_dcb_class_init (NMSettingDcbClass *klass)
 	 * description: Priority of FCoE frames.
 	 * ---end---
 	 */
-	g_object_class_install_property
-		(object_class, PROP_APP_FCOE_PRIORITY,
-		 g_param_spec_int (NM_SETTING_DCB_APP_FCOE_PRIORITY, "", "",
-		                   -1, 7, -1,
-		                   G_PARAM_READWRITE |
-		                   G_PARAM_CONSTRUCT |
-		                   G_PARAM_STATIC_STRINGS));
+	obj_properties[PROP_APP_FCOE_PRIORITY] =
+	    g_param_spec_int (NM_SETTING_DCB_APP_FCOE_PRIORITY, "", "",
+	                      -1, 7, -1,
+	                      G_PARAM_READWRITE |
+	                      G_PARAM_CONSTRUCT |
+	                      G_PARAM_STATIC_STRINGS);
 
 	/**
 	 * NMSettingDcb:app-fcoe-mode:
@@ -978,13 +983,12 @@ nm_setting_dcb_class_init (NMSettingDcbClass *klass)
 	 * description: FCoE controller mode.
 	 * ---end---
 	 */
-	g_object_class_install_property
-		(object_class, PROP_APP_FCOE_MODE,
-		 g_param_spec_string (NM_SETTING_DCB_APP_FCOE_MODE, "", "",
-		                      NM_SETTING_DCB_FCOE_MODE_FABRIC,
-		                      G_PARAM_READWRITE |
-		                      G_PARAM_CONSTRUCT |
-		                      G_PARAM_STATIC_STRINGS));
+	obj_properties[PROP_APP_FCOE_MODE] =
+	    g_param_spec_string (NM_SETTING_DCB_APP_FCOE_MODE, "", "",
+	                         NM_SETTING_DCB_FCOE_MODE_FABRIC,
+	                         G_PARAM_READWRITE |
+	                         G_PARAM_CONSTRUCT |
+	                         G_PARAM_STATIC_STRINGS);
 
 	/**
 	 * NMSettingDcb:app-iscsi-flags:
@@ -1000,13 +1004,12 @@ nm_setting_dcb_class_init (NMSettingDcbClass *klass)
 	 * description: iSCSI flags.
 	 * ---end---
 	 */
-	g_object_class_install_property
-		(object_class, PROP_APP_ISCSI_FLAGS,
-		 g_param_spec_flags (NM_SETTING_DCB_APP_ISCSI_FLAGS, "", "",
-		                     NM_TYPE_SETTING_DCB_FLAGS,
-		                     NM_SETTING_DCB_FLAG_NONE,
-		                     G_PARAM_READWRITE |
-		                     G_PARAM_STATIC_STRINGS));
+	obj_properties[PROP_APP_ISCSI_FLAGS] =
+	    g_param_spec_flags (NM_SETTING_DCB_APP_ISCSI_FLAGS, "", "",
+	                        NM_TYPE_SETTING_DCB_FLAGS,
+	                        NM_SETTING_DCB_FLAG_NONE,
+	                        G_PARAM_READWRITE |
+	                        G_PARAM_STATIC_STRINGS);
 
 	/**
 	 * NMSettingDcb:app-iscsi-priority:
@@ -1022,13 +1025,12 @@ nm_setting_dcb_class_init (NMSettingDcbClass *klass)
 	 * description: Priority of iSCSI frames.
 	 * ---end---
 	 */
-	g_object_class_install_property
-		(object_class, PROP_APP_ISCSI_PRIORITY,
-		 g_param_spec_int (NM_SETTING_DCB_APP_ISCSI_PRIORITY, "", "",
-		                   -1, 7, -1,
-		                   G_PARAM_READWRITE |
-		                   G_PARAM_CONSTRUCT |
-		                   G_PARAM_STATIC_STRINGS));
+	obj_properties[PROP_APP_ISCSI_PRIORITY] =
+	    g_param_spec_int (NM_SETTING_DCB_APP_ISCSI_PRIORITY, "", "",
+	                      -1, 7, -1,
+	                      G_PARAM_READWRITE |
+	                      G_PARAM_CONSTRUCT |
+	                      G_PARAM_STATIC_STRINGS);
 
 	/**
 	 * NMSettingDcb:app-fip-flags:
@@ -1044,13 +1046,12 @@ nm_setting_dcb_class_init (NMSettingDcbClass *klass)
 	 * description: FIP flags.
 	 * ---end---
 	 */
-	g_object_class_install_property
-		(object_class, PROP_APP_FIP_FLAGS,
-		 g_param_spec_flags (NM_SETTING_DCB_APP_FIP_FLAGS, "", "",
-		                     NM_TYPE_SETTING_DCB_FLAGS,
-		                     NM_SETTING_DCB_FLAG_NONE,
-		                     G_PARAM_READWRITE |
-		                     G_PARAM_STATIC_STRINGS));
+	obj_properties[PROP_APP_FIP_FLAGS] =
+	    g_param_spec_flags (NM_SETTING_DCB_APP_FIP_FLAGS, "", "",
+	                        NM_TYPE_SETTING_DCB_FLAGS,
+	                        NM_SETTING_DCB_FLAG_NONE,
+	                        G_PARAM_READWRITE |
+	                        G_PARAM_STATIC_STRINGS);
 
 	/**
 	 * NMSettingDcb:app-fip-priority:
@@ -1066,13 +1067,12 @@ nm_setting_dcb_class_init (NMSettingDcbClass *klass)
 	 * description: Priority of FIP frames.
 	 * ---end---
 	 */
-	g_object_class_install_property
-		(object_class, PROP_APP_FIP_PRIORITY,
-		 g_param_spec_int (NM_SETTING_DCB_APP_FIP_PRIORITY, "", "",
-		                   -1, 7, -1,
-		                   G_PARAM_READWRITE |
-		                   G_PARAM_CONSTRUCT |
-		                   G_PARAM_STATIC_STRINGS));
+	obj_properties[PROP_APP_FIP_PRIORITY] =
+	    g_param_spec_int (NM_SETTING_DCB_APP_FIP_PRIORITY, "", "",
+	                      -1, 7, -1,
+	                      G_PARAM_READWRITE |
+	                      G_PARAM_CONSTRUCT |
+	                      G_PARAM_STATIC_STRINGS);
 
 	/**
 	 * NMSettingDcb:priority-flow-control-flags:
@@ -1088,13 +1088,12 @@ nm_setting_dcb_class_init (NMSettingDcbClass *klass)
 	 * description: Priority flow control flags.
 	 * ---end---
 	 */
-	g_object_class_install_property
-		(object_class, PROP_PFC_FLAGS,
-		 g_param_spec_flags (NM_SETTING_DCB_PRIORITY_FLOW_CONTROL_FLAGS, "", "",
-		                     NM_TYPE_SETTING_DCB_FLAGS,
-		                     NM_SETTING_DCB_FLAG_NONE,
-		                     G_PARAM_READWRITE |
-		                     G_PARAM_STATIC_STRINGS));
+	obj_properties[PROP_PFC_FLAGS] =
+	    g_param_spec_flags (NM_SETTING_DCB_PRIORITY_FLOW_CONTROL_FLAGS, "", "",
+	                        NM_TYPE_SETTING_DCB_FLAGS,
+	                        NM_SETTING_DCB_FLAG_NONE,
+	                        G_PARAM_READWRITE |
+	                        G_PARAM_STATIC_STRINGS);
 
 	/**
 	 * NMSettingDcb:priority-flow-control: (type GArray(gboolean))
@@ -1111,19 +1110,17 @@ nm_setting_dcb_class_init (NMSettingDcbClass *klass)
 	 * example: DCB_PFC_UP=01101110
 	 * ---end---
 	 */
-	g_object_class_install_property
-		(object_class, PROP_PFC,
-		 g_param_spec_boxed (NM_SETTING_DCB_PRIORITY_FLOW_CONTROL, "", "",
-		                     G_TYPE_ARRAY,
-		                     G_PARAM_READWRITE |
-		                     G_PARAM_STATIC_STRINGS));
+	obj_properties[PROP_PRIORITY_FLOW_CONTROL] =
+	    g_param_spec_boxed (NM_SETTING_DCB_PRIORITY_FLOW_CONTROL, "", "",
+	                        G_TYPE_ARRAY,
+	                        G_PARAM_READWRITE |
+	                        G_PARAM_STATIC_STRINGS);
 
 	_properties_override_add_transform (properties_override,
-	                                    g_object_class_find_property (G_OBJECT_CLASS (setting_class),
-	                                                                  NM_SETTING_DCB_PRIORITY_FLOW_CONTROL),
-	                                    G_VARIANT_TYPE ("au"),
-	                                    _nm_setting_dcb_uint_array_to_dbus,
-	                                    _nm_setting_dcb_uint_array_from_dbus);
+	                                   obj_properties[PROP_PRIORITY_FLOW_CONTROL],
+	                                   G_VARIANT_TYPE ("au"),
+	                                   _nm_setting_dcb_uint_array_to_dbus,
+	                                   _nm_setting_dcb_uint_array_from_dbus);
 
 	/**
 	 * NMSettingDcb:priority-group-flags:
@@ -1139,13 +1136,12 @@ nm_setting_dcb_class_init (NMSettingDcbClass *klass)
 	 * description: Priority groups flags.
 	 * ---end---
 	 */
-	g_object_class_install_property
-		(object_class, PROP_PRIORITY_GROUP_FLAGS,
-		 g_param_spec_flags (NM_SETTING_DCB_PRIORITY_GROUP_FLAGS, "", "",
-		                     NM_TYPE_SETTING_DCB_FLAGS,
-		                     NM_SETTING_DCB_FLAG_NONE,
-		                     G_PARAM_READWRITE |
-		                     G_PARAM_STATIC_STRINGS));
+	obj_properties[PROP_PRIORITY_GROUP_FLAGS] =
+	    g_param_spec_flags (NM_SETTING_DCB_PRIORITY_GROUP_FLAGS, "", "",
+	                        NM_TYPE_SETTING_DCB_FLAGS,
+	                        NM_SETTING_DCB_FLAG_NONE,
+	                        G_PARAM_READWRITE |
+	                        G_PARAM_STATIC_STRINGS);
 
 	/**
 	 * NMSettingDcb:priority-group-id: (type GArray(guint))
@@ -1162,19 +1158,17 @@ nm_setting_dcb_class_init (NMSettingDcbClass *klass)
 	 * example: DCB_PG_ID=1205f173
 	 * ---end---
 	 */
-	g_object_class_install_property
-		(object_class, PROP_PRIORITY_GROUP_ID,
-		 g_param_spec_boxed (NM_SETTING_DCB_PRIORITY_GROUP_ID, "", "",
-		                     G_TYPE_ARRAY,
-		                     G_PARAM_READWRITE |
-		                     G_PARAM_STATIC_STRINGS));
+	obj_properties[PROP_PRIORITY_GROUP_ID] =
+	    g_param_spec_boxed (NM_SETTING_DCB_PRIORITY_GROUP_ID, "", "",
+	                        G_TYPE_ARRAY,
+	                        G_PARAM_READWRITE |
+	                        G_PARAM_STATIC_STRINGS);
 
 	_properties_override_add_transform (properties_override,
-	                                    g_object_class_find_property (G_OBJECT_CLASS (setting_class),
-	                                                                  NM_SETTING_DCB_PRIORITY_GROUP_ID),
-	                                    G_VARIANT_TYPE ("au"),
-	                                    _nm_setting_dcb_uint_array_to_dbus,
-	                                    _nm_setting_dcb_uint_array_from_dbus);
+	                                   obj_properties[PROP_PRIORITY_GROUP_ID],
+	                                   G_VARIANT_TYPE ("au"),
+	                                   _nm_setting_dcb_uint_array_to_dbus,
+	                                   _nm_setting_dcb_uint_array_from_dbus);
 
 	/**
 	 * NMSettingDcb:priority-group-bandwidth: (type GArray(guint))
@@ -1191,19 +1185,17 @@ nm_setting_dcb_class_init (NMSettingDcbClass *klass)
 	 * example: DCB_PG_PCT=10,5,10,15,10,10,10,30
 	 * ---end---
 	 */
-	g_object_class_install_property
-		(object_class, PROP_PRIORITY_GROUP_BANDWIDTH,
-		 g_param_spec_boxed (NM_SETTING_DCB_PRIORITY_GROUP_BANDWIDTH, "", "",
-		                     G_TYPE_ARRAY,
-		                     G_PARAM_READWRITE |
-		                     G_PARAM_STATIC_STRINGS));
+	obj_properties[PROP_PRIORITY_GROUP_BANDWIDTH] =
+	    g_param_spec_boxed (NM_SETTING_DCB_PRIORITY_GROUP_BANDWIDTH, "", "",
+	                        G_TYPE_ARRAY,
+	                        G_PARAM_READWRITE |
+	                        G_PARAM_STATIC_STRINGS);
 
 	_properties_override_add_transform (properties_override,
-	                                    g_object_class_find_property (G_OBJECT_CLASS (setting_class),
-	                                                                  NM_SETTING_DCB_PRIORITY_GROUP_BANDWIDTH),
-	                                    G_VARIANT_TYPE ("au"),
-	                                    _nm_setting_dcb_uint_array_to_dbus,
-	                                    _nm_setting_dcb_uint_array_from_dbus);
+	                                   obj_properties[PROP_PRIORITY_GROUP_BANDWIDTH],
+	                                   G_VARIANT_TYPE ("au"),
+	                                   _nm_setting_dcb_uint_array_to_dbus,
+	                                   _nm_setting_dcb_uint_array_from_dbus);
 
 	/**
 	 * NMSettingDcb:priority-bandwidth: (type GArray(guint))
@@ -1222,19 +1214,17 @@ nm_setting_dcb_class_init (NMSettingDcbClass *klass)
 	 * example: DCB_PG_UPPCT=7,13,10,10,15,15,10,20
 	 * ---end---
 	 */
-	g_object_class_install_property
-		(object_class, PROP_PRIORITY_BANDWIDTH,
-		 g_param_spec_boxed (NM_SETTING_DCB_PRIORITY_BANDWIDTH, "", "",
-		                     G_TYPE_ARRAY,
-		                     G_PARAM_READWRITE |
-		                     G_PARAM_STATIC_STRINGS));
+	obj_properties[PROP_PRIORITY_BANDWIDTH] =
+	    g_param_spec_boxed (NM_SETTING_DCB_PRIORITY_BANDWIDTH, "", "",
+	                        G_TYPE_ARRAY,
+	                        G_PARAM_READWRITE |
+	                        G_PARAM_STATIC_STRINGS);
 
 	_properties_override_add_transform (properties_override,
-	                                    g_object_class_find_property (G_OBJECT_CLASS (setting_class),
-	                                                                  NM_SETTING_DCB_PRIORITY_BANDWIDTH),
-	                                    G_VARIANT_TYPE ("au"),
-	                                    _nm_setting_dcb_uint_array_to_dbus,
-	                                    _nm_setting_dcb_uint_array_from_dbus);
+	                                   obj_properties[PROP_PRIORITY_BANDWIDTH],
+	                                   G_VARIANT_TYPE ("au"),
+	                                   _nm_setting_dcb_uint_array_to_dbus,
+	                                   _nm_setting_dcb_uint_array_from_dbus);
 
 	/**
 	 * NMSettingDcb:priority-strict-bandwidth: (type GArray(gboolean))
@@ -1251,19 +1241,17 @@ nm_setting_dcb_class_init (NMSettingDcbClass *klass)
 	 * example: DCB_PG_STRICT=01101110
 	 * ---end---
 	 */
-	g_object_class_install_property
-		(object_class, PROP_PRIORITY_STRICT,
-		 g_param_spec_boxed (NM_SETTING_DCB_PRIORITY_STRICT_BANDWIDTH, "", "",
-		                     G_TYPE_ARRAY,
-		                     G_PARAM_READWRITE |
-		                     G_PARAM_STATIC_STRINGS));
+	obj_properties[PROP_PRIORITY_STRICT_BANDWIDTH] =
+	    g_param_spec_boxed (NM_SETTING_DCB_PRIORITY_STRICT_BANDWIDTH, "", "",
+	                        G_TYPE_ARRAY,
+	                        G_PARAM_READWRITE |
+	                        G_PARAM_STATIC_STRINGS);
 
 	_properties_override_add_transform (properties_override,
-	                                    g_object_class_find_property (G_OBJECT_CLASS (setting_class),
-	                                                                  NM_SETTING_DCB_PRIORITY_STRICT_BANDWIDTH),
-	                                    G_VARIANT_TYPE ("au"),
-	                                    _nm_setting_dcb_uint_array_to_dbus,
-	                                    _nm_setting_dcb_uint_array_from_dbus);
+	                                   obj_properties[PROP_PRIORITY_STRICT_BANDWIDTH],
+	                                   G_VARIANT_TYPE ("au"),
+	                                   _nm_setting_dcb_uint_array_to_dbus,
+	                                   _nm_setting_dcb_uint_array_from_dbus);
 
 	/**
 	 * NMSettingDcb:priority-traffic-class: (type GArray(guint))
@@ -1275,24 +1263,24 @@ nm_setting_dcb_class_init (NMSettingDcbClass *klass)
 	/* ---ifcfg-rh---
 	 * property: priority-traffic-class
 	 * variable: DCB_PG_UP2TC
-	 * description: Priority values. String of eight trafic class values (0 - 7).
+	 * description: Priority values. String of eight traffic class values (0 - 7).
 	 * example: DCB_PG_UP2TC=01623701
 	 * ---end---
 	 */
-	g_object_class_install_property
-		(object_class, PROP_PRIORITY_TRAFFIC_CLASS,
-		 g_param_spec_boxed (NM_SETTING_DCB_PRIORITY_TRAFFIC_CLASS, "", "",
-		                     G_TYPE_ARRAY,
-		                     G_PARAM_READWRITE |
-		                     G_PARAM_STATIC_STRINGS));
+	obj_properties[PROP_PRIORITY_TRAFFIC_CLASS] =
+	    g_param_spec_boxed (NM_SETTING_DCB_PRIORITY_TRAFFIC_CLASS, "", "",
+	                        G_TYPE_ARRAY,
+	                        G_PARAM_READWRITE |
+	                        G_PARAM_STATIC_STRINGS);
 
 	_properties_override_add_transform (properties_override,
-	                                    g_object_class_find_property (G_OBJECT_CLASS (setting_class),
-	                                                                  NM_SETTING_DCB_PRIORITY_TRAFFIC_CLASS),
+	                                    obj_properties[PROP_PRIORITY_TRAFFIC_CLASS],
 	                                    G_VARIANT_TYPE ("au"),
 	                                    _nm_setting_dcb_uint_array_to_dbus,
 	                                    _nm_setting_dcb_uint_array_from_dbus);
 
+	g_object_class_install_properties (object_class, _PROPERTY_ENUMS_LAST, obj_properties);
+
 	_nm_setting_class_commit_full (setting_class, NM_META_SETTING_TYPE_DCB,
 	                               NULL, properties_override);
 }
diff --git a/libnm-core/nm-setting-dummy.c b/libnm-core/nm-setting-dummy.c
index 9ae05ec4..bd85a74e 100644
--- a/libnm-core/nm-setting-dummy.c
+++ b/libnm-core/nm-setting-dummy.c
@@ -34,22 +34,11 @@
  * necessary for connection to dummy devices
  **/
 
+/*****************************************************************************/
+
 G_DEFINE_TYPE (NMSettingDummy, nm_setting_dummy, NM_TYPE_SETTING)
 
-/**
- * nm_setting_dummy_new:
- *
- * Creates a new #NMSettingDummy object with default values.
- *
- * Returns: (transfer full): the new empty #NMSettingDummy object
- *
- * Since: 1.8
- **/
-NMSetting *
-nm_setting_dummy_new (void)
-{
-	return (NMSetting *) g_object_new (NM_TYPE_SETTING_DUMMY, NULL);
-}
+/*****************************************************************************/
 
 static gboolean
 verify (NMSetting *setting, NMConnection *connection, GError **error)
@@ -60,11 +49,28 @@ verify (NMSetting *setting, NMConnection *connection, GError **error)
 	return TRUE;
 }
 
+/*****************************************************************************/
+
 static void
 nm_setting_dummy_init (NMSettingDummy *setting)
 {
 }
 
+/**
+ * nm_setting_dummy_new:
+ *
+ * Creates a new #NMSettingDummy object with default values.
+ *
+ * Returns: (transfer full): the new empty #NMSettingDummy object
+ *
+ * Since: 1.8
+ **/
+NMSetting *
+nm_setting_dummy_new (void)
+{
+	return (NMSetting *) g_object_new (NM_TYPE_SETTING_DUMMY, NULL);
+}
+
 static void
 nm_setting_dummy_class_init (NMSettingDummyClass *klass)
 {
diff --git a/libnm-core/nm-setting-generic.c b/libnm-core/nm-setting-generic.c
index 44402e39..fe5ce3ca 100644
--- a/libnm-core/nm-setting-generic.c
+++ b/libnm-core/nm-setting-generic.c
@@ -22,6 +22,7 @@
 #include "nm-default.h"
 
 #include "nm-setting-generic.h"
+
 #include "nm-setting-private.h"
 
 /**
@@ -36,16 +37,23 @@
  * the "connection type" setting on #NMConnections for generic devices.
  **/
 
-G_DEFINE_TYPE (NMSettingGeneric, nm_setting_generic, NM_TYPE_SETTING)
-
-#define NM_SETTING_GENERIC_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), NM_TYPE_SETTING_GENERIC, NMSettingGenericPrivate))
+/*****************************************************************************/
 
 typedef struct {
 	int dummy;
 } NMSettingGenericPrivate;
 
+G_DEFINE_TYPE (NMSettingGeneric, nm_setting_generic, NM_TYPE_SETTING)
+
+#define NM_SETTING_GENERIC_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), NM_TYPE_SETTING_GENERIC, NMSettingGenericPrivate))
+
 /*****************************************************************************/
 
+static void
+nm_setting_generic_init (NMSettingGeneric *setting)
+{
+}
+
 /**
  * nm_setting_generic_new:
  *
@@ -60,11 +68,6 @@ nm_setting_generic_new (void)
 }
 
 static void
-nm_setting_generic_init (NMSettingGeneric *setting)
-{
-}
-
-static void
 nm_setting_generic_class_init (NMSettingGenericClass *klass)
 {
 	NMSettingClass *setting_class = NM_SETTING_CLASS (klass);
diff --git a/libnm-core/nm-setting-gsm.c b/libnm-core/nm-setting-gsm.c
index b31da689..68d29032 100644
--- a/libnm-core/nm-setting-gsm.c
+++ b/libnm-core/nm-setting-gsm.c
@@ -22,9 +22,10 @@
 
 #include "nm-default.h"
 
+#include "nm-setting-gsm.h"
+
 #include <string.h>
 
-#include "nm-setting-gsm.h"
 #include "nm-utils.h"
 #include "nm-setting-private.h"
 #include "nm-core-enum-types.h"
@@ -38,9 +39,23 @@
  * networks, including those using GPRS/EDGE and UMTS/HSPA technology.
  */
 
-G_DEFINE_TYPE (NMSettingGsm, nm_setting_gsm, NM_TYPE_SETTING)
+/*****************************************************************************/
 
-#define NM_SETTING_GSM_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), NM_TYPE_SETTING_GSM, NMSettingGsmPrivate))
+NM_GOBJECT_PROPERTIES_DEFINE_BASE (
+	PROP_NUMBER,
+	PROP_USERNAME,
+	PROP_PASSWORD,
+	PROP_PASSWORD_FLAGS,
+	PROP_APN,
+	PROP_NETWORK_ID,
+	PROP_PIN,
+	PROP_PIN_FLAGS,
+	PROP_HOME_ONLY,
+	PROP_DEVICE_ID,
+	PROP_SIM_ID,
+	PROP_SIM_OPERATOR_ID,
+	PROP_MTU,
+);
 
 typedef struct {
 	char *number; /* For dialing, duh */
@@ -63,43 +78,19 @@ typedef struct {
 	guint32 mtu;
 } NMSettingGsmPrivate;
 
-enum {
-	PROP_0,
-	PROP_NUMBER,
-	PROP_USERNAME,
-	PROP_PASSWORD,
-	PROP_PASSWORD_FLAGS,
-	PROP_APN,
-	PROP_NETWORK_ID,
-	PROP_PIN,
-	PROP_PIN_FLAGS,
-	PROP_HOME_ONLY,
-	PROP_DEVICE_ID,
-	PROP_SIM_ID,
-	PROP_SIM_OPERATOR_ID,
-	PROP_MTU,
+G_DEFINE_TYPE (NMSettingGsm, nm_setting_gsm, NM_TYPE_SETTING)
 
-	LAST_PROP
-};
+#define NM_SETTING_GSM_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), NM_TYPE_SETTING_GSM, NMSettingGsmPrivate))
 
-/**
- * nm_setting_gsm_new:
- *
- * Creates a new #NMSettingGsm object with default values.
- *
- * Returns: the new empty #NMSettingGsm object
- **/
-NMSetting *
-nm_setting_gsm_new (void)
-{
-	return (NMSetting *) g_object_new (NM_TYPE_SETTING_GSM, NULL);
-}
+/*****************************************************************************/
 
 /**
  * nm_setting_gsm_get_number:
  * @setting: the #NMSettingGsm
  *
  * Returns: the #NMSettingGsm:number property of the setting
+ *
+ * Deprecated: 1.16:  user-provided values for this setting are no longer used.
  **/
 const char *
 nm_setting_gsm_get_number (NMSettingGsm *setting)
@@ -458,27 +449,58 @@ need_secrets (NMSetting *setting)
 	return secrets;
 }
 
-static void
-nm_setting_gsm_init (NMSettingGsm *setting)
-{
-}
+/*****************************************************************************/
 
 static void
-finalize (GObject *object)
+get_property (GObject *object, guint prop_id,
+              GValue *value, GParamSpec *pspec)
 {
-	NMSettingGsmPrivate *priv = NM_SETTING_GSM_GET_PRIVATE (object);
-
-	g_free (priv->number);
-	g_free (priv->username);
-	g_free (priv->password);
-	g_free (priv->apn);
-	g_free (priv->network_id);
-	g_free (priv->pin);
-	g_free (priv->device_id);
-	g_free (priv->sim_id);
-	g_free (priv->sim_operator_id);
+	NMSettingGsm *setting = NM_SETTING_GSM (object);
 
-	G_OBJECT_CLASS (nm_setting_gsm_parent_class)->finalize (object);
+	switch (prop_id) {
+	case PROP_NUMBER:
+		g_value_set_string (value, nm_setting_gsm_get_number (setting));
+		break;
+	case PROP_USERNAME:
+		g_value_set_string (value, nm_setting_gsm_get_username (setting));
+		break;
+	case PROP_PASSWORD:
+		g_value_set_string (value, nm_setting_gsm_get_password (setting));
+		break;
+	case PROP_PASSWORD_FLAGS:
+		g_value_set_flags (value, nm_setting_gsm_get_password_flags (setting));
+		break;
+	case PROP_APN:
+		g_value_set_string (value, nm_setting_gsm_get_apn (setting));
+		break;
+	case PROP_NETWORK_ID:
+		g_value_set_string (value, nm_setting_gsm_get_network_id (setting));
+		break;
+	case PROP_PIN:
+		g_value_set_string (value, nm_setting_gsm_get_pin (setting));
+		break;
+	case PROP_PIN_FLAGS:
+		g_value_set_flags (value, nm_setting_gsm_get_pin_flags (setting));
+		break;
+	case PROP_HOME_ONLY:
+		g_value_set_boolean (value, nm_setting_gsm_get_home_only (setting));
+		break;
+	case PROP_DEVICE_ID:
+		g_value_set_string (value, nm_setting_gsm_get_device_id (setting));
+		break;
+	case PROP_SIM_ID:
+		g_value_set_string (value, nm_setting_gsm_get_sim_id (setting));
+		break;
+	case PROP_SIM_OPERATOR_ID:
+		g_value_set_string (value, nm_setting_gsm_get_sim_operator_id (setting));
+		break;
+	case PROP_MTU:
+		g_value_set_uint (value, nm_setting_gsm_get_mtu (setting));
+		break;
+	default:
+		G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+		break;
+	}
 }
 
 static void
@@ -549,56 +571,42 @@ set_property (GObject *object, guint prop_id,
 	}
 }
 
+/*****************************************************************************/
+
 static void
-get_property (GObject *object, guint prop_id,
-              GValue *value, GParamSpec *pspec)
+nm_setting_gsm_init (NMSettingGsm *setting)
 {
-	NMSettingGsm *setting = NM_SETTING_GSM (object);
+}
 
-	switch (prop_id) {
-	case PROP_NUMBER:
-		g_value_set_string (value, nm_setting_gsm_get_number (setting));
-		break;
-	case PROP_USERNAME:
-		g_value_set_string (value, nm_setting_gsm_get_username (setting));
-		break;
-	case PROP_PASSWORD:
-		g_value_set_string (value, nm_setting_gsm_get_password (setting));
-		break;
-	case PROP_PASSWORD_FLAGS:
-		g_value_set_flags (value, nm_setting_gsm_get_password_flags (setting));
-		break;
-	case PROP_APN:
-		g_value_set_string (value, nm_setting_gsm_get_apn (setting));
-		break;
-	case PROP_NETWORK_ID:
-		g_value_set_string (value, nm_setting_gsm_get_network_id (setting));
-		break;
-	case PROP_PIN:
-		g_value_set_string (value, nm_setting_gsm_get_pin (setting));
-		break;
-	case PROP_PIN_FLAGS:
-		g_value_set_flags (value, nm_setting_gsm_get_pin_flags (setting));
-		break;
-	case PROP_HOME_ONLY:
-		g_value_set_boolean (value, nm_setting_gsm_get_home_only (setting));
-		break;
-	case PROP_DEVICE_ID:
-		g_value_set_string (value, nm_setting_gsm_get_device_id (setting));
-		break;
-	case PROP_SIM_ID:
-		g_value_set_string (value, nm_setting_gsm_get_sim_id (setting));
-		break;
-	case PROP_SIM_OPERATOR_ID:
-		g_value_set_string (value, nm_setting_gsm_get_sim_operator_id (setting));
-		break;
-	case PROP_MTU:
-		g_value_set_uint (value, nm_setting_gsm_get_mtu (setting));
-		break;
-	default:
-		G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
-		break;
-	}
+/**
+ * nm_setting_gsm_new:
+ *
+ * Creates a new #NMSettingGsm object with default values.
+ *
+ * Returns: the new empty #NMSettingGsm object
+ **/
+NMSetting *
+nm_setting_gsm_new (void)
+{
+	return (NMSetting *) g_object_new (NM_TYPE_SETTING_GSM, NULL);
+}
+
+static void
+finalize (GObject *object)
+{
+	NMSettingGsmPrivate *priv = NM_SETTING_GSM_GET_PRIVATE (object);
+
+	g_free (priv->number);
+	g_free (priv->username);
+	g_free (priv->password);
+	g_free (priv->apn);
+	g_free (priv->network_id);
+	g_free (priv->pin);
+	g_free (priv->device_id);
+	g_free (priv->sim_id);
+	g_free (priv->sim_operator_id);
+
+	G_OBJECT_CLASS (nm_setting_gsm_parent_class)->finalize (object);
 }
 
 static void
@@ -610,8 +618,8 @@ nm_setting_gsm_class_init (NMSettingGsmClass *klass)
 
 	g_type_class_add_private (klass, sizeof (NMSettingGsmPrivate));
 
-	object_class->set_property = set_property;
 	object_class->get_property = get_property;
+	object_class->set_property = set_property;
 	object_class->finalize     = finalize;
 
 	setting_class->verify         = verify;
@@ -621,17 +629,16 @@ nm_setting_gsm_class_init (NMSettingGsmClass *klass)
 	/**
 	 * NMSettingGsm:number:
 	 *
-	 * Number to dial when establishing a PPP data session with the GSM-based
-	 * mobile broadband network.  Many modems do not require PPP for connections
-	 * to the mobile network and thus this property should be left blank, which
-	 * allows NetworkManager to select the appropriate settings automatically.
+	 * Legacy setting that used to help establishing PPP data sessions for
+	 * GSM-based modems.
+	 *
+	 * Deprecated: 1.16: user-provided values for this setting are no longer used.
 	 **/
-	g_object_class_install_property
-		(object_class, PROP_NUMBER,
-		 g_param_spec_string (NM_SETTING_GSM_NUMBER, "", "",
-		                      NULL,
-		                      G_PARAM_READWRITE |
-		                      G_PARAM_STATIC_STRINGS));
+	obj_properties[PROP_NUMBER] =
+	    g_param_spec_string (NM_SETTING_GSM_NUMBER, "", "",
+	                         NULL,
+	                         G_PARAM_READWRITE |
+	                         G_PARAM_STATIC_STRINGS);
 
 	/**
 	 * NMSettingGsm:username:
@@ -640,12 +647,11 @@ nm_setting_gsm_class_init (NMSettingGsmClass *klass)
 	 * providers do not require a username, or accept any username.  But if a
 	 * username is required, it is specified here.
 	 **/
-	g_object_class_install_property
-		(object_class, PROP_USERNAME,
-		 g_param_spec_string (NM_SETTING_GSM_USERNAME, "", "",
-		                      NULL,
-		                      G_PARAM_READWRITE |
-		                      G_PARAM_STATIC_STRINGS));
+	obj_properties[PROP_USERNAME] =
+	    g_param_spec_string (NM_SETTING_GSM_USERNAME, "", "",
+	                         NULL,
+	                         G_PARAM_READWRITE |
+	                         G_PARAM_STATIC_STRINGS);
 
 	/**
 	 * NMSettingGsm:password:
@@ -654,26 +660,24 @@ nm_setting_gsm_class_init (NMSettingGsmClass *klass)
 	 * providers do not require a password, or accept any password.  But if a
 	 * password is required, it is specified here.
 	 **/
-	g_object_class_install_property
-		(object_class, PROP_PASSWORD,
-		 g_param_spec_string (NM_SETTING_GSM_PASSWORD, "", "",
-		                      NULL,
-		                      G_PARAM_READWRITE |
-		                      NM_SETTING_PARAM_SECRET |
-		                      G_PARAM_STATIC_STRINGS));
+	obj_properties[PROP_PASSWORD] =
+	    g_param_spec_string (NM_SETTING_GSM_PASSWORD, "", "",
+	                         NULL,
+	                         G_PARAM_READWRITE |
+	                         NM_SETTING_PARAM_SECRET |
+	                         G_PARAM_STATIC_STRINGS);
 
 	/**
 	 * NMSettingGsm:password-flags:
 	 *
 	 * Flags indicating how to handle the #NMSettingGsm:password property.
 	 **/
-	g_object_class_install_property
-		(object_class, PROP_PASSWORD_FLAGS,
-		 g_param_spec_flags (NM_SETTING_GSM_PASSWORD_FLAGS, "", "",
-		                     NM_TYPE_SETTING_SECRET_FLAGS,
-		                     NM_SETTING_SECRET_FLAG_NONE,
-		                     G_PARAM_READWRITE |
-		                     G_PARAM_STATIC_STRINGS));
+	obj_properties[PROP_PASSWORD_FLAGS] =
+	    g_param_spec_flags (NM_SETTING_GSM_PASSWORD_FLAGS, "", "",
+	                        NM_TYPE_SETTING_SECRET_FLAGS,
+	                        NM_SETTING_SECRET_FLAG_NONE,
+	                        G_PARAM_READWRITE |
+	                        G_PARAM_STATIC_STRINGS);
 
 	/**
 	 * NMSettingGsm:apn:
@@ -686,12 +690,11 @@ nm_setting_gsm_class_init (NMSettingGsmClass *klass)
 	 * The APN may only be composed of the characters a-z, 0-9, ., and - per GSM
 	 * 03.60 Section 14.9.
 	 **/
-	g_object_class_install_property
-		(object_class, PROP_APN,
-		 g_param_spec_string (NM_SETTING_GSM_APN, "", "",
-		                      NULL,
-		                      G_PARAM_READWRITE |
-		                      G_PARAM_STATIC_STRINGS));
+	obj_properties[PROP_APN] =
+	    g_param_spec_string (NM_SETTING_GSM_APN, "", "",
+	                         NULL,
+	                         G_PARAM_READWRITE |
+	                         G_PARAM_STATIC_STRINGS);
 
 	/**
 	 * NMSettingGsm:network-id:
@@ -702,12 +705,11 @@ nm_setting_gsm_class_init (NMSettingGsmClass *klass)
 	 * This can be used to ensure that the device does not roam when direct
 	 * roaming control of the device is not otherwise possible.
 	 **/
-	g_object_class_install_property
-		(object_class, PROP_NETWORK_ID,
-		 g_param_spec_string (NM_SETTING_GSM_NETWORK_ID, "", "",
-		                      NULL,
-		                      G_PARAM_READWRITE |
-		                      G_PARAM_STATIC_STRINGS));
+	obj_properties[PROP_NETWORK_ID] =
+	    g_param_spec_string (NM_SETTING_GSM_NETWORK_ID, "", "",
+	                         NULL,
+	                         G_PARAM_READWRITE |
+	                         G_PARAM_STATIC_STRINGS);
 
 	/**
 	 * NMSettingGsm:pin:
@@ -716,26 +718,24 @@ nm_setting_gsm_class_init (NMSettingGsmClass *klass)
 	 * operations are requested.  Specify the PIN here to allow operation of the
 	 * device.
 	 **/
-	g_object_class_install_property
-		(object_class, PROP_PIN,
-		 g_param_spec_string (NM_SETTING_GSM_PIN, "", "",
-		                      NULL,
-		                      G_PARAM_READWRITE |
-		                      NM_SETTING_PARAM_SECRET |
-		                      G_PARAM_STATIC_STRINGS));
+	obj_properties[PROP_PIN] =
+	    g_param_spec_string (NM_SETTING_GSM_PIN, "", "",
+	                         NULL,
+	                         G_PARAM_READWRITE |
+	                         NM_SETTING_PARAM_SECRET |
+	                         G_PARAM_STATIC_STRINGS);
 
 	/**
 	 * NMSettingGsm:pin-flags:
 	 *
 	 * Flags indicating how to handle the #NMSettingGsm:pin property.
 	 **/
-	g_object_class_install_property
-		(object_class, PROP_PIN_FLAGS,
-		 g_param_spec_flags (NM_SETTING_GSM_PIN_FLAGS, "", "",
-		                     NM_TYPE_SETTING_SECRET_FLAGS,
-		                     NM_SETTING_SECRET_FLAG_NONE,
-		                     G_PARAM_READWRITE |
-		                     G_PARAM_STATIC_STRINGS));
+	obj_properties[PROP_PIN_FLAGS] =
+	    g_param_spec_flags (NM_SETTING_GSM_PIN_FLAGS, "", "",
+	                        NM_TYPE_SETTING_SECRET_FLAGS,
+	                        NM_SETTING_SECRET_FLAG_NONE,
+	                        G_PARAM_READWRITE |
+	                        G_PARAM_STATIC_STRINGS);
 
 	/**
 	 * NMSettingGsm:home-only:
@@ -743,12 +743,11 @@ nm_setting_gsm_class_init (NMSettingGsmClass *klass)
 	 * When %TRUE, only connections to the home network will be allowed.
 	 * Connections to roaming networks will not be made.
 	 **/
-	g_object_class_install_property
-		(object_class, PROP_HOME_ONLY,
-		 g_param_spec_boolean (NM_SETTING_GSM_HOME_ONLY, "", "",
-		                       FALSE,
-		                       G_PARAM_READWRITE |
-		                       G_PARAM_STATIC_STRINGS));
+	obj_properties[PROP_HOME_ONLY] =
+	    g_param_spec_boolean (NM_SETTING_GSM_HOME_ONLY, "", "",
+	                          FALSE,
+	                          G_PARAM_READWRITE |
+	                          G_PARAM_STATIC_STRINGS);
 
 	/**
 	 * NMSettingGsm:device-id:
@@ -759,12 +758,11 @@ nm_setting_gsm_class_init (NMSettingGsmClass *klass)
 	 *
 	 * Since: 1.2
 	 **/
-	g_object_class_install_property
-		(object_class, PROP_DEVICE_ID,
-		 g_param_spec_string (NM_SETTING_GSM_DEVICE_ID, "", "",
-		                      NULL,
-		                      G_PARAM_READWRITE |
-		                      G_PARAM_STATIC_STRINGS));
+	obj_properties[PROP_DEVICE_ID] =
+	    g_param_spec_string (NM_SETTING_GSM_DEVICE_ID, "", "",
+	                         NULL,
+	                         G_PARAM_READWRITE |
+	                         G_PARAM_STATIC_STRINGS);
 
 	/**
 	 * NMSettingGsm:sim-id:
@@ -776,12 +774,11 @@ nm_setting_gsm_class_init (NMSettingGsmClass *klass)
 	 *
 	 * Since: 1.2
 	 **/
-	g_object_class_install_property
-		(object_class, PROP_SIM_ID,
-		 g_param_spec_string (NM_SETTING_GSM_SIM_ID, "", "",
-		                      NULL,
-		                      G_PARAM_READWRITE |
-		                      G_PARAM_STATIC_STRINGS));
+	obj_properties[PROP_SIM_ID] =
+	    g_param_spec_string (NM_SETTING_GSM_SIM_ID, "", "",
+	                         NULL,
+	                         G_PARAM_READWRITE |
+	                         G_PARAM_STATIC_STRINGS);
 
 	/**
 	 * NMSettingGsm:sim-operator-id:
@@ -794,12 +791,11 @@ nm_setting_gsm_class_init (NMSettingGsmClass *klass)
 	 *
 	 * Since: 1.2
 	 **/
-	g_object_class_install_property
-		(object_class, PROP_SIM_OPERATOR_ID,
-		 g_param_spec_string (NM_SETTING_GSM_SIM_OPERATOR_ID, "", "",
-		                      NULL,
-		                      G_PARAM_READWRITE |
-		                      G_PARAM_STATIC_STRINGS));
+	obj_properties[PROP_SIM_OPERATOR_ID] =
+	    g_param_spec_string (NM_SETTING_GSM_SIM_OPERATOR_ID, "", "",
+	                         NULL,
+	                         G_PARAM_READWRITE |
+	                         G_PARAM_STATIC_STRINGS);
 
 	/**
 	 * NMSettingGsm:mtu:
@@ -809,14 +805,13 @@ nm_setting_gsm_class_init (NMSettingGsmClass *klass)
 	 *
 	 * Since: 1.8
 	 **/
-	g_object_class_install_property
-		(object_class, PROP_MTU,
-		 g_param_spec_uint (NM_SETTING_GSM_MTU, "", "",
-		                    0, G_MAXUINT32, 0,
-		                    G_PARAM_READWRITE |
-		                    G_PARAM_CONSTRUCT |
-		                    NM_SETTING_PARAM_FUZZY_IGNORE |
-		                    G_PARAM_STATIC_STRINGS));
+	obj_properties[PROP_MTU] =
+	    g_param_spec_uint (NM_SETTING_GSM_MTU, "", "",
+	                       0, G_MAXUINT32, 0,
+	                       G_PARAM_READWRITE |
+	                       G_PARAM_CONSTRUCT |
+	                       NM_SETTING_PARAM_FUZZY_IGNORE |
+	                       G_PARAM_STATIC_STRINGS);
 
 	/* Ignore incoming deprecated properties */
 	_properties_override_add_dbus_only (properties_override,
@@ -831,6 +826,8 @@ nm_setting_gsm_class_init (NMSettingGsmClass *klass)
 	                                    NULL,
 	                                    NULL);
 
+	g_object_class_install_properties (object_class, _PROPERTY_ENUMS_LAST, obj_properties);
+
 	_nm_setting_class_commit_full (setting_class, NM_META_SETTING_TYPE_GSM,
 	                               NULL, properties_override);
 }
diff --git a/libnm-core/nm-setting-gsm.h b/libnm-core/nm-setting-gsm.h
index 8516698d..0763b9df 100644
--- a/libnm-core/nm-setting-gsm.h
+++ b/libnm-core/nm-setting-gsm.h
@@ -40,7 +40,6 @@ G_BEGIN_DECLS
 
 #define NM_SETTING_GSM_SETTING_NAME "gsm"
 
-#define NM_SETTING_GSM_NUMBER          "number"
 #define NM_SETTING_GSM_USERNAME        "username"
 #define NM_SETTING_GSM_PASSWORD        "password"
 #define NM_SETTING_GSM_PASSWORD_FLAGS  "password-flags"
@@ -54,6 +53,9 @@ G_BEGIN_DECLS
 #define NM_SETTING_GSM_SIM_OPERATOR_ID "sim-operator-id"
 #define NM_SETTING_GSM_MTU             "mtu"
 
+/* Deprecated */
+#define NM_SETTING_GSM_NUMBER          "number"
+
 /**
  * NMSettingGsm:
  *
@@ -73,7 +75,6 @@ typedef struct {
 GType nm_setting_gsm_get_type (void);
 
 NMSetting *nm_setting_gsm_new                  (void);
-const char *nm_setting_gsm_get_number          (NMSettingGsm *setting);
 const char *nm_setting_gsm_get_username        (NMSettingGsm *setting);
 const char *nm_setting_gsm_get_password        (NMSettingGsm *setting);
 const char *nm_setting_gsm_get_apn             (NMSettingGsm *setting);
@@ -90,6 +91,9 @@ const char *nm_setting_gsm_get_sim_operator_id (NMSettingGsm *setting);
 NM_AVAILABLE_IN_1_8
 guint32 nm_setting_gsm_get_mtu                 (NMSettingGsm *setting);
 
+NM_DEPRECATED_IN_1_16
+const char *nm_setting_gsm_get_number          (NMSettingGsm *setting);
+
 NMSettingSecretFlags nm_setting_gsm_get_pin_flags      (NMSettingGsm *setting);
 NMSettingSecretFlags nm_setting_gsm_get_password_flags (NMSettingGsm *setting);
 
diff --git a/libnm-core/nm-setting-infiniband.c b/libnm-core/nm-setting-infiniband.c
index d5ae7085..9348fa2b 100644
--- a/libnm-core/nm-setting-infiniband.c
+++ b/libnm-core/nm-setting-infiniband.c
@@ -21,9 +21,10 @@
 
 #include "nm-default.h"
 
+#include "nm-setting-infiniband.h"
+
 #include <stdlib.h>
 
-#include "nm-setting-infiniband.h"
 #include "nm-utils.h"
 #include "nm-utils-private.h"
 #include "nm-setting-private.h"
@@ -37,9 +38,15 @@
  * necessary for connection to IP-over-InfiniBand networks.
  **/
 
-G_DEFINE_TYPE (NMSettingInfiniband, nm_setting_infiniband, NM_TYPE_SETTING)
+/*****************************************************************************/
 
-#define NM_SETTING_INFINIBAND_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), NM_TYPE_SETTING_INFINIBAND, NMSettingInfinibandPrivate))
+NM_GOBJECT_PROPERTIES_DEFINE_BASE (
+	PROP_MAC_ADDRESS,
+	PROP_MTU,
+	PROP_TRANSPORT_MODE,
+	PROP_P_KEY,
+	PROP_PARENT,
+);
 
 typedef struct {
 	char *mac_address;
@@ -49,29 +56,11 @@ typedef struct {
 	char *parent, *virtual_iface_name;
 } NMSettingInfinibandPrivate;
 
-enum {
-	PROP_0,
-	PROP_MAC_ADDRESS,
-	PROP_MTU,
-	PROP_TRANSPORT_MODE,
-	PROP_P_KEY,
-	PROP_PARENT,
+G_DEFINE_TYPE (NMSettingInfiniband, nm_setting_infiniband, NM_TYPE_SETTING)
 
-	LAST_PROP
-};
+#define NM_SETTING_INFINIBAND_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), NM_TYPE_SETTING_INFINIBAND, NMSettingInfinibandPrivate))
 
-/**
- * nm_setting_infiniband_new:
- *
- * Creates a new #NMSettingInfiniband object with default values.
- *
- * Returns: (transfer full): the new empty #NMSettingInfiniband object
- **/
-NMSetting *
-nm_setting_infiniband_new (void)
-{
-	return (NMSetting *) g_object_new (NM_TYPE_SETTING_INFINIBAND, NULL);
-}
+/*****************************************************************************/
 
 /**
  * nm_setting_infiniband_get_mac_address:
@@ -295,22 +284,34 @@ verify (NMSetting *setting, NMConnection *connection, GError **error)
 	return TRUE;
 }
 
-static void
-nm_setting_infiniband_init (NMSettingInfiniband *setting)
-{
-}
+/*****************************************************************************/
 
 static void
-finalize (GObject *object)
+get_property (GObject *object, guint prop_id,
+              GValue *value, GParamSpec *pspec)
 {
-	NMSettingInfinibandPrivate *priv = NM_SETTING_INFINIBAND_GET_PRIVATE (object);
-
-	g_free (priv->transport_mode);
-	g_free (priv->mac_address);
-	g_free (priv->parent);
-	g_free (priv->virtual_iface_name);
+	NMSettingInfiniband *setting = NM_SETTING_INFINIBAND (object);
 
-	G_OBJECT_CLASS (nm_setting_infiniband_parent_class)->finalize (object);
+	switch (prop_id) {
+	case PROP_MAC_ADDRESS:
+		g_value_set_string (value, nm_setting_infiniband_get_mac_address (setting));
+		break;
+	case PROP_MTU:
+		g_value_set_uint (value, nm_setting_infiniband_get_mtu (setting));
+		break;
+	case PROP_TRANSPORT_MODE:
+		g_value_set_string (value, nm_setting_infiniband_get_transport_mode (setting));
+		break;
+	case PROP_P_KEY:
+		g_value_set_int (value, nm_setting_infiniband_get_p_key (setting));
+		break;
+	case PROP_PARENT:
+		g_value_set_string (value, nm_setting_infiniband_get_parent (setting));
+		break;
+	default:
+		G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+		break;
+	}
 }
 
 static void
@@ -347,32 +348,37 @@ set_property (GObject *object, guint prop_id,
 	}
 }
 
+/*****************************************************************************/
+
 static void
-get_property (GObject *object, guint prop_id,
-              GValue *value, GParamSpec *pspec)
+nm_setting_infiniband_init (NMSettingInfiniband *setting)
 {
-	NMSettingInfiniband *setting = NM_SETTING_INFINIBAND (object);
+}
 
-	switch (prop_id) {
-	case PROP_MAC_ADDRESS:
-		g_value_set_string (value, nm_setting_infiniband_get_mac_address (setting));
-		break;
-	case PROP_MTU:
-		g_value_set_uint (value, nm_setting_infiniband_get_mtu (setting));
-		break;
-	case PROP_TRANSPORT_MODE:
-		g_value_set_string (value, nm_setting_infiniband_get_transport_mode (setting));
-		break;
-	case PROP_P_KEY:
-		g_value_set_int (value, nm_setting_infiniband_get_p_key (setting));
-		break;
-	case PROP_PARENT:
-		g_value_set_string (value, nm_setting_infiniband_get_parent (setting));
-		break;
-	default:
-		G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
-		break;
-	}
+/**
+ * nm_setting_infiniband_new:
+ *
+ * Creates a new #NMSettingInfiniband object with default values.
+ *
+ * Returns: (transfer full): the new empty #NMSettingInfiniband object
+ **/
+NMSetting *
+nm_setting_infiniband_new (void)
+{
+	return (NMSetting *) g_object_new (NM_TYPE_SETTING_INFINIBAND, NULL);
+}
+
+static void
+finalize (GObject *object)
+{
+	NMSettingInfinibandPrivate *priv = NM_SETTING_INFINIBAND_GET_PRIVATE (object);
+
+	g_free (priv->transport_mode);
+	g_free (priv->mac_address);
+	g_free (priv->parent);
+	g_free (priv->virtual_iface_name);
+
+	G_OBJECT_CLASS (nm_setting_infiniband_parent_class)->finalize (object);
 }
 
 static void
@@ -384,8 +390,8 @@ nm_setting_infiniband_class_init (NMSettingInfinibandClass *klass)
 
 	g_type_class_add_private (klass, sizeof (NMSettingInfinibandPrivate));
 
-	object_class->set_property = set_property;
 	object_class->get_property = get_property;
+	object_class->set_property = set_property;
 	object_class->finalize     = finalize;
 
 	setting_class->verify = verify;
@@ -415,17 +421,15 @@ nm_setting_infiniband_class_init (NMSettingInfinibandClass *klass)
 	 * example: HWADDR=01:02:03:04:05:06:07:08:09:0A:01:02:03:04:05:06:07:08:09:11
 	 * ---end---
 	 */
-	g_object_class_install_property
-		(object_class, PROP_MAC_ADDRESS,
-		 g_param_spec_string (NM_SETTING_INFINIBAND_MAC_ADDRESS, "", "",
-		                      NULL,
-		                      G_PARAM_READWRITE |
-		                      NM_SETTING_PARAM_INFERRABLE |
-		                      G_PARAM_STATIC_STRINGS));
+	obj_properties[PROP_MAC_ADDRESS] =
+	    g_param_spec_string (NM_SETTING_INFINIBAND_MAC_ADDRESS, "", "",
+	                         NULL,
+	                         G_PARAM_READWRITE |
+	                         NM_SETTING_PARAM_INFERRABLE |
+	                         G_PARAM_STATIC_STRINGS);
 
 	_properties_override_add_transform (properties_override,
-	                                    g_object_class_find_property (G_OBJECT_CLASS (setting_class),
-	                                                                  NM_SETTING_INFINIBAND_MAC_ADDRESS),
+	                                    obj_properties[PROP_MAC_ADDRESS],
 	                                    G_VARIANT_TYPE_BYTESTRING,
 	                                    _nm_utils_hwaddr_to_dbus,
 	                                    _nm_utils_hwaddr_from_dbus);
@@ -442,14 +446,13 @@ nm_setting_infiniband_class_init (NMSettingInfinibandClass *klass)
 	 * description: MTU of the interface.
 	 * ---end---
 	 */
-	g_object_class_install_property
-		(object_class, PROP_MTU,
-		 g_param_spec_uint (NM_SETTING_INFINIBAND_MTU, "", "",
-		                    0, G_MAXUINT32, 0,
-		                    G_PARAM_READWRITE |
-		                    G_PARAM_CONSTRUCT |
-		                    NM_SETTING_PARAM_FUZZY_IGNORE |
-		                    G_PARAM_STATIC_STRINGS));
+	obj_properties[PROP_MTU] =
+	    g_param_spec_uint (NM_SETTING_INFINIBAND_MTU, "", "",
+	                       0, G_MAXUINT32, 0,
+	                       G_PARAM_READWRITE |
+	                       G_PARAM_CONSTRUCT |
+	                       NM_SETTING_PARAM_FUZZY_IGNORE |
+	                       G_PARAM_STATIC_STRINGS);
 
 	/**
 	 * NMSettingInfiniband:transport-mode:
@@ -465,14 +468,13 @@ nm_setting_infiniband_class_init (NMSettingInfinibandClass *klass)
 	 *   "datagram" mode
 	 * ---end---
 	 */
-	g_object_class_install_property
-		(object_class, PROP_TRANSPORT_MODE,
-		 g_param_spec_string (NM_SETTING_INFINIBAND_TRANSPORT_MODE, "", "",
-		                      NULL,
-		                      G_PARAM_READWRITE |
-		                      G_PARAM_CONSTRUCT |
-		                      NM_SETTING_PARAM_INFERRABLE |
-		                      G_PARAM_STATIC_STRINGS));
+	obj_properties[PROP_TRANSPORT_MODE] =
+	    g_param_spec_string (NM_SETTING_INFINIBAND_TRANSPORT_MODE, "", "",
+	                         NULL,
+	                         G_PARAM_READWRITE |
+	                         G_PARAM_CONSTRUCT |
+	                         NM_SETTING_PARAM_INFERRABLE |
+	                         G_PARAM_STATIC_STRINGS);
 
 	/**
 	 * NMSettingInfiniband:p-key:
@@ -492,14 +494,13 @@ nm_setting_infiniband_class_init (NMSettingInfinibandClass *klass)
 	 * example: PKEY=yes PKEY_ID=2 PHYSDEV=mlx4_ib0 DEVICE=mlx4_ib0.8002
 	 * ---end---
 	 */
-	g_object_class_install_property
-		(object_class, PROP_P_KEY,
-		 g_param_spec_int (NM_SETTING_INFINIBAND_P_KEY, "", "",
-		                   -1, 0xFFFF, -1,
-		                   G_PARAM_READWRITE |
-		                   G_PARAM_CONSTRUCT |
-		                   NM_SETTING_PARAM_INFERRABLE |
-		                   G_PARAM_STATIC_STRINGS));
+	obj_properties[PROP_P_KEY] =
+	    g_param_spec_int (NM_SETTING_INFINIBAND_P_KEY, "", "",
+	                      -1, 0xFFFF, -1,
+	                      G_PARAM_READWRITE |
+	                      G_PARAM_CONSTRUCT |
+	                      NM_SETTING_PARAM_INFERRABLE |
+	                      G_PARAM_STATIC_STRINGS);
 
 	/**
 	 * NMSettingInfiniband:parent:
@@ -517,14 +518,15 @@ nm_setting_infiniband_class_init (NMSettingInfinibandClass *klass)
 	 * example: PHYSDEV=ib0
 	 * ---end---
 	 */
-	g_object_class_install_property
-		(object_class, PROP_PARENT,
-		 g_param_spec_string (NM_SETTING_INFINIBAND_PARENT, "", "",
-		                      NULL,
-		                      G_PARAM_READWRITE |
-		                      G_PARAM_CONSTRUCT |
-		                      NM_SETTING_PARAM_INFERRABLE |
-		                      G_PARAM_STATIC_STRINGS));
+	obj_properties[PROP_PARENT] =
+	    g_param_spec_string (NM_SETTING_INFINIBAND_PARENT, "", "",
+	                         NULL,
+	                         G_PARAM_READWRITE |
+	                         G_PARAM_CONSTRUCT |
+	                         NM_SETTING_PARAM_INFERRABLE |
+	                         G_PARAM_STATIC_STRINGS);
+
+	g_object_class_install_properties (object_class, _PROPERTY_ENUMS_LAST, obj_properties);
 
 	_nm_setting_class_commit_full (setting_class, NM_META_SETTING_TYPE_INFINIBAND,
 	                               NULL, properties_override);
diff --git a/libnm-core/nm-setting-ip-config.c b/libnm-core/nm-setting-ip-config.c
index 2b3134b6..8fff030e 100644
--- a/libnm-core/nm-setting-ip-config.c
+++ b/libnm-core/nm-setting-ip-config.c
@@ -22,10 +22,11 @@
 
 #include "nm-default.h"
 
+#include "nm-setting-ip-config.h"
+
 #include <string.h>
 #include <arpa/inet.h>
 
-#include "nm-setting-ip-config.h"
 #include "nm-setting-ip4-config.h"
 #include "nm-setting-ip6-config.h"
 #include "nm-utils.h"
@@ -44,6 +45,8 @@
  * related to IP addressing, routing, and Domain Name Service.
  **/
 
+/*****************************************************************************/
+
 const NMUtilsDNSOptionDesc _nm_utils_dns_option_descs[] = {
 	{ NM_SETTING_DNS_OPTION_DEBUG,                 FALSE,   FALSE },
 	{ NM_SETTING_DNS_OPTION_NDOTS,                 TRUE,    FALSE },
@@ -1382,9 +1385,26 @@ _nm_ip_route_attribute_validate_all (const NMIPRoute *route)
 
 /*****************************************************************************/
 
-G_DEFINE_ABSTRACT_TYPE (NMSettingIPConfig, nm_setting_ip_config, NM_TYPE_SETTING)
-
-#define NM_SETTING_IP_CONFIG_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), NM_TYPE_SETTING_IP_CONFIG, NMSettingIPConfigPrivate))
+NM_GOBJECT_PROPERTIES_DEFINE (NMSettingIPConfig,
+	PROP_METHOD,
+	PROP_DNS,
+	PROP_DNS_SEARCH,
+	PROP_DNS_OPTIONS,
+	PROP_DNS_PRIORITY,
+	PROP_ADDRESSES,
+	PROP_GATEWAY,
+	PROP_ROUTES,
+	PROP_ROUTE_METRIC,
+	PROP_ROUTE_TABLE,
+	PROP_IGNORE_AUTO_ROUTES,
+	PROP_IGNORE_AUTO_DNS,
+	PROP_DHCP_HOSTNAME,
+	PROP_DHCP_SEND_HOSTNAME,
+	PROP_NEVER_DEFAULT,
+	PROP_MAY_FAIL,
+	PROP_DAD_TIMEOUT,
+	PROP_DHCP_TIMEOUT,
+);
 
 typedef struct {
 	char *method;
@@ -1407,29 +1427,11 @@ typedef struct {
 	int dhcp_timeout;
 } NMSettingIPConfigPrivate;
 
-enum {
-	PROP_0,
-	PROP_METHOD,
-	PROP_DNS,
-	PROP_DNS_SEARCH,
-	PROP_DNS_OPTIONS,
-	PROP_DNS_PRIORITY,
-	PROP_ADDRESSES,
-	PROP_GATEWAY,
-	PROP_ROUTES,
-	PROP_ROUTE_METRIC,
-	PROP_ROUTE_TABLE,
-	PROP_IGNORE_AUTO_ROUTES,
-	PROP_IGNORE_AUTO_DNS,
-	PROP_DHCP_HOSTNAME,
-	PROP_DHCP_SEND_HOSTNAME,
-	PROP_NEVER_DEFAULT,
-	PROP_MAY_FAIL,
-	PROP_DAD_TIMEOUT,
-	PROP_DHCP_TIMEOUT,
+G_DEFINE_ABSTRACT_TYPE (NMSettingIPConfig, nm_setting_ip_config, NM_TYPE_SETTING)
 
-	LAST_PROP
-};
+#define NM_SETTING_IP_CONFIG_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), NM_TYPE_SETTING_IP_CONFIG, NMSettingIPConfigPrivate))
+
+/*****************************************************************************/
 
 #define NM_SETTING_IP_CONFIG_GET_FAMILY(setting) (NM_IS_SETTING_IP4_CONFIG (setting) ? AF_INET : AF_INET6)
 
@@ -1515,7 +1517,7 @@ nm_setting_ip_config_add_dns (NMSettingIPConfig *setting, const char *dns)
 	}
 
 	g_ptr_array_add (priv->dns, dns_canonical);
-	g_object_notify (G_OBJECT (setting), NM_SETTING_IP_CONFIG_DNS);
+	_notify (setting, PROP_DNS);
 	return TRUE;
 }
 
@@ -1537,7 +1539,7 @@ nm_setting_ip_config_remove_dns (NMSettingIPConfig *setting, int idx)
 	g_return_if_fail (idx >= 0 && idx < priv->dns->len);
 
 	g_ptr_array_remove_index (priv->dns, idx);
-	g_object_notify (G_OBJECT (setting), NM_SETTING_IP_CONFIG_DNS);
+	_notify (setting, PROP_DNS);
 }
 
 /**
@@ -1566,7 +1568,7 @@ nm_setting_ip_config_remove_dns_by_value (NMSettingIPConfig *setting, const char
 	for (i = 0; i < priv->dns->len; i++) {
 		if (!strcmp (dns_canonical, priv->dns->pdata[i])) {
 			g_ptr_array_remove_index (priv->dns, i);
-			g_object_notify (G_OBJECT (setting), NM_SETTING_IP_CONFIG_DNS);
+			_notify (setting, PROP_DNS);
 			g_free (dns_canonical);
 			return TRUE;
 		}
@@ -1592,7 +1594,7 @@ nm_setting_ip_config_clear_dns (NMSettingIPConfig *setting)
 
 	if (priv->dns->len != 0) {
 		g_ptr_array_set_size (priv->dns, 0);
-		g_object_notify (G_OBJECT (setting), NM_SETTING_IP_CONFIG_DNS);
+		_notify (setting, PROP_DNS);
 	}
 }
 
@@ -1658,7 +1660,7 @@ nm_setting_ip_config_add_dns_search (NMSettingIPConfig *setting,
 	}
 
 	g_ptr_array_add (priv->dns_search, g_strdup (dns_search));
-	g_object_notify (G_OBJECT (setting), NM_SETTING_IP_CONFIG_DNS_SEARCH);
+	_notify (setting, PROP_DNS_SEARCH);
 	return TRUE;
 }
 
@@ -1680,7 +1682,7 @@ nm_setting_ip_config_remove_dns_search (NMSettingIPConfig *setting, int idx)
 	g_return_if_fail (idx >= 0 && idx < priv->dns_search->len);
 
 	g_ptr_array_remove_index (priv->dns_search, idx);
-	g_object_notify (G_OBJECT (setting), NM_SETTING_IP_CONFIG_DNS_SEARCH);
+	_notify (setting, PROP_DNS_SEARCH);
 }
 
 /**
@@ -1707,7 +1709,7 @@ nm_setting_ip_config_remove_dns_search_by_value (NMSettingIPConfig *setting,
 	for (i = 0; i < priv->dns_search->len; i++) {
 		if (!strcmp (dns_search, priv->dns_search->pdata[i])) {
 			g_ptr_array_remove_index (priv->dns_search, i);
-			g_object_notify (G_OBJECT (setting), NM_SETTING_IP_CONFIG_DNS_SEARCH);
+			_notify (setting, PROP_DNS_SEARCH);
 			return TRUE;
 		}
 	}
@@ -1731,7 +1733,7 @@ nm_setting_ip_config_clear_dns_searches (NMSettingIPConfig *setting)
 
 	if (priv->dns_search->len != 0) {
 		g_ptr_array_set_size (priv->dns_search, 0);
-		g_object_notify (G_OBJECT (setting), NM_SETTING_IP_CONFIG_DNS_SEARCH);
+		_notify (setting, PROP_DNS_SEARCH);
 	}
 }
 
@@ -1863,7 +1865,7 @@ nm_setting_ip_config_add_dns_option (NMSettingIPConfig *setting,
 	}
 
 	g_ptr_array_add (priv->dns_options, g_strdup (dns_option));
-	g_object_notify (G_OBJECT (setting), NM_SETTING_IP_CONFIG_DNS_OPTIONS);
+	_notify (setting, PROP_DNS_OPTIONS);
 	return TRUE;
 }
 
@@ -1888,7 +1890,7 @@ nm_setting_ip_config_remove_dns_option (NMSettingIPConfig *setting, int idx)
 	g_return_if_fail (idx >= 0 && idx < priv->dns_options->len);
 
 	g_ptr_array_remove_index (priv->dns_options, idx);
-	g_object_notify (G_OBJECT (setting), NM_SETTING_IP_CONFIG_DNS_OPTIONS);
+	_notify (setting, PROP_DNS_OPTIONS);
 }
 
 /**
@@ -1920,7 +1922,7 @@ nm_setting_ip_config_remove_dns_option_by_value (NMSettingIPConfig *setting,
 	i = _nm_utils_dns_option_find_idx (priv->dns_options, dns_option);
 	if (i >= 0) {
 		g_ptr_array_remove_index (priv->dns_options, i);
-		g_object_notify (G_OBJECT (setting), NM_SETTING_IP_CONFIG_DNS_OPTIONS);
+		_notify (setting, PROP_DNS_OPTIONS);
 		return TRUE;
 	}
 
@@ -1959,7 +1961,7 @@ nm_setting_ip_config_clear_dns_options (NMSettingIPConfig *setting, gboolean is_
 			g_ptr_array_set_size (priv->dns_options, 0);
 		}
 	}
-	g_object_notify (G_OBJECT (setting), NM_SETTING_IP_CONFIG_DNS_OPTIONS);
+	_notify (setting, PROP_DNS_OPTIONS);
 }
 
 /**
@@ -2042,7 +2044,7 @@ nm_setting_ip_config_add_address (NMSettingIPConfig *setting,
 
 	g_ptr_array_add (priv->addresses, nm_ip_address_dup (address));
 
-	g_object_notify (G_OBJECT (setting), NM_SETTING_IP_CONFIG_ADDRESSES);
+	_notify (setting, PROP_ADDRESSES);
 	return TRUE;
 }
 
@@ -2065,7 +2067,7 @@ nm_setting_ip_config_remove_address (NMSettingIPConfig *setting, int idx)
 
 	g_ptr_array_remove_index (priv->addresses, idx);
 
-	g_object_notify (G_OBJECT (setting), NM_SETTING_IP_CONFIG_ADDRESSES);
+	_notify (setting, PROP_ADDRESSES);
 }
 
 /**
@@ -2091,7 +2093,7 @@ nm_setting_ip_config_remove_address_by_value (NMSettingIPConfig *setting,
 	for (i = 0; i < priv->addresses->len; i++) {
 		if (nm_ip_address_equal (priv->addresses->pdata[i], address)) {
 			g_ptr_array_remove_index (priv->addresses, i);
-			g_object_notify (G_OBJECT (setting), NM_SETTING_IP_CONFIG_ADDRESSES);
+			_notify (setting, PROP_ADDRESSES);
 			return TRUE;
 		}
 	}
@@ -2113,7 +2115,7 @@ nm_setting_ip_config_clear_addresses (NMSettingIPConfig *setting)
 
 	if (priv->addresses->len != 0) {
 		g_ptr_array_set_size (priv->addresses, 0);
-		g_object_notify (G_OBJECT (setting), NM_SETTING_IP_CONFIG_ADDRESSES);
+		_notify (setting, PROP_ADDRESSES);
 	}
 }
 
@@ -2200,7 +2202,7 @@ nm_setting_ip_config_add_route (NMSettingIPConfig *setting,
 	}
 
 	g_ptr_array_add (priv->routes, nm_ip_route_dup (route));
-	g_object_notify (G_OBJECT (setting), NM_SETTING_IP_CONFIG_ROUTES);
+	_notify (setting, PROP_ROUTES);
 	return TRUE;
 }
 
@@ -2222,7 +2224,7 @@ nm_setting_ip_config_remove_route (NMSettingIPConfig *setting, int idx)
 	g_return_if_fail (idx >= 0 && idx < priv->routes->len);
 
 	g_ptr_array_remove_index (priv->routes, idx);
-	g_object_notify (G_OBJECT (setting), NM_SETTING_IP_CONFIG_ROUTES);
+	_notify (setting, PROP_ROUTES);
 }
 
 /**
@@ -2250,7 +2252,7 @@ nm_setting_ip_config_remove_route_by_value (NMSettingIPConfig *setting,
 	for (i = 0; i < priv->routes->len; i++) {
 		if (nm_ip_route_equal_full (priv->routes->pdata[i], route, NM_IP_ROUTE_EQUAL_CMP_FLAGS_WITH_ATTRS)) {
 			g_ptr_array_remove_index (priv->routes, i);
-			g_object_notify (G_OBJECT (setting), NM_SETTING_IP_CONFIG_ROUTES);
+			_notify (setting, PROP_ROUTES);
 			return TRUE;
 		}
 	}
@@ -2272,7 +2274,7 @@ nm_setting_ip_config_clear_routes (NMSettingIPConfig *setting)
 
 	if (priv->routes->len != 0) {
 		g_ptr_array_set_size (priv->routes, 0);
-		g_object_notify (G_OBJECT (setting), NM_SETTING_IP_CONFIG_ROUTES);
+		_notify (setting, PROP_ROUTES);
 	}
 }
 
@@ -2612,78 +2614,161 @@ verify (NMSetting *setting, NMConnection *connection, GError **error)
 	return TRUE;
 }
 
-static gboolean
-compare_property (NMSetting *setting,
+static NMTernary
+compare_property (const NMSettInfoSetting *sett_info,
+                  guint property_idx,
+                  NMSetting *setting,
                   NMSetting *other,
-                  const GParamSpec *prop_spec,
                   NMSettingCompareFlags flags)
 {
-	NMSettingIPConfigPrivate *a_priv, *b_priv;
-	NMSettingClass *setting_class;
+	NMSettingIPConfigPrivate *a_priv;
+	NMSettingIPConfigPrivate *b_priv;
 	guint i;
 
-	if (nm_streq (prop_spec->name, NM_SETTING_IP_CONFIG_ADDRESSES)) {
-		a_priv = NM_SETTING_IP_CONFIG_GET_PRIVATE (setting);
-		b_priv = NM_SETTING_IP_CONFIG_GET_PRIVATE (other);
+	if (nm_streq (sett_info->property_infos[property_idx].name, NM_SETTING_IP_CONFIG_ADDRESSES)) {
+		if (other) {
+			a_priv = NM_SETTING_IP_CONFIG_GET_PRIVATE (setting);
+			b_priv = NM_SETTING_IP_CONFIG_GET_PRIVATE (other);
 
-		if (a_priv->addresses->len != b_priv->addresses->len)
-			return FALSE;
-		for (i = 0; i < a_priv->addresses->len; i++) {
-			if (!_nm_ip_address_equal (a_priv->addresses->pdata[i], b_priv->addresses->pdata[i], TRUE))
+			if (a_priv->addresses->len != b_priv->addresses->len)
 				return FALSE;
+			for (i = 0; i < a_priv->addresses->len; i++) {
+				if (!_nm_ip_address_equal (a_priv->addresses->pdata[i], b_priv->addresses->pdata[i], TRUE))
+					return FALSE;
+			}
 		}
 		return TRUE;
 	}
 
-	if (nm_streq (prop_spec->name, NM_SETTING_IP_CONFIG_ROUTES)) {
-		a_priv = NM_SETTING_IP_CONFIG_GET_PRIVATE (setting);
-		b_priv = NM_SETTING_IP_CONFIG_GET_PRIVATE (other);
+	if (nm_streq (sett_info->property_infos[property_idx].name, NM_SETTING_IP_CONFIG_ROUTES)) {
+		if (other) {
+			a_priv = NM_SETTING_IP_CONFIG_GET_PRIVATE (setting);
+			b_priv = NM_SETTING_IP_CONFIG_GET_PRIVATE (other);
 
-		if (a_priv->routes->len != b_priv->routes->len)
-			return FALSE;
-		for (i = 0; i < a_priv->routes->len; i++) {
-			if (!nm_ip_route_equal_full (a_priv->routes->pdata[i], b_priv->routes->pdata[i], NM_IP_ROUTE_EQUAL_CMP_FLAGS_WITH_ATTRS))
+			if (a_priv->routes->len != b_priv->routes->len)
 				return FALSE;
+			for (i = 0; i < a_priv->routes->len; i++) {
+				if (!nm_ip_route_equal_full (a_priv->routes->pdata[i], b_priv->routes->pdata[i], NM_IP_ROUTE_EQUAL_CMP_FLAGS_WITH_ATTRS))
+					return FALSE;
+			}
 		}
 		return TRUE;
 	}
 
-	setting_class = NM_SETTING_CLASS (nm_setting_ip_config_parent_class);
-	return setting_class->compare_property (setting, other, prop_spec, flags);
+	return NM_SETTING_CLASS (nm_setting_ip_config_parent_class)->compare_property (sett_info,
+	                                                                               property_idx,
+	                                                                               setting,
+	                                                                               other,
+	                                                                               flags);
 }
 
 /*****************************************************************************/
 
-static void
-nm_setting_ip_config_init (NMSettingIPConfig *setting)
+static gboolean
+ip_gateway_set (NMSetting  *setting,
+                GVariant   *connection_dict,
+                const char *property,
+                GVariant   *value,
+                NMSettingParseFlags parse_flags,
+                GError    **error)
 {
-	NMSettingIPConfigPrivate *priv = NM_SETTING_IP_CONFIG_GET_PRIVATE (setting);
+	/* FIXME: properly handle errors */
 
-	priv->dns = g_ptr_array_new_with_free_func (g_free);
-	priv->dns_search = g_ptr_array_new_with_free_func (g_free);
-	priv->dns_options = NULL;
-	priv->addresses = g_ptr_array_new_with_free_func ((GDestroyNotify) nm_ip_address_unref);
-	priv->routes = g_ptr_array_new_with_free_func ((GDestroyNotify) nm_ip_route_unref);
+	/* 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 TRUE;
+
+	g_object_set (setting, property, g_variant_get_string (value, NULL), NULL);
+	return TRUE;
 }
 
-static void
-finalize (GObject *object)
+GArray *
+_nm_sett_info_property_override_create_array_ip_config (void)
 {
-	NMSettingIPConfig *self = NM_SETTING_IP_CONFIG (object);
-	NMSettingIPConfigPrivate *priv = NM_SETTING_IP_CONFIG_GET_PRIVATE (self);
+	GArray *properties_override = _nm_sett_info_property_override_create_array ();
 
-	g_free (priv->method);
-	g_free (priv->gateway);
-	g_free (priv->dhcp_hostname);
+	_properties_override_add_override (properties_override,
+	                                   obj_properties[PROP_GATEWAY],
+	                                   G_VARIANT_TYPE_STRING,
+	                                   NULL,
+	                                   ip_gateway_set,
+	                                   NULL);
 
-	g_ptr_array_unref (priv->dns);
-	g_ptr_array_unref (priv->dns_search);
-	if (priv->dns_options)
-		g_ptr_array_unref (priv->dns_options);
-	g_ptr_array_unref (priv->addresses);
-	g_ptr_array_unref (priv->routes);
+	return properties_override;
+}
 
-	G_OBJECT_CLASS (nm_setting_ip_config_parent_class)->finalize (object);
+/*****************************************************************************/
+
+static void
+get_property (GObject *object, guint prop_id,
+              GValue *value, GParamSpec *pspec)
+{
+	NMSettingIPConfig *setting = NM_SETTING_IP_CONFIG (object);
+	NMSettingIPConfigPrivate *priv = NM_SETTING_IP_CONFIG_GET_PRIVATE (setting);
+
+	switch (prop_id) {
+	case PROP_METHOD:
+		g_value_set_string (value, nm_setting_ip_config_get_method (setting));
+		break;
+	case PROP_DNS:
+		g_value_take_boxed (value, _nm_utils_ptrarray_to_strv (priv->dns));
+		break;
+	case PROP_DNS_SEARCH:
+		g_value_take_boxed (value, _nm_utils_ptrarray_to_strv (priv->dns_search));
+		break;
+	case PROP_DNS_OPTIONS:
+		g_value_take_boxed (value, priv->dns_options ? _nm_utils_ptrarray_to_strv (priv->dns_options) : NULL);
+		break;
+	case PROP_DNS_PRIORITY:
+		g_value_set_int (value, priv->dns_priority);
+		break;
+	case PROP_ADDRESSES:
+		g_value_take_boxed (value, _nm_utils_copy_array (priv->addresses,
+		                                                 (NMUtilsCopyFunc) nm_ip_address_dup,
+		                                                 (GDestroyNotify) nm_ip_address_unref));
+		break;
+	case PROP_GATEWAY:
+		g_value_set_string (value, nm_setting_ip_config_get_gateway (setting));
+		break;
+	case PROP_ROUTES:
+		g_value_take_boxed (value, _nm_utils_copy_array (priv->routes,
+		                                                 (NMUtilsCopyFunc) nm_ip_route_dup,
+		                                                 (GDestroyNotify) nm_ip_route_unref));
+		break;
+	case PROP_ROUTE_METRIC:
+		g_value_set_int64 (value, priv->route_metric);
+		break;
+	case PROP_ROUTE_TABLE:
+		g_value_set_uint (value, priv->route_table);
+		break;
+	case PROP_IGNORE_AUTO_ROUTES:
+		g_value_set_boolean (value, nm_setting_ip_config_get_ignore_auto_routes (setting));
+		break;
+	case PROP_IGNORE_AUTO_DNS:
+		g_value_set_boolean (value, nm_setting_ip_config_get_ignore_auto_dns (setting));
+		break;
+	case PROP_DHCP_HOSTNAME:
+		g_value_set_string (value, nm_setting_ip_config_get_dhcp_hostname (setting));
+		break;
+	case PROP_DHCP_SEND_HOSTNAME:
+		g_value_set_boolean (value, nm_setting_ip_config_get_dhcp_send_hostname (setting));
+		break;
+	case PROP_NEVER_DEFAULT:
+		g_value_set_boolean (value, priv->never_default);
+		break;
+	case PROP_MAY_FAIL:
+		g_value_set_boolean (value, priv->may_fail);
+		break;
+	case PROP_DAD_TIMEOUT:
+		g_value_set_int (value, nm_setting_ip_config_get_dad_timeout (setting));
+		break;
+	case PROP_DHCP_TIMEOUT:
+		g_value_set_int (value, nm_setting_ip_config_get_dhcp_timeout (setting));
+		break;
+	default:
+		G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+		break;
+	}
 }
 
 static void
@@ -2786,111 +2871,38 @@ set_property (GObject *object, guint prop_id,
 	}
 }
 
+/*****************************************************************************/
+
 static void
-get_property (GObject *object, guint prop_id,
-              GValue *value, GParamSpec *pspec)
+nm_setting_ip_config_init (NMSettingIPConfig *setting)
 {
-	NMSettingIPConfig *setting = NM_SETTING_IP_CONFIG (object);
 	NMSettingIPConfigPrivate *priv = NM_SETTING_IP_CONFIG_GET_PRIVATE (setting);
 
-	switch (prop_id) {
-	case PROP_METHOD:
-		g_value_set_string (value, nm_setting_ip_config_get_method (setting));
-		break;
-	case PROP_DNS:
-		g_value_take_boxed (value, _nm_utils_ptrarray_to_strv (priv->dns));
-		break;
-	case PROP_DNS_SEARCH:
-		g_value_take_boxed (value, _nm_utils_ptrarray_to_strv (priv->dns_search));
-		break;
-	case PROP_DNS_OPTIONS:
-		g_value_take_boxed (value, priv->dns_options ? _nm_utils_ptrarray_to_strv (priv->dns_options) : NULL);
-		break;
-	case PROP_DNS_PRIORITY:
-		g_value_set_int (value, priv->dns_priority);
-		break;
-	case PROP_ADDRESSES:
-		g_value_take_boxed (value, _nm_utils_copy_array (priv->addresses,
-		                                                 (NMUtilsCopyFunc) nm_ip_address_dup,
-		                                                 (GDestroyNotify) nm_ip_address_unref));
-		break;
-	case PROP_GATEWAY:
-		g_value_set_string (value, nm_setting_ip_config_get_gateway (setting));
-		break;
-	case PROP_ROUTES:
-		g_value_take_boxed (value, _nm_utils_copy_array (priv->routes,
-		                                                 (NMUtilsCopyFunc) nm_ip_route_dup,
-		                                                 (GDestroyNotify) nm_ip_route_unref));
-		break;
-	case PROP_ROUTE_METRIC:
-		g_value_set_int64 (value, priv->route_metric);
-		break;
-	case PROP_ROUTE_TABLE:
-		g_value_set_uint (value, priv->route_table);
-		break;
-	case PROP_IGNORE_AUTO_ROUTES:
-		g_value_set_boolean (value, nm_setting_ip_config_get_ignore_auto_routes (setting));
-		break;
-	case PROP_IGNORE_AUTO_DNS:
-		g_value_set_boolean (value, nm_setting_ip_config_get_ignore_auto_dns (setting));
-		break;
-	case PROP_DHCP_HOSTNAME:
-		g_value_set_string (value, nm_setting_ip_config_get_dhcp_hostname (setting));
-		break;
-	case PROP_DHCP_SEND_HOSTNAME:
-		g_value_set_boolean (value, nm_setting_ip_config_get_dhcp_send_hostname (setting));
-		break;
-	case PROP_NEVER_DEFAULT:
-		g_value_set_boolean (value, priv->never_default);
-		break;
-	case PROP_MAY_FAIL:
-		g_value_set_boolean (value, priv->may_fail);
-		break;
-	case PROP_DAD_TIMEOUT:
-		g_value_set_int (value, nm_setting_ip_config_get_dad_timeout (setting));
-		break;
-	case PROP_DHCP_TIMEOUT:
-		g_value_set_int (value, nm_setting_ip_config_get_dhcp_timeout (setting));
-		break;
-	default:
-		G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
-		break;
-	}
+	priv->dns = g_ptr_array_new_with_free_func (g_free);
+	priv->dns_search = g_ptr_array_new_with_free_func (g_free);
+	priv->dns_options = NULL;
+	priv->addresses = g_ptr_array_new_with_free_func ((GDestroyNotify) nm_ip_address_unref);
+	priv->routes = g_ptr_array_new_with_free_func ((GDestroyNotify) nm_ip_route_unref);
 }
 
-static gboolean
-ip_gateway_set (NMSetting  *setting,
-                GVariant   *connection_dict,
-                const char *property,
-                GVariant   *value,
-                NMSettingParseFlags parse_flags,
-                GError    **error)
+static void
+finalize (GObject *object)
 {
-	/* 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 TRUE;
-
-	g_object_set (setting, property, g_variant_get_string (value, NULL), NULL);
-	return TRUE;
-}
+	NMSettingIPConfig *self = NM_SETTING_IP_CONFIG (object);
+	NMSettingIPConfigPrivate *priv = NM_SETTING_IP_CONFIG_GET_PRIVATE (self);
 
-GArray *
-_nm_sett_info_property_override_create_array_ip_config (void)
-{
-	nm_auto_unref_gtypeclass NMSettingClass *setting_class = g_type_class_ref (NM_TYPE_SETTING_IP_CONFIG);
-	GArray *properties_override = _nm_sett_info_property_override_create_array ();
+	g_free (priv->method);
+	g_free (priv->gateway);
+	g_free (priv->dhcp_hostname);
 
-	_properties_override_add_override (properties_override,
-	                                   g_object_class_find_property (G_OBJECT_CLASS (setting_class),
-	                                                                 NM_SETTING_IP_CONFIG_GATEWAY),
-	                                   G_VARIANT_TYPE_STRING,
-	                                   NULL,
-	                                   ip_gateway_set,
-	                                   NULL);
+	g_ptr_array_unref (priv->dns);
+	g_ptr_array_unref (priv->dns_search);
+	if (priv->dns_options)
+		g_ptr_array_unref (priv->dns_options);
+	g_ptr_array_unref (priv->addresses);
+	g_ptr_array_unref (priv->routes);
 
-	return properties_override;
+	G_OBJECT_CLASS (nm_setting_ip_config_parent_class)->finalize (object);
 }
 
 static void
@@ -2901,8 +2913,8 @@ nm_setting_ip_config_class_init (NMSettingIPConfigClass *klass)
 
 	g_type_class_add_private (klass, sizeof (NMSettingIPConfigPrivate));
 
-	object_class->set_property = set_property;
 	object_class->get_property = get_property;
+	object_class->set_property = set_property;
 	object_class->finalize     = finalize;
 
 	setting_class->verify           = verify;
@@ -2931,25 +2943,23 @@ nm_setting_ip_config_class_init (NMSettingIPConfigClass *klass)
 	 * shared method must be configured on the interface which shares the internet
 	 * to a subnet, not on the uplink which is shared.
 	 **/
-	g_object_class_install_property
-		(object_class, PROP_METHOD,
-		 g_param_spec_string (NM_SETTING_IP_CONFIG_METHOD, "", "",
-		                      NULL,
-		                      G_PARAM_READWRITE |
-		                      NM_SETTING_PARAM_INFERRABLE |
-		                      G_PARAM_STATIC_STRINGS));
+	obj_properties[PROP_METHOD] =
+	    g_param_spec_string (NM_SETTING_IP_CONFIG_METHOD, "", "",
+	                         NULL,
+	                         G_PARAM_READWRITE |
+	                         NM_SETTING_PARAM_INFERRABLE |
+	                         G_PARAM_STATIC_STRINGS);
 
 	/**
 	 * NMSettingIPConfig:dns:
 	 *
 	 * Array of IP addresses of DNS servers.
 	 **/
-	g_object_class_install_property
-		(object_class, PROP_DNS,
-		 g_param_spec_boxed (NM_SETTING_IP_CONFIG_DNS, "", "",
-		                     G_TYPE_STRV,
-		                     G_PARAM_READWRITE |
-		                     G_PARAM_STATIC_STRINGS));
+	obj_properties[PROP_DNS] =
+	    g_param_spec_boxed (NM_SETTING_IP_CONFIG_DNS, "", "",
+	                        G_TYPE_STRV,
+	                        G_PARAM_READWRITE |
+	                        G_PARAM_STATIC_STRINGS);
 
 	/**
 	 * NMSettingIPConfig:dns-search:
@@ -2959,12 +2969,11 @@ nm_setting_ip_config_class_init (NMSettingIPConfigClass *klass)
 	 * interface over which a query must be forwarded; they are not used
 	 * to complete unqualified host names.
 	 **/
-	g_object_class_install_property
-		(object_class, PROP_DNS_SEARCH,
-		 g_param_spec_boxed (NM_SETTING_IP_CONFIG_DNS_SEARCH, "", "",
-		                     G_TYPE_STRV,
-		                     G_PARAM_READWRITE |
-		                     G_PARAM_STATIC_STRINGS));
+	obj_properties[PROP_DNS_SEARCH] =
+	    g_param_spec_boxed (NM_SETTING_IP_CONFIG_DNS_SEARCH, "", "",
+	                        G_TYPE_STRV,
+	                        G_PARAM_READWRITE |
+	                        G_PARAM_STATIC_STRINGS);
 
 	/**
 	 * NMSettingIPConfig:dns-options:
@@ -2977,12 +2986,11 @@ nm_setting_ip_config_class_init (NMSettingIPConfigClass *klass)
 	 *
 	 * Since: 1.2
 	 **/
-	g_object_class_install_property
-		(object_class, PROP_DNS_OPTIONS,
-		 g_param_spec_boxed (NM_SETTING_IP_CONFIG_DNS_OPTIONS, "", "",
-		                     G_TYPE_STRV,
-		                     G_PARAM_READWRITE |
-		                     G_PARAM_STATIC_STRINGS));
+	obj_properties[PROP_DNS_OPTIONS] =
+	    g_param_spec_boxed (NM_SETTING_IP_CONFIG_DNS_OPTIONS, "", "",
+	                        G_TYPE_STRV,
+	                        G_PARAM_READWRITE |
+	                        G_PARAM_STATIC_STRINGS);
 
 	/**
 	 * NMSettingIPConfig:dns-priority:
@@ -2990,8 +2998,9 @@ nm_setting_ip_config_class_init (NMSettingIPConfigClass *klass)
 	 * DNS servers priority.
 	 *
 	 * The relative priority for DNS servers specified by this setting.  A lower
-	 * value is better (higher priority).  Zero selects the default value, which
-	 * is 50 for VPNs and 100 for other connections.
+	 * value is better (higher priority). Zero selects a globally configured
+	 * default value. If the latter is missing or zero too, it defaults to
+	 * 50 for VPNs and 100 for other connections.
 	 *
 	 * Note that the priority is to order DNS settings for multiple active
 	 * connections.  It does not disambiguate multiple DNS servers within the
@@ -3018,31 +3027,29 @@ nm_setting_ip_config_class_init (NMSettingIPConfigClass *klass)
 	 *
 	 * Since: 1.4
 	 **/
-	g_object_class_install_property
-	    (object_class, PROP_DNS_PRIORITY,
+	obj_properties[PROP_DNS_PRIORITY] =
 	     g_param_spec_int (NM_SETTING_IP_CONFIG_DNS_PRIORITY, "", "",
 	                       G_MININT32, G_MAXINT32, 0,
 	                       G_PARAM_READWRITE |
 	                       G_PARAM_CONSTRUCT |
-	                       G_PARAM_STATIC_STRINGS));
+	                       G_PARAM_STATIC_STRINGS);
 
 	/**
 	 * NMSettingIPConfig:addresses: (type GPtrArray(NMIPAddress))
 	 *
 	 * Array of IP addresses.
 	 **/
-	g_object_class_install_property
-		(object_class, PROP_ADDRESSES,
-		 g_param_spec_boxed (NM_SETTING_IP_CONFIG_ADDRESSES, "", "",
-		                     G_TYPE_PTR_ARRAY,
-		                     G_PARAM_READWRITE |
-		                     NM_SETTING_PARAM_INFERRABLE |
-		                     /* "addresses" is a legacy D-Bus property, because the
-		                      * "addresses" GObject property normally gets set from
-		                      * the "address-data" D-Bus property...
-		                      */
-		                     NM_SETTING_PARAM_LEGACY |
-		                     G_PARAM_STATIC_STRINGS));
+	obj_properties[PROP_ADDRESSES] =
+	    g_param_spec_boxed (NM_SETTING_IP_CONFIG_ADDRESSES, "", "",
+	                        G_TYPE_PTR_ARRAY,
+	                        G_PARAM_READWRITE |
+	                        NM_SETTING_PARAM_INFERRABLE |
+	                        /* "addresses" is a legacy D-Bus property, because the
+	                         * "addresses" GObject property normally gets set from
+	                         * the "address-data" D-Bus property...
+	                         */
+	                        NM_SETTING_PARAM_LEGACY |
+	                        G_PARAM_STATIC_STRINGS);
 
 	/**
 	 * NMSettingIPConfig:gateway:
@@ -3050,28 +3057,26 @@ nm_setting_ip_config_class_init (NMSettingIPConfigClass *klass)
 	 * The gateway associated with this configuration. This is only meaningful
 	 * if #NMSettingIPConfig:addresses is also set.
 	 **/
-	g_object_class_install_property
-		(object_class, PROP_GATEWAY,
-		 g_param_spec_string (NM_SETTING_IP_CONFIG_GATEWAY, "", "",
-		                      NULL,
-		                      G_PARAM_READWRITE |
-		                      NM_SETTING_PARAM_INFERRABLE |
-		                      G_PARAM_STATIC_STRINGS));
+	obj_properties[PROP_GATEWAY] =
+	    g_param_spec_string (NM_SETTING_IP_CONFIG_GATEWAY, "", "",
+	                         NULL,
+	                         G_PARAM_READWRITE |
+	                         NM_SETTING_PARAM_INFERRABLE |
+	                         G_PARAM_STATIC_STRINGS);
 
 	/**
 	 * NMSettingIPConfig:routes: (type GPtrArray(NMIPRoute))
 	 *
 	 * Array of IP routes.
 	 **/
-	g_object_class_install_property
-		(object_class, PROP_ROUTES,
-		 g_param_spec_boxed (NM_SETTING_IP_CONFIG_ROUTES, "", "",
-		                     G_TYPE_PTR_ARRAY,
-		                     G_PARAM_READWRITE |
-		                     NM_SETTING_PARAM_INFERRABLE |
-		                     /* See :addresses above Re: LEGACY */
-		                     NM_SETTING_PARAM_LEGACY |
-		                     G_PARAM_STATIC_STRINGS));
+	obj_properties[PROP_ROUTES] =
+	    g_param_spec_boxed (NM_SETTING_IP_CONFIG_ROUTES, "", "",
+	                        G_TYPE_PTR_ARRAY,
+	                        G_PARAM_READWRITE |
+	                        NM_SETTING_PARAM_INFERRABLE |
+	                        /* See :addresses above Re: LEGACY */
+	                        NM_SETTING_PARAM_LEGACY |
+	                        G_PARAM_STATIC_STRINGS);
 
 	/**
 	 * NMSettingIPConfig:route-metric:
@@ -3087,13 +3092,12 @@ nm_setting_ip_config_class_init (NMSettingIPConfigClass *klass)
 	 * mean setting it to 1024.
 	 * For IPv4, zero is a regular value for the metric.
 	 **/
-	g_object_class_install_property
-	    (object_class, PROP_ROUTE_METRIC,
+	obj_properties[PROP_ROUTE_METRIC] =
 	     g_param_spec_int64 (NM_SETTING_IP_CONFIG_ROUTE_METRIC, "", "",
 	                         -1, G_MAXUINT32, -1,
 	                         G_PARAM_READWRITE |
 	                         G_PARAM_CONSTRUCT |
-	                         G_PARAM_STATIC_STRINGS));
+	                         G_PARAM_STATIC_STRINGS);
 
 	/**
 	 * NMSettingIPConfig:route-table:
@@ -3116,13 +3120,12 @@ nm_setting_ip_config_class_init (NMSettingIPConfigClass *klass)
 	 *
 	 * Since: 1.10
 	 **/
-	g_object_class_install_property
-		(object_class, PROP_ROUTE_TABLE,
-		 g_param_spec_uint (NM_SETTING_IP_CONFIG_ROUTE_TABLE, "", "",
-		                    0, G_MAXUINT32, 0,
-		                    G_PARAM_READWRITE |
-		                    NM_SETTING_PARAM_FUZZY_IGNORE |
-		                    G_PARAM_STATIC_STRINGS));
+	obj_properties[PROP_ROUTE_TABLE] =
+	    g_param_spec_uint (NM_SETTING_IP_CONFIG_ROUTE_TABLE, "", "",
+	                       0, G_MAXUINT32, 0,
+	                       G_PARAM_READWRITE |
+	                       NM_SETTING_PARAM_FUZZY_IGNORE |
+	                       G_PARAM_STATIC_STRINGS);
 	/**
 	 * NMSettingIPConfig:ignore-auto-routes:
 	 *
@@ -3130,13 +3133,12 @@ nm_setting_ip_config_class_init (NMSettingIPConfigClass *klass)
 	 * %TRUE, automatically configured routes are ignored and only routes
 	 * specified in the #NMSettingIPConfig:routes property, if any, are used.
 	 **/
-	g_object_class_install_property
-		(object_class, PROP_IGNORE_AUTO_ROUTES,
-		 g_param_spec_boolean (NM_SETTING_IP_CONFIG_IGNORE_AUTO_ROUTES, "", "",
-		                       FALSE,
-		                       G_PARAM_READWRITE |
-		                       G_PARAM_CONSTRUCT |
-		                       G_PARAM_STATIC_STRINGS));
+	obj_properties[PROP_IGNORE_AUTO_ROUTES] =
+	    g_param_spec_boolean (NM_SETTING_IP_CONFIG_IGNORE_AUTO_ROUTES, "", "",
+	                          FALSE,
+	                          G_PARAM_READWRITE |
+	                          G_PARAM_CONSTRUCT |
+	                          G_PARAM_STATIC_STRINGS);
 
 	/**
 	 * NMSettingIPConfig:ignore-auto-dns:
@@ -3147,13 +3149,12 @@ nm_setting_ip_config_class_init (NMSettingIPConfigClass *klass)
 	 * #NMSettingIPConfig:dns and #NMSettingIPConfig:dns-search properties, if
 	 * any, are used.
 	 **/
-	g_object_class_install_property
-		(object_class, PROP_IGNORE_AUTO_DNS,
-		 g_param_spec_boolean (NM_SETTING_IP_CONFIG_IGNORE_AUTO_DNS, "", "",
-		                       FALSE,
-		                       G_PARAM_READWRITE |
-		                       G_PARAM_CONSTRUCT |
-		                       G_PARAM_STATIC_STRINGS));
+	obj_properties[PROP_IGNORE_AUTO_DNS] =
+	    g_param_spec_boolean (NM_SETTING_IP_CONFIG_IGNORE_AUTO_DNS, "", "",
+	                          FALSE,
+	                          G_PARAM_READWRITE |
+	                          G_PARAM_CONSTRUCT |
+	                          G_PARAM_STATIC_STRINGS);
 
 	/**
 	 * NMSettingIPConfig:dhcp-hostname:
@@ -3163,12 +3164,11 @@ nm_setting_ip_config_class_init (NMSettingIPConfigClass *klass)
 	 * This property and #NMSettingIP4Config:dhcp-fqdn are mutually exclusive and
 	 * cannot be set at the same time.
 	 **/
-	g_object_class_install_property
-		(object_class, PROP_DHCP_HOSTNAME,
-		 g_param_spec_string (NM_SETTING_IP_CONFIG_DHCP_HOSTNAME, "", "",
-		                      NULL,
-		                      G_PARAM_READWRITE |
-		                      G_PARAM_STATIC_STRINGS));
+	obj_properties[PROP_DHCP_HOSTNAME] =
+	    g_param_spec_string (NM_SETTING_IP_CONFIG_DHCP_HOSTNAME, "", "",
+	                         NULL,
+	                         G_PARAM_READWRITE |
+	                         G_PARAM_STATIC_STRINGS);
 
 	/**
 	 * NMSettingIPConfig:dhcp-send-hostname:
@@ -3179,13 +3179,12 @@ nm_setting_ip_config_class_init (NMSettingIPConfigClass *klass)
 	 * #NMSettingIPConfig:dhcp-hostname property is %NULL and this property is
 	 * %TRUE, the current persistent hostname of the computer is sent.
 	 **/
-	g_object_class_install_property
-		(object_class, PROP_DHCP_SEND_HOSTNAME,
-		 g_param_spec_boolean (NM_SETTING_IP_CONFIG_DHCP_SEND_HOSTNAME, "", "",
-		                       TRUE,
-		                       G_PARAM_READWRITE |
-		                       G_PARAM_CONSTRUCT |
-		                       G_PARAM_STATIC_STRINGS));
+	obj_properties[PROP_DHCP_SEND_HOSTNAME] =
+	    g_param_spec_boolean (NM_SETTING_IP_CONFIG_DHCP_SEND_HOSTNAME, "", "",
+	                          TRUE,
+	                          G_PARAM_READWRITE |
+	                          G_PARAM_CONSTRUCT |
+	                          G_PARAM_STATIC_STRINGS);
 
 	/**
 	 * NMSettingIPConfig:never-default:
@@ -3194,13 +3193,12 @@ nm_setting_ip_config_class_init (NMSettingIPConfigClass *klass)
 	 * IP type, meaning it will never be assigned the default route by
 	 * NetworkManager.
 	 **/
-	g_object_class_install_property
-		(object_class, PROP_NEVER_DEFAULT,
-		 g_param_spec_boolean (NM_SETTING_IP_CONFIG_NEVER_DEFAULT, "", "",
-		                       FALSE,
-		                       G_PARAM_READWRITE |
-		                       G_PARAM_CONSTRUCT |
-		                       G_PARAM_STATIC_STRINGS));
+	obj_properties[PROP_NEVER_DEFAULT] =
+	    g_param_spec_boolean (NM_SETTING_IP_CONFIG_NEVER_DEFAULT, "", "",
+	                          FALSE,
+	                          G_PARAM_READWRITE |
+	                          G_PARAM_CONSTRUCT |
+	                          G_PARAM_STATIC_STRINGS);
 
 	/**
 	 * NMSettingIPConfig:may-fail:
@@ -3213,13 +3211,12 @@ nm_setting_ip_config_class_init (NMSettingIPConfigClass *klass)
 	 * to succeed if IPv4 configuration fails but IPv6 configuration completes
 	 * successfully.
 	 **/
-	g_object_class_install_property
-		(object_class, PROP_MAY_FAIL,
-		 g_param_spec_boolean (NM_SETTING_IP_CONFIG_MAY_FAIL, "", "",
-		                       TRUE,
-		                       G_PARAM_READWRITE |
-		                       G_PARAM_CONSTRUCT |
-		                       G_PARAM_STATIC_STRINGS));
+	obj_properties[PROP_MAY_FAIL] =
+	    g_param_spec_boolean (NM_SETTING_IP_CONFIG_MAY_FAIL, "", "",
+	                          TRUE,
+	                          G_PARAM_READWRITE |
+	                          G_PARAM_CONSTRUCT |
+	                          G_PARAM_STATIC_STRINGS);
 
 	/**
 	 * NMSettingIPConfig:dad-timeout:
@@ -3235,25 +3232,25 @@ nm_setting_ip_config_class_init (NMSettingIPConfigClass *klass)
 	 *
 	 * Since: 1.2
 	 **/
-	g_object_class_install_property
-		(object_class, PROP_DAD_TIMEOUT,
-		 g_param_spec_int (NM_SETTING_IP_CONFIG_DAD_TIMEOUT, "", "",
-		                    -1, NM_SETTING_IP_CONFIG_DAD_TIMEOUT_MAX, -1,
-		                    G_PARAM_READWRITE |
-		                    G_PARAM_CONSTRUCT |
-		                    NM_SETTING_PARAM_FUZZY_IGNORE |
-		                    G_PARAM_STATIC_STRINGS));
+	obj_properties[PROP_DAD_TIMEOUT] =
+	    g_param_spec_int (NM_SETTING_IP_CONFIG_DAD_TIMEOUT, "", "",
+	                       -1, NM_SETTING_IP_CONFIG_DAD_TIMEOUT_MAX, -1,
+	                       G_PARAM_READWRITE |
+	                       G_PARAM_CONSTRUCT |
+	                       NM_SETTING_PARAM_FUZZY_IGNORE |
+	                       G_PARAM_STATIC_STRINGS);
 
 	/**
 	 * NMSettingIPConfig:dhcp-timeout:
 	 *
 	 * A timeout for a DHCP transaction in seconds.
 	 **/
-	g_object_class_install_property
-		(object_class, PROP_DHCP_TIMEOUT,
-		 g_param_spec_int (NM_SETTING_IP_CONFIG_DHCP_TIMEOUT, "", "",
-		                   0, G_MAXINT32, 0,
-		                   G_PARAM_READWRITE |
-		                   NM_SETTING_PARAM_FUZZY_IGNORE |
-		                   G_PARAM_STATIC_STRINGS));
+	obj_properties[PROP_DHCP_TIMEOUT] =
+	    g_param_spec_int (NM_SETTING_IP_CONFIG_DHCP_TIMEOUT, "", "",
+	                      0, G_MAXINT32, 0,
+	                      G_PARAM_READWRITE |
+	                      NM_SETTING_PARAM_FUZZY_IGNORE |
+	                      G_PARAM_STATIC_STRINGS);
+
+	g_object_class_install_properties (object_class, _PROPERTY_ENUMS_LAST, obj_properties);
 }
diff --git a/libnm-core/nm-setting-ip-tunnel.c b/libnm-core/nm-setting-ip-tunnel.c
index 41314f58..9fdb5481 100644
--- a/libnm-core/nm-setting-ip-tunnel.c
+++ b/libnm-core/nm-setting-ip-tunnel.c
@@ -30,9 +30,23 @@
  * @short_description: Describes connection properties for IP tunnel devices
  **/
 
-G_DEFINE_TYPE (NMSettingIPTunnel, nm_setting_ip_tunnel, NM_TYPE_SETTING)
+/*****************************************************************************/
 
-#define NM_SETTING_IP_TUNNEL_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), NM_TYPE_SETTING_IP_TUNNEL, NMSettingIPTunnelPrivate))
+NM_GOBJECT_PROPERTIES_DEFINE_BASE (
+	PROP_PARENT,
+	PROP_MODE,
+	PROP_LOCAL,
+	PROP_REMOTE,
+	PROP_TTL,
+	PROP_TOS,
+	PROP_PATH_MTU_DISCOVERY,
+	PROP_INPUT_KEY,
+	PROP_OUTPUT_KEY,
+	PROP_ENCAPSULATION_LIMIT,
+	PROP_FLOW_LABEL,
+	PROP_MTU,
+	PROP_FLAGS,
+);
 
 typedef struct {
 	char *parent;
@@ -50,24 +64,11 @@ typedef struct {
 	guint32 flags;
 } NMSettingIPTunnelPrivate;
 
-enum {
-	PROP_0,
-	PROP_PARENT,
-	PROP_MODE,
-	PROP_LOCAL,
-	PROP_REMOTE,
-	PROP_TTL,
-	PROP_TOS,
-	PROP_PATH_MTU_DISCOVERY,
-	PROP_INPUT_KEY,
-	PROP_OUTPUT_KEY,
-	PROP_ENCAPSULATION_LIMIT,
-	PROP_FLOW_LABEL,
-	PROP_MTU,
-	PROP_FLAGS,
+G_DEFINE_TYPE (NMSettingIPTunnel, nm_setting_ip_tunnel, NM_TYPE_SETTING)
 
-	LAST_PROP
-};
+#define NM_SETTING_IP_TUNNEL_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), NM_TYPE_SETTING_IP_TUNNEL, NMSettingIPTunnelPrivate))
+
+/*****************************************************************************/
 
 /**
  * nm_setting_ip_tunnel_get_parent:
@@ -474,77 +475,54 @@ verify (NMSetting *setting, NMConnection *connection, GError **error)
 	return TRUE;
 }
 
-/**
- * nm_setting_ip_tunnel_new:
- *
- * Creates a new #NMSettingIPTunnel object with default values.
- *
- * Returns: (transfer full): the new empty #NMSettingIPTunnel object
- *
- * Since: 1.2
- **/
-NMSetting *
-nm_setting_ip_tunnel_new (void)
-{
-	return (NMSetting *) g_object_new (NM_TYPE_SETTING_IP_TUNNEL, NULL);
-}
-
-static void
-nm_setting_ip_tunnel_init (NMSettingIPTunnel *setting)
-{
-}
+/*****************************************************************************/
 
 static void
-set_property (GObject *object, guint prop_id,
-              const GValue *value, GParamSpec *pspec)
+get_property (GObject *object, guint prop_id,
+              GValue *value, GParamSpec *pspec)
 {
 	NMSettingIPTunnel *setting = NM_SETTING_IP_TUNNEL (object);
 	NMSettingIPTunnelPrivate *priv = NM_SETTING_IP_TUNNEL_GET_PRIVATE (setting);
 
 	switch (prop_id) {
 	case PROP_PARENT:
-		g_free (priv->parent);
-		priv->parent = g_value_dup_string (value);
+		g_value_set_string (value, priv->parent);
 		break;
 	case PROP_MODE:
-		priv->mode = g_value_get_uint (value);
+		g_value_set_uint (value, priv->mode);
 		break;
 	case PROP_LOCAL:
-		g_free (priv->local);
-		priv->local = g_value_dup_string (value);
+		g_value_set_string (value, priv->local);
 		break;
 	case PROP_REMOTE:
-		g_free (priv->remote);
-		priv->remote = g_value_dup_string (value);
+		g_value_set_string (value, priv->remote);
 		break;
 	case PROP_TTL:
-		priv->ttl = g_value_get_uint (value);
+		g_value_set_uint (value, priv->ttl);
 		break;
 	case PROP_TOS:
-		priv->tos = g_value_get_uint (value);
+		g_value_set_uint (value, priv->tos);
 		break;
 	case PROP_PATH_MTU_DISCOVERY:
-		priv->path_mtu_discovery = g_value_get_boolean (value);
+		g_value_set_boolean (value, priv->path_mtu_discovery);
 		break;
 	case PROP_INPUT_KEY:
-		g_free (priv->input_key);
-		priv->input_key = g_value_dup_string (value);
+		g_value_set_string (value, priv->input_key);
 		break;
 	case PROP_OUTPUT_KEY:
-		g_free (priv->output_key);
-		priv->output_key = g_value_dup_string (value);
+		g_value_set_string (value, priv->output_key);
 		break;
 	case PROP_ENCAPSULATION_LIMIT:
-		priv->encapsulation_limit = g_value_get_uint (value);
+		g_value_set_uint (value, priv->encapsulation_limit);
 		break;
 	case PROP_FLOW_LABEL:
-		priv->flow_label = g_value_get_uint (value);
+		g_value_set_uint (value, priv->flow_label);
 		break;
 	case PROP_MTU:
-		priv->mtu = g_value_get_uint (value);
+		g_value_set_uint (value, priv->mtu);
 		break;
 	case PROP_FLAGS:
-		priv->flags = g_value_get_uint (value);
+		g_value_set_uint (value, priv->flags);
 		break;
 	default:
 		G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
@@ -553,51 +531,56 @@ set_property (GObject *object, guint prop_id,
 }
 
 static void
-get_property (GObject *object, guint prop_id,
-              GValue *value, GParamSpec *pspec)
+set_property (GObject *object, guint prop_id,
+              const GValue *value, GParamSpec *pspec)
 {
 	NMSettingIPTunnel *setting = NM_SETTING_IP_TUNNEL (object);
 	NMSettingIPTunnelPrivate *priv = NM_SETTING_IP_TUNNEL_GET_PRIVATE (setting);
 
 	switch (prop_id) {
 	case PROP_PARENT:
-		g_value_set_string (value, priv->parent);
+		g_free (priv->parent);
+		priv->parent = g_value_dup_string (value);
 		break;
 	case PROP_MODE:
-		g_value_set_uint (value, priv->mode);
+		priv->mode = g_value_get_uint (value);
 		break;
 	case PROP_LOCAL:
-		g_value_set_string (value, priv->local);
+		g_free (priv->local);
+		priv->local = g_value_dup_string (value);
 		break;
 	case PROP_REMOTE:
-		g_value_set_string (value, priv->remote);
+		g_free (priv->remote);
+		priv->remote = g_value_dup_string (value);
 		break;
 	case PROP_TTL:
-		g_value_set_uint (value, priv->ttl);
+		priv->ttl = g_value_get_uint (value);
 		break;
 	case PROP_TOS:
-		g_value_set_uint (value, priv->tos);
+		priv->tos = g_value_get_uint (value);
 		break;
 	case PROP_PATH_MTU_DISCOVERY:
-		g_value_set_boolean (value, priv->path_mtu_discovery);
+		priv->path_mtu_discovery = g_value_get_boolean (value);
 		break;
 	case PROP_INPUT_KEY:
-		g_value_set_string (value, priv->input_key);
+		g_free (priv->input_key);
+		priv->input_key = g_value_dup_string (value);
 		break;
 	case PROP_OUTPUT_KEY:
-		g_value_set_string (value, priv->output_key);
+		g_free (priv->output_key);
+		priv->output_key = g_value_dup_string (value);
 		break;
 	case PROP_ENCAPSULATION_LIMIT:
-		g_value_set_uint (value, priv->encapsulation_limit);
+		priv->encapsulation_limit = g_value_get_uint (value);
 		break;
 	case PROP_FLOW_LABEL:
-		g_value_set_uint (value, priv->flow_label);
+		priv->flow_label = g_value_get_uint (value);
 		break;
 	case PROP_MTU:
-		g_value_set_uint (value, priv->mtu);
+		priv->mtu = g_value_get_uint (value);
 		break;
 	case PROP_FLAGS:
-		g_value_set_uint (value, priv->flags);
+		priv->flags = g_value_get_uint (value);
 		break;
 	default:
 		G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
@@ -605,6 +588,28 @@ get_property (GObject *object, guint prop_id,
 	}
 }
 
+/*****************************************************************************/
+
+static void
+nm_setting_ip_tunnel_init (NMSettingIPTunnel *setting)
+{
+}
+
+/**
+ * nm_setting_ip_tunnel_new:
+ *
+ * Creates a new #NMSettingIPTunnel object with default values.
+ *
+ * Returns: (transfer full): the new empty #NMSettingIPTunnel object
+ *
+ * Since: 1.2
+ **/
+NMSetting *
+nm_setting_ip_tunnel_new (void)
+{
+	return (NMSetting *) g_object_new (NM_TYPE_SETTING_IP_TUNNEL, NULL);
+}
+
 static void
 finalize (GObject *object)
 {
@@ -628,8 +633,8 @@ nm_setting_ip_tunnel_class_init (NMSettingIPTunnelClass *klass)
 
 	g_type_class_add_private (klass, sizeof (NMSettingIPTunnelPrivate));
 
-	object_class->set_property = set_property;
 	object_class->get_property = get_property;
+	object_class->set_property = set_property;
 	object_class->finalize     = finalize;
 
 	setting_class->verify = verify;
@@ -643,13 +648,12 @@ nm_setting_ip_tunnel_class_init (NMSettingIPTunnelClass *klass)
 	 *
 	 * Since: 1.2
 	 **/
-	g_object_class_install_property
-		(object_class, PROP_PARENT,
-		 g_param_spec_string (NM_SETTING_IP_TUNNEL_PARENT, "", "",
-		                      NULL,
-		                      G_PARAM_READWRITE |
-		                      NM_SETTING_PARAM_INFERRABLE |
-		                      G_PARAM_STATIC_STRINGS));
+	obj_properties[PROP_PARENT] =
+	    g_param_spec_string (NM_SETTING_IP_TUNNEL_PARENT, "", "",
+	                         NULL,
+	                         G_PARAM_READWRITE |
+	                         NM_SETTING_PARAM_INFERRABLE |
+	                         G_PARAM_STATIC_STRINGS);
 
 	/**
 	 * NMSettingIPTunnel:mode:
@@ -659,13 +663,12 @@ nm_setting_ip_tunnel_class_init (NMSettingIPTunnelClass *klass)
 	 *
 	 * Since: 1.2
 	 **/
-	g_object_class_install_property
-		(object_class, PROP_MODE,
-		 g_param_spec_uint (NM_SETTING_IP_TUNNEL_MODE, "", "",
-		                    0, G_MAXUINT, 0,
-		                    G_PARAM_READWRITE |
-		                    NM_SETTING_PARAM_INFERRABLE |
-		                    G_PARAM_STATIC_STRINGS));
+	obj_properties[PROP_MODE] =
+	    g_param_spec_uint (NM_SETTING_IP_TUNNEL_MODE, "", "",
+	                       0, G_MAXUINT, 0,
+	                       G_PARAM_READWRITE |
+	                       NM_SETTING_PARAM_INFERRABLE |
+	                       G_PARAM_STATIC_STRINGS);
 
 	/**
 	 * NMSettingIPTunnel:local:
@@ -675,13 +678,12 @@ nm_setting_ip_tunnel_class_init (NMSettingIPTunnelClass *klass)
 	 *
 	 * Since: 1.2
 	 **/
-	g_object_class_install_property
-		(object_class, PROP_LOCAL,
-		 g_param_spec_string (NM_SETTING_IP_TUNNEL_LOCAL, "", "",
-		                      NULL,
-		                      G_PARAM_READWRITE |
-		                      NM_SETTING_PARAM_INFERRABLE |
-		                      G_PARAM_STATIC_STRINGS));
+	obj_properties[PROP_LOCAL] =
+	    g_param_spec_string (NM_SETTING_IP_TUNNEL_LOCAL, "", "",
+	                         NULL,
+	                         G_PARAM_READWRITE |
+	                         NM_SETTING_PARAM_INFERRABLE |
+	                         G_PARAM_STATIC_STRINGS);
 
 	/**
 	 * NMSettingIPTunnel:remote:
@@ -691,13 +693,12 @@ nm_setting_ip_tunnel_class_init (NMSettingIPTunnelClass *klass)
 	 *
 	 * Since: 1.2
 	 **/
-	g_object_class_install_property
-		(object_class, PROP_REMOTE,
-		 g_param_spec_string (NM_SETTING_IP_TUNNEL_REMOTE, "", "",
-		                      NULL,
-		                      G_PARAM_READWRITE |
-		                      NM_SETTING_PARAM_INFERRABLE |
-		                      G_PARAM_STATIC_STRINGS));
+	obj_properties[PROP_REMOTE] =
+	    g_param_spec_string (NM_SETTING_IP_TUNNEL_REMOTE, "", "",
+	                         NULL,
+	                         G_PARAM_READWRITE |
+	                         NM_SETTING_PARAM_INFERRABLE |
+	                         G_PARAM_STATIC_STRINGS);
 
 	/**
 	 * NMSettingIPTunnel:ttl
@@ -707,14 +708,13 @@ nm_setting_ip_tunnel_class_init (NMSettingIPTunnelClass *klass)
 	 *
 	 * Since: 1.2
 	 **/
-	g_object_class_install_property
-		(object_class, PROP_TTL,
-		 g_param_spec_uint (NM_SETTING_IP_TUNNEL_TTL, "", "",
-		                    0, 255, 0,
-		                    G_PARAM_READWRITE |
-		                    G_PARAM_CONSTRUCT |
-		                    NM_SETTING_PARAM_INFERRABLE |
-		                    G_PARAM_STATIC_STRINGS));
+	obj_properties[PROP_TTL] =
+	    g_param_spec_uint (NM_SETTING_IP_TUNNEL_TTL, "", "",
+	                       0, 255, 0,
+	                       G_PARAM_READWRITE |
+	                       G_PARAM_CONSTRUCT |
+	                       NM_SETTING_PARAM_INFERRABLE |
+	                       G_PARAM_STATIC_STRINGS);
 
 	/**
 	 * NMSettingIPTunnel:tos
@@ -724,14 +724,13 @@ nm_setting_ip_tunnel_class_init (NMSettingIPTunnelClass *klass)
 	 *
 	 * Since: 1.2
 	 **/
-	g_object_class_install_property
-		(object_class, PROP_TOS,
-		 g_param_spec_uint (NM_SETTING_IP_TUNNEL_TOS, "", "",
-		                    0, 255, 0,
-		                    G_PARAM_READWRITE |
-		                    G_PARAM_CONSTRUCT |
-		                    NM_SETTING_PARAM_INFERRABLE |
-		                    G_PARAM_STATIC_STRINGS));
+	obj_properties[PROP_TOS] =
+	    g_param_spec_uint (NM_SETTING_IP_TUNNEL_TOS, "", "",
+	                       0, 255, 0,
+	                       G_PARAM_READWRITE |
+	                       G_PARAM_CONSTRUCT |
+	                       NM_SETTING_PARAM_INFERRABLE |
+	                       G_PARAM_STATIC_STRINGS);
 
 	/**
 	 * NMSettingIPTunnel:path-mtu-discovery
@@ -740,14 +739,13 @@ nm_setting_ip_tunnel_class_init (NMSettingIPTunnelClass *klass)
 	 *
 	 * Since: 1.2
 	 **/
-	g_object_class_install_property
-		(object_class, PROP_PATH_MTU_DISCOVERY,
-		 g_param_spec_boolean (NM_SETTING_IP_TUNNEL_PATH_MTU_DISCOVERY, "", "",
-		                       TRUE,
-		                       G_PARAM_READWRITE |
-		                       G_PARAM_CONSTRUCT |
-		                       NM_SETTING_PARAM_INFERRABLE |
-		                       G_PARAM_STATIC_STRINGS));
+	obj_properties[PROP_PATH_MTU_DISCOVERY] =
+	    g_param_spec_boolean (NM_SETTING_IP_TUNNEL_PATH_MTU_DISCOVERY, "", "",
+	                          TRUE,
+	                          G_PARAM_READWRITE |
+	                          G_PARAM_CONSTRUCT |
+	                          NM_SETTING_PARAM_INFERRABLE |
+	                          G_PARAM_STATIC_STRINGS);
 
 	/**
 	 * NMSettingIPTunnel:input-key:
@@ -757,13 +755,12 @@ nm_setting_ip_tunnel_class_init (NMSettingIPTunnelClass *klass)
 	 *
 	 * Since: 1.2
 	 **/
-	g_object_class_install_property
-		(object_class, PROP_INPUT_KEY,
-		 g_param_spec_string (NM_SETTING_IP_TUNNEL_INPUT_KEY, "", "",
-		                      NULL,
-		                      G_PARAM_READWRITE |
-		                      NM_SETTING_PARAM_INFERRABLE |
-		                      G_PARAM_STATIC_STRINGS));
+	obj_properties[PROP_INPUT_KEY] =
+	    g_param_spec_string (NM_SETTING_IP_TUNNEL_INPUT_KEY, "", "",
+	                         NULL,
+	                         G_PARAM_READWRITE |
+	                         NM_SETTING_PARAM_INFERRABLE |
+	                         G_PARAM_STATIC_STRINGS);
 
 	/**
 	 * NMSettingIPTunnel:output-key:
@@ -773,13 +770,12 @@ nm_setting_ip_tunnel_class_init (NMSettingIPTunnelClass *klass)
 	 *
 	 * Since: 1.2
 	 **/
-	g_object_class_install_property
-		(object_class, PROP_OUTPUT_KEY,
-		 g_param_spec_string (NM_SETTING_IP_TUNNEL_OUTPUT_KEY, "", "",
-		                      NULL,
-		                      G_PARAM_READWRITE |
-		                      NM_SETTING_PARAM_INFERRABLE |
-		                      G_PARAM_STATIC_STRINGS));
+	obj_properties[PROP_OUTPUT_KEY] =
+	    g_param_spec_string (NM_SETTING_IP_TUNNEL_OUTPUT_KEY, "", "",
+	                         NULL,
+	                         G_PARAM_READWRITE |
+	                         NM_SETTING_PARAM_INFERRABLE |
+	                         G_PARAM_STATIC_STRINGS);
 
 	/**
 	 * NMSettingIPTunnel:encapsulation-limit:
@@ -789,14 +785,13 @@ nm_setting_ip_tunnel_class_init (NMSettingIPTunnelClass *klass)
 	 *
 	 * Since: 1.2
 	 **/
-	g_object_class_install_property
-		(object_class, PROP_ENCAPSULATION_LIMIT,
-		 g_param_spec_uint (NM_SETTING_IP_TUNNEL_ENCAPSULATION_LIMIT, "", "",
-		                    0, 255, 0,
-		                    G_PARAM_READWRITE |
-		                    G_PARAM_CONSTRUCT |
-		                    NM_SETTING_PARAM_INFERRABLE |
-		                    G_PARAM_STATIC_STRINGS));
+	obj_properties[PROP_ENCAPSULATION_LIMIT] =
+	    g_param_spec_uint (NM_SETTING_IP_TUNNEL_ENCAPSULATION_LIMIT, "", "",
+	                       0, 255, 0,
+	                       G_PARAM_READWRITE |
+	                       G_PARAM_CONSTRUCT |
+	                       NM_SETTING_PARAM_INFERRABLE |
+	                       G_PARAM_STATIC_STRINGS);
 
 	/**
 	 * NMSettingIPTunnel:flow-label:
@@ -806,14 +801,13 @@ nm_setting_ip_tunnel_class_init (NMSettingIPTunnelClass *klass)
 	 *
 	 * Since: 1.2
 	 **/
-	g_object_class_install_property
-		(object_class, PROP_FLOW_LABEL,
-		 g_param_spec_uint (NM_SETTING_IP_TUNNEL_FLOW_LABEL, "", "",
-		                    0, (1 << 20) - 1, 0,
-		                    G_PARAM_READWRITE |
-		                    G_PARAM_CONSTRUCT |
-		                    NM_SETTING_PARAM_INFERRABLE |
-		                    G_PARAM_STATIC_STRINGS));
+	obj_properties[PROP_FLOW_LABEL] =
+	    g_param_spec_uint (NM_SETTING_IP_TUNNEL_FLOW_LABEL, "", "",
+	                       0, (1 << 20) - 1, 0,
+	                       G_PARAM_READWRITE |
+	                       G_PARAM_CONSTRUCT |
+	                       NM_SETTING_PARAM_INFERRABLE |
+	                       G_PARAM_STATIC_STRINGS);
 
 	/**
 	 * NMSettingIPTunnel:mtu:
@@ -823,14 +817,13 @@ nm_setting_ip_tunnel_class_init (NMSettingIPTunnelClass *klass)
 	 *
 	 * Since: 1.2
 	 **/
-	g_object_class_install_property
-		(object_class, PROP_MTU,
-		 g_param_spec_uint (NM_SETTING_IP_TUNNEL_MTU, "", "",
-		                    0, G_MAXUINT, 0,
-		                    G_PARAM_READWRITE |
-		                    G_PARAM_CONSTRUCT |
-		                    NM_SETTING_PARAM_FUZZY_IGNORE |
-		                    G_PARAM_STATIC_STRINGS));
+	obj_properties[PROP_MTU] =
+	    g_param_spec_uint (NM_SETTING_IP_TUNNEL_MTU, "", "",
+	                       0, G_MAXUINT, 0,
+	                       G_PARAM_READWRITE |
+	                       G_PARAM_CONSTRUCT |
+	                       NM_SETTING_PARAM_FUZZY_IGNORE |
+	                       G_PARAM_STATIC_STRINGS);
 
 	/**
 	 * NMSettingIPTunnel:flags:
@@ -843,13 +836,14 @@ nm_setting_ip_tunnel_class_init (NMSettingIPTunnelClass *klass)
 	 *
 	 * Since: 1.12
 	 **/
-	g_object_class_install_property
-		(object_class, PROP_FLAGS,
-		 g_param_spec_uint (NM_SETTING_IP_TUNNEL_FLAGS, "", "",
-		                    0, G_MAXUINT32, 0,
-		                    G_PARAM_READWRITE |
-		                    NM_SETTING_PARAM_FUZZY_IGNORE |
-		                    G_PARAM_STATIC_STRINGS));
+	obj_properties[PROP_FLAGS] =
+	    g_param_spec_uint (NM_SETTING_IP_TUNNEL_FLAGS, "", "",
+	                       0, G_MAXUINT32, 0,
+	                       G_PARAM_READWRITE |
+	                       NM_SETTING_PARAM_FUZZY_IGNORE |
+	                       G_PARAM_STATIC_STRINGS);
+
+	g_object_class_install_properties (object_class, _PROPERTY_ENUMS_LAST, obj_properties);
 
 	_nm_setting_class_commit (setting_class, NM_META_SETTING_TYPE_IP_TUNNEL);
 }
diff --git a/libnm-core/nm-setting-ip4-config.c b/libnm-core/nm-setting-ip4-config.c
index 19f1cc8d..59529bc2 100644
--- a/libnm-core/nm-setting-ip4-config.c
+++ b/libnm-core/nm-setting-ip4-config.c
@@ -21,9 +21,10 @@
 
 #include "nm-default.h"
 
+#include "nm-setting-ip4-config.h"
+
 #include <string.h>
 
-#include "nm-setting-ip4-config.h"
 #include "nm-setting-private.h"
 
 /**
@@ -50,35 +51,23 @@
  * connection.
  **/
 
-G_DEFINE_TYPE (NMSettingIP4Config, nm_setting_ip4_config, NM_TYPE_SETTING_IP_CONFIG)
+/*****************************************************************************/
 
-#define NM_SETTING_IP4_CONFIG_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), NM_TYPE_SETTING_IP4_CONFIG, NMSettingIP4ConfigPrivate))
+NM_GOBJECT_PROPERTIES_DEFINE_BASE (
+	PROP_DHCP_CLIENT_ID,
+	PROP_DHCP_FQDN,
+);
 
 typedef struct {
 	char *dhcp_client_id;
 	char *dhcp_fqdn;
 } NMSettingIP4ConfigPrivate;
 
-enum {
-	PROP_0,
-	PROP_DHCP_CLIENT_ID,
-	PROP_DHCP_FQDN,
+G_DEFINE_TYPE (NMSettingIP4Config, nm_setting_ip4_config, NM_TYPE_SETTING_IP_CONFIG)
 
-	LAST_PROP
-};
+#define NM_SETTING_IP4_CONFIG_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), NM_TYPE_SETTING_IP4_CONFIG, NMSettingIP4ConfigPrivate))
 
-/**
- * nm_setting_ip4_config_new:
- *
- * Creates a new #NMSettingIP4Config object with default values.
- *
- * Returns: (transfer full): the new empty #NMSettingIP4Config object
- **/
-NMSetting *
-nm_setting_ip4_config_new (void)
-{
-	return (NMSetting *) g_object_new (NM_TYPE_SETTING_IP4_CONFIG, NULL);
-}
+/*****************************************************************************/
 
 /**
  * nm_setting_ip4_config_get_dhcp_client_id:
@@ -252,62 +241,6 @@ verify (NMSetting *setting, NMConnection *connection, GError **error)
 	return TRUE;
 }
 
-static void
-nm_setting_ip4_config_init (NMSettingIP4Config *setting)
-{
-}
-
-static void
-finalize (GObject *object)
-{
-	NMSettingIP4ConfigPrivate *priv = NM_SETTING_IP4_CONFIG_GET_PRIVATE (object);
-
-	g_free (priv->dhcp_client_id);
-	g_free (priv->dhcp_fqdn);
-
-	G_OBJECT_CLASS (nm_setting_ip4_config_parent_class)->finalize (object);
-}
-
-static void
-set_property (GObject *object, guint prop_id,
-              const GValue *value, GParamSpec *pspec)
-{
-	NMSettingIP4ConfigPrivate *priv = NM_SETTING_IP4_CONFIG_GET_PRIVATE (object);
-
-	switch (prop_id) {
-	case PROP_DHCP_CLIENT_ID:
-		g_free (priv->dhcp_client_id);
-		priv->dhcp_client_id = g_value_dup_string (value);
-		break;
-	case PROP_DHCP_FQDN:
-		g_free (priv->dhcp_fqdn);
-		priv->dhcp_fqdn = g_value_dup_string (value);
-		break;
-	default:
-		G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
-		break;
-	}
-}
-
-static void
-get_property (GObject *object, guint prop_id,
-              GValue *value, GParamSpec *pspec)
-{
-	NMSettingIP4Config *s_ip4 = NM_SETTING_IP4_CONFIG (object);
-
-	switch (prop_id) {
-	case PROP_DHCP_CLIENT_ID:
-		g_value_set_string (value, nm_setting_ip4_config_get_dhcp_client_id (s_ip4));
-		break;
-	case PROP_DHCP_FQDN:
-		g_value_set_string (value, nm_setting_ip4_config_get_dhcp_fqdn (s_ip4));
-		break;
-	default:
-		G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
-		break;
-	}
-}
-
 static GVariant *
 ip4_dns_to_dbus (const GValue *prop_value)
 {
@@ -376,9 +309,11 @@ ip4_addresses_set (NMSetting  *setting,
 }
 
 static GVariant *
-ip4_address_labels_get (NMSetting    *setting,
+ip4_address_labels_get (const NMSettInfoSetting *sett_info,
+                        guint property_idx,
                         NMConnection *connection,
-                        const char   *property)
+                        NMSetting *setting,
+                        NMConnectionSerializationFlags flags)
 {
 	NMSettingIPConfig *s_ip = NM_SETTING_IP_CONFIG (setting);
 	gboolean have_labels = FALSE;
@@ -386,6 +321,9 @@ ip4_address_labels_get (NMSetting    *setting,
 	GVariant *ret;
 	int num_addrs, i;
 
+	if (flags & NM_CONNECTION_SERIALIZE_ONLY_SECRETS)
+		return NULL;
+
 	num_addrs = nm_setting_ip_config_get_num_addresses (s_ip);
 	for (i = 0; i < num_addrs; i++) {
 		NMIPAddress *addr = nm_setting_ip_config_get_address (s_ip, i);
@@ -414,18 +352,19 @@ ip4_address_labels_get (NMSetting    *setting,
 }
 
 static GVariant *
-ip4_address_data_get (NMSetting    *setting,
+ip4_address_data_get (const NMSettInfoSetting *sett_info,
+                      guint property_idx,
                       NMConnection *connection,
-                      const char   *property)
+                      NMSetting *setting,
+                      NMConnectionSerializationFlags flags)
 {
-	GPtrArray *addrs;
-	GVariant *ret;
+	gs_unref_ptrarray GPtrArray *addrs = NULL;
 
-	g_object_get (setting, NM_SETTING_IP_CONFIG_ADDRESSES, &addrs, NULL);
-	ret = nm_utils_ip_addresses_to_variant (addrs);
-	g_ptr_array_unref (addrs);
+	if (flags & NM_CONNECTION_SERIALIZE_ONLY_SECRETS)
+		return NULL;
 
-	return ret;
+	g_object_get (setting, NM_SETTING_IP_CONFIG_ADDRESSES, &addrs, NULL);
+	return nm_utils_ip_addresses_to_variant (addrs);
 }
 
 static gboolean
@@ -486,18 +425,19 @@ ip4_routes_set (NMSetting  *setting,
 }
 
 static GVariant *
-ip4_route_data_get (NMSetting    *setting,
+ip4_route_data_get (const NMSettInfoSetting *sett_info,
+                    guint property_idx,
                     NMConnection *connection,
-                    const char   *property)
+                    NMSetting *setting,
+                    NMConnectionSerializationFlags flags)
 {
-	GPtrArray *routes;
-	GVariant *ret;
+	gs_unref_ptrarray GPtrArray *routes = NULL;
 
-	g_object_get (setting, NM_SETTING_IP_CONFIG_ROUTES, &routes, NULL);
-	ret = nm_utils_ip_routes_to_variant (routes);
-	g_ptr_array_unref (routes);
+	if (flags & NM_CONNECTION_SERIALIZE_ONLY_SECRETS)
+		return NULL;
 
-	return ret;
+	g_object_get (setting, NM_SETTING_IP_CONFIG_ROUTES, &routes, NULL);
+	return nm_utils_ip_routes_to_variant (routes);
 }
 
 static gboolean
@@ -522,6 +462,79 @@ ip4_route_data_set (NMSetting  *setting,
 	return TRUE;
 }
 
+/*****************************************************************************/
+
+static void
+get_property (GObject *object, guint prop_id,
+              GValue *value, GParamSpec *pspec)
+{
+	NMSettingIP4Config *s_ip4 = NM_SETTING_IP4_CONFIG (object);
+
+	switch (prop_id) {
+	case PROP_DHCP_CLIENT_ID:
+		g_value_set_string (value, nm_setting_ip4_config_get_dhcp_client_id (s_ip4));
+		break;
+	case PROP_DHCP_FQDN:
+		g_value_set_string (value, nm_setting_ip4_config_get_dhcp_fqdn (s_ip4));
+		break;
+	default:
+		G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+		break;
+	}
+}
+
+static void
+set_property (GObject *object, guint prop_id,
+              const GValue *value, GParamSpec *pspec)
+{
+	NMSettingIP4ConfigPrivate *priv = NM_SETTING_IP4_CONFIG_GET_PRIVATE (object);
+
+	switch (prop_id) {
+	case PROP_DHCP_CLIENT_ID:
+		g_free (priv->dhcp_client_id);
+		priv->dhcp_client_id = g_value_dup_string (value);
+		break;
+	case PROP_DHCP_FQDN:
+		g_free (priv->dhcp_fqdn);
+		priv->dhcp_fqdn = g_value_dup_string (value);
+		break;
+	default:
+		G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+		break;
+	}
+}
+
+/*****************************************************************************/
+
+static void
+nm_setting_ip4_config_init (NMSettingIP4Config *setting)
+{
+}
+
+/**
+ * nm_setting_ip4_config_new:
+ *
+ * Creates a new #NMSettingIP4Config object with default values.
+ *
+ * Returns: (transfer full): the new empty #NMSettingIP4Config object
+ **/
+NMSetting *
+nm_setting_ip4_config_new (void)
+{
+	return (NMSetting *) g_object_new (NM_TYPE_SETTING_IP4_CONFIG, NULL);
+}
+
+static void
+finalize (GObject *object)
+{
+	NMSettingIP4ConfigPrivate *priv = NM_SETTING_IP4_CONFIG_GET_PRIVATE (object);
+
+	g_free (priv->dhcp_client_id);
+	g_free (priv->dhcp_fqdn);
+
+	G_OBJECT_CLASS (nm_setting_ip4_config_parent_class)->finalize (object);
+}
+
 static void
 nm_setting_ip4_config_class_init (NMSettingIP4ConfigClass *klass)
 {
@@ -531,8 +544,8 @@ nm_setting_ip4_config_class_init (NMSettingIP4ConfigClass *klass)
 
 	g_type_class_add_private (setting_class, sizeof (NMSettingIP4ConfigPrivate));
 
-	object_class->set_property = set_property;
 	object_class->get_property = get_property;
+	object_class->set_property = set_property;
 	object_class->finalize     = finalize;
 
 	setting_class->verify = verify;
@@ -721,11 +734,16 @@ nm_setting_ip4_config_class_init (NMSettingIP4ConfigClass *klass)
 	 * with type ethernet (01). Currently, these options only work for ethernet
 	 * type of links.
 	 *
+	 * The special value "duid" generates a RFC4361-compliant client identifier based
+	 * on a hash of the interface name as IAID and /etc/machine-id.
+	 *
 	 * The special value "stable" is supported to generate a type 0 client identifier based
-	 * on the stable-id (see connection.stable-id) and a per-host key.
+	 * on the stable-id (see connection.stable-id) and a per-host key. If you set the
+	 * stable-id, you may want to include the "${DEVICE}" or "${MAC}" specifier to get a
+	 * per-device key.
 	 *
-	 * If unset, a globally configured default is used. If still unset, the
-	 * client-id from the last lease is reused.
+	 * If unset, a globally configured default is used. If still unset, the default
+	 * depends on the DHCP plugin.
 	 **/
 	/* ---ifcfg-rh---
 	 * property: dhcp-client-id
@@ -735,12 +753,11 @@ nm_setting_ip4_config_class_init (NMSettingIP4ConfigClass *klass)
 	 * example: DHCP_CLIENT_ID=ax-srv-1; DHCP_CLIENT_ID=01:44:44:44:44:44:44
 	 * ---end---
 	 */
-	g_object_class_install_property
-		(object_class, PROP_DHCP_CLIENT_ID,
-		 g_param_spec_string (NM_SETTING_IP4_CONFIG_DHCP_CLIENT_ID, "", "",
-		                      NULL,
-		                      G_PARAM_READWRITE |
-		                      G_PARAM_STATIC_STRINGS));
+	obj_properties[PROP_DHCP_CLIENT_ID] =
+	    g_param_spec_string (NM_SETTING_IP4_CONFIG_DHCP_CLIENT_ID, "", "",
+	                         NULL,
+	                         G_PARAM_READWRITE |
+	                         G_PARAM_STATIC_STRINGS);
 
 	/* ---ifcfg-rh---
 	 * property: dad-timeout
@@ -779,12 +796,11 @@ nm_setting_ip4_config_class_init (NMSettingIP4ConfigClass *klass)
 	 * example: DHCP_FQDN=foo.bar.com
 	 * ---end---
 	 */
-	g_object_class_install_property
-		(object_class, PROP_DHCP_FQDN,
-		 g_param_spec_string (NM_SETTING_IP4_CONFIG_DHCP_FQDN, "", "",
-		                      NULL,
-		                      G_PARAM_READWRITE |
-		                      G_PARAM_STATIC_STRINGS));
+	obj_properties[PROP_DHCP_FQDN] =
+	    g_param_spec_string (NM_SETTING_IP4_CONFIG_DHCP_FQDN, "", "",
+	                         NULL,
+	                         G_PARAM_READWRITE |
+	                         G_PARAM_STATIC_STRINGS);
 
 	/* IP4-specific property overrides */
 
@@ -890,6 +906,8 @@ nm_setting_ip4_config_class_init (NMSettingIP4ConfigClass *klass)
 	                                    ip4_route_data_get,
 	                                    ip4_route_data_set);
 
+	g_object_class_install_properties (object_class, _PROPERTY_ENUMS_LAST, obj_properties);
+
 	_nm_setting_class_commit_full (setting_class, NM_META_SETTING_TYPE_IP4_CONFIG,
 	                               NULL, properties_override);
 }
diff --git a/libnm-core/nm-setting-ip6-config.c b/libnm-core/nm-setting-ip6-config.c
index a55fd801..bf3acf96 100644
--- a/libnm-core/nm-setting-ip6-config.c
+++ b/libnm-core/nm-setting-ip6-config.c
@@ -52,9 +52,14 @@
  * supported.
  **/
 
-G_DEFINE_TYPE (NMSettingIP6Config, nm_setting_ip6_config, NM_TYPE_SETTING_IP_CONFIG)
+/*****************************************************************************/
 
-#define NM_SETTING_IP6_CONFIG_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), NM_TYPE_SETTING_IP6_CONFIG, NMSettingIP6ConfigPrivate))
+NM_GOBJECT_PROPERTIES_DEFINE_BASE (
+	PROP_IP6_PRIVACY,
+	PROP_ADDR_GEN_MODE,
+	PROP_TOKEN,
+	PROP_DHCP_DUID,
+);
 
 typedef struct {
 	NMSettingIP6ConfigPrivacy ip6_privacy;
@@ -63,28 +68,11 @@ typedef struct {
 	char *dhcp_duid;
 } NMSettingIP6ConfigPrivate;
 
-enum {
-	PROP_0,
-	PROP_IP6_PRIVACY,
-	PROP_ADDR_GEN_MODE,
-	PROP_TOKEN,
-	PROP_DHCP_DUID,
+G_DEFINE_TYPE (NMSettingIP6Config, nm_setting_ip6_config, NM_TYPE_SETTING_IP_CONFIG)
 
-	LAST_PROP
-};
+#define NM_SETTING_IP6_CONFIG_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), NM_TYPE_SETTING_IP6_CONFIG, NMSettingIP6ConfigPrivate))
 
-/**
- * nm_setting_ip6_config_new:
- *
- * Creates a new #NMSettingIP6Config object with default values.
- *
- * Returns: (transfer full): the new empty #NMSettingIP6Config object
- **/
-NMSetting *
-nm_setting_ip6_config_new (void)
-{
-	return (NMSetting *) g_object_new (NM_TYPE_SETTING_IP6_CONFIG, NULL);
-}
+/*****************************************************************************/
 
 /**
  * nm_setting_ip6_config_get_ip6_privacy:
@@ -312,11 +300,6 @@ verify (NMSetting *setting, NMConnection *connection, GError **error)
 	return TRUE;
 }
 
-static void
-nm_setting_ip6_config_init (NMSettingIP6Config *setting)
-{
-}
-
 static GVariant *
 ip6_dns_to_dbus (const GValue *prop_value)
 {
@@ -374,18 +357,19 @@ ip6_addresses_set (NMSetting  *setting,
 }
 
 static GVariant *
-ip6_address_data_get (NMSetting    *setting,
+ip6_address_data_get (const NMSettInfoSetting *sett_info,
+                      guint property_idx,
                       NMConnection *connection,
-                      const char   *property)
+                      NMSetting *setting,
+                      NMConnectionSerializationFlags flags)
 {
-	GPtrArray *addrs;
-	GVariant *ret;
+	gs_unref_ptrarray GPtrArray *addrs = NULL;
 
-	g_object_get (setting, NM_SETTING_IP_CONFIG_ADDRESSES, &addrs, NULL);
-	ret = nm_utils_ip_addresses_to_variant (addrs);
-	g_ptr_array_unref (addrs);
+	if (flags & NM_CONNECTION_SERIALIZE_ONLY_SECRETS)
+		return NULL;
 
-	return ret;
+	g_object_get (setting, NM_SETTING_IP_CONFIG_ADDRESSES, &addrs, NULL);
+	return nm_utils_ip_addresses_to_variant (addrs);
 }
 
 static gboolean
@@ -446,18 +430,19 @@ ip6_routes_set (NMSetting  *setting,
 }
 
 static GVariant *
-ip6_route_data_get (NMSetting    *setting,
+ip6_route_data_get (const NMSettInfoSetting *sett_info,
+                    guint property_idx,
                     NMConnection *connection,
-                    const char   *property)
+                    NMSetting *setting,
+                    NMConnectionSerializationFlags flags)
 {
-	GPtrArray *routes;
-	GVariant *ret;
+	gs_unref_ptrarray GPtrArray *routes = NULL;
 
-	g_object_get (setting, NM_SETTING_IP_CONFIG_ROUTES, &routes, NULL);
-	ret = nm_utils_ip_routes_to_variant (routes);
-	g_ptr_array_unref (routes);
+	if (flags & NM_CONNECTION_SERIALIZE_ONLY_SECRETS)
+		return NULL;
 
-	return ret;
+	g_object_get (setting, NM_SETTING_IP_CONFIG_ROUTES, &routes, NULL);
+	return nm_utils_ip_routes_to_variant (routes);
 }
 
 static gboolean
@@ -482,26 +467,26 @@ ip6_route_data_set (NMSetting  *setting,
 	return TRUE;
 }
 
+/*****************************************************************************/
+
 static void
-set_property (GObject *object, guint prop_id,
-              const GValue *value, GParamSpec *pspec)
+get_property (GObject *object, guint prop_id,
+              GValue *value, GParamSpec *pspec)
 {
 	NMSettingIP6ConfigPrivate *priv = NM_SETTING_IP6_CONFIG_GET_PRIVATE (object);
 
 	switch (prop_id) {
 	case PROP_IP6_PRIVACY:
-		priv->ip6_privacy = g_value_get_enum (value);
+		g_value_set_enum (value, priv->ip6_privacy);
 		break;
 	case PROP_ADDR_GEN_MODE:
-		priv->addr_gen_mode = g_value_get_int (value);
+		g_value_set_int (value, priv->addr_gen_mode);
 		break;
 	case PROP_TOKEN:
-		g_free (priv->token);
-		priv->token = g_value_dup_string (value);
+		g_value_set_string (value, priv->token);
 		break;
 	case PROP_DHCP_DUID:
-		g_free (priv->dhcp_duid);
-		priv->dhcp_duid = g_value_dup_string (value);
+		g_value_set_string (value, priv->dhcp_duid);
 		break;
 	default:
 		G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
@@ -510,23 +495,25 @@ set_property (GObject *object, guint prop_id,
 }
 
 static void
-get_property (GObject *object, guint prop_id,
-              GValue *value, GParamSpec *pspec)
+set_property (GObject *object, guint prop_id,
+              const GValue *value, GParamSpec *pspec)
 {
 	NMSettingIP6ConfigPrivate *priv = NM_SETTING_IP6_CONFIG_GET_PRIVATE (object);
 
 	switch (prop_id) {
 	case PROP_IP6_PRIVACY:
-		g_value_set_enum (value, priv->ip6_privacy);
+		priv->ip6_privacy = g_value_get_enum (value);
 		break;
 	case PROP_ADDR_GEN_MODE:
-		g_value_set_int (value, priv->addr_gen_mode);
+		priv->addr_gen_mode = g_value_get_int (value);
 		break;
 	case PROP_TOKEN:
-		g_value_set_string (value, priv->token);
+		g_free (priv->token);
+		priv->token = g_value_dup_string (value);
 		break;
 	case PROP_DHCP_DUID:
-		g_value_set_string (value, priv->dhcp_duid);
+		g_free (priv->dhcp_duid);
+		priv->dhcp_duid = g_value_dup_string (value);
 		break;
 	default:
 		G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
@@ -534,6 +521,26 @@ get_property (GObject *object, guint prop_id,
 	}
 }
 
+/*****************************************************************************/
+
+static void
+nm_setting_ip6_config_init (NMSettingIP6Config *setting)
+{
+}
+
+/**
+ * nm_setting_ip6_config_new:
+ *
+ * Creates a new #NMSettingIP6Config object with default values.
+ *
+ * Returns: (transfer full): the new empty #NMSettingIP6Config object
+ **/
+NMSetting *
+nm_setting_ip6_config_new (void)
+{
+	return (NMSetting *) g_object_new (NM_TYPE_SETTING_IP6_CONFIG, NULL);
+}
+
 static void
 finalize (GObject *object)
 {
@@ -555,8 +562,8 @@ nm_setting_ip6_config_class_init (NMSettingIP6ConfigClass *klass)
 
 	g_type_class_add_private (klass, sizeof (NMSettingIP6ConfigPrivate));
 
-	object_class->set_property = set_property;
 	object_class->get_property = get_property;
+	object_class->set_property = set_property;
 	object_class->finalize     = finalize;
 
 	setting_class->verify = verify;
@@ -747,14 +754,13 @@ nm_setting_ip6_config_class_init (NMSettingIP6ConfigClass *klass)
 	 * example: IPV6_PRIVACY=rfc3041 IPV6_PRIVACY_PREFER_PUBLIC_IP=yes
 	 * ---end---
 	 */
-	g_object_class_install_property
-		(object_class, PROP_IP6_PRIVACY,
-		 g_param_spec_enum (NM_SETTING_IP6_CONFIG_IP6_PRIVACY, "", "",
-		                    NM_TYPE_SETTING_IP6_CONFIG_PRIVACY,
-		                    NM_SETTING_IP6_CONFIG_PRIVACY_UNKNOWN,
-		                    G_PARAM_READWRITE |
-		                    G_PARAM_CONSTRUCT |
-		                    G_PARAM_STATIC_STRINGS));
+	obj_properties[PROP_IP6_PRIVACY] =
+	    g_param_spec_enum (NM_SETTING_IP6_CONFIG_IP6_PRIVACY, "", "",
+	                       NM_TYPE_SETTING_IP6_CONFIG_PRIVACY,
+	                       NM_SETTING_IP6_CONFIG_PRIVACY_UNKNOWN,
+	                       G_PARAM_READWRITE |
+	                       G_PARAM_CONSTRUCT |
+	                       G_PARAM_STATIC_STRINGS);
 
 	/**
 	 * NMSettingIP6Config:addr-gen-mode:
@@ -797,14 +803,13 @@ nm_setting_ip6_config_class_init (NMSettingIP6ConfigClass *klass)
 	 * example: IPV6_ADDR_GEN_MODE=stable-privacy
 	 * ---end---
 	 */
-	g_object_class_install_property
-		(object_class, PROP_ADDR_GEN_MODE,
-		 g_param_spec_int (NM_SETTING_IP6_CONFIG_ADDR_GEN_MODE, "", "",
-		                   G_MININT, G_MAXINT,
-		                   NM_SETTING_IP6_CONFIG_ADDR_GEN_MODE_STABLE_PRIVACY,
-		                   G_PARAM_READWRITE |
-		                   G_PARAM_CONSTRUCT |
-		                   G_PARAM_STATIC_STRINGS));
+	obj_properties[PROP_ADDR_GEN_MODE] =
+	    g_param_spec_int (NM_SETTING_IP6_CONFIG_ADDR_GEN_MODE, "", "",
+	                      G_MININT, G_MAXINT,
+	                      NM_SETTING_IP6_CONFIG_ADDR_GEN_MODE_STABLE_PRIVACY,
+	                      G_PARAM_READWRITE |
+	                      G_PARAM_CONSTRUCT |
+	                      G_PARAM_STATIC_STRINGS);
 
 	/**
 	 * NMSettingIP6Config:token:
@@ -821,13 +826,12 @@ nm_setting_ip6_config_class_init (NMSettingIP6ConfigClass *klass)
 	 * example: IPV6_TOKEN=::53
 	 * ---end---
 	 */
-	g_object_class_install_property
-		(object_class, PROP_TOKEN,
-		 g_param_spec_string (NM_SETTING_IP6_CONFIG_TOKEN, "", "",
-		                      NULL,
-		                      G_PARAM_READWRITE |
-		                      NM_SETTING_PARAM_INFERRABLE |
-		                      G_PARAM_STATIC_STRINGS));
+	obj_properties[PROP_TOKEN] =
+	    g_param_spec_string (NM_SETTING_IP6_CONFIG_TOKEN, "", "",
+	                         NULL,
+	                         G_PARAM_READWRITE |
+	                         NM_SETTING_PARAM_INFERRABLE |
+	                         G_PARAM_STATIC_STRINGS);
 
 	/**
 	 * NMSettingIP6Config:dhcp-duid:
@@ -852,7 +856,8 @@ nm_setting_ip6_config_class_init (NMSettingIP6ConfigClass *klass)
 	 *
 	 * The special values "stable-llt", "stable-ll" and "stable-uuid" will generate
 	 * a DUID of the corresponding type, derived from the connection's stable-id and
-	 * a per-host unique key.
+	 * a per-host unique key. You may want to include the "${DEVICE}" or "${MAC}" specifier
+	 * in the stable-id, in case this profile gets activated on multiple devices.
 	 * So, the link-layer address of "stable-ll" and "stable-llt" will be a generated
 	 * address derived from the stable id. The DUID-LLT time value in the "stable-llt"
 	 * option will be picked among a static timespan of three years (the upper bound
@@ -873,12 +878,11 @@ nm_setting_ip6_config_class_init (NMSettingIP6ConfigClass *klass)
 	 * example: DHCPV6_DUID=LL; DHCPV6_DUID=0301deadbeef0001; DHCPV6_DUID=03:01:de:ad:be:ef:00:01
 	 * ---end---
 	 */
-	g_object_class_install_property
-		(object_class, PROP_DHCP_DUID,
-		 g_param_spec_string (NM_SETTING_IP6_CONFIG_DHCP_DUID, "", "",
-		                      NULL,
-		                      G_PARAM_READWRITE |
-		                      G_PARAM_STATIC_STRINGS));
+	obj_properties[PROP_DHCP_DUID] =
+	    g_param_spec_string (NM_SETTING_IP6_CONFIG_DHCP_DUID, "", "",
+	                         NULL,
+	                         G_PARAM_READWRITE |
+	                         G_PARAM_STATIC_STRINGS);
 
 	/* IP6-specific property overrides */
 
@@ -973,6 +977,8 @@ nm_setting_ip6_config_class_init (NMSettingIP6ConfigClass *klass)
 	                                    ip6_route_data_get,
 	                                    ip6_route_data_set);
 
+	g_object_class_install_properties (object_class, _PROPERTY_ENUMS_LAST, obj_properties);
+
 	_nm_setting_class_commit_full (setting_class, NM_META_SETTING_TYPE_IP6_CONFIG,
 	                               NULL, properties_override);
 }
diff --git a/libnm-core/nm-setting-macsec.c b/libnm-core/nm-setting-macsec.c
index 2c7cff23..3d93ac5a 100644
--- a/libnm-core/nm-setting-macsec.c
+++ b/libnm-core/nm-setting-macsec.c
@@ -25,6 +25,8 @@
 #include <stdlib.h>
 #include <string.h>
 
+#include "nm-utils/nm-secret-utils.h"
+
 #include "nm-utils.h"
 #include "nm-core-types-internal.h"
 #include "nm-setting-connection.h"
@@ -40,9 +42,19 @@
  * necessary for connection to MACsec (IEEE 802.1AE) interfaces.
  **/
 
-G_DEFINE_TYPE (NMSettingMacsec, nm_setting_macsec, NM_TYPE_SETTING)
+/*****************************************************************************/
 
-#define NM_SETTING_MACSEC_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), NM_TYPE_SETTING_MACSEC, NMSettingMacsecPrivate))
+NM_GOBJECT_PROPERTIES_DEFINE_BASE (
+	PROP_PARENT,
+	PROP_MODE,
+	PROP_ENCRYPT,
+	PROP_MKA_CAK,
+	PROP_MKA_CAK_FLAGS,
+	PROP_MKA_CKN,
+	PROP_PORT,
+	PROP_VALIDATION,
+	PROP_SEND_SCI,
+);
 
 typedef struct {
 	char *parent;
@@ -56,32 +68,11 @@ typedef struct {
 	NMSettingMacsecValidation validation;
 } NMSettingMacsecPrivate;
 
-NM_GOBJECT_PROPERTIES_DEFINE_BASE (
-	PROP_PARENT,
-	PROP_MODE,
-	PROP_ENCRYPT,
-	PROP_MKA_CAK,
-	PROP_MKA_CAK_FLAGS,
-	PROP_MKA_CKN,
-	PROP_PORT,
-	PROP_VALIDATION,
-	PROP_SEND_SCI,
-);
+G_DEFINE_TYPE (NMSettingMacsec, nm_setting_macsec, NM_TYPE_SETTING)
 
-/**
- * nm_setting_macsec_new:
- *
- * Creates a new #NMSettingMacsec object with default values.
- *
- * Returns: (transfer full): the new empty #NMSettingMacsec object
- *
- * Since: 1.6
- **/
-NMSetting *
-nm_setting_macsec_new (void)
-{
-	return (NMSetting *) g_object_new (NM_TYPE_SETTING_MACSEC, NULL);
-}
+#define NM_SETTING_MACSEC_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), NM_TYPE_SETTING_MACSEC, NMSettingMacsecPrivate))
+
+/*****************************************************************************/
 
 /**
  * nm_setting_macsec_get_parent:
@@ -243,6 +234,12 @@ verify_macsec_key (const char *key, gboolean cak, GError **error)
 {
 	int req_len;
 
+	/* CAK is a connection secret and can be NULL for various
+	 * reasons (agent-owned, no permissions to get secrets, etc.)
+	 */
+	if (cak && !key)
+		return TRUE;
+
 	if (!key || !key[0]) {
 		g_set_error_literal (error,
 		                     NM_CONNECTION_ERROR,
@@ -254,7 +251,7 @@ verify_macsec_key (const char *key, gboolean cak, GError **error)
 	req_len = cak ?
 	    NM_SETTING_MACSEC_MKA_CAK_LENGTH :
 	    NM_SETTING_MACSEC_MKA_CKN_LENGTH;
-	if (strlen (key) != req_len) {
+	if (strlen (key) != (gsize) req_len) {
 		g_set_error (error,
 		             NM_CONNECTION_ERROR,
 		             NM_CONNECTION_ERROR_INVALID_PROPERTY,
@@ -340,6 +337,10 @@ verify (NMSetting *setting, NMConnection *connection, GError **error)
 			g_prefix_error (error, "%s.%s: ", NM_SETTING_MACSEC_SETTING_NAME, NM_SETTING_MACSEC_MKA_CKN);
 			return FALSE;
 		}
+		if (!verify_macsec_key (priv->mka_cak, TRUE, error)) {
+			g_prefix_error (error, "%s.%s: ", NM_SETTING_MACSEC_SETTING_NAME, NM_SETTING_MACSEC_MKA_CAK);
+			return FALSE;
+		}
 	} else if (priv->mode == NM_SETTING_MACSEC_MODE_EAP) {
 		if (!s_8021x) {
 			g_set_error (error,
@@ -350,6 +351,13 @@ verify (NMSetting *setting, NMConnection *connection, GError **error)
 			g_prefix_error (error, "%s: ", NM_SETTING_MACSEC_SETTING_NAME);
 			return FALSE;
 		}
+	} else {
+		g_set_error_literal (error,
+		                     NM_CONNECTION_ERROR,
+		                     NM_CONNECTION_ERROR_INVALID_PROPERTY,
+		                     _("must be either psk (0) or eap (1)"));
+		g_prefix_error (error, "%s.%s: ", NM_SETTING_MACSEC_SETTING_NAME, NM_SETTING_MACSEC_MODE);
+		return FALSE;
 	}
 
 	if (priv->port <= 0 || priv->port > 65534) {
@@ -362,51 +370,56 @@ verify (NMSetting *setting, NMConnection *connection, GError **error)
 		return FALSE;
 	}
 
+	if (   priv->mode != NM_SETTING_MACSEC_MODE_PSK
+	    && (priv->mka_cak || priv->mka_ckn)) {
+		g_set_error_literal (error,
+		                     NM_CONNECTION_ERROR,
+		                     NM_CONNECTION_ERROR_INVALID_PROPERTY,
+		                     _("only valid for psk mode"));
+		g_prefix_error (error, "%s.%s: ", NM_SETTING_MACSEC_SETTING_NAME,
+		                priv->mka_cak ? NM_SETTING_MACSEC_MKA_CAK : NM_SETTING_MACSEC_MKA_CKN);
+		return NM_SETTING_VERIFY_NORMALIZABLE;
+	}
+
 	return TRUE;
 }
 
-static void
-nm_setting_macsec_init (NMSettingMacsec *setting)
-{
-}
+/*****************************************************************************/
 
 static void
-set_property (GObject *object, guint prop_id,
-              const GValue *value, GParamSpec *pspec)
+get_property (GObject *object, guint prop_id,
+              GValue *value, GParamSpec *pspec)
 {
 	NMSettingMacsec *setting = NM_SETTING_MACSEC (object);
 	NMSettingMacsecPrivate *priv = NM_SETTING_MACSEC_GET_PRIVATE (setting);
 
 	switch (prop_id) {
 	case PROP_PARENT:
-		g_free (priv->parent);
-		priv->parent = g_value_dup_string (value);
+		g_value_set_string (value, priv->parent);
 		break;
 	case PROP_MODE:
-		priv->mode = g_value_get_int (value);
+		g_value_set_int (value, priv->mode);
 		break;
 	case PROP_ENCRYPT:
-		priv->encrypt = g_value_get_boolean (value);
+		g_value_set_boolean (value, priv->encrypt);
 		break;
 	case PROP_MKA_CAK:
-		g_free (priv->mka_cak);
-		priv->mka_cak = g_value_dup_string (value);
+		g_value_set_string (value, priv->mka_cak);
 		break;
 	case PROP_MKA_CAK_FLAGS:
-		priv->mka_cak_flags = g_value_get_flags (value);
+		g_value_set_flags (value, priv->mka_cak_flags);
 		break;
 	case PROP_MKA_CKN:
-		g_free (priv->mka_ckn);
-		priv->mka_ckn = g_value_dup_string (value);
+		g_value_set_string (value, priv->mka_ckn);
 		break;
 	case PROP_PORT:
-		priv->port = g_value_get_int (value);
+		g_value_set_int (value, priv->port);
 		break;
 	case PROP_VALIDATION:
-		priv->validation = g_value_get_int (value);
+		g_value_set_int (value, priv->validation);
 		break;
 	case PROP_SEND_SCI:
-		priv->send_sci = g_value_get_boolean (value);
+		g_value_set_boolean (value, priv->send_sci);
 		break;
 	default:
 		G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
@@ -415,39 +428,42 @@ set_property (GObject *object, guint prop_id,
 }
 
 static void
-get_property (GObject *object, guint prop_id,
-              GValue *value, GParamSpec *pspec)
+set_property (GObject *object, guint prop_id,
+              const GValue *value, GParamSpec *pspec)
 {
 	NMSettingMacsec *setting = NM_SETTING_MACSEC (object);
 	NMSettingMacsecPrivate *priv = NM_SETTING_MACSEC_GET_PRIVATE (setting);
 
 	switch (prop_id) {
 	case PROP_PARENT:
-		g_value_set_string (value, priv->parent);
+		g_free (priv->parent);
+		priv->parent = g_value_dup_string (value);
 		break;
 	case PROP_MODE:
-		g_value_set_int (value, priv->mode);
+		priv->mode = g_value_get_int (value);
 		break;
 	case PROP_ENCRYPT:
-		g_value_set_boolean (value, priv->encrypt);
+		priv->encrypt = g_value_get_boolean (value);
 		break;
 	case PROP_MKA_CAK:
-		g_value_set_string (value, priv->mka_cak);
+		nm_free_secret (priv->mka_cak);
+		priv->mka_cak = g_value_dup_string (value);
 		break;
 	case PROP_MKA_CAK_FLAGS:
-		g_value_set_flags (value, priv->mka_cak_flags);
+		priv->mka_cak_flags = g_value_get_flags (value);
 		break;
 	case PROP_MKA_CKN:
-		g_value_set_string (value, priv->mka_ckn);
+		g_free (priv->mka_ckn);
+		priv->mka_ckn = g_value_dup_string (value);
 		break;
 	case PROP_PORT:
-		g_value_set_int (value, priv->port);
+		priv->port = g_value_get_int (value);
 		break;
 	case PROP_VALIDATION:
-		g_value_set_int (value, priv->validation);
+		priv->validation = g_value_get_int (value);
 		break;
 	case PROP_SEND_SCI:
-		g_value_set_boolean (value, priv->send_sci);
+		priv->send_sci = g_value_get_boolean (value);
 		break;
 	default:
 		G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
@@ -455,6 +471,28 @@ get_property (GObject *object, guint prop_id,
 	}
 }
 
+/*****************************************************************************/
+
+static void
+nm_setting_macsec_init (NMSettingMacsec *setting)
+{
+}
+
+/**
+ * nm_setting_macsec_new:
+ *
+ * Creates a new #NMSettingMacsec object with default values.
+ *
+ * Returns: (transfer full): the new empty #NMSettingMacsec object
+ *
+ * Since: 1.6
+ **/
+NMSetting *
+nm_setting_macsec_new (void)
+{
+	return (NMSetting *) g_object_new (NM_TYPE_SETTING_MACSEC, NULL);
+}
+
 static void
 finalize (GObject *object)
 {
@@ -462,10 +500,7 @@ finalize (GObject *object)
 	NMSettingMacsecPrivate *priv = NM_SETTING_MACSEC_GET_PRIVATE (setting);
 
 	g_free (priv->parent);
-	if (priv->mka_cak) {
-		memset (priv->mka_cak, 0, strlen (priv->mka_cak));
-		g_free (priv->mka_cak);
-	}
+	nm_free_secret (priv->mka_cak);
 	g_free (priv->mka_ckn);
 
 	G_OBJECT_CLASS (nm_setting_macsec_parent_class)->finalize (object);
@@ -479,8 +514,8 @@ nm_setting_macsec_class_init (NMSettingMacsecClass *klass)
 
 	g_type_class_add_private (klass, sizeof (NMSettingMacsecPrivate));
 
-	object_class->set_property = set_property;
 	object_class->get_property = get_property;
+	object_class->set_property = set_property;
 	object_class->finalize     = finalize;
 
 	setting_class->verify       = verify;
diff --git a/libnm-core/nm-setting-macvlan.c b/libnm-core/nm-setting-macvlan.c
index 1fc16116..a25e1055 100644
--- a/libnm-core/nm-setting-macvlan.c
+++ b/libnm-core/nm-setting-macvlan.c
@@ -21,10 +21,11 @@
 
 #include "nm-default.h"
 
+#include "nm-setting-macvlan.h"
+
 #include <stdlib.h>
 #include <string.h>
 
-#include "nm-setting-macvlan.h"
 #include "nm-utils.h"
 #include "nm-setting-connection.h"
 #include "nm-setting-private.h"
@@ -39,9 +40,14 @@
  * necessary for connection to macvlan interfaces.
  **/
 
-G_DEFINE_TYPE (NMSettingMacvlan, nm_setting_macvlan, NM_TYPE_SETTING)
+/*****************************************************************************/
 
-#define NM_SETTING_MACVLAN_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), NM_TYPE_SETTING_MACVLAN, NMSettingMacvlanPrivate))
+NM_GOBJECT_PROPERTIES_DEFINE_BASE (
+	PROP_PARENT,
+	PROP_MODE,
+	PROP_PROMISCUOUS,
+	PROP_TAP,
+);
 
 typedef struct {
 	char *parent;
@@ -50,29 +56,11 @@ typedef struct {
 	gboolean tap;
 } NMSettingMacvlanPrivate;
 
-enum {
-	PROP_0,
-	PROP_PARENT,
-	PROP_MODE,
-	PROP_PROMISCUOUS,
-	PROP_TAP,
-	LAST_PROP
-};
+G_DEFINE_TYPE (NMSettingMacvlan, nm_setting_macvlan, NM_TYPE_SETTING)
 
-/**
- * nm_setting_macvlan_new:
- *
- * Creates a new #NMSettingMacvlan object with default values.
- *
- * Returns: (transfer full): the new empty #NMSettingMacvlan object
- *
- * Since: 1.2
- **/
-NMSetting *
-nm_setting_macvlan_new (void)
-{
-	return (NMSetting *) g_object_new (NM_TYPE_SETTING_MACVLAN, NULL);
-}
+#define NM_SETTING_MACVLAN_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), NM_TYPE_SETTING_MACVLAN, NMSettingMacvlanPrivate))
+
+/*****************************************************************************/
 
 /**
  * nm_setting_macvlan_get_parent:
@@ -136,11 +124,6 @@ nm_setting_macvlan_get_tap (NMSettingMacvlan *setting)
 
 /*****************************************************************************/
 
-static void
-nm_setting_macvlan_init (NMSettingMacvlan *setting)
-{
-}
-
 static gboolean
 verify (NMSetting *setting, NMConnection *connection, GError **error)
 {
@@ -193,26 +176,27 @@ verify (NMSetting *setting, NMConnection *connection, GError **error)
 	return TRUE;
 }
 
+/*****************************************************************************/
+
 static void
-set_property (GObject *object, guint prop_id,
-              const GValue *value, GParamSpec *pspec)
+get_property (GObject *object, guint prop_id,
+              GValue *value, GParamSpec *pspec)
 {
 	NMSettingMacvlan *setting = NM_SETTING_MACVLAN (object);
 	NMSettingMacvlanPrivate *priv = NM_SETTING_MACVLAN_GET_PRIVATE (setting);
 
 	switch (prop_id) {
 	case PROP_PARENT:
-		g_free (priv->parent);
-		priv->parent = g_value_dup_string (value);
+		g_value_set_string (value, priv->parent);
 		break;
 	case PROP_MODE:
-		priv->mode = g_value_get_uint (value);
+		g_value_set_uint (value, priv->mode);
 		break;
 	case PROP_PROMISCUOUS:
-		priv->promiscuous = g_value_get_boolean (value);
+		g_value_set_boolean (value, priv->promiscuous);
 		break;
 	case PROP_TAP:
-		priv->tap = g_value_get_boolean (value);
+		g_value_set_boolean (value, priv->tap);
 		break;
 	default:
 		G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
@@ -221,24 +205,25 @@ set_property (GObject *object, guint prop_id,
 }
 
 static void
-get_property (GObject *object, guint prop_id,
-              GValue *value, GParamSpec *pspec)
+set_property (GObject *object, guint prop_id,
+              const GValue *value, GParamSpec *pspec)
 {
 	NMSettingMacvlan *setting = NM_SETTING_MACVLAN (object);
 	NMSettingMacvlanPrivate *priv = NM_SETTING_MACVLAN_GET_PRIVATE (setting);
 
 	switch (prop_id) {
 	case PROP_PARENT:
-		g_value_set_string (value, priv->parent);
+		g_free (priv->parent);
+		priv->parent = g_value_dup_string (value);
 		break;
 	case PROP_MODE:
-		g_value_set_uint (value, priv->mode);
+		priv->mode = g_value_get_uint (value);
 		break;
 	case PROP_PROMISCUOUS:
-		g_value_set_boolean (value, priv->promiscuous);
+		priv->promiscuous = g_value_get_boolean (value);
 		break;
 	case PROP_TAP:
-		g_value_set_boolean (value, priv->tap);
+		priv->tap = g_value_get_boolean (value);
 		break;
 	default:
 		G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
@@ -246,6 +231,28 @@ get_property (GObject *object, guint prop_id,
 	}
 }
 
+/*****************************************************************************/
+
+static void
+nm_setting_macvlan_init (NMSettingMacvlan *setting)
+{
+}
+
+/**
+ * nm_setting_macvlan_new:
+ *
+ * Creates a new #NMSettingMacvlan object with default values.
+ *
+ * Returns: (transfer full): the new empty #NMSettingMacvlan object
+ *
+ * Since: 1.2
+ **/
+NMSetting *
+nm_setting_macvlan_new (void)
+{
+	return (NMSetting *) g_object_new (NM_TYPE_SETTING_MACVLAN, NULL);
+}
+
 static void
 finalize (GObject *object)
 {
@@ -265,8 +272,8 @@ nm_setting_macvlan_class_init (NMSettingMacvlanClass *klass)
 
 	g_type_class_add_private (klass, sizeof (NMSettingMacvlanPrivate));
 
-	object_class->set_property = set_property;
 	object_class->get_property = get_property;
+	object_class->set_property = set_property;
 	object_class->finalize     = finalize;
 
 	setting_class->verify = verify;
@@ -281,14 +288,13 @@ nm_setting_macvlan_class_init (NMSettingMacvlanClass *klass)
 	 *
 	 * Since: 1.2
 	 **/
-	g_object_class_install_property
-		(object_class, PROP_PARENT,
-		 g_param_spec_string (NM_SETTING_MACVLAN_PARENT, "", "",
-		                      NULL,
-		                      G_PARAM_READWRITE |
-		                      G_PARAM_CONSTRUCT |
-		                      NM_SETTING_PARAM_INFERRABLE |
-		                      G_PARAM_STATIC_STRINGS));
+	obj_properties[PROP_PARENT] =
+	    g_param_spec_string (NM_SETTING_MACVLAN_PARENT, "", "",
+	                         NULL,
+	                         G_PARAM_READWRITE |
+	                         G_PARAM_CONSTRUCT |
+	                         NM_SETTING_PARAM_INFERRABLE |
+	                         G_PARAM_STATIC_STRINGS);
 
 	/**
 	 * NMSettingMacvlan:mode:
@@ -298,14 +304,13 @@ nm_setting_macvlan_class_init (NMSettingMacvlanClass *klass)
 	 *
 	 * Since: 1.2
 	 **/
-	g_object_class_install_property
-		(object_class, PROP_MODE,
-		 g_param_spec_uint (NM_SETTING_MACVLAN_MODE, "", "",
-		                    0, G_MAXUINT, 0,
-		                    G_PARAM_READWRITE |
-		                    G_PARAM_CONSTRUCT |
-		                    NM_SETTING_PARAM_INFERRABLE |
-		                    G_PARAM_STATIC_STRINGS));
+	obj_properties[PROP_MODE] =
+	    g_param_spec_uint (NM_SETTING_MACVLAN_MODE, "", "",
+	                       0, G_MAXUINT, 0,
+	                       G_PARAM_READWRITE |
+	                       G_PARAM_CONSTRUCT |
+	                       NM_SETTING_PARAM_INFERRABLE |
+	                       G_PARAM_STATIC_STRINGS);
 
 	/**
 	 * NMSettingMacvlan:promiscuous:
@@ -314,14 +319,13 @@ nm_setting_macvlan_class_init (NMSettingMacvlanClass *klass)
 	 *
 	 * Since: 1.2
 	 **/
-	g_object_class_install_property
-		(object_class, PROP_PROMISCUOUS,
-		 g_param_spec_boolean (NM_SETTING_MACVLAN_PROMISCUOUS, "", "",
-		                       TRUE,
-		                       G_PARAM_READWRITE |
-		                       G_PARAM_CONSTRUCT |
-		                       NM_SETTING_PARAM_INFERRABLE |
-		                       G_PARAM_STATIC_STRINGS));
+	obj_properties[PROP_PROMISCUOUS] =
+	    g_param_spec_boolean (NM_SETTING_MACVLAN_PROMISCUOUS, "", "",
+	                          TRUE,
+	                          G_PARAM_READWRITE |
+	                          G_PARAM_CONSTRUCT |
+	                          NM_SETTING_PARAM_INFERRABLE |
+	                          G_PARAM_STATIC_STRINGS);
 
 	/**
 	 * NMSettingMacvlan:tap:
@@ -330,14 +334,15 @@ nm_setting_macvlan_class_init (NMSettingMacvlanClass *klass)
 	 *
 	 * Since: 1.2
 	 **/
-	g_object_class_install_property
-		(object_class, PROP_TAP,
-		 g_param_spec_boolean (NM_SETTING_MACVLAN_TAP, "", "",
-		                       FALSE,
-		                       G_PARAM_READWRITE |
-		                       G_PARAM_CONSTRUCT |
-		                       NM_SETTING_PARAM_INFERRABLE |
-		                       G_PARAM_STATIC_STRINGS));
+	obj_properties[PROP_TAP] =
+	    g_param_spec_boolean (NM_SETTING_MACVLAN_TAP, "", "",
+	                          FALSE,
+	                          G_PARAM_READWRITE |
+	                          G_PARAM_CONSTRUCT |
+	                          NM_SETTING_PARAM_INFERRABLE |
+	                          G_PARAM_STATIC_STRINGS);
+
+	g_object_class_install_properties (object_class, _PROPERTY_ENUMS_LAST, obj_properties);
 
 	_nm_setting_class_commit (setting_class, NM_META_SETTING_TYPE_MACVLAN);
 }
diff --git a/libnm-core/nm-setting-match.c b/libnm-core/nm-setting-match.c
index 0964c644..2f331060 100644
--- a/libnm-core/nm-setting-match.c
+++ b/libnm-core/nm-setting-match.c
@@ -15,6 +15,7 @@
 #include "nm-default.h"
 
 #include "nm-setting-match.h"
+
 #include "nm-setting-private.h"
 #include "nm-utils-private.h"
 
@@ -24,6 +25,12 @@
  * @include: nm-setting-match.h
  **/
 
+/*****************************************************************************/
+
+NM_GOBJECT_PROPERTIES_DEFINE (NMSettingMatch,
+	PROP_INTERFACE_NAME,
+);
+
 /**
  * NMSettingMatch:
  *
@@ -42,10 +49,6 @@ struct _NMSettingMatchClass {
 
 G_DEFINE_TYPE (NMSettingMatch, nm_setting_match, NM_TYPE_SETTING)
 
-NM_GOBJECT_PROPERTIES_DEFINE (NMSettingMatch,
-	PROP_INTERFACE_NAME,
-);
-
 /*****************************************************************************/
 
 /**
@@ -194,6 +197,8 @@ nm_setting_match_get_interface_names (NMSettingMatch *setting, guint *length)
 	return (const char *const *) setting->interface_name->pdata;
 }
 
+/*****************************************************************************/
+
 static void
 get_property (GObject *object, guint prop_id,
               GValue *value, GParamSpec *pspec)
@@ -227,6 +232,8 @@ set_property (GObject *object, guint prop_id,
 	}
 }
 
+/*****************************************************************************/
+
 static void
 nm_setting_match_init (NMSettingMatch *setting)
 {
@@ -264,9 +271,9 @@ nm_setting_match_class_init (NMSettingMatchClass *klass)
 	GObjectClass *object_class = G_OBJECT_CLASS (klass);
 	NMSettingClass *setting_class = NM_SETTING_CLASS (klass);
 
-	object_class->finalize     = finalize;
 	object_class->get_property = get_property;
 	object_class->set_property = set_property;
+	object_class->finalize     = finalize;
 
 	/**
 	 * NMSettingMatch:interface-name
diff --git a/libnm-core/nm-setting-olpc-mesh.c b/libnm-core/nm-setting-olpc-mesh.c
index 7f4a1bbf..eb87e1ff 100644
--- a/libnm-core/nm-setting-olpc-mesh.c
+++ b/libnm-core/nm-setting-olpc-mesh.c
@@ -22,9 +22,10 @@
 
 #include "nm-default.h"
 
+#include "nm-setting-olpc-mesh.h"
+
 #include <string.h>
 
-#include "nm-setting-olpc-mesh.h"
 #include "nm-utils.h"
 #include "nm-utils-private.h"
 #include "nm-setting-private.h"
@@ -37,11 +38,13 @@
  * necessary for connection to OLPC-Mesh devices.
  **/
 
-static void nm_setting_olpc_mesh_init (NMSettingOlpcMesh *setting);
+/*****************************************************************************/
 
-G_DEFINE_TYPE (NMSettingOlpcMesh, nm_setting_olpc_mesh, NM_TYPE_SETTING)
-
-#define NM_SETTING_OLPC_MESH_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), NM_TYPE_SETTING_OLPC_MESH, NMSettingOlpcMeshPrivate))
+NM_GOBJECT_PROPERTIES_DEFINE_BASE (
+	PROP_SSID,
+	PROP_CHANNEL,
+	PROP_DHCP_ANYCAST_ADDRESS,
+);
 
 typedef struct {
 	GBytes *ssid;
@@ -49,31 +52,11 @@ typedef struct {
 	char *dhcp_anycast_addr;
 } NMSettingOlpcMeshPrivate;
 
-enum {
-	PROP_0,
-	PROP_SSID,
-	PROP_CHANNEL,
-	PROP_DHCP_ANYCAST_ADDRESS,
-
-	LAST_PROP
-};
+G_DEFINE_TYPE (NMSettingOlpcMesh, nm_setting_olpc_mesh, NM_TYPE_SETTING)
 
-/**
- * nm_setting_olpc_mesh_new:
- *
- * Creates a new #NMSettingOlpcMesh object with default values.
- *
- * Returns: the new empty #NMSettingOlpcMesh object
- **/
-NMSetting *nm_setting_olpc_mesh_new (void)
-{
-	return (NMSetting *) g_object_new (NM_TYPE_SETTING_OLPC_MESH, NULL);
-}
+#define NM_SETTING_OLPC_MESH_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), NM_TYPE_SETTING_OLPC_MESH, NMSettingOlpcMeshPrivate))
 
-static void
-nm_setting_olpc_mesh_init (NMSettingOlpcMesh *setting)
-{
-}
+/*****************************************************************************/
 
 /**
  * nm_setting_olpc_mesh_get_ssid:
@@ -152,16 +135,28 @@ verify (NMSetting *setting, NMConnection *connection, GError **error)
 	return TRUE;
 }
 
+/*****************************************************************************/
+
 static void
-finalize (GObject *object)
+get_property (GObject *object, guint prop_id,
+              GValue *value, GParamSpec *pspec)
 {
-	NMSettingOlpcMeshPrivate *priv = NM_SETTING_OLPC_MESH_GET_PRIVATE (object);
-
-	if (priv->ssid)
-		g_bytes_unref (priv->ssid);
-	g_free (priv->dhcp_anycast_addr);
+	NMSettingOlpcMesh *setting = NM_SETTING_OLPC_MESH (object);
 
-	G_OBJECT_CLASS (nm_setting_olpc_mesh_parent_class)->finalize (object);
+	switch (prop_id) {
+	case PROP_SSID:
+		g_value_set_boxed (value, nm_setting_olpc_mesh_get_ssid (setting));
+		break;
+	case PROP_CHANNEL:
+		g_value_set_uint (value, nm_setting_olpc_mesh_get_channel (setting));
+		break;
+	case PROP_DHCP_ANYCAST_ADDRESS:
+		g_value_set_string (value, nm_setting_olpc_mesh_get_dhcp_anycast_address (setting));
+		break;
+	default:
+		G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+		break;
+	}
 }
 
 static void
@@ -189,26 +184,35 @@ set_property (GObject *object, guint prop_id,
 	}
 }
 
+/*****************************************************************************/
+
 static void
-get_property (GObject *object, guint prop_id,
-              GValue *value, GParamSpec *pspec)
+nm_setting_olpc_mesh_init (NMSettingOlpcMesh *setting)
 {
-	NMSettingOlpcMesh *setting = NM_SETTING_OLPC_MESH (object);
+}
 
-	switch (prop_id) {
-	case PROP_SSID:
-		g_value_set_boxed (value, nm_setting_olpc_mesh_get_ssid (setting));
-		break;
-	case PROP_CHANNEL:
-		g_value_set_uint (value, nm_setting_olpc_mesh_get_channel (setting));
-		break;
-	case PROP_DHCP_ANYCAST_ADDRESS:
-		g_value_set_string (value, nm_setting_olpc_mesh_get_dhcp_anycast_address (setting));
-		break;
-	default:
-		G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
-		break;
-	}
+/**
+ * nm_setting_olpc_mesh_new:
+ *
+ * Creates a new #NMSettingOlpcMesh object with default values.
+ *
+ * Returns: the new empty #NMSettingOlpcMesh object
+ **/
+NMSetting *nm_setting_olpc_mesh_new (void)
+{
+	return (NMSetting *) g_object_new (NM_TYPE_SETTING_OLPC_MESH, NULL);
+}
+
+static void
+finalize (GObject *object)
+{
+	NMSettingOlpcMeshPrivate *priv = NM_SETTING_OLPC_MESH_GET_PRIVATE (object);
+
+	if (priv->ssid)
+		g_bytes_unref (priv->ssid);
+	g_free (priv->dhcp_anycast_addr);
+
+	G_OBJECT_CLASS (nm_setting_olpc_mesh_parent_class)->finalize (object);
 }
 
 static void
@@ -220,8 +224,8 @@ nm_setting_olpc_mesh_class_init (NMSettingOlpcMeshClass *klass)
 
 	g_type_class_add_private (klass, sizeof (NMSettingOlpcMeshPrivate));
 
-	object_class->set_property = set_property;
 	object_class->get_property = get_property;
+	object_class->set_property = set_property;
 	object_class->finalize     = finalize;
 
 	setting_class->verify = verify;
@@ -231,27 +235,25 @@ nm_setting_olpc_mesh_class_init (NMSettingOlpcMeshClass *klass)
 	 *
 	 * SSID of the mesh network to join.
 	 **/
-	g_object_class_install_property
-		(object_class, PROP_SSID,
-		 g_param_spec_boxed (NM_SETTING_OLPC_MESH_SSID, "", "",
-		                     G_TYPE_BYTES,
-		                     G_PARAM_READWRITE |
-		                     NM_SETTING_PARAM_INFERRABLE |
-		                     G_PARAM_STATIC_STRINGS));
+	obj_properties[PROP_SSID] =
+	    g_param_spec_boxed (NM_SETTING_OLPC_MESH_SSID, "", "",
+	                        G_TYPE_BYTES,
+	                        G_PARAM_READWRITE |
+	                        NM_SETTING_PARAM_INFERRABLE |
+	                        G_PARAM_STATIC_STRINGS);
 
 	/**
 	 * NMSettingOlpcMesh:channel:
 	 *
 	 * Channel on which the mesh network to join is located.
 	 **/
-	g_object_class_install_property
-		(object_class, PROP_CHANNEL,
-		 g_param_spec_uint (NM_SETTING_OLPC_MESH_CHANNEL, "", "",
-		                    0, G_MAXUINT32, 0,
-		                    G_PARAM_READWRITE |
-		                    G_PARAM_CONSTRUCT |
-		                    NM_SETTING_PARAM_INFERRABLE |
-		                    G_PARAM_STATIC_STRINGS));
+	obj_properties[PROP_CHANNEL] =
+	    g_param_spec_uint (NM_SETTING_OLPC_MESH_CHANNEL, "", "",
+	                       0, G_MAXUINT32, 0,
+	                       G_PARAM_READWRITE |
+	                       G_PARAM_CONSTRUCT |
+	                       NM_SETTING_PARAM_INFERRABLE |
+	                       G_PARAM_STATIC_STRINGS);
 
 	/**
 	 * NMSettingOlpcMesh:dhcp-anycast-address:
@@ -260,20 +262,20 @@ nm_setting_olpc_mesh_class_init (NMSettingOlpcMeshClass *klass)
 	 * The specific anycast address used determines which DHCP server class
 	 * answers the request.
 	 **/
-	g_object_class_install_property
-		(object_class, PROP_DHCP_ANYCAST_ADDRESS,
-		 g_param_spec_string (NM_SETTING_OLPC_MESH_DHCP_ANYCAST_ADDRESS, "", "",
-		                      NULL,
-		                      G_PARAM_READWRITE |
-		                      G_PARAM_STATIC_STRINGS));
+	obj_properties[PROP_DHCP_ANYCAST_ADDRESS] =
+	    g_param_spec_string (NM_SETTING_OLPC_MESH_DHCP_ANYCAST_ADDRESS, "", "",
+	                         NULL,
+	                         G_PARAM_READWRITE |
+	                         G_PARAM_STATIC_STRINGS);
 
 	_properties_override_add_transform (properties_override,
-	                                    g_object_class_find_property (G_OBJECT_CLASS (setting_class),
-	                                                                  NM_SETTING_OLPC_MESH_DHCP_ANYCAST_ADDRESS),
+	                                    obj_properties[PROP_DHCP_ANYCAST_ADDRESS],
 	                                    G_VARIANT_TYPE_BYTESTRING,
 	                                    _nm_utils_hwaddr_to_dbus,
 	                                    _nm_utils_hwaddr_from_dbus);
 
+	g_object_class_install_properties (object_class, _PROPERTY_ENUMS_LAST, obj_properties);
+
 	_nm_setting_class_commit_full (setting_class, NM_META_SETTING_TYPE_OLPC_MESH,
 	                               NULL, properties_override);
 }
diff --git a/libnm-core/nm-setting-ovs-bridge.c b/libnm-core/nm-setting-ovs-bridge.c
index 9ca5566f..e69dcdea 100644
--- a/libnm-core/nm-setting-ovs-bridge.c
+++ b/libnm-core/nm-setting-ovs-bridge.c
@@ -34,14 +34,14 @@
  * necessary for Open vSwitch bridges.
  **/
 
-enum {
-	PROP_0,
+/*****************************************************************************/
+
+NM_GOBJECT_PROPERTIES_DEFINE_BASE (
 	PROP_FAIL_MODE,
 	PROP_MCAST_SNOOPING_ENABLE,
 	PROP_RSTP_ENABLE,
 	PROP_STP_ENABLE,
-	LAST_PROP
-};
+);
 
 /**
  * NMSettingOvsBridge:
@@ -267,8 +267,8 @@ nm_setting_ovs_bridge_class_init (NMSettingOvsBridgeClass *klass)
 	GObjectClass *object_class = G_OBJECT_CLASS (klass);
 	NMSettingClass *setting_class = NM_SETTING_CLASS (klass);
 
-	object_class->set_property = set_property;
 	object_class->get_property = get_property;
+	object_class->set_property = set_property;
 	object_class->finalize     = finalize;
 
 	setting_class->verify = verify;
@@ -280,14 +280,13 @@ nm_setting_ovs_bridge_class_init (NMSettingOvsBridgeClass *klass)
 	 *
 	 * Since: 1.10
 	 **/
-	g_object_class_install_property
-	        (object_class, PROP_FAIL_MODE,
-	         g_param_spec_string (NM_SETTING_OVS_BRIDGE_FAIL_MODE, "", "",
-	                              NULL,
-	                              G_PARAM_READWRITE |
-	                              G_PARAM_CONSTRUCT |
-	                              NM_SETTING_PARAM_INFERRABLE |
-	                              G_PARAM_STATIC_STRINGS));
+	obj_properties[PROP_FAIL_MODE] =
+	    g_param_spec_string (NM_SETTING_OVS_BRIDGE_FAIL_MODE, "", "",
+	                         NULL,
+	                         G_PARAM_READWRITE |
+	                         G_PARAM_CONSTRUCT |
+	                         NM_SETTING_PARAM_INFERRABLE |
+	                         G_PARAM_STATIC_STRINGS);
 
 	/**
 	 * NMSettingOvsBridge:mcast-snooping-enable:
@@ -296,13 +295,12 @@ nm_setting_ovs_bridge_class_init (NMSettingOvsBridgeClass *klass)
 	 *
 	 * Since: 1.10
 	 **/
-	g_object_class_install_property
-	        (object_class, PROP_MCAST_SNOOPING_ENABLE,
-	         g_param_spec_boolean (NM_SETTING_OVS_BRIDGE_MCAST_SNOOPING_ENABLE, "", "",
-	                               FALSE,
-	                               G_PARAM_READWRITE |
-	                               G_PARAM_CONSTRUCT |
-	                               G_PARAM_STATIC_STRINGS));
+	obj_properties[PROP_MCAST_SNOOPING_ENABLE] =
+	    g_param_spec_boolean (NM_SETTING_OVS_BRIDGE_MCAST_SNOOPING_ENABLE, "", "",
+	                          FALSE,
+	                          G_PARAM_READWRITE |
+	                          G_PARAM_CONSTRUCT |
+	                          G_PARAM_STATIC_STRINGS);
 
 	/**
 	 * NMSettingOvsBridge:rstp-enable:
@@ -311,13 +309,12 @@ nm_setting_ovs_bridge_class_init (NMSettingOvsBridgeClass *klass)
 	 *
 	 * Since: 1.10
 	 **/
-	g_object_class_install_property
-	        (object_class, PROP_RSTP_ENABLE,
-	         g_param_spec_boolean (NM_SETTING_OVS_BRIDGE_RSTP_ENABLE, "", "",
-	                               FALSE,
-	                               G_PARAM_READWRITE |
-	                               G_PARAM_CONSTRUCT |
-	                               G_PARAM_STATIC_STRINGS));
+	obj_properties[PROP_RSTP_ENABLE] =
+	    g_param_spec_boolean (NM_SETTING_OVS_BRIDGE_RSTP_ENABLE, "", "",
+	                          FALSE,
+	                          G_PARAM_READWRITE |
+	                          G_PARAM_CONSTRUCT |
+	                          G_PARAM_STATIC_STRINGS);
 
 	/**
 	 * NMSettingOvsBridge:stp-enable:
@@ -326,13 +323,14 @@ nm_setting_ovs_bridge_class_init (NMSettingOvsBridgeClass *klass)
 	 *
 	 * Since: 1.10
 	 **/
-	g_object_class_install_property
-	        (object_class, PROP_STP_ENABLE,
-	         g_param_spec_boolean (NM_SETTING_OVS_BRIDGE_STP_ENABLE, "", "",
-	                               FALSE,
-	                               G_PARAM_READWRITE |
-	                               G_PARAM_CONSTRUCT |
-	                               G_PARAM_STATIC_STRINGS));
+	obj_properties[PROP_STP_ENABLE] =
+	    g_param_spec_boolean (NM_SETTING_OVS_BRIDGE_STP_ENABLE, "", "",
+	                          FALSE,
+	                          G_PARAM_READWRITE |
+	                          G_PARAM_CONSTRUCT |
+	                          G_PARAM_STATIC_STRINGS);
+
+	g_object_class_install_properties (object_class, _PROPERTY_ENUMS_LAST, obj_properties);
 
 	_nm_setting_class_commit (setting_class, NM_META_SETTING_TYPE_OVS_BRIDGE);
 }
diff --git a/libnm-core/nm-setting-ovs-interface.c b/libnm-core/nm-setting-ovs-interface.c
index a177098d..ad7f2ead 100644
--- a/libnm-core/nm-setting-ovs-interface.c
+++ b/libnm-core/nm-setting-ovs-interface.c
@@ -33,11 +33,11 @@
  * necessary for Open vSwitch interfaces.
  **/
 
-enum {
-	PROP_0,
+/*****************************************************************************/
+
+NM_GOBJECT_PROPERTIES_DEFINE_BASE (
 	PROP_TYPE,
-	LAST_PROP
-};
+);
 
 /**
  * NMSettingOvsInterface:
@@ -366,8 +366,8 @@ nm_setting_ovs_interface_class_init (NMSettingOvsInterfaceClass *klass)
 	GObjectClass *object_class = G_OBJECT_CLASS (klass);
 	NMSettingClass *setting_class = NM_SETTING_CLASS (klass);
 
-	object_class->set_property = set_property;
 	object_class->get_property = get_property;
+	object_class->set_property = set_property;
 	object_class->finalize     = finalize;
 
 	setting_class->verify = verify;
@@ -379,14 +379,15 @@ nm_setting_ovs_interface_class_init (NMSettingOvsInterfaceClass *klass)
 	 *
 	 * Since: 1.10
 	 **/
-	g_object_class_install_property
-	        (object_class, PROP_TYPE,
-	         g_param_spec_string (NM_SETTING_OVS_INTERFACE_TYPE, "", "",
-	                              NULL,
-	                              G_PARAM_READWRITE |
-	                              G_PARAM_CONSTRUCT |
-	                              NM_SETTING_PARAM_INFERRABLE |
-	                              G_PARAM_STATIC_STRINGS));
+	obj_properties[PROP_TYPE] =
+	    g_param_spec_string (NM_SETTING_OVS_INTERFACE_TYPE, "", "",
+	                         NULL,
+	                         G_PARAM_READWRITE |
+	                         G_PARAM_CONSTRUCT |
+	                         NM_SETTING_PARAM_INFERRABLE |
+	                         G_PARAM_STATIC_STRINGS);
+
+	g_object_class_install_properties (object_class, _PROPERTY_ENUMS_LAST, obj_properties);
 
 	_nm_setting_class_commit (setting_class, NM_META_SETTING_TYPE_OVS_INTERFACE);
 }
diff --git a/libnm-core/nm-setting-ovs-patch.c b/libnm-core/nm-setting-ovs-patch.c
index 15005eea..2a46810c 100644
--- a/libnm-core/nm-setting-ovs-patch.c
+++ b/libnm-core/nm-setting-ovs-patch.c
@@ -34,11 +34,11 @@
  * necessary for Open vSwitch interfaces of type "patch".
  **/
 
-enum {
-	PROP_0,
+/*****************************************************************************/
+
+NM_GOBJECT_PROPERTIES_DEFINE_BASE (
 	PROP_PEER,
-	LAST_PROP
-};
+);
 
 /**
  * NMSettingOvsPatch:
@@ -199,14 +199,15 @@ nm_setting_ovs_patch_class_init (NMSettingOvsPatchClass *klass)
 	 *
 	 * Since: 1.10
 	 **/
-	g_object_class_install_property
-	        (object_class, PROP_PEER,
-	         g_param_spec_string (NM_SETTING_OVS_PATCH_PEER, "", "",
-	                              NULL,
-	                              G_PARAM_READWRITE |
-	                              G_PARAM_CONSTRUCT |
-	                              NM_SETTING_PARAM_INFERRABLE |
-	                              G_PARAM_STATIC_STRINGS));
+	obj_properties[PROP_PEER] =
+	    g_param_spec_string (NM_SETTING_OVS_PATCH_PEER, "", "",
+	                         NULL,
+	                         G_PARAM_READWRITE |
+	                         G_PARAM_CONSTRUCT |
+	                         NM_SETTING_PARAM_INFERRABLE |
+	                         G_PARAM_STATIC_STRINGS);
+
+	g_object_class_install_properties (object_class, _PROPERTY_ENUMS_LAST, obj_properties);
 
 	_nm_setting_class_commit (setting_class, NM_META_SETTING_TYPE_OVS_PATCH);
 }
diff --git a/libnm-core/nm-setting-ovs-port.c b/libnm-core/nm-setting-ovs-port.c
index 10e542e7..e690d641 100644
--- a/libnm-core/nm-setting-ovs-port.c
+++ b/libnm-core/nm-setting-ovs-port.c
@@ -34,16 +34,16 @@
  * necessary for Open vSwitch ports.
  **/
 
-enum {
-	PROP_0,
+/*****************************************************************************/
+
+NM_GOBJECT_PROPERTIES_DEFINE_BASE (
 	PROP_VLAN_MODE,
 	PROP_TAG,
 	PROP_LACP,
 	PROP_BOND_MODE,
 	PROP_BOND_UPDELAY,
 	PROP_BOND_DOWNDELAY,
-	LAST_PROP
-};
+);
 
 /**
  * NMSettingOvsPort:
@@ -364,8 +364,8 @@ nm_setting_ovs_port_class_init (NMSettingOvsPortClass *klass)
 	GObjectClass *object_class = G_OBJECT_CLASS (klass);
 	NMSettingClass *setting_class = NM_SETTING_CLASS (klass);
 
-	object_class->set_property = set_property;
 	object_class->get_property = get_property;
+	object_class->set_property = set_property;
 	object_class->finalize     = finalize;
 
 	setting_class->verify = verify;
@@ -378,14 +378,13 @@ nm_setting_ovs_port_class_init (NMSettingOvsPortClass *klass)
 	 *
 	 * Since: 1.10
 	 **/
-	g_object_class_install_property
-	        (object_class, PROP_VLAN_MODE,
-	         g_param_spec_string (NM_SETTING_OVS_PORT_VLAN_MODE, "", "",
-	                              NULL,
-	                              G_PARAM_READWRITE |
-	                              G_PARAM_CONSTRUCT |
-	                              NM_SETTING_PARAM_INFERRABLE |
-	                              G_PARAM_STATIC_STRINGS));
+	obj_properties[PROP_VLAN_MODE] =
+	    g_param_spec_string (NM_SETTING_OVS_PORT_VLAN_MODE, "", "",
+	                         NULL,
+	                         G_PARAM_READWRITE |
+	                         G_PARAM_CONSTRUCT |
+	                         NM_SETTING_PARAM_INFERRABLE |
+	                         G_PARAM_STATIC_STRINGS);
 
 	/**
 	 * NMSettingOvsPort:tag:
@@ -394,14 +393,13 @@ nm_setting_ovs_port_class_init (NMSettingOvsPortClass *klass)
 	 *
 	 * Since: 1.10
 	 **/
-	g_object_class_install_property
-	        (object_class, PROP_TAG,
-	         g_param_spec_uint (NM_SETTING_OVS_PORT_TAG, "", "",
-	                            0, 4095, 0,
-	                            G_PARAM_READWRITE |
-	                            G_PARAM_CONSTRUCT |
-	                            NM_SETTING_PARAM_INFERRABLE |
-	                            G_PARAM_STATIC_STRINGS));
+	obj_properties[PROP_TAG] =
+	    g_param_spec_uint (NM_SETTING_OVS_PORT_TAG, "", "",
+	                       0, 4095, 0,
+	                       G_PARAM_READWRITE |
+	                       G_PARAM_CONSTRUCT |
+	                       NM_SETTING_PARAM_INFERRABLE |
+	                       G_PARAM_STATIC_STRINGS);
 
 	/**
 	 * NMSettingOvsPort:lacp:
@@ -410,14 +408,13 @@ nm_setting_ovs_port_class_init (NMSettingOvsPortClass *klass)
 	 *
 	 * Since: 1.10
 	 **/
-	g_object_class_install_property
-	        (object_class, PROP_LACP,
-	         g_param_spec_string (NM_SETTING_OVS_PORT_LACP, "", "",
-	                              NULL,
-	                              G_PARAM_READWRITE |
-	                              G_PARAM_CONSTRUCT |
-	                              NM_SETTING_PARAM_INFERRABLE |
-	                              G_PARAM_STATIC_STRINGS));
+	obj_properties[PROP_LACP] =
+	    g_param_spec_string (NM_SETTING_OVS_PORT_LACP, "", "",
+	                         NULL,
+	                         G_PARAM_READWRITE |
+	                         G_PARAM_CONSTRUCT |
+	                         NM_SETTING_PARAM_INFERRABLE |
+	                         G_PARAM_STATIC_STRINGS);
 
 	/**
 	 * NMSettingOvsPort:bond-mode:
@@ -426,14 +423,13 @@ nm_setting_ovs_port_class_init (NMSettingOvsPortClass *klass)
 	 *
 	 * Since: 1.10
 	 **/
-	g_object_class_install_property
-	        (object_class, PROP_BOND_MODE,
-	         g_param_spec_string (NM_SETTING_OVS_PORT_BOND_MODE, "", "",
-	                              NULL,
-	                              G_PARAM_READWRITE |
-	                              G_PARAM_CONSTRUCT |
-	                              NM_SETTING_PARAM_INFERRABLE |
-	                              G_PARAM_STATIC_STRINGS));
+	obj_properties[PROP_BOND_MODE] =
+	    g_param_spec_string (NM_SETTING_OVS_PORT_BOND_MODE, "", "",
+	                         NULL,
+	                         G_PARAM_READWRITE |
+	                         G_PARAM_CONSTRUCT |
+	                         NM_SETTING_PARAM_INFERRABLE |
+	                         G_PARAM_STATIC_STRINGS);
 
 	/**
 	 * NMSettingOvsPort:bond-updelay:
@@ -442,14 +438,13 @@ nm_setting_ovs_port_class_init (NMSettingOvsPortClass *klass)
 	 *
 	 * Since: 1.10
 	 **/
-	g_object_class_install_property
-	        (object_class, PROP_BOND_UPDELAY,
-	         g_param_spec_uint (NM_SETTING_OVS_PORT_BOND_UPDELAY, "", "",
-	                            0, G_MAXUINT, 0,
-	                            G_PARAM_READWRITE |
-	                            G_PARAM_CONSTRUCT |
-	                            NM_SETTING_PARAM_INFERRABLE |
-	                            G_PARAM_STATIC_STRINGS));
+	obj_properties[PROP_BOND_UPDELAY] =
+	    g_param_spec_uint (NM_SETTING_OVS_PORT_BOND_UPDELAY, "", "",
+	                       0, G_MAXUINT, 0,
+	                       G_PARAM_READWRITE |
+	                       G_PARAM_CONSTRUCT |
+	                       NM_SETTING_PARAM_INFERRABLE |
+	                       G_PARAM_STATIC_STRINGS);
 
 	/**
 	 * NMSettingOvsPort:bond-downdelay:
@@ -458,14 +453,15 @@ nm_setting_ovs_port_class_init (NMSettingOvsPortClass *klass)
 	 *
 	 * Since: 1.10
 	 **/
-	g_object_class_install_property
-	        (object_class, PROP_BOND_DOWNDELAY,
-	         g_param_spec_uint (NM_SETTING_OVS_PORT_BOND_DOWNDELAY, "", "",
-	                            0, G_MAXUINT, 0,
-	                            G_PARAM_READWRITE |
-	                            G_PARAM_CONSTRUCT |
-	                            NM_SETTING_PARAM_INFERRABLE |
-	                            G_PARAM_STATIC_STRINGS));
+	obj_properties[PROP_BOND_DOWNDELAY] =
+	    g_param_spec_uint (NM_SETTING_OVS_PORT_BOND_DOWNDELAY, "", "",
+	                       0, G_MAXUINT, 0,
+	                       G_PARAM_READWRITE |
+	                       G_PARAM_CONSTRUCT |
+	                       NM_SETTING_PARAM_INFERRABLE |
+	                       G_PARAM_STATIC_STRINGS);
+
+	g_object_class_install_properties (object_class, _PROPERTY_ENUMS_LAST, obj_properties);
 
 	_nm_setting_class_commit (setting_class, NM_META_SETTING_TYPE_OVS_PORT);
 }
diff --git a/libnm-core/nm-setting-ppp.c b/libnm-core/nm-setting-ppp.c
index 7425da19..12a8c366 100644
--- a/libnm-core/nm-setting-ppp.c
+++ b/libnm-core/nm-setting-ppp.c
@@ -23,6 +23,7 @@
 #include "nm-default.h"
 
 #include "nm-setting-ppp.h"
+
 #include "nm-setting-private.h"
 
 /**
@@ -35,9 +36,28 @@
  * cable and DSL modems and some mobile broadband devices.
  **/
 
-G_DEFINE_TYPE (NMSettingPpp, nm_setting_ppp, NM_TYPE_SETTING)
+/*****************************************************************************/
 
-#define NM_SETTING_PPP_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), NM_TYPE_SETTING_PPP, NMSettingPppPrivate))
+NM_GOBJECT_PROPERTIES_DEFINE_BASE (
+	PROP_NOAUTH,
+	PROP_REFUSE_EAP,
+	PROP_REFUSE_PAP,
+	PROP_REFUSE_CHAP,
+	PROP_REFUSE_MSCHAP,
+	PROP_REFUSE_MSCHAPV2,
+	PROP_NOBSDCOMP,
+	PROP_NODEFLATE,
+	PROP_NO_VJ_COMP,
+	PROP_REQUIRE_MPPE,
+	PROP_REQUIRE_MPPE_128,
+	PROP_MPPE_STATEFUL,
+	PROP_CRTSCTS,
+	PROP_BAUD,
+	PROP_MRU,
+	PROP_MTU,
+	PROP_LCP_ECHO_FAILURE,
+	PROP_LCP_ECHO_INTERVAL,
+);
 
 typedef struct {
 	gboolean noauth;
@@ -60,42 +80,11 @@ typedef struct {
 	guint32 lcp_echo_interval;
 } NMSettingPppPrivate;
 
-enum {
-	PROP_0,
-	PROP_NOAUTH,
-	PROP_REFUSE_EAP,
-	PROP_REFUSE_PAP,
-	PROP_REFUSE_CHAP,
-	PROP_REFUSE_MSCHAP,
-	PROP_REFUSE_MSCHAPV2,
-	PROP_NOBSDCOMP,
-	PROP_NODEFLATE,
-	PROP_NO_VJ_COMP,
-	PROP_REQUIRE_MPPE,
-	PROP_REQUIRE_MPPE_128,
-	PROP_MPPE_STATEFUL,
-	PROP_CRTSCTS,
-	PROP_BAUD,
-	PROP_MRU,
-	PROP_MTU,
-	PROP_LCP_ECHO_FAILURE,
-	PROP_LCP_ECHO_INTERVAL,
+G_DEFINE_TYPE (NMSettingPpp, nm_setting_ppp, NM_TYPE_SETTING)
 
-	LAST_PROP
-};
+#define NM_SETTING_PPP_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), NM_TYPE_SETTING_PPP, NMSettingPppPrivate))
 
-/**
- * nm_setting_ppp_new:
- *
- * Creates a new #NMSettingPpp object with default values.
- *
- * Returns: (transfer full): the new empty #NMSettingPpp object
- **/
-NMSetting *
-nm_setting_ppp_new (void)
-{
-	return (NMSetting *) g_object_new (NM_TYPE_SETTING_PPP, NULL);
-}
+/*****************************************************************************/
 
 /**
  * nm_setting_ppp_get_noauth:
@@ -383,71 +372,68 @@ verify (NMSetting *setting, NMConnection *connection, GError **error)
 	return TRUE;
 }
 
-static void
-nm_setting_ppp_init (NMSettingPpp *setting)
-{
-}
+/*****************************************************************************/
 
 static void
-set_property (GObject *object, guint prop_id,
-              const GValue *value, GParamSpec *pspec)
+get_property (GObject *object, guint prop_id,
+              GValue *value, GParamSpec *pspec)
 {
-	NMSettingPppPrivate *priv = NM_SETTING_PPP_GET_PRIVATE (object);
+	NMSettingPpp *setting = NM_SETTING_PPP (object);
 
 	switch (prop_id) {
 	case PROP_NOAUTH:
-		priv->noauth = g_value_get_boolean (value);
+		g_value_set_boolean (value, nm_setting_ppp_get_noauth (setting));
 		break;
 	case PROP_REFUSE_EAP:
-		priv->refuse_eap = g_value_get_boolean (value);
+		g_value_set_boolean (value, nm_setting_ppp_get_refuse_eap (setting));
 		break;
 	case PROP_REFUSE_PAP:
-		priv->refuse_pap = g_value_get_boolean (value);
+		g_value_set_boolean (value, nm_setting_ppp_get_refuse_pap (setting));
 		break;
 	case PROP_REFUSE_CHAP:
-		priv->refuse_chap = g_value_get_boolean (value);
+		g_value_set_boolean (value, nm_setting_ppp_get_refuse_chap (setting));
 		break;
 	case PROP_REFUSE_MSCHAP:
-		priv->refuse_mschap = g_value_get_boolean (value);
+		g_value_set_boolean (value, nm_setting_ppp_get_refuse_mschap (setting));
 		break;
 	case PROP_REFUSE_MSCHAPV2:
-		priv->refuse_mschapv2 = g_value_get_boolean (value);
+		g_value_set_boolean (value, nm_setting_ppp_get_refuse_mschapv2 (setting));
 		break;
 	case PROP_NOBSDCOMP:
-		priv->nobsdcomp = g_value_get_boolean (value);
+		g_value_set_boolean (value, nm_setting_ppp_get_nobsdcomp (setting));
 		break;
 	case PROP_NODEFLATE:
-		priv->nodeflate = g_value_get_boolean (value);
+		g_value_set_boolean (value, nm_setting_ppp_get_nodeflate (setting));
 		break;
 	case PROP_NO_VJ_COMP:
-		priv->no_vj_comp = g_value_get_boolean (value);
+		g_value_set_boolean (value, nm_setting_ppp_get_no_vj_comp (setting));
 		break;
 	case PROP_REQUIRE_MPPE:
-		priv->require_mppe = g_value_get_boolean (value);
+		g_value_set_boolean (value, nm_setting_ppp_get_require_mppe (setting));
 		break;
 	case PROP_REQUIRE_MPPE_128:
-		priv->require_mppe_128 = g_value_get_boolean (value);
+		g_value_set_boolean (value, nm_setting_ppp_get_require_mppe_128 (setting));
 		break;
 	case PROP_MPPE_STATEFUL:
-		priv->mppe_stateful = g_value_get_boolean (value);
+		g_value_set_boolean (value, nm_setting_ppp_get_mppe_stateful (setting));
 		break;
 	case PROP_CRTSCTS:
-		priv->crtscts = g_value_get_boolean (value);
+		g_value_set_boolean (value, nm_setting_ppp_get_crtscts (setting));
 		break;
 	case PROP_BAUD:
-		priv->baud = g_value_get_uint (value);
+		g_value_set_uint (value, nm_setting_ppp_get_baud (setting));
 		break;
 	case PROP_MRU:
-		priv->mru = g_value_get_uint (value);
+		g_value_set_uint (value, nm_setting_ppp_get_mru (setting));
 		break;
 	case PROP_MTU:
-		priv->mtu = g_value_get_uint (value);
+		g_value_set_uint (value, nm_setting_ppp_get_mtu (setting));
 		break;
 	case PROP_LCP_ECHO_FAILURE:
-		priv->lcp_echo_failure = g_value_get_uint (value);
+		g_value_set_uint (value, nm_setting_ppp_get_lcp_echo_failure (setting));
 		break;
 	case PROP_LCP_ECHO_INTERVAL:
-		priv->lcp_echo_interval = g_value_get_uint (value);
+		g_value_set_uint (value, nm_setting_ppp_get_lcp_echo_interval (setting));
 		break;
 	default:
 		G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
@@ -456,65 +442,65 @@ set_property (GObject *object, guint prop_id,
 }
 
 static void
-get_property (GObject *object, guint prop_id,
-              GValue *value, GParamSpec *pspec)
+set_property (GObject *object, guint prop_id,
+              const GValue *value, GParamSpec *pspec)
 {
-	NMSettingPpp *setting = NM_SETTING_PPP (object);
+	NMSettingPppPrivate *priv = NM_SETTING_PPP_GET_PRIVATE (object);
 
 	switch (prop_id) {
 	case PROP_NOAUTH:
-		g_value_set_boolean (value, nm_setting_ppp_get_noauth (setting));
+		priv->noauth = g_value_get_boolean (value);
 		break;
 	case PROP_REFUSE_EAP:
-		g_value_set_boolean (value, nm_setting_ppp_get_refuse_eap (setting));
+		priv->refuse_eap = g_value_get_boolean (value);
 		break;
 	case PROP_REFUSE_PAP:
-		g_value_set_boolean (value, nm_setting_ppp_get_refuse_pap (setting));
+		priv->refuse_pap = g_value_get_boolean (value);
 		break;
 	case PROP_REFUSE_CHAP:
-		g_value_set_boolean (value, nm_setting_ppp_get_refuse_chap (setting));
+		priv->refuse_chap = g_value_get_boolean (value);
 		break;
 	case PROP_REFUSE_MSCHAP:
-		g_value_set_boolean (value, nm_setting_ppp_get_refuse_mschap (setting));
+		priv->refuse_mschap = g_value_get_boolean (value);
 		break;
 	case PROP_REFUSE_MSCHAPV2:
-		g_value_set_boolean (value, nm_setting_ppp_get_refuse_mschapv2 (setting));
+		priv->refuse_mschapv2 = g_value_get_boolean (value);
 		break;
 	case PROP_NOBSDCOMP:
-		g_value_set_boolean (value, nm_setting_ppp_get_nobsdcomp (setting));
+		priv->nobsdcomp = g_value_get_boolean (value);
 		break;
 	case PROP_NODEFLATE:
-		g_value_set_boolean (value, nm_setting_ppp_get_nodeflate (setting));
+		priv->nodeflate = g_value_get_boolean (value);
 		break;
 	case PROP_NO_VJ_COMP:
-		g_value_set_boolean (value, nm_setting_ppp_get_no_vj_comp (setting));
+		priv->no_vj_comp = g_value_get_boolean (value);
 		break;
 	case PROP_REQUIRE_MPPE:
-		g_value_set_boolean (value, nm_setting_ppp_get_require_mppe (setting));
+		priv->require_mppe = g_value_get_boolean (value);
 		break;
 	case PROP_REQUIRE_MPPE_128:
-		g_value_set_boolean (value, nm_setting_ppp_get_require_mppe_128 (setting));
+		priv->require_mppe_128 = g_value_get_boolean (value);
 		break;
 	case PROP_MPPE_STATEFUL:
-		g_value_set_boolean (value, nm_setting_ppp_get_mppe_stateful (setting));
+		priv->mppe_stateful = g_value_get_boolean (value);
 		break;
 	case PROP_CRTSCTS:
-		g_value_set_boolean (value, nm_setting_ppp_get_crtscts (setting));
+		priv->crtscts = g_value_get_boolean (value);
 		break;
 	case PROP_BAUD:
-		g_value_set_uint (value, nm_setting_ppp_get_baud (setting));
+		priv->baud = g_value_get_uint (value);
 		break;
 	case PROP_MRU:
-		g_value_set_uint (value, nm_setting_ppp_get_mru (setting));
+		priv->mru = g_value_get_uint (value);
 		break;
 	case PROP_MTU:
-		g_value_set_uint (value, nm_setting_ppp_get_mtu (setting));
+		priv->mtu = g_value_get_uint (value);
 		break;
 	case PROP_LCP_ECHO_FAILURE:
-		g_value_set_uint (value, nm_setting_ppp_get_lcp_echo_failure (setting));
+		priv->lcp_echo_failure = g_value_get_uint (value);
 		break;
 	case PROP_LCP_ECHO_INTERVAL:
-		g_value_set_uint (value, nm_setting_ppp_get_lcp_echo_interval (setting));
+		priv->lcp_echo_interval = g_value_get_uint (value);
 		break;
 	default:
 		G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
@@ -522,6 +508,26 @@ get_property (GObject *object, guint prop_id,
 	}
 }
 
+/*****************************************************************************/
+
+static void
+nm_setting_ppp_init (NMSettingPpp *setting)
+{
+}
+
+/**
+ * nm_setting_ppp_new:
+ *
+ * Creates a new #NMSettingPpp object with default values.
+ *
+ * Returns: (transfer full): the new empty #NMSettingPpp object
+ **/
+NMSetting *
+nm_setting_ppp_new (void)
+{
+	return (NMSetting *) g_object_new (NM_TYPE_SETTING_PPP, NULL);
+}
+
 static void
 nm_setting_ppp_class_init (NMSettingPppClass *klass)
 {
@@ -530,8 +536,8 @@ nm_setting_ppp_class_init (NMSettingPppClass *klass)
 
 	g_type_class_add_private (klass, sizeof (NMSettingPppPrivate));
 
-	object_class->set_property = set_property;
 	object_class->get_property = get_property;
+	object_class->set_property = set_property;
 
 	setting_class->verify = verify;
 
@@ -542,120 +548,111 @@ nm_setting_ppp_class_init (NMSettingPppClass *klass)
 	 * authenticate itself to the client.  If %FALSE, require authentication
 	 * from the remote side.  In almost all cases, this should be %TRUE.
 	 **/
-	g_object_class_install_property
-		(object_class, PROP_NOAUTH,
-		 g_param_spec_boolean (NM_SETTING_PPP_NOAUTH, "", "",
-		                       TRUE,
-		                       G_PARAM_READWRITE |
-		                       G_PARAM_CONSTRUCT |
-		                       G_PARAM_STATIC_STRINGS));
+	obj_properties[PROP_NOAUTH] =
+	    g_param_spec_boolean (NM_SETTING_PPP_NOAUTH, "", "",
+	                          TRUE,
+	                          G_PARAM_READWRITE |
+	                          G_PARAM_CONSTRUCT |
+	                          G_PARAM_STATIC_STRINGS);
 
 	/**
 	 * NMSettingPpp:refuse-eap:
 	 *
 	 * If %TRUE, the EAP authentication method will not be used.
 	 **/
-	g_object_class_install_property
-		(object_class, PROP_REFUSE_EAP,
-		 g_param_spec_boolean (NM_SETTING_PPP_REFUSE_EAP, "", "",
-		                       FALSE,
-		                       G_PARAM_READWRITE |
-		                       G_PARAM_CONSTRUCT |
-		                       G_PARAM_STATIC_STRINGS));
+	obj_properties[PROP_REFUSE_EAP] =
+	    g_param_spec_boolean (NM_SETTING_PPP_REFUSE_EAP, "", "",
+	                          FALSE,
+	                          G_PARAM_READWRITE |
+	                          G_PARAM_CONSTRUCT |
+	                          G_PARAM_STATIC_STRINGS);
 
 	/**
 	 * NMSettingPpp:refuse-pap:
 	 *
 	 * If %TRUE, the PAP authentication method will not be used.
 	 **/
-	g_object_class_install_property
-		(object_class, PROP_REFUSE_PAP,
-		 g_param_spec_boolean (NM_SETTING_PPP_REFUSE_PAP, "", "",
-		                       FALSE,
-		                       G_PARAM_READWRITE |
-		                       G_PARAM_CONSTRUCT |
-		                       G_PARAM_STATIC_STRINGS));
+	obj_properties[PROP_REFUSE_PAP] =
+	    g_param_spec_boolean (NM_SETTING_PPP_REFUSE_PAP, "", "",
+	                          FALSE,
+	                          G_PARAM_READWRITE |
+	                          G_PARAM_CONSTRUCT |
+	                          G_PARAM_STATIC_STRINGS);
 
 	/**
 	 * NMSettingPpp:refuse-chap:
 	 *
 	 * If %TRUE, the CHAP authentication method will not be used.
 	 **/
-	g_object_class_install_property
-		(object_class, PROP_REFUSE_CHAP,
-		 g_param_spec_boolean (NM_SETTING_PPP_REFUSE_CHAP, "", "",
-		                       FALSE,
-		                       G_PARAM_READWRITE |
-		                       G_PARAM_CONSTRUCT |
-		                       G_PARAM_STATIC_STRINGS));
+	obj_properties[PROP_REFUSE_CHAP] =
+	    g_param_spec_boolean (NM_SETTING_PPP_REFUSE_CHAP, "", "",
+	                          FALSE,
+	                          G_PARAM_READWRITE |
+	                          G_PARAM_CONSTRUCT |
+	                          G_PARAM_STATIC_STRINGS);
 
 	/**
 	 * NMSettingPpp:refuse-mschap:
 	 *
 	 * If %TRUE, the MSCHAP authentication method will not be used.
 	 **/
-	g_object_class_install_property
-		(object_class, PROP_REFUSE_MSCHAP,
-		 g_param_spec_boolean (NM_SETTING_PPP_REFUSE_MSCHAP, "", "",
-		                       FALSE,
-		                       G_PARAM_READWRITE |
-		                       G_PARAM_CONSTRUCT |
-		                       G_PARAM_STATIC_STRINGS));
+	obj_properties[PROP_REFUSE_MSCHAP] =
+	    g_param_spec_boolean (NM_SETTING_PPP_REFUSE_MSCHAP, "", "",
+	                          FALSE,
+	                          G_PARAM_READWRITE |
+	                          G_PARAM_CONSTRUCT |
+	                          G_PARAM_STATIC_STRINGS);
 
 	/**
 	 * NMSettingPpp:refuse-mschapv2:
 	 *
 	 * If %TRUE, the MSCHAPv2 authentication method will not be used.
 	 **/
-	g_object_class_install_property
-		(object_class, PROP_REFUSE_MSCHAPV2,
-		 g_param_spec_boolean (NM_SETTING_PPP_REFUSE_MSCHAPV2, "", "",
-		                       FALSE,
-		                       G_PARAM_READWRITE |
-		                       G_PARAM_CONSTRUCT |
-		                       G_PARAM_STATIC_STRINGS));
+	obj_properties[PROP_REFUSE_MSCHAPV2] =
+	    g_param_spec_boolean (NM_SETTING_PPP_REFUSE_MSCHAPV2, "", "",
+	                          FALSE,
+	                          G_PARAM_READWRITE |
+	                          G_PARAM_CONSTRUCT |
+	                          G_PARAM_STATIC_STRINGS);
 
 	/**
 	 * NMSettingPpp:nobsdcomp:
 	 *
 	 * If %TRUE, BSD compression will not be requested.
 	 **/
-	g_object_class_install_property
-		(object_class, PROP_NOBSDCOMP,
-		 g_param_spec_boolean (NM_SETTING_PPP_NOBSDCOMP, "", "",
-		                       FALSE,
-		                       G_PARAM_READWRITE |
-		                       G_PARAM_CONSTRUCT |
-		                       NM_SETTING_PARAM_FUZZY_IGNORE |
-		                       G_PARAM_STATIC_STRINGS));
+	obj_properties[PROP_NOBSDCOMP] =
+	    g_param_spec_boolean (NM_SETTING_PPP_NOBSDCOMP, "", "",
+	                          FALSE,
+	                          G_PARAM_READWRITE |
+	                          G_PARAM_CONSTRUCT |
+	                          NM_SETTING_PARAM_FUZZY_IGNORE |
+	                          G_PARAM_STATIC_STRINGS);
 
 	/**
 	 * NMSettingPpp:nodeflate:
 	 *
 	 * If %TRUE, "deflate" compression will not be requested.
 	 **/
-	g_object_class_install_property
-		(object_class, PROP_NODEFLATE,
-		 g_param_spec_boolean (NM_SETTING_PPP_NODEFLATE, "", "",
-		                       FALSE,
-		                       G_PARAM_READWRITE |
-		                       G_PARAM_CONSTRUCT |
-		                       NM_SETTING_PARAM_FUZZY_IGNORE |
-		                       G_PARAM_STATIC_STRINGS));
+	obj_properties[PROP_NODEFLATE] =
+	    g_param_spec_boolean (NM_SETTING_PPP_NODEFLATE, "", "",
+	                          FALSE,
+	                          G_PARAM_READWRITE |
+	                          G_PARAM_CONSTRUCT |
+	                          NM_SETTING_PARAM_FUZZY_IGNORE |
+	                          G_PARAM_STATIC_STRINGS);
 
 	/**
 	 * NMSettingPpp:no-vj-comp:
 	 *
 	 * If %TRUE, Van Jacobsen TCP header compression will not be requested.
 	 **/
-	g_object_class_install_property
-		(object_class, PROP_NO_VJ_COMP,
-		 g_param_spec_boolean (NM_SETTING_PPP_NO_VJ_COMP, "", "",
-		                       FALSE,
-		                       G_PARAM_READWRITE |
-		                       G_PARAM_CONSTRUCT |
-		                       NM_SETTING_PARAM_FUZZY_IGNORE |
-		                       G_PARAM_STATIC_STRINGS));
+	obj_properties[PROP_NO_VJ_COMP] =
+	    g_param_spec_boolean (NM_SETTING_PPP_NO_VJ_COMP, "", "",
+	                          FALSE,
+	                          G_PARAM_READWRITE |
+	                          G_PARAM_CONSTRUCT |
+	                          NM_SETTING_PARAM_FUZZY_IGNORE |
+	                          G_PARAM_STATIC_STRINGS);
 
 	/**
 	 * NMSettingPpp:require-mppe:
@@ -665,13 +662,12 @@ nm_setting_ppp_class_init (NMSettingPppClass *klass)
 	 * session will fail.  Note that MPPE is not used on mobile broadband
 	 * connections.
 	 **/
-	g_object_class_install_property
-		(object_class, PROP_REQUIRE_MPPE,
-		 g_param_spec_boolean (NM_SETTING_PPP_REQUIRE_MPPE, "", "",
-		                       FALSE,
-		                       G_PARAM_READWRITE |
-		                       G_PARAM_CONSTRUCT |
-		                       G_PARAM_STATIC_STRINGS));
+	obj_properties[PROP_REQUIRE_MPPE] =
+	    g_param_spec_boolean (NM_SETTING_PPP_REQUIRE_MPPE, "", "",
+	                          FALSE,
+	                          G_PARAM_READWRITE |
+	                          G_PARAM_CONSTRUCT |
+	                          G_PARAM_STATIC_STRINGS);
 
 	/**
 	 * NMSettingPpp:require-mppe-128:
@@ -680,12 +676,11 @@ nm_setting_ppp_class_init (NMSettingPppClass *klass)
 	 * required for the PPP session, and the "require-mppe" property must also
 	 * be set to %TRUE.  If 128-bit MPPE is not available the session will fail.
 	 **/
-	g_object_class_install_property
-		(object_class, PROP_REQUIRE_MPPE_128,
-		 g_param_spec_boolean (NM_SETTING_PPP_REQUIRE_MPPE_128, "", "",
-		                       FALSE,
-		                       G_PARAM_READWRITE  | G_PARAM_CONSTRUCT |
-		                       G_PARAM_STATIC_STRINGS));
+	obj_properties[PROP_REQUIRE_MPPE_128] =
+	    g_param_spec_boolean (NM_SETTING_PPP_REQUIRE_MPPE_128, "", "",
+	                          FALSE,
+	                          G_PARAM_READWRITE  | G_PARAM_CONSTRUCT |
+	                          G_PARAM_STATIC_STRINGS);
 
 	/**
 	 * NMSettingPpp:mppe-stateful:
@@ -693,13 +688,12 @@ nm_setting_ppp_class_init (NMSettingPppClass *klass)
 	 * If %TRUE, stateful MPPE is used.  See pppd documentation for more
 	 * information on stateful MPPE.
 	 **/
-	g_object_class_install_property
-		(object_class, PROP_MPPE_STATEFUL,
-		 g_param_spec_boolean (NM_SETTING_PPP_MPPE_STATEFUL, "", "",
-		                       FALSE,
-		                       G_PARAM_READWRITE |
-		                       G_PARAM_CONSTRUCT |
-		                       G_PARAM_STATIC_STRINGS));
+	obj_properties[PROP_MPPE_STATEFUL] =
+	    g_param_spec_boolean (NM_SETTING_PPP_MPPE_STATEFUL, "", "",
+	                          FALSE,
+	                          G_PARAM_READWRITE |
+	                          G_PARAM_CONSTRUCT |
+	                          G_PARAM_STATIC_STRINGS);
 
 	/**
 	 * NMSettingPpp:crtscts:
@@ -708,13 +702,12 @@ nm_setting_ppp_class_init (NMSettingPppClass *klass)
 	 * flow control with RTS and CTS signals.  This value should normally be set
 	 * to %FALSE.
 	 **/
-	g_object_class_install_property
-		(object_class, PROP_CRTSCTS,
-		 g_param_spec_boolean (NM_SETTING_PPP_CRTSCTS, "", "",
-		                       FALSE,
-		                       G_PARAM_READWRITE |
-		                       G_PARAM_CONSTRUCT |
-		                       G_PARAM_STATIC_STRINGS));
+	obj_properties[PROP_CRTSCTS] =
+	    g_param_spec_boolean (NM_SETTING_PPP_CRTSCTS, "", "",
+	                          FALSE,
+	                          G_PARAM_READWRITE |
+	                          G_PARAM_CONSTRUCT |
+	                          G_PARAM_STATIC_STRINGS);
 
 	/**
 	 * NMSettingPpp:baud:
@@ -723,14 +716,13 @@ nm_setting_ppp_class_init (NMSettingPppClass *klass)
 	 * baudrate.  This value should normally be left as 0 to automatically
 	 * choose the speed.
 	 **/
-	g_object_class_install_property
-		(object_class, PROP_BAUD,
-		 g_param_spec_uint (NM_SETTING_PPP_BAUD, "", "",
-		                    0, G_MAXUINT32, 0,
-		                    G_PARAM_READWRITE |
-		                    G_PARAM_CONSTRUCT |
-		                    NM_SETTING_PARAM_FUZZY_IGNORE |
-		                    G_PARAM_STATIC_STRINGS));
+	obj_properties[PROP_BAUD] =
+	    g_param_spec_uint (NM_SETTING_PPP_BAUD, "", "",
+	                       0, G_MAXUINT32, 0,
+	                       G_PARAM_READWRITE |
+	                       G_PARAM_CONSTRUCT |
+	                       NM_SETTING_PARAM_FUZZY_IGNORE |
+	                       G_PARAM_STATIC_STRINGS);
 
 	/**
 	 * NMSettingPpp:mru:
@@ -739,13 +731,12 @@ nm_setting_ppp_class_init (NMSettingPppClass *klass)
 	 * larger than the specified size.  If non-zero, the MRU should be between
 	 * 128 and 16384.
 	 */
-	g_object_class_install_property
-		(object_class, PROP_MRU,
-		 g_param_spec_uint (NM_SETTING_PPP_MRU, "", "",
-		                    0, 16384, 0,
-		                    G_PARAM_READWRITE |
-		                    G_PARAM_CONSTRUCT |
-		                    G_PARAM_STATIC_STRINGS));
+	obj_properties[PROP_MRU] =
+	    g_param_spec_uint (NM_SETTING_PPP_MRU, "", "",
+	                       0, 16384, 0,
+	                       G_PARAM_READWRITE |
+	                       G_PARAM_CONSTRUCT |
+	                       G_PARAM_STATIC_STRINGS);
 
 	/**
 	 * NMSettingPpp:mtu:
@@ -753,14 +744,13 @@ nm_setting_ppp_class_init (NMSettingPppClass *klass)
 	 * If non-zero, instruct pppd to send packets no larger than the specified
 	 * size.
 	 **/
-	g_object_class_install_property
-		(object_class, PROP_MTU,
-		 g_param_spec_uint (NM_SETTING_PPP_MTU, "", "",
-		                    0, G_MAXUINT32, 0,
-		                    G_PARAM_READWRITE |
-		                    G_PARAM_CONSTRUCT |
-		                    NM_SETTING_PARAM_FUZZY_IGNORE |
-		                    G_PARAM_STATIC_STRINGS));
+	obj_properties[PROP_MTU] =
+	    g_param_spec_uint (NM_SETTING_PPP_MTU, "", "",
+	                       0, G_MAXUINT32, 0,
+	                       G_PARAM_READWRITE |
+	                       G_PARAM_CONSTRUCT |
+	                       NM_SETTING_PARAM_FUZZY_IGNORE |
+	                       G_PARAM_STATIC_STRINGS);
 
 	/**
 	 * NMSettingPpp:lcp-echo-failure:
@@ -770,14 +760,13 @@ nm_setting_ppp_class_init (NMSettingPppClass *klass)
 	 * peer.  The "lcp-echo-interval" property must also be set to a non-zero
 	 * value if this property is used.
 	 **/
-	g_object_class_install_property
-		(object_class, PROP_LCP_ECHO_FAILURE,
-		 g_param_spec_uint (NM_SETTING_PPP_LCP_ECHO_FAILURE, "", "",
-		                    0, G_MAXUINT32, 0,
-		                    G_PARAM_READWRITE |
-		                    G_PARAM_CONSTRUCT |
-		                    NM_SETTING_PARAM_FUZZY_IGNORE |
-		                    G_PARAM_STATIC_STRINGS));
+	obj_properties[PROP_LCP_ECHO_FAILURE] =
+	    g_param_spec_uint (NM_SETTING_PPP_LCP_ECHO_FAILURE, "", "",
+	                       0, G_MAXUINT32, 0,
+	                       G_PARAM_READWRITE |
+	                       G_PARAM_CONSTRUCT |
+	                       NM_SETTING_PARAM_FUZZY_IGNORE |
+	                       G_PARAM_STATIC_STRINGS);
 
 	/**
 	 * NMSettingPpp:lcp-echo-interval:
@@ -787,14 +776,15 @@ nm_setting_ppp_class_init (NMSettingPppClass *klass)
 	 * peers will respond to echo requests and some will not, and it is not
 	 * possible to autodetect this.
 	 **/
-	g_object_class_install_property
-		(object_class, PROP_LCP_ECHO_INTERVAL,
-		 g_param_spec_uint (NM_SETTING_PPP_LCP_ECHO_INTERVAL, "", "",
-		                    0, G_MAXUINT32, 0,
-		                    G_PARAM_READWRITE |
-		                    G_PARAM_CONSTRUCT |
-		                    NM_SETTING_PARAM_FUZZY_IGNORE |
-		                    G_PARAM_STATIC_STRINGS));
+	obj_properties[PROP_LCP_ECHO_INTERVAL] =
+	    g_param_spec_uint (NM_SETTING_PPP_LCP_ECHO_INTERVAL, "", "",
+	                       0, G_MAXUINT32, 0,
+	                       G_PARAM_READWRITE |
+	                       G_PARAM_CONSTRUCT |
+	                       NM_SETTING_PARAM_FUZZY_IGNORE |
+	                       G_PARAM_STATIC_STRINGS);
+
+	g_object_class_install_properties (object_class, _PROPERTY_ENUMS_LAST, obj_properties);
 
 	_nm_setting_class_commit (setting_class, NM_META_SETTING_TYPE_PPP);
 }
diff --git a/libnm-core/nm-setting-pppoe.c b/libnm-core/nm-setting-pppoe.c
index 793d93ce..e3166888 100644
--- a/libnm-core/nm-setting-pppoe.c
+++ b/libnm-core/nm-setting-pppoe.c
@@ -22,9 +22,10 @@
 
 #include "nm-default.h"
 
+#include "nm-setting-pppoe.h"
+
 #include <string.h>
 
-#include "nm-setting-pppoe.h"
 #include "nm-setting-ppp.h"
 #include "nm-setting-private.h"
 #include "nm-core-enum-types.h"
@@ -38,9 +39,15 @@
  * to provide IP transport, for example cable or DSL modems.
  **/
 
-G_DEFINE_TYPE (NMSettingPppoe, nm_setting_pppoe, NM_TYPE_SETTING)
+/*****************************************************************************/
 
-#define NM_SETTING_PPPOE_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), NM_TYPE_SETTING_PPPOE, NMSettingPppoePrivate))
+NM_GOBJECT_PROPERTIES_DEFINE_BASE (
+	PROP_PARENT,
+	PROP_SERVICE,
+	PROP_USERNAME,
+	PROP_PASSWORD,
+	PROP_PASSWORD_FLAGS,
+);
 
 typedef struct {
 	char *parent;
@@ -50,29 +57,11 @@ typedef struct {
 	NMSettingSecretFlags password_flags;
 } NMSettingPppoePrivate;
 
-enum {
-	PROP_0,
-	PROP_PARENT,
-	PROP_SERVICE,
-	PROP_USERNAME,
-	PROP_PASSWORD,
-	PROP_PASSWORD_FLAGS,
+G_DEFINE_TYPE (NMSettingPppoe, nm_setting_pppoe, NM_TYPE_SETTING)
 
-	LAST_PROP
-};
+#define NM_SETTING_PPPOE_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), NM_TYPE_SETTING_PPPOE, NMSettingPppoePrivate))
 
-/**
- * nm_setting_pppoe_new:
- *
- * Creates a new #NMSettingPppoe object with default values.
- *
- * Returns: (transfer full): the new empty #NMSettingPppoe object
- **/
-NMSetting *
-nm_setting_pppoe_new (void)
-{
-	return (NMSetting *) g_object_new (NM_TYPE_SETTING_PPPOE, NULL);
-}
+/*****************************************************************************/
 
 /**
  * nm_setting_pppoe_get_parent:
@@ -207,36 +196,29 @@ need_secrets (NMSetting *setting)
 	return secrets;
 }
 
-static void
-nm_setting_pppoe_init (NMSettingPppoe *setting)
-{
-}
+/*****************************************************************************/
 
 static void
-set_property (GObject *object, guint prop_id,
-              const GValue *value, GParamSpec *pspec)
+get_property (GObject *object, guint prop_id,
+              GValue *value, GParamSpec *pspec)
 {
-	NMSettingPppoePrivate *priv = NM_SETTING_PPPOE_GET_PRIVATE (object);
+	NMSettingPppoe *setting = NM_SETTING_PPPOE (object);
 
 	switch (prop_id) {
 	case PROP_PARENT:
-		g_free (priv->parent);
-		priv->parent = g_value_dup_string (value);
+		g_value_set_string (value, nm_setting_pppoe_get_parent (setting));
 		break;
 	case PROP_SERVICE:
-		g_free (priv->service);
-		priv->service = g_value_dup_string (value);
+		g_value_set_string (value, nm_setting_pppoe_get_service (setting));
 		break;
 	case PROP_USERNAME:
-		g_free (priv->username);
-		priv->username = g_value_dup_string (value);
+		g_value_set_string (value, nm_setting_pppoe_get_username (setting));
 		break;
 	case PROP_PASSWORD:
-		g_free (priv->password);
-		priv->password = g_value_dup_string (value);
+		g_value_set_string (value, nm_setting_pppoe_get_password (setting));
 		break;
 	case PROP_PASSWORD_FLAGS:
-		priv->password_flags = g_value_get_flags (value);
+		g_value_set_flags (value, nm_setting_pppoe_get_password_flags (setting));
 		break;
 	default:
 		G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
@@ -245,26 +227,30 @@ set_property (GObject *object, guint prop_id,
 }
 
 static void
-get_property (GObject *object, guint prop_id,
-              GValue *value, GParamSpec *pspec)
+set_property (GObject *object, guint prop_id,
+              const GValue *value, GParamSpec *pspec)
 {
-	NMSettingPppoe *setting = NM_SETTING_PPPOE (object);
+	NMSettingPppoePrivate *priv = NM_SETTING_PPPOE_GET_PRIVATE (object);
 
 	switch (prop_id) {
 	case PROP_PARENT:
-		g_value_set_string (value, nm_setting_pppoe_get_parent (setting));
+		g_free (priv->parent);
+		priv->parent = g_value_dup_string (value);
 		break;
 	case PROP_SERVICE:
-		g_value_set_string (value, nm_setting_pppoe_get_service (setting));
+		g_free (priv->service);
+		priv->service = g_value_dup_string (value);
 		break;
 	case PROP_USERNAME:
-		g_value_set_string (value, nm_setting_pppoe_get_username (setting));
+		g_free (priv->username);
+		priv->username = g_value_dup_string (value);
 		break;
 	case PROP_PASSWORD:
-		g_value_set_string (value, nm_setting_pppoe_get_password (setting));
+		g_free (priv->password);
+		priv->password = g_value_dup_string (value);
 		break;
 	case PROP_PASSWORD_FLAGS:
-		g_value_set_flags (value, nm_setting_pppoe_get_password_flags (setting));
+		priv->password_flags = g_value_get_flags (value);
 		break;
 	default:
 		G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
@@ -272,6 +258,26 @@ get_property (GObject *object, guint prop_id,
 	}
 }
 
+/*****************************************************************************/
+
+static void
+nm_setting_pppoe_init (NMSettingPppoe *setting)
+{
+}
+
+/**
+ * nm_setting_pppoe_new:
+ *
+ * Creates a new #NMSettingPppoe object with default values.
+ *
+ * Returns: (transfer full): the new empty #NMSettingPppoe object
+ **/
+NMSetting *
+nm_setting_pppoe_new (void)
+{
+	return (NMSetting *) g_object_new (NM_TYPE_SETTING_PPPOE, NULL);
+}
+
 static void
 finalize (GObject *object)
 {
@@ -293,8 +299,8 @@ nm_setting_pppoe_class_init (NMSettingPppoeClass *klass)
 
 	g_type_class_add_private (klass, sizeof (NMSettingPppoePrivate));
 
-	object_class->set_property = set_property;
 	object_class->get_property = get_property;
+	object_class->set_property = set_property;
 	object_class->finalize     = finalize;
 
 	setting_class->verify       = verify;
@@ -310,14 +316,13 @@ nm_setting_pppoe_class_init (NMSettingPppoeClass *klass)
 	 *
 	 * Since: 1.10
 	 **/
-	g_object_class_install_property
-		(object_class, PROP_PARENT,
-		 g_param_spec_string (NM_SETTING_PPPOE_PARENT, "", "",
-		                      NULL,
-		                      G_PARAM_READWRITE |
-		                      G_PARAM_CONSTRUCT |
-		                      NM_SETTING_PARAM_INFERRABLE |
-		                      G_PARAM_STATIC_STRINGS));
+	obj_properties[PROP_PARENT] =
+	    g_param_spec_string (NM_SETTING_PPPOE_PARENT, "", "",
+	                         NULL,
+	                         G_PARAM_READWRITE |
+	                         G_PARAM_CONSTRUCT |
+	                         NM_SETTING_PARAM_INFERRABLE |
+	                         G_PARAM_STATIC_STRINGS);
 
 	/**
 	 * NMSettingPppoe:service:
@@ -327,50 +332,48 @@ nm_setting_pppoe_class_init (NMSettingPppoeClass *klass)
 	 * this should be left blank.  It is only required if there are multiple
 	 * access concentrators or a specific service is known to be required.
 	 **/
-	g_object_class_install_property
-		(object_class, PROP_SERVICE,
-		 g_param_spec_string (NM_SETTING_PPPOE_SERVICE, "", "",
-		                      NULL,
-		                      G_PARAM_READWRITE |
-		                      G_PARAM_STATIC_STRINGS));
+	obj_properties[PROP_SERVICE] =
+	    g_param_spec_string (NM_SETTING_PPPOE_SERVICE, "", "",
+	                         NULL,
+	                         G_PARAM_READWRITE |
+	                         G_PARAM_STATIC_STRINGS);
 
 	/**
 	 * NMSettingPppoe:username:
 	 *
 	 * Username used to authenticate with the PPPoE service.
 	 **/
-	g_object_class_install_property
-		(object_class, PROP_USERNAME,
-		 g_param_spec_string (NM_SETTING_PPPOE_USERNAME, "", "",
-		                      NULL,
-		                      G_PARAM_READWRITE |
-		                      G_PARAM_STATIC_STRINGS));
+	obj_properties[PROP_USERNAME] =
+	    g_param_spec_string (NM_SETTING_PPPOE_USERNAME, "", "",
+	                         NULL,
+	                         G_PARAM_READWRITE |
+	                         G_PARAM_STATIC_STRINGS);
 
 	/**
 	 * NMSettingPppoe:password:
 	 *
 	 * Password used to authenticate with the PPPoE service.
 	 **/
-	g_object_class_install_property
-		(object_class, PROP_PASSWORD,
-		 g_param_spec_string (NM_SETTING_PPPOE_PASSWORD, "", "",
-		                      NULL,
-		                      G_PARAM_READWRITE |
-		                      NM_SETTING_PARAM_SECRET |
-		                      G_PARAM_STATIC_STRINGS));
+	obj_properties[PROP_PASSWORD] =
+	    g_param_spec_string (NM_SETTING_PPPOE_PASSWORD, "", "",
+	                         NULL,
+	                         G_PARAM_READWRITE |
+	                         NM_SETTING_PARAM_SECRET |
+	                         G_PARAM_STATIC_STRINGS);
 
 	/**
 	 * NMSettingPppoe:password-flags:
 	 *
 	 * Flags indicating how to handle the #NMSettingPppoe:password property.
 	 **/
-	g_object_class_install_property
-		(object_class, PROP_PASSWORD_FLAGS,
-		 g_param_spec_flags (NM_SETTING_PPPOE_PASSWORD_FLAGS, "", "",
-		                     NM_TYPE_SETTING_SECRET_FLAGS,
-		                     NM_SETTING_SECRET_FLAG_NONE,
-		                     G_PARAM_READWRITE |
-		                     G_PARAM_STATIC_STRINGS));
+	obj_properties[PROP_PASSWORD_FLAGS] =
+	    g_param_spec_flags (NM_SETTING_PPPOE_PASSWORD_FLAGS, "", "",
+	                        NM_TYPE_SETTING_SECRET_FLAGS,
+	                        NM_SETTING_SECRET_FLAG_NONE,
+	                        G_PARAM_READWRITE |
+	                        G_PARAM_STATIC_STRINGS);
+
+	g_object_class_install_properties (object_class, _PROPERTY_ENUMS_LAST, obj_properties);
 
 	_nm_setting_class_commit (setting_class, NM_META_SETTING_TYPE_PPPOE);
 }
diff --git a/libnm-core/nm-setting-private.h b/libnm-core/nm-setting-private.h
index 1e25226e..8f61b0ff 100644
--- a/libnm-core/nm-setting-private.h
+++ b/libnm-core/nm-setting-private.h
@@ -48,10 +48,9 @@ typedef enum NMSettingUpdateSecretResult {
 NMSettingUpdateSecretResult _nm_setting_update_secrets (NMSetting *setting,
                                                         GVariant *secrets,
                                                         GError **error);
-gboolean _nm_setting_clear_secrets (NMSetting *setting);
-gboolean _nm_setting_clear_secrets_with_flags (NMSetting *setting,
-                                               NMSettingClearSecretsWithFlagsFn func,
-                                               gpointer user_data);
+gboolean _nm_setting_clear_secrets (NMSetting *setting,
+                                    NMSettingClearSecretsWithFlagsFn func,
+                                    gpointer user_data);
 
 /* The property of the #NMSetting should be considered during comparisons that
  * use the %NM_SETTING_COMPARE_FLAG_INFERRABLE flag. Properties that don't have
@@ -82,9 +81,11 @@ gboolean _nm_setting_clear_secrets_with_flags (NMSetting *setting,
 
 #define NM_SETTING_PARAM_GENDATA_BACKED (1 << (7 + G_PARAM_USER_SHIFT))
 
-GVariant *_nm_setting_get_deprecated_virtual_interface_name (NMSetting *setting,
+GVariant *_nm_setting_get_deprecated_virtual_interface_name (const NMSettInfoSetting *sett_info,
+                                                             guint property_idx,
                                                              NMConnection *connection,
-                                                             const char *property);
+                                                             NMSetting *setting,
+                                                             NMConnectionSerializationFlags flags);
 
 NMSettingVerifyResult _nm_setting_verify (NMSetting *setting,
                                           NMConnection *connection,
@@ -95,6 +96,13 @@ gboolean _nm_setting_verify_secret_string (const char *str,
                                            const char *property,
                                            GError **error);
 
+gboolean _nm_setting_aggregate (NMSetting *setting,
+                                NMConnectionAggregateType type,
+                                gpointer arg);
+gboolean _nm_setting_vpn_aggregate (NMSettingVpn *setting,
+                                    NMConnectionAggregateType type,
+                                    gpointer arg);
+
 gboolean _nm_setting_slave_type_is_valid (const char *slave_type, const char **out_port_type);
 
 GVariant   *_nm_setting_to_dbus       (NMSetting *setting,
@@ -107,6 +115,11 @@ NMSetting  *_nm_setting_new_from_dbus (GType setting_type,
                                        NMSettingParseFlags parse_flags,
                                        GError **error);
 
+gboolean _nm_setting_property_is_regular_secret (NMSetting *setting,
+                                                 const char *secret_name);
+gboolean _nm_setting_property_is_regular_secret_flags (NMSetting *setting,
+                                                       const char *secret_flags_name);
+
 /*****************************************************************************/
 
 static inline GArray *
@@ -187,6 +200,11 @@ gboolean _nm_setting_use_legacy_property (NMSetting *setting,
 
 GPtrArray  *_nm_setting_need_secrets (NMSetting *setting);
 
+gboolean _nm_setting_should_compare_secret_property (NMSetting *setting,
+                                                     NMSetting *other,
+                                                     const char *secret_name,
+                                                     NMSettingCompareFlags flags);
+
 /*****************************************************************************/
 
 #endif  /* NM_SETTING_PRIVATE_H */
diff --git a/libnm-core/nm-setting-proxy.c b/libnm-core/nm-setting-proxy.c
index d544c7fa..dbb69aeb 100644
--- a/libnm-core/nm-setting-proxy.c
+++ b/libnm-core/nm-setting-proxy.c
@@ -22,6 +22,7 @@
 #include "nm-default.h"
 
 #include "nm-setting-proxy.h"
+
 #include "nm-utils.h"
 #include "nm-setting-private.h"
 
@@ -39,9 +40,14 @@
  * to fulfill client queries.
  **/
 
-G_DEFINE_TYPE (NMSettingProxy, nm_setting_proxy, NM_TYPE_SETTING)
+/*****************************************************************************/
 
-#define NM_SETTING_PROXY_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), NM_TYPE_SETTING_PROXY, NMSettingProxyPrivate))
+NM_GOBJECT_PROPERTIES_DEFINE_BASE (
+	PROP_METHOD,
+	PROP_BROWSER_ONLY,
+	PROP_PAC_URL,
+	PROP_PAC_SCRIPT,
+);
 
 typedef struct {
 	NMSettingProxyMethod method;
@@ -50,30 +56,11 @@ typedef struct {
 	char *pac_script;
 } NMSettingProxyPrivate;
 
-enum {
-	PROP_0,
-	PROP_METHOD,
-	PROP_BROWSER_ONLY,
-	PROP_PAC_URL,
-	PROP_PAC_SCRIPT,
+G_DEFINE_TYPE (NMSettingProxy, nm_setting_proxy, NM_TYPE_SETTING)
 
-	LAST_PROP
-};
+#define NM_SETTING_PROXY_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), NM_TYPE_SETTING_PROXY, NMSettingProxyPrivate))
 
-/**
- * nm_setting_proxy_new:
- *
- * Creates a new #NMSettingProxy object.
- *
- * Returns: the new empty #NMSettingProxy object
- *
- * Since: 1.6
- **/
-NMSetting *
-nm_setting_proxy_new (void)
-{
-	return (NMSetting *) g_object_new (NM_TYPE_SETTING_PROXY, NULL);
-}
+/*****************************************************************************/
 
 /**
  * nm_setting_proxy_get_method:
@@ -213,22 +200,7 @@ verify (NMSetting *setting, NMConnection *connection, GError **error)
 	return TRUE;
 }
 
-static void
-nm_setting_proxy_init (NMSettingProxy *setting)
-{
-}
-
-static void
-finalize (GObject *object)
-{
-	NMSettingProxy *self = NM_SETTING_PROXY (object);
-	NMSettingProxyPrivate *priv = NM_SETTING_PROXY_GET_PRIVATE (self);
-
-	g_free (priv->pac_url);
-	g_free (priv->pac_script);
-
-	G_OBJECT_CLASS (nm_setting_proxy_parent_class)->finalize (object);
-}
+/*****************************************************************************/
 
 static void
 get_property (GObject *object, guint prop_id,
@@ -282,6 +254,40 @@ set_property (GObject *object, guint prop_id,
 	}
 }
 
+/*****************************************************************************/
+
+static void
+nm_setting_proxy_init (NMSettingProxy *setting)
+{
+}
+
+/**
+ * nm_setting_proxy_new:
+ *
+ * Creates a new #NMSettingProxy object.
+ *
+ * Returns: the new empty #NMSettingProxy object
+ *
+ * Since: 1.6
+ **/
+NMSetting *
+nm_setting_proxy_new (void)
+{
+	return (NMSetting *) g_object_new (NM_TYPE_SETTING_PROXY, NULL);
+}
+
+static void
+finalize (GObject *object)
+{
+	NMSettingProxy *self = NM_SETTING_PROXY (object);
+	NMSettingProxyPrivate *priv = NM_SETTING_PROXY_GET_PRIVATE (self);
+
+	g_free (priv->pac_url);
+	g_free (priv->pac_script);
+
+	G_OBJECT_CLASS (nm_setting_proxy_parent_class)->finalize (object);
+}
+
 static void
 nm_setting_proxy_class_init (NMSettingProxyClass *klass)
 {
@@ -290,8 +296,8 @@ nm_setting_proxy_class_init (NMSettingProxyClass *klass)
 
 	g_type_class_add_private (klass, sizeof (NMSettingProxyPrivate));
 
-	object_class->set_property = set_property;
 	object_class->get_property = get_property;
+	object_class->set_property = set_property;
 	object_class->finalize     = finalize;
 
 	setting_class->verify = verify;
@@ -312,13 +318,12 @@ nm_setting_proxy_class_init (NMSettingProxyClass *klass)
 	 * values: none, auto
 	 * ---end---
 	 */
-	g_object_class_install_property
-	    (object_class, PROP_METHOD,
-	     g_param_spec_int (NM_SETTING_PROXY_METHOD, "", "",
-	                       G_MININT32, G_MAXINT32, NM_SETTING_PROXY_METHOD_NONE,
-	                       G_PARAM_READWRITE |
-	                       G_PARAM_CONSTRUCT |
-	                       G_PARAM_STATIC_STRINGS));
+	obj_properties[PROP_METHOD] =
+	    g_param_spec_int (NM_SETTING_PROXY_METHOD, "", "",
+	                      G_MININT32, G_MAXINT32, NM_SETTING_PROXY_METHOD_NONE,
+	                      G_PARAM_READWRITE |
+	                      G_PARAM_CONSTRUCT |
+	                      G_PARAM_STATIC_STRINGS);
 
 	/**
 	 * NMSettingProxy:browser-only:
@@ -334,12 +339,11 @@ nm_setting_proxy_class_init (NMSettingProxyClass *klass)
 	 * description: Whether the proxy configuration is for browser only.
 	 * ---end---
 	 */
-	g_object_class_install_property
-	    (object_class, PROP_BROWSER_ONLY,
-	     g_param_spec_boolean (NM_SETTING_PROXY_BROWSER_ONLY, "", "",
-	                           FALSE,
-	                           G_PARAM_READWRITE |
-	                           G_PARAM_STATIC_STRINGS));
+	obj_properties[PROP_BROWSER_ONLY] =
+	    g_param_spec_boolean (NM_SETTING_PROXY_BROWSER_ONLY, "", "",
+	                          FALSE,
+	                          G_PARAM_READWRITE |
+	                          G_PARAM_STATIC_STRINGS);
 
 	/**
 	 * NMSettingProxy:pac-url:
@@ -355,12 +359,11 @@ nm_setting_proxy_class_init (NMSettingProxyClass *klass)
 	 * example: PAC_URL=http://wpad.mycompany.com/wpad.dat
 	 * ---end---
 	 */
-	g_object_class_install_property
-	    (object_class, PROP_PAC_URL,
-	     g_param_spec_string (NM_SETTING_PROXY_PAC_URL, "", "",
-	                          NULL,
-	                          G_PARAM_READWRITE |
-	                          G_PARAM_STATIC_STRINGS));
+	obj_properties[PROP_PAC_URL] =
+	    g_param_spec_string (NM_SETTING_PROXY_PAC_URL, "", "",
+	                         NULL,
+	                         G_PARAM_READWRITE |
+	                         G_PARAM_STATIC_STRINGS);
 
 	/**
 	 * NMSettingProxy:pac-script:
@@ -376,12 +379,13 @@ nm_setting_proxy_class_init (NMSettingProxyClass *klass)
 	 * example: PAC_SCRIPT=/home/joe/proxy.pac
 	 * ---end---
 	 */
-	g_object_class_install_property
-	    (object_class, PROP_PAC_SCRIPT,
-	     g_param_spec_string (NM_SETTING_PROXY_PAC_SCRIPT, "", "",
-	                          NULL,
-	                          G_PARAM_READWRITE |
-	                          G_PARAM_STATIC_STRINGS));
+	obj_properties[PROP_PAC_SCRIPT] =
+	    g_param_spec_string (NM_SETTING_PROXY_PAC_SCRIPT, "", "",
+	                         NULL,
+	                         G_PARAM_READWRITE |
+	                         G_PARAM_STATIC_STRINGS);
+
+	g_object_class_install_properties (object_class, _PROPERTY_ENUMS_LAST, obj_properties);
 
 	_nm_setting_class_commit (setting_class, NM_META_SETTING_TYPE_PROXY);
 }
diff --git a/libnm-core/nm-setting-serial.c b/libnm-core/nm-setting-serial.c
index b173197d..8b8bb76d 100644
--- a/libnm-core/nm-setting-serial.c
+++ b/libnm-core/nm-setting-serial.c
@@ -22,9 +22,10 @@
 
 #include "nm-default.h"
 
+#include "nm-setting-serial.h"
+
 #include <string.h>
 
-#include "nm-setting-serial.h"
 #include "nm-setting-private.h"
 
 /**
@@ -37,9 +38,15 @@
  * such as mobile broadband or analog telephone connections.
  **/
 
-G_DEFINE_TYPE (NMSettingSerial, nm_setting_serial, NM_TYPE_SETTING)
+/*****************************************************************************/
 
-#define NM_SETTING_SERIAL_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), NM_TYPE_SETTING_SERIAL, NMSettingSerialPrivate))
+NM_GOBJECT_PROPERTIES_DEFINE_BASE (
+	PROP_BAUD,
+	PROP_BITS,
+	PROP_PARITY,
+	PROP_STOPBITS,
+	PROP_SEND_DELAY,
+);
 
 typedef struct {
 	guint baud;
@@ -49,29 +56,11 @@ typedef struct {
 	guint64 send_delay;
 } NMSettingSerialPrivate;
 
-enum {
-	PROP_0,
-	PROP_BAUD,
-	PROP_BITS,
-	PROP_PARITY,
-	PROP_STOPBITS,
-	PROP_SEND_DELAY,
+G_DEFINE_TYPE (NMSettingSerial, nm_setting_serial, NM_TYPE_SETTING)
 
-	LAST_PROP
-};
+#define NM_SETTING_SERIAL_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), NM_TYPE_SETTING_SERIAL, NMSettingSerialPrivate))
 
-/**
- * nm_setting_serial_new:
- *
- * Creates a new #NMSettingSerial object with default values.
- *
- * Returns: (transfer full): the new empty #NMSettingSerial object
- **/
-NMSetting *
-nm_setting_serial_new (void)
-{
-	return (NMSetting *) g_object_new (NM_TYPE_SETTING_SERIAL, NULL);
-}
+/*****************************************************************************/
 
 /**
  * nm_setting_serial_get_baud:
@@ -143,11 +132,6 @@ nm_setting_serial_get_send_delay (NMSettingSerial *setting)
 	return NM_SETTING_SERIAL_GET_PRIVATE (setting)->send_delay;
 }
 
-static void
-nm_setting_serial_init (NMSettingSerial *setting)
-{
-}
-
 static GVariant *
 parity_to_dbus (const GValue *from)
 {
@@ -179,27 +163,29 @@ parity_from_dbus (GVariant *from, GValue *to)
 	}
 }
 
+/*****************************************************************************/
+
 static void
-set_property (GObject *object, guint prop_id,
-              const GValue *value, GParamSpec *pspec)
+get_property (GObject *object, guint prop_id,
+              GValue *value, GParamSpec *pspec)
 {
-	NMSettingSerialPrivate *priv = NM_SETTING_SERIAL_GET_PRIVATE (object);
+	NMSettingSerial *setting = NM_SETTING_SERIAL (object);
 
 	switch (prop_id) {
 	case PROP_BAUD:
-		priv->baud = g_value_get_uint (value);
+		g_value_set_uint (value, nm_setting_serial_get_baud (setting));
 		break;
 	case PROP_BITS:
-		priv->bits = g_value_get_uint (value);
+		g_value_set_uint (value, nm_setting_serial_get_bits (setting));
 		break;
 	case PROP_PARITY:
-		priv->parity = g_value_get_enum (value);
+		g_value_set_enum (value, nm_setting_serial_get_parity (setting));
 		break;
 	case PROP_STOPBITS:
-		priv->stopbits = g_value_get_uint (value);
+		g_value_set_uint (value, nm_setting_serial_get_stopbits (setting));
 		break;
 	case PROP_SEND_DELAY:
-		priv->send_delay = g_value_get_uint64 (value);
+		g_value_set_uint64 (value, nm_setting_serial_get_send_delay (setting));
 		break;
 	default:
 		G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
@@ -208,26 +194,26 @@ set_property (GObject *object, guint prop_id,
 }
 
 static void
-get_property (GObject *object, guint prop_id,
-              GValue *value, GParamSpec *pspec)
+set_property (GObject *object, guint prop_id,
+              const GValue *value, GParamSpec *pspec)
 {
-	NMSettingSerial *setting = NM_SETTING_SERIAL (object);
+	NMSettingSerialPrivate *priv = NM_SETTING_SERIAL_GET_PRIVATE (object);
 
 	switch (prop_id) {
 	case PROP_BAUD:
-		g_value_set_uint (value, nm_setting_serial_get_baud (setting));
+		priv->baud = g_value_get_uint (value);
 		break;
 	case PROP_BITS:
-		g_value_set_uint (value, nm_setting_serial_get_bits (setting));
+		priv->bits = g_value_get_uint (value);
 		break;
 	case PROP_PARITY:
-		g_value_set_enum (value, nm_setting_serial_get_parity (setting));
+		priv->parity = g_value_get_enum (value);
 		break;
 	case PROP_STOPBITS:
-		g_value_set_uint (value, nm_setting_serial_get_stopbits (setting));
+		priv->stopbits = g_value_get_uint (value);
 		break;
 	case PROP_SEND_DELAY:
-		g_value_set_uint64 (value, nm_setting_serial_get_send_delay (setting));
+		priv->send_delay = g_value_get_uint64 (value);
 		break;
 	default:
 		G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
@@ -235,6 +221,26 @@ get_property (GObject *object, guint prop_id,
 	}
 }
 
+/*****************************************************************************/
+
+static void
+nm_setting_serial_init (NMSettingSerial *setting)
+{
+}
+
+/**
+ * nm_setting_serial_new:
+ *
+ * Creates a new #NMSettingSerial object with default values.
+ *
+ * Returns: (transfer full): the new empty #NMSettingSerial object
+ **/
+NMSetting *
+nm_setting_serial_new (void)
+{
+	return (NMSetting *) g_object_new (NM_TYPE_SETTING_SERIAL, NULL);
+}
+
 static void
 nm_setting_serial_class_init (NMSettingSerialClass *klass)
 {
@@ -244,8 +250,8 @@ nm_setting_serial_class_init (NMSettingSerialClass *klass)
 
 	g_type_class_add_private (klass, sizeof (NMSettingSerialPrivate));
 
-	object_class->set_property = set_property;
 	object_class->get_property = get_property;
+	object_class->set_property = set_property;
 
 	/**
 	 * NMSettingSerial:baud:
@@ -254,26 +260,24 @@ nm_setting_serial_class_init (NMSettingSerialClass *klass)
 	 * value usually has no effect for mobile broadband modems as they generally
 	 * ignore speed settings and use the highest available speed.
 	 **/
-	g_object_class_install_property
-		(object_class, PROP_BAUD,
-		 g_param_spec_uint (NM_SETTING_SERIAL_BAUD, "", "",
-		                    0, G_MAXUINT, 57600,
-		                    G_PARAM_READWRITE |
-		                    G_PARAM_CONSTRUCT |
-		                    G_PARAM_STATIC_STRINGS));
+	obj_properties[PROP_BAUD] =
+	    g_param_spec_uint (NM_SETTING_SERIAL_BAUD, "", "",
+	                       0, G_MAXUINT, 57600,
+	                       G_PARAM_READWRITE |
+	                       G_PARAM_CONSTRUCT |
+	                       G_PARAM_STATIC_STRINGS);
 
 	/**
 	 * NMSettingSerial:bits:
 	 *
 	 * Byte-width of the serial communication. The 8 in "8n1" for example.
 	 **/
-	g_object_class_install_property
-		(object_class, PROP_BITS,
-		 g_param_spec_uint (NM_SETTING_SERIAL_BITS, "", "",
-		                    5, 8, 8,
-		                    G_PARAM_READWRITE |
-		                    G_PARAM_CONSTRUCT |
-		                    G_PARAM_STATIC_STRINGS));
+	obj_properties[PROP_BITS] =
+	    g_param_spec_uint (NM_SETTING_SERIAL_BITS, "", "",
+	                       5, 8, 8,
+	                       G_PARAM_READWRITE |
+	                       G_PARAM_CONSTRUCT |
+	                       G_PARAM_STATIC_STRINGS);
 
 	/**
 	 * NMSettingSerial:parity:
@@ -295,18 +299,16 @@ nm_setting_serial_class_init (NMSettingSerialClass *klass)
 	 *   111 (ASCII 'o') for odd, 110 (ASCII 'n') for none.
 	 * ---end---
 	 */
-	g_object_class_install_property
-		(object_class, PROP_PARITY,
-		 g_param_spec_enum (NM_SETTING_SERIAL_PARITY, "", "",
-		                    NM_TYPE_SETTING_SERIAL_PARITY,
-		                    NM_SETTING_SERIAL_PARITY_NONE,
-		                    G_PARAM_READWRITE |
-		                    G_PARAM_CONSTRUCT |
-		                    G_PARAM_STATIC_STRINGS));
+	obj_properties[PROP_PARITY] =
+	    g_param_spec_enum (NM_SETTING_SERIAL_PARITY, "", "",
+	                       NM_TYPE_SETTING_SERIAL_PARITY,
+	                       NM_SETTING_SERIAL_PARITY_NONE,
+	                       G_PARAM_READWRITE |
+	                       G_PARAM_CONSTRUCT |
+	                       G_PARAM_STATIC_STRINGS);
 
 	_properties_override_add_transform (properties_override,
-	                                    g_object_class_find_property (G_OBJECT_CLASS (setting_class),
-	                                                                  NM_SETTING_SERIAL_PARITY),
+	                                    obj_properties[PROP_PARITY],
 	                                    G_VARIANT_TYPE_BYTE,
 	                                    parity_to_dbus,
 	                                    parity_from_dbus);
@@ -317,26 +319,26 @@ nm_setting_serial_class_init (NMSettingSerialClass *klass)
 	 * Number of stop bits for communication on the serial port.  Either 1 or 2.
 	 * The 1 in "8n1" for example.
 	 **/
-	g_object_class_install_property
-		(object_class, PROP_STOPBITS,
-		 g_param_spec_uint (NM_SETTING_SERIAL_STOPBITS, "", "",
-		                    1, 2, 1,
-		                    G_PARAM_READWRITE |
-		                    G_PARAM_CONSTRUCT |
-		                    G_PARAM_STATIC_STRINGS));
+	obj_properties[PROP_STOPBITS] =
+	    g_param_spec_uint (NM_SETTING_SERIAL_STOPBITS, "", "",
+	                       1, 2, 1,
+	                       G_PARAM_READWRITE |
+	                       G_PARAM_CONSTRUCT |
+	                       G_PARAM_STATIC_STRINGS);
 
 	/**
 	 * NMSettingSerial:send-delay:
 	 *
 	 * Time to delay between each byte sent to the modem, in microseconds.
 	 **/
-	g_object_class_install_property
-		(object_class, PROP_SEND_DELAY,
-		 g_param_spec_uint64 (NM_SETTING_SERIAL_SEND_DELAY, "", "",
-		                      0, G_MAXUINT64, 0,
-		                      G_PARAM_READWRITE |
-		                      G_PARAM_CONSTRUCT |
-		                      G_PARAM_STATIC_STRINGS));
+	obj_properties[PROP_SEND_DELAY] =
+	    g_param_spec_uint64 (NM_SETTING_SERIAL_SEND_DELAY, "", "",
+	                         0, G_MAXUINT64, 0,
+	                         G_PARAM_READWRITE |
+	                         G_PARAM_CONSTRUCT |
+	                         G_PARAM_STATIC_STRINGS);
+
+	g_object_class_install_properties (object_class, _PROPERTY_ENUMS_LAST, obj_properties);
 
 	_nm_setting_class_commit_full (setting_class, NM_META_SETTING_TYPE_SERIAL,
 	                               NULL, properties_override);
diff --git a/libnm-core/nm-setting-sriov.c b/libnm-core/nm-setting-sriov.c
index 7228fb0c..068d2185 100644
--- a/libnm-core/nm-setting-sriov.c
+++ b/libnm-core/nm-setting-sriov.c
@@ -15,6 +15,7 @@
 #include "nm-default.h"
 
 #include "nm-setting-sriov.h"
+
 #include "nm-setting-private.h"
 #include "nm-utils-private.h"
 
@@ -24,6 +25,14 @@
  * @include: nm-setting-sriov.h
  **/
 
+/*****************************************************************************/
+
+NM_GOBJECT_PROPERTIES_DEFINE (NMSettingSriov,
+	PROP_TOTAL_VFS,
+	PROP_VFS,
+	PROP_AUTOPROBE_DRIVERS,
+);
+
 /**
  * NMSettingSriov:
  *
@@ -44,15 +53,6 @@ struct _NMSettingSriovClass {
 
 G_DEFINE_TYPE (NMSettingSriov, nm_setting_sriov, NM_TYPE_SETTING)
 
-enum {
-	PROP_0,
-	PROP_TOTAL_VFS,
-	PROP_VFS,
-	PROP_AUTOPROBE_DRIVERS,
-
-	LAST_PROP
-};
-
 /*****************************************************************************/
 
 G_DEFINE_BOXED_TYPE (NMSriovVF, nm_sriov_vf, nm_sriov_vf_dup, nm_sriov_vf_unref)
@@ -705,21 +705,6 @@ nm_sriov_vf_get_vlan_protocol (const NMSriovVF *vf, guint vlan_id)
 /*****************************************************************************/
 
 /**
- * nm_setting_sriov_new:
- *
- * Creates a new #NMSettingSriov object with default values.
- *
- * Returns: (transfer full): the new empty #NMSettingSriov object
- *
- * Since: 1.14
- **/
-NMSetting *
-nm_setting_sriov_new (void)
-{
-	return (NMSetting *) g_object_new (NM_TYPE_SETTING_SRIOV, NULL);
-}
-
-/**
  * nm_setting_sriov_get_total_vfs:
  * @setting: the #NMSettingSriov
  *
@@ -790,7 +775,7 @@ nm_setting_sriov_add_vf (NMSettingSriov *setting, NMSriovVF *vf)
 	g_return_if_fail (vf->refcount > 0);
 
 	g_ptr_array_add (setting->vfs, nm_sriov_vf_dup (vf));
-	g_object_notify (G_OBJECT (setting), NM_SETTING_SRIOV_VFS);
+	_notify (setting, PROP_VFS);
 }
 
 /**
@@ -809,7 +794,7 @@ nm_setting_sriov_remove_vf (NMSettingSriov *setting, guint idx)
 	g_return_if_fail (idx < setting->vfs->len);
 
 	g_ptr_array_remove_index (setting->vfs, idx);
-	g_object_notify (G_OBJECT (setting), NM_SETTING_SRIOV_VFS);
+	_notify (setting, PROP_VFS);
 }
 
 /**
@@ -834,7 +819,7 @@ nm_setting_sriov_remove_vf_by_index (NMSettingSriov *setting,
 	for (i = 0; i < setting->vfs->len; i++) {
 		if (nm_sriov_vf_get_index  (setting->vfs->pdata[i]) == index) {
 			g_ptr_array_remove_index (setting->vfs, i);
-			g_object_notify (G_OBJECT (setting), NM_SETTING_SRIOV_VFS);
+			_notify (setting, PROP_VFS);
 			return TRUE;
 		}
 	}
@@ -856,7 +841,7 @@ nm_setting_sriov_clear_vfs (NMSettingSriov *setting)
 
 	if (setting->vfs->len != 0) {
 		g_ptr_array_set_size (setting->vfs, 0);
-		g_object_notify (G_OBJECT (setting), NM_SETTING_SRIOV_VFS);
+		_notify (setting, PROP_VFS);
 	}
 }
 
@@ -952,7 +937,7 @@ vfs_to_dbus (NMSetting *setting, const char *property)
 
 			/* VLANs are translated into an array of maps, where each map has
 			 * keys 'id', 'qos' and 'proto'. This guarantees enough flexibility
-			 * to accomodate any future new option. */
+			 * to accommodate any future new option. */
 			vlan_ids = nm_sriov_vf_get_vlan_ids (vf, &num_vlans);
 			if (num_vlans) {
 				GVariantBuilder vlans_builder;
@@ -1139,24 +1124,58 @@ verify (NMSetting *setting, NMConnection *connection, GError **error)
 	return TRUE;
 }
 
+static NMTernary
+compare_property (const NMSettInfoSetting *sett_info,
+                  guint property_idx,
+                  NMSetting *setting,
+                  NMSetting *other,
+                  NMSettingCompareFlags flags)
+{
+	NMSettingSriov *a;
+	NMSettingSriov *b;
+	guint i;
+
+	if (nm_streq (sett_info->property_infos[property_idx].name, NM_SETTING_SRIOV_VFS)) {
+		if (other) {
+			a = NM_SETTING_SRIOV (setting);
+			b = NM_SETTING_SRIOV (other);
+
+			if (a->vfs->len != b->vfs->len)
+				return FALSE;
+			for (i = 0; i < a->vfs->len; i++) {
+				if (!nm_sriov_vf_equal (a->vfs->pdata[i], b->vfs->pdata[i]))
+					return FALSE;
+			}
+		}
+		return TRUE;
+	}
+
+	return NM_SETTING_CLASS (nm_setting_sriov_parent_class)->compare_property (sett_info,
+	                                                                           property_idx,
+	                                                                           setting,
+	                                                                           other,
+	                                                                           flags);
+}
+
+/*****************************************************************************/
+
 static void
-set_property (GObject *object, guint prop_id,
-              const GValue *value, GParamSpec *pspec)
+get_property (GObject *object, guint prop_id,
+              GValue *value, GParamSpec *pspec)
 {
 	NMSettingSriov *self = NM_SETTING_SRIOV (object);
 
 	switch (prop_id) {
 	case PROP_TOTAL_VFS:
-		self->total_vfs = g_value_get_uint (value);
+		g_value_set_uint (value, self->total_vfs);
 		break;
 	case PROP_VFS:
-		g_ptr_array_unref (self->vfs);
-		self->vfs = _nm_utils_copy_array (g_value_get_boxed (value),
-		                                  (NMUtilsCopyFunc) nm_sriov_vf_dup,
-		                                  (GDestroyNotify) nm_sriov_vf_unref);
+		g_value_take_boxed (value, _nm_utils_copy_array (self->vfs,
+		                                                 (NMUtilsCopyFunc) nm_sriov_vf_dup,
+		                                                 (GDestroyNotify) nm_sriov_vf_unref));
 		break;
 	case PROP_AUTOPROBE_DRIVERS:
-		self->autoprobe_drivers = g_value_get_enum (value);
+		g_value_set_enum (value, self->autoprobe_drivers);
 		break;
 	default:
 		G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
@@ -1165,22 +1184,23 @@ set_property (GObject *object, guint prop_id,
 }
 
 static void
-get_property (GObject *object, guint prop_id,
-              GValue *value, GParamSpec *pspec)
+set_property (GObject *object, guint prop_id,
+              const GValue *value, GParamSpec *pspec)
 {
 	NMSettingSriov *self = NM_SETTING_SRIOV (object);
 
 	switch (prop_id) {
 	case PROP_TOTAL_VFS:
-		g_value_set_uint (value, self->total_vfs);
+		self->total_vfs = g_value_get_uint (value);
 		break;
 	case PROP_VFS:
-		g_value_take_boxed (value, _nm_utils_copy_array (self->vfs,
-		                                                 (NMUtilsCopyFunc) nm_sriov_vf_dup,
-		                                                 (GDestroyNotify) nm_sriov_vf_unref));
+		g_ptr_array_unref (self->vfs);
+		self->vfs = _nm_utils_copy_array (g_value_get_boxed (value),
+		                                  (NMUtilsCopyFunc) nm_sriov_vf_dup,
+		                                  (GDestroyNotify) nm_sriov_vf_unref);
 		break;
 	case PROP_AUTOPROBE_DRIVERS:
-		g_value_set_enum (value, self->autoprobe_drivers);
+		self->autoprobe_drivers = g_value_get_enum (value);
 		break;
 	default:
 		G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
@@ -1188,30 +1208,7 @@ get_property (GObject *object, guint prop_id,
 	}
 }
 
-static gboolean
-compare_property (NMSetting *setting,
-                  NMSetting *other,
-                  const GParamSpec *prop_spec,
-                  NMSettingCompareFlags flags)
-{
-	NMSettingSriov *a = NM_SETTING_SRIOV (setting);
-	NMSettingSriov *b = NM_SETTING_SRIOV (other);
-	NMSettingClass *setting_class;
-	guint i;
-
-	if (nm_streq (prop_spec->name, NM_SETTING_SRIOV_VFS)) {
-		if (a->vfs->len != b->vfs->len)
-			return FALSE;
-		for (i = 0; i < a->vfs->len; i++) {
-			if (!nm_sriov_vf_equal (a->vfs->pdata[i], b->vfs->pdata[i]))
-				return FALSE;
-		}
-		return TRUE;
-	}
-
-	setting_class = NM_SETTING_CLASS (nm_setting_sriov_parent_class);
-	return setting_class->compare_property (setting, other, prop_spec, flags);
-}
+/*****************************************************************************/
 
 static void
 nm_setting_sriov_init (NMSettingSriov *setting)
@@ -1219,6 +1216,21 @@ nm_setting_sriov_init (NMSettingSriov *setting)
 	setting->vfs = g_ptr_array_new_with_free_func ((GDestroyNotify) nm_sriov_vf_unref);
 }
 
+/**
+ * nm_setting_sriov_new:
+ *
+ * Creates a new #NMSettingSriov object with default values.
+ *
+ * Returns: (transfer full): the new empty #NMSettingSriov object
+ *
+ * Since: 1.14
+ **/
+NMSetting *
+nm_setting_sriov_new (void)
+{
+	return (NMSetting *) g_object_new (NM_TYPE_SETTING_SRIOV, NULL);
+}
+
 static void
 finalize (GObject *object)
 {
@@ -1248,6 +1260,11 @@ nm_setting_sriov_class_init (NMSettingSriovClass *klass)
 	 *
 	 * The total number of virtual functions to create.
 	 *
+	 * Note that when the sriov setting is present NetworkManager
+	 * enforces the number of virtual functions on the interface
+	 * also when it is zero. To prevent any changes to SR-IOV
+	 * parameters don't add a sriov setting to the connection.
+	 *
 	 * Since: 1.14
 	 **/
 	/* ---ifcfg-rh---
@@ -1257,14 +1274,13 @@ nm_setting_sriov_class_init (NMSettingSriovClass *klass)
 	 * example: SRIOV_TOTAL_VFS=16
 	 * ---end---
 	 */
-	g_object_class_install_property
-		(object_class, PROP_TOTAL_VFS,
-		 g_param_spec_uint (NM_SETTING_SRIOV_TOTAL_VFS, "", "",
-		                    0, G_MAXUINT32, 0,
-		                    NM_SETTING_PARAM_FUZZY_IGNORE |
-		                    G_PARAM_READWRITE |
-		                    G_PARAM_CONSTRUCT |
-		                    G_PARAM_STATIC_STRINGS));
+	obj_properties[PROP_TOTAL_VFS] =
+	    g_param_spec_uint (NM_SETTING_SRIOV_TOTAL_VFS, "", "",
+	                       0, G_MAXUINT32, 0,
+	                       NM_SETTING_PARAM_FUZZY_IGNORE |
+	                       G_PARAM_READWRITE |
+	                       G_PARAM_CONSTRUCT |
+	                       G_PARAM_STATIC_STRINGS);
 
 	/**
 	 * NMSettingSriov:vfs: (type GPtrArray(NMSriovVF))
@@ -1283,7 +1299,11 @@ nm_setting_sriov_class_init (NMSettingSriovClass *klass)
 	 *
 	 *   "2 mac=00:11:22:33:44:55 spoof-check=true".
 	 *
-	 * The "vlans" attribute is represented as a semicolor-separated
+	 * Multiple VFs can be specified using a comma as separator.
+	 * Currently the following attributes are supported: mac,
+	 * spoof-check, trust, min-tx-rate, max-tx-rate, vlans.
+	 *
+	 * The "vlans" attribute is represented as a semicolon-separated
 	 * list of VLAN descriptors, where each descriptor has the form
 	 *
 	 *   "ID[.PRIORITY[.PROTO]]".
@@ -1291,6 +1311,7 @@ nm_setting_sriov_class_init (NMSettingSriovClass *klass)
 	 * PROTO can be either 'q' for 802.1Q (the default) or 'ad' for
 	 * 802.1ad.
 	 *
+
 	 * Since: 1.14
 	 **/
 	/* ---ifcfg-rh---
@@ -1300,17 +1321,15 @@ nm_setting_sriov_class_init (NMSettingSriovClass *klass)
 	 * example: SRIOV_VF10="mac=00:11:22:33:44:55", ...
 	 * ---end---
 	 */
-	g_object_class_install_property
-		(object_class, PROP_VFS,
-		 g_param_spec_boxed (NM_SETTING_SRIOV_VFS, "", "",
-		                     G_TYPE_PTR_ARRAY,
-		                     G_PARAM_READWRITE |
-		                     NM_SETTING_PARAM_INFERRABLE |
-		                     G_PARAM_STATIC_STRINGS));
+	obj_properties[PROP_VFS] =
+	    g_param_spec_boxed (NM_SETTING_SRIOV_VFS, "", "",
+	                        G_TYPE_PTR_ARRAY,
+	                        G_PARAM_READWRITE |
+	                        NM_SETTING_PARAM_INFERRABLE |
+	                        G_PARAM_STATIC_STRINGS);
 
 	_properties_override_add_override (properties_override,
-	                                   g_object_class_find_property (G_OBJECT_CLASS (setting_class),
-	                                                                 NM_SETTING_SRIOV_VFS),
+	                                   obj_properties[PROP_VFS],
 	                                   G_VARIANT_TYPE ("aa{sv}"),
 	                                   vfs_to_dbus,
 	                                   vfs_from_dbus,
@@ -1342,15 +1361,16 @@ nm_setting_sriov_class_init (NMSettingSriovClass *klass)
 	 * example: SRIOV_AUTOPROBE_DRIVERS=0,1
 	 * ---end---
 	 */
-	g_object_class_install_property
-		(object_class, PROP_AUTOPROBE_DRIVERS,
-		 g_param_spec_enum (NM_SETTING_SRIOV_AUTOPROBE_DRIVERS, "", "",
-		                    nm_ternary_get_type (),
-		                    NM_TERNARY_DEFAULT,
-		                    NM_SETTING_PARAM_FUZZY_IGNORE |
-		                    G_PARAM_READWRITE |
-		                    G_PARAM_CONSTRUCT |
-		                    G_PARAM_STATIC_STRINGS));
+	obj_properties[PROP_AUTOPROBE_DRIVERS] =
+	    g_param_spec_enum (NM_SETTING_SRIOV_AUTOPROBE_DRIVERS, "", "",
+	                       nm_ternary_get_type (),
+	                       NM_TERNARY_DEFAULT,
+	                       NM_SETTING_PARAM_FUZZY_IGNORE |
+	                       G_PARAM_READWRITE |
+	                       G_PARAM_CONSTRUCT |
+	                       G_PARAM_STATIC_STRINGS);
+
+	g_object_class_install_properties (object_class, _PROPERTY_ENUMS_LAST, obj_properties);
 
 	_nm_setting_class_commit_full (setting_class, NM_META_SETTING_TYPE_SRIOV,
 	                               NULL, properties_override);
diff --git a/libnm-core/nm-setting-tc-config.c b/libnm-core/nm-setting-tc-config.c
index 43015d37..7425ae73 100644
--- a/libnm-core/nm-setting-tc-config.c
+++ b/libnm-core/nm-setting-tc-config.c
@@ -19,9 +19,10 @@
 
 #include "nm-default.h"
 
+#include "nm-setting-tc-config.h"
+
 #include <linux/pkt_sched.h>
 
-#include "nm-setting-tc-config.h"
 #include "nm-setting-private.h"
 
 /**
@@ -809,13 +810,10 @@ nm_tc_tfilter_set_action (NMTCTfilter *tfilter, NMTCAction *action)
 
 /*****************************************************************************/
 
-enum {
-	PROP_0,
+NM_GOBJECT_PROPERTIES_DEFINE (NMSettingTCConfig,
 	PROP_QDISCS,
 	PROP_TFILTERS,
-
-	LAST_PROP
-};
+);
 
 /**
  * NMSettingTCConfig:
@@ -836,20 +834,7 @@ struct _NMSettingTCConfigClass {
 
 G_DEFINE_TYPE (NMSettingTCConfig, nm_setting_tc_config, NM_TYPE_SETTING)
 
-/**
- * nm_setting_tc_config_new:
- *
- * Creates a new #NMSettingTCConfig object with default values.
- *
- * Returns: (transfer full): the new empty #NMSettingTCConfig object
- *
- * Since: 1.12
- **/
-NMSetting *
-nm_setting_tc_config_new (void)
-{
-	return (NMSetting *) g_object_new (NM_TYPE_SETTING_TC_CONFIG, NULL);
-}
+/*****************************************************************************/
 
 /**
  * nm_setting_tc_config_get_num_qdiscs:
@@ -914,7 +899,7 @@ nm_setting_tc_config_add_qdisc (NMSettingTCConfig *self,
 	}
 
 	g_ptr_array_add (self->qdiscs, nm_tc_qdisc_dup (qdisc));
-	g_object_notify (G_OBJECT (self), NM_SETTING_TC_CONFIG_QDISCS);
+	_notify (self, PROP_QDISCS);
 	return TRUE;
 }
 
@@ -935,7 +920,7 @@ nm_setting_tc_config_remove_qdisc (NMSettingTCConfig *self, guint idx)
 	g_return_if_fail (idx < self->qdiscs->len);
 
 	g_ptr_array_remove_index (self->qdiscs, idx);
-	g_object_notify (G_OBJECT (self), NM_SETTING_TC_CONFIG_QDISCS);
+	_notify (self, PROP_QDISCS);
 }
 
 /**
@@ -961,7 +946,7 @@ nm_setting_tc_config_remove_qdisc_by_value (NMSettingTCConfig *self,
 	for (i = 0; i < self->qdiscs->len; i++) {
 		if (nm_tc_qdisc_equal (self->qdiscs->pdata[i], qdisc)) {
 			g_ptr_array_remove_index (self->qdiscs, i);
-			g_object_notify (G_OBJECT (self), NM_SETTING_TC_CONFIG_QDISCS);
+			_notify (self, PROP_QDISCS);
 			return TRUE;
 		}
 	}
@@ -983,7 +968,7 @@ nm_setting_tc_config_clear_qdiscs (NMSettingTCConfig *self)
 
 	if (self->qdiscs->len != 0) {
 		g_ptr_array_set_size (self->qdiscs, 0);
-		g_object_notify (G_OBJECT (self), NM_SETTING_TC_CONFIG_QDISCS);
+		_notify (self, PROP_QDISCS);
 	}
 }
 
@@ -1051,7 +1036,7 @@ nm_setting_tc_config_add_tfilter (NMSettingTCConfig *self,
 	}
 
 	g_ptr_array_add (self->tfilters, nm_tc_tfilter_dup (tfilter));
-	g_object_notify (G_OBJECT (self), NM_SETTING_TC_CONFIG_TFILTERS);
+	_notify (self, PROP_TFILTERS);
 	return TRUE;
 }
 
@@ -1071,7 +1056,7 @@ nm_setting_tc_config_remove_tfilter (NMSettingTCConfig *self, guint idx)
 	g_return_if_fail (idx < self->tfilters->len);
 
 	g_ptr_array_remove_index (self->tfilters, idx);
-	g_object_notify (G_OBJECT (self), NM_SETTING_TC_CONFIG_TFILTERS);
+	_notify (self, PROP_TFILTERS);
 }
 
 /**
@@ -1097,7 +1082,7 @@ nm_setting_tc_config_remove_tfilter_by_value (NMSettingTCConfig *self,
 	for (i = 0; i < self->tfilters->len; i++) {
 		if (nm_tc_tfilter_equal (self->tfilters->pdata[i], tfilter)) {
 			g_ptr_array_remove_index (self->tfilters, i);
-			g_object_notify (G_OBJECT (self), NM_SETTING_TC_CONFIG_TFILTERS);
+			_notify (self, PROP_TFILTERS);
 			return TRUE;
 		}
 	}
@@ -1119,71 +1104,12 @@ nm_setting_tc_config_clear_tfilters (NMSettingTCConfig *self)
 
 	if (self->tfilters->len != 0) {
 		g_ptr_array_set_size (self->tfilters, 0);
-		g_object_notify (G_OBJECT (self), NM_SETTING_TC_CONFIG_TFILTERS);
+		_notify (self, PROP_TFILTERS);
 	}
 }
 
 /*****************************************************************************/
 
-static void
-set_property (GObject *object, guint prop_id,
-              const GValue *value, GParamSpec *pspec)
-{
-	NMSettingTCConfig *self = NM_SETTING_TC_CONFIG (object);
-
-	switch (prop_id) {
-	case PROP_QDISCS:
-		g_ptr_array_unref (self->qdiscs);
-		self->qdiscs = _nm_utils_copy_array (g_value_get_boxed (value),
-		                                     (NMUtilsCopyFunc) nm_tc_qdisc_dup,
-		                                     (GDestroyNotify) nm_tc_qdisc_unref);
-		break;
-	case PROP_TFILTERS:
-		g_ptr_array_unref (self->tfilters);
-		self->tfilters = _nm_utils_copy_array (g_value_get_boxed (value),
-		                                       (NMUtilsCopyFunc) nm_tc_tfilter_dup,
-		                                       (GDestroyNotify) nm_tc_tfilter_unref);
-		break;
-	default:
-		G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
-		break;
-	}
-}
-
-static void
-get_property (GObject *object, guint prop_id,
-              GValue *value, GParamSpec *pspec)
-{
-	NMSettingTCConfig *self = NM_SETTING_TC_CONFIG (object);
-
-	switch (prop_id) {
-	case PROP_QDISCS:
-		g_value_take_boxed (value, _nm_utils_copy_array (self->qdiscs,
-		                                                 (NMUtilsCopyFunc) nm_tc_qdisc_dup,
-		                                                 (GDestroyNotify) nm_tc_qdisc_unref));
-		break;
-	case PROP_TFILTERS:
-		g_value_take_boxed (value, _nm_utils_copy_array (self->tfilters,
-		                                                 (NMUtilsCopyFunc) nm_tc_tfilter_dup,
-		                                                 (GDestroyNotify) nm_tc_tfilter_unref));
-		break;
-	default:
-		G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
-		break;
-	}
-}
-
-static void
-finalize (GObject *object)
-{
-	NMSettingTCConfig *self = NM_SETTING_TC_CONFIG (object);
-
-	g_ptr_array_unref (self->qdiscs);
-	g_ptr_array_unref (self->tfilters);
-
-	G_OBJECT_CLASS (nm_setting_tc_config_parent_class)->finalize (object);
-}
-
 static gboolean
 verify (NMSetting *setting, NMConnection *connection, GError **error)
 {
@@ -1233,46 +1159,46 @@ verify (NMSetting *setting, NMConnection *connection, GError **error)
 	return TRUE;
 }
 
-static gboolean
-compare_property (NMSetting *setting,
+static NMTernary
+compare_property (const NMSettInfoSetting *sett_info,
+                  guint property_idx,
+                  NMSetting *setting,
                   NMSetting *other,
-                  const GParamSpec *prop_spec,
                   NMSettingCompareFlags flags)
 {
 	NMSettingTCConfig *a_tc_config = NM_SETTING_TC_CONFIG (setting);
 	NMSettingTCConfig *b_tc_config = NM_SETTING_TC_CONFIG (other);
-	NMSettingClass *setting_class;
 	guint i;
 
-	if (nm_streq (prop_spec->name, NM_SETTING_TC_CONFIG_QDISCS)) {
-		if (a_tc_config->qdiscs->len != b_tc_config->qdiscs->len)
-			return FALSE;
-		for (i = 0; i < a_tc_config->qdiscs->len; i++) {
-			if (!nm_tc_qdisc_equal (a_tc_config->qdiscs->pdata[i], b_tc_config->qdiscs->pdata[i]))
+	if (nm_streq (sett_info->property_infos[property_idx].name, NM_SETTING_TC_CONFIG_QDISCS)) {
+		if (other) {
+			if (a_tc_config->qdiscs->len != b_tc_config->qdiscs->len)
 				return FALSE;
+			for (i = 0; i < a_tc_config->qdiscs->len; i++) {
+				if (!nm_tc_qdisc_equal (a_tc_config->qdiscs->pdata[i], b_tc_config->qdiscs->pdata[i]))
+					return FALSE;
+			}
 		}
 		return TRUE;
 	}
 
-	if (nm_streq (prop_spec->name, NM_SETTING_TC_CONFIG_TFILTERS)) {
-		if (a_tc_config->tfilters->len != b_tc_config->tfilters->len)
-			return FALSE;
-		for (i = 0; i < a_tc_config->tfilters->len; i++) {
-			if (!nm_tc_tfilter_equal (a_tc_config->tfilters->pdata[i], b_tc_config->tfilters->pdata[i]))
+	if (nm_streq (sett_info->property_infos[property_idx].name, NM_SETTING_TC_CONFIG_TFILTERS)) {
+		if (other) {
+			if (a_tc_config->tfilters->len != b_tc_config->tfilters->len)
 				return FALSE;
+			for (i = 0; i < a_tc_config->tfilters->len; i++) {
+				if (!nm_tc_tfilter_equal (a_tc_config->tfilters->pdata[i], b_tc_config->tfilters->pdata[i]))
+					return FALSE;
+			}
 		}
 		return TRUE;
 	}
 
-	setting_class = NM_SETTING_CLASS (nm_setting_tc_config_parent_class);
-	return setting_class->compare_property (setting, other, prop_spec, flags);
-}
-
-static void
-nm_setting_tc_config_init (NMSettingTCConfig *self)
-{
-	self->qdiscs = g_ptr_array_new_with_free_func ((GDestroyNotify) nm_tc_qdisc_unref);
-	self->tfilters = g_ptr_array_new_with_free_func ((GDestroyNotify) nm_tc_tfilter_unref);
+	return NM_SETTING_CLASS (nm_setting_tc_config_parent_class)->compare_property (sett_info,
+	                                                                               property_idx,
+	                                                                               setting,
+	                                                                               other,
+	                                                                               flags);
 }
 
 /**
@@ -1586,6 +1512,91 @@ tc_tfilters_set (NMSetting *setting,
 	return TRUE;
 }
 
+/*****************************************************************************/
+
+static void
+get_property (GObject *object, guint prop_id,
+              GValue *value, GParamSpec *pspec)
+{
+	NMSettingTCConfig *self = NM_SETTING_TC_CONFIG (object);
+
+	switch (prop_id) {
+	case PROP_QDISCS:
+		g_value_take_boxed (value, _nm_utils_copy_array (self->qdiscs,
+		                                                 (NMUtilsCopyFunc) nm_tc_qdisc_dup,
+		                                                 (GDestroyNotify) nm_tc_qdisc_unref));
+		break;
+	case PROP_TFILTERS:
+		g_value_take_boxed (value, _nm_utils_copy_array (self->tfilters,
+		                                                 (NMUtilsCopyFunc) nm_tc_tfilter_dup,
+		                                                 (GDestroyNotify) nm_tc_tfilter_unref));
+		break;
+	default:
+		G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+		break;
+	}
+}
+
+static void
+set_property (GObject *object, guint prop_id,
+              const GValue *value, GParamSpec *pspec)
+{
+	NMSettingTCConfig *self = NM_SETTING_TC_CONFIG (object);
+
+	switch (prop_id) {
+	case PROP_QDISCS:
+		g_ptr_array_unref (self->qdiscs);
+		self->qdiscs = _nm_utils_copy_array (g_value_get_boxed (value),
+		                                     (NMUtilsCopyFunc) nm_tc_qdisc_dup,
+		                                     (GDestroyNotify) nm_tc_qdisc_unref);
+		break;
+	case PROP_TFILTERS:
+		g_ptr_array_unref (self->tfilters);
+		self->tfilters = _nm_utils_copy_array (g_value_get_boxed (value),
+		                                       (NMUtilsCopyFunc) nm_tc_tfilter_dup,
+		                                       (GDestroyNotify) nm_tc_tfilter_unref);
+		break;
+	default:
+		G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+		break;
+	}
+}
+
+/*****************************************************************************/
+
+static void
+nm_setting_tc_config_init (NMSettingTCConfig *self)
+{
+	self->qdiscs = g_ptr_array_new_with_free_func ((GDestroyNotify) nm_tc_qdisc_unref);
+	self->tfilters = g_ptr_array_new_with_free_func ((GDestroyNotify) nm_tc_tfilter_unref);
+}
+
+/**
+ * nm_setting_tc_config_new:
+ *
+ * Creates a new #NMSettingTCConfig object with default values.
+ *
+ * Returns: (transfer full): the new empty #NMSettingTCConfig object
+ *
+ * Since: 1.12
+ **/
+NMSetting *
+nm_setting_tc_config_new (void)
+{
+	return (NMSetting *) g_object_new (NM_TYPE_SETTING_TC_CONFIG, NULL);
+}
+
+static void
+finalize (GObject *object)
+{
+	NMSettingTCConfig *self = NM_SETTING_TC_CONFIG (object);
+
+	g_ptr_array_unref (self->qdiscs);
+	g_ptr_array_unref (self->tfilters);
+
+	G_OBJECT_CLASS (nm_setting_tc_config_parent_class)->finalize (object);
+}
+
 static void
 nm_setting_tc_config_class_init (NMSettingTCConfigClass *klass)
 {
@@ -1593,8 +1604,8 @@ nm_setting_tc_config_class_init (NMSettingTCConfigClass *klass)
 	NMSettingClass *setting_class = NM_SETTING_CLASS (klass);
 	GArray *properties_override = _nm_sett_info_property_override_create_array ();
 
-	object_class->set_property     = set_property;
 	object_class->get_property     = get_property;
+	object_class->set_property     = set_property;
 	object_class->finalize         = finalize;
 
 	setting_class->compare_property = compare_property;
@@ -1612,17 +1623,15 @@ nm_setting_tc_config_class_init (NMSettingTCConfigClass *klass)
 	 * example: QDISC1=ingress, QDISC2="root handle 1234: fq_codel"
 	 * ---end---
 	 */
-	g_object_class_install_property
-		(object_class, PROP_QDISCS,
-		 g_param_spec_boxed (NM_SETTING_TC_CONFIG_QDISCS, "", "",
-		                     G_TYPE_PTR_ARRAY,
-		                     G_PARAM_READWRITE |
-		                     NM_SETTING_PARAM_INFERRABLE |
-		                     G_PARAM_STATIC_STRINGS));
+	obj_properties[PROP_QDISCS] =
+	    g_param_spec_boxed (NM_SETTING_TC_CONFIG_QDISCS, "", "",
+	                        G_TYPE_PTR_ARRAY,
+	                        G_PARAM_READWRITE |
+	                        NM_SETTING_PARAM_INFERRABLE |
+	                        G_PARAM_STATIC_STRINGS);
 
 	_properties_override_add_override (properties_override,
-	                                   g_object_class_find_property (G_OBJECT_CLASS (setting_class),
-	                                                                 NM_SETTING_TC_CONFIG_QDISCS),
+	                                   obj_properties[PROP_QDISCS],
 	                                   G_VARIANT_TYPE ("aa{sv}"),
 	                                   tc_qdiscs_get,
 	                                   tc_qdiscs_set,
@@ -1640,22 +1649,22 @@ nm_setting_tc_config_class_init (NMSettingTCConfigClass *klass)
 	 * example: FILTER1="parent ffff: matchall action simple sdata Input", ...
 	 * ---end---
 	 */
-	g_object_class_install_property
-		(object_class, PROP_TFILTERS,
-		 g_param_spec_boxed (NM_SETTING_TC_CONFIG_TFILTERS, "", "",
-		                     G_TYPE_PTR_ARRAY,
-		                     G_PARAM_READWRITE |
-		                     NM_SETTING_PARAM_INFERRABLE |
-		                     G_PARAM_STATIC_STRINGS));
+	obj_properties[PROP_TFILTERS] =
+	    g_param_spec_boxed (NM_SETTING_TC_CONFIG_TFILTERS, "", "",
+	                        G_TYPE_PTR_ARRAY,
+	                        G_PARAM_READWRITE |
+	                        NM_SETTING_PARAM_INFERRABLE |
+	                        G_PARAM_STATIC_STRINGS);
 
 	_properties_override_add_override (properties_override,
-	                                   g_object_class_find_property (G_OBJECT_CLASS (setting_class),
-	                                                                 NM_SETTING_TC_CONFIG_TFILTERS),
+	                                   obj_properties[PROP_TFILTERS],
 	                                   G_VARIANT_TYPE ("aa{sv}"),
 	                                   tc_tfilters_get,
 	                                   tc_tfilters_set,
 	                                   NULL);
 
+	g_object_class_install_properties (object_class, _PROPERTY_ENUMS_LAST, obj_properties);
+
 	_nm_setting_class_commit_full (setting_class, NM_META_SETTING_TYPE_TC_CONFIG,
 	                               NULL, properties_override);
 }
diff --git a/libnm-core/nm-setting-team-port.c b/libnm-core/nm-setting-team-port.c
index ee84aaf7..5277e9c0 100644
--- a/libnm-core/nm-setting-team-port.c
+++ b/libnm-core/nm-setting-team-port.c
@@ -21,11 +21,12 @@
 
 #include "nm-default.h"
 
+#include "nm-setting-team-port.h"
+
 #include <string.h>
 #include <ctype.h>
 #include <stdlib.h>
 
-#include "nm-setting-team-port.h"
 #include "nm-utils.h"
 #include "nm-utils-private.h"
 #include "nm-connection-private.h"
@@ -39,23 +40,10 @@
  * optional properties that apply to team ports.
  **/
 
-G_DEFINE_TYPE (NMSettingTeamPort, nm_setting_team_port, NM_TYPE_SETTING)
-
-#define NM_SETTING_TEAM_PORT_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), NM_TYPE_SETTING_TEAM_PORT, NMSettingTeamPortPrivate))
-
-typedef struct {
-	char *config;
-	int queue_id;
-	int prio;
-	gboolean sticky;
-	int lacp_prio;
-	int lacp_key;
-	GPtrArray *link_watchers; /* Array of NMTeamLinkWatcher */
-} NMSettingTeamPortPrivate;
+/*****************************************************************************/
 
 /* Keep aligned with _prop_to_keys[] */
-enum {
-	PROP_0,
+NM_GOBJECT_PROPERTIES_DEFINE (NMSettingTeamPort,
 	PROP_CONFIG,
 	PROP_QUEUE_ID,
 	PROP_PRIO,
@@ -63,12 +51,10 @@ enum {
 	PROP_LACP_PRIO,
 	PROP_LACP_KEY,
 	PROP_LINK_WATCHERS,
-	LAST_PROP
-};
+);
 
 /* Keep aligned with team-port properties enum */
-static const _NMUtilsTeamPropertyKeys _prop_to_keys[LAST_PROP] = {
-	[PROP_0] =             { NULL, NULL, NULL, 0 },
+static const _NMUtilsTeamPropertyKeys _prop_to_keys[_PROPERTY_ENUMS_LAST] = {
 	[PROP_CONFIG] =        { NULL, NULL, NULL, 0 },
 	[PROP_QUEUE_ID] =      { "queue_id", NULL, NULL, NM_SETTING_TEAM_PORT_QUEUE_ID_DEFAULT },
 	[PROP_PRIO] =          { "prio", NULL, NULL, 0 },
@@ -78,18 +64,21 @@ static const _NMUtilsTeamPropertyKeys _prop_to_keys[LAST_PROP] = {
 	[PROP_LINK_WATCHERS] = { "link_watch", NULL, NULL, 0 }
 };
 
-/**
- * nm_setting_team_port_new:
- *
- * Creates a new #NMSettingTeamPort object with default values.
- *
- * Returns: (transfer full): the new empty #NMSettingTeamPort object
- **/
-NMSetting *
-nm_setting_team_port_new (void)
-{
-	return (NMSetting *) g_object_new (NM_TYPE_SETTING_TEAM_PORT, NULL);
-}
+typedef struct {
+	char *config;
+	int queue_id;
+	int prio;
+	gboolean sticky;
+	int lacp_prio;
+	int lacp_key;
+	GPtrArray *link_watchers; /* Array of NMTeamLinkWatcher */
+} NMSettingTeamPortPrivate;
+
+G_DEFINE_TYPE (NMSettingTeamPort, nm_setting_team_port, NM_TYPE_SETTING)
+
+#define NM_SETTING_TEAM_PORT_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), NM_TYPE_SETTING_TEAM_PORT, NMSettingTeamPortPrivate))
+
+/*****************************************************************************/
 
 /**
  * nm_setting_team_port_get_config:
@@ -251,7 +240,7 @@ nm_setting_team_port_add_link_watcher (NMSettingTeamPort *setting,
 	}
 
 	g_ptr_array_add (priv->link_watchers, nm_team_link_watcher_dup (link_watcher));
-	g_object_notify (G_OBJECT (setting), NM_SETTING_TEAM_PORT_LINK_WATCHERS);
+	_notify (setting, PROP_LINK_WATCHERS);
 	return TRUE;
 }
 
@@ -273,7 +262,7 @@ nm_setting_team_port_remove_link_watcher (NMSettingTeamPort *setting, guint idx)
 	g_return_if_fail (idx < priv->link_watchers->len);
 
 	g_ptr_array_remove_index (priv->link_watchers, idx);
-	g_object_notify (G_OBJECT (setting), NM_SETTING_TEAM_PORT_LINK_WATCHERS);
+	_notify (setting, PROP_LINK_WATCHERS);
 }
 
 /**
@@ -299,7 +288,7 @@ nm_setting_team_port_remove_link_watcher_by_value (NMSettingTeamPort *setting,
 	for (i = 0; i < priv->link_watchers->len; i++) {
 		if (nm_team_link_watcher_equal (priv->link_watchers->pdata[i], link_watcher)) {
 			g_ptr_array_remove_index (priv->link_watchers, i);
-			g_object_notify (G_OBJECT (setting), NM_SETTING_TEAM_PORT_LINK_WATCHERS);
+			_notify (setting, PROP_LINK_WATCHERS);
 			return TRUE;
 		}
 	}
@@ -323,7 +312,7 @@ nm_setting_team_port_clear_link_watchers (NMSettingTeamPort *setting)
 
 	if (priv->link_watchers->len != 0) {
 		g_ptr_array_set_size (priv->link_watchers, 0);
-		g_object_notify (G_OBJECT (setting), NM_SETTING_TEAM_PORT_LINK_WATCHERS);
+		_notify (setting, PROP_LINK_WATCHERS);
 	}
 }
 
@@ -401,62 +390,109 @@ verify (NMSetting *setting, NMConnection *connection, GError **error)
 	return TRUE;
 }
 
-static gboolean
-compare_property (NMSetting *setting,
+static NMTernary
+compare_property (const NMSettInfoSetting *sett_info,
+                  guint property_idx,
+                  NMSetting *setting,
                   NMSetting *other,
-                  const GParamSpec *prop_spec,
                   NMSettingCompareFlags flags)
 {
-	NMSettingClass *setting_class;
-	NMSettingTeamPortPrivate *a_priv, *b_priv;
+	NMSettingTeamPortPrivate *a_priv;
+	NMSettingTeamPortPrivate *b_priv;
 	guint i, j;
 
-	/* If we are trying to match a connection in order to assume it (and thus
-	 * @flags contains INFERRABLE), use the "relaxed" matching for team
-	 * configuration. Otherwise, for all other purposes (including connection
-	 * comparison before an update), resort to the default string comparison.
-	 */
-	if (   NM_FLAGS_HAS (flags, NM_SETTING_COMPARE_FLAG_INFERRABLE)
-	    && nm_streq0 (prop_spec->name, NM_SETTING_TEAM_PORT_CONFIG)) {
-		return _nm_utils_team_config_equal (NM_SETTING_TEAM_PORT_GET_PRIVATE (setting)->config,
-		                                    NM_SETTING_TEAM_PORT_GET_PRIVATE (other)->config,
-		                                    TRUE);
-	}
-	if (nm_streq0 (prop_spec->name, NM_SETTING_TEAM_PORT_LINK_WATCHERS)) {
-		a_priv = NM_SETTING_TEAM_PORT_GET_PRIVATE (setting);
-		b_priv = NM_SETTING_TEAM_PORT_GET_PRIVATE (other);
+	if (nm_streq (sett_info->property_infos[property_idx].name, NM_SETTING_TEAM_PORT_LINK_WATCHERS)) {
 
-		if (a_priv->link_watchers->len != b_priv->link_watchers->len)
-			return FALSE;
-		for (i = 0; i < a_priv->link_watchers->len; i++) {
-			for (j = 0; j < b_priv->link_watchers->len; j++) {
-				if (nm_team_link_watcher_equal (a_priv->link_watchers->pdata[i],
-				                                b_priv->link_watchers->pdata[j])) {
-					break;
+		if (NM_FLAGS_HAS (flags, NM_SETTING_COMPARE_FLAG_INFERRABLE))
+			return NM_TERNARY_DEFAULT;
+
+		if (other) {
+			a_priv = NM_SETTING_TEAM_PORT_GET_PRIVATE (setting);
+			b_priv = NM_SETTING_TEAM_PORT_GET_PRIVATE (other);
+
+			if (a_priv->link_watchers->len != b_priv->link_watchers->len)
+				return FALSE;
+			for (i = 0; i < a_priv->link_watchers->len; i++) {
+				for (j = 0; j < b_priv->link_watchers->len; j++) {
+					if (nm_team_link_watcher_equal (a_priv->link_watchers->pdata[i],
+					                                b_priv->link_watchers->pdata[j])) {
+						break;
+					}
 				}
+				if (j == b_priv->link_watchers->len)
+					return FALSE;
 			}
-			if (j == b_priv->link_watchers->len)
-				return FALSE;
 		}
 		return TRUE;
 	}
 
-	setting_class = NM_SETTING_CLASS (nm_setting_team_port_parent_class);
-	return setting_class->compare_property (setting, other, prop_spec, flags);
+	if (nm_streq (sett_info->property_infos[property_idx].name, NM_SETTING_TEAM_PORT_CONFIG)) {
+		if (other) {
+			a_priv = NM_SETTING_TEAM_PORT_GET_PRIVATE (setting);
+			b_priv = NM_SETTING_TEAM_PORT_GET_PRIVATE (other);
+
+			if (NM_FLAGS_HAS (flags, NM_SETTING_COMPARE_FLAG_INFERRABLE)) {
+				/* If we are trying to match a connection in order to assume it (and thus
+				 * @flags contains INFERRABLE), use the "relaxed" matching for team
+				 * configuration. Otherwise, for all other purposes (including connection
+				 * comparison before an update), resort to the default string comparison. */
+				return _nm_utils_team_config_equal (a_priv->config,
+				                                    b_priv->config,
+				                                    TRUE);
+			}
+
+			return nm_streq0 (a_priv->config, b_priv->config);
+		}
+
+		return TRUE;
+	}
+
+	return NM_SETTING_CLASS (nm_setting_team_port_parent_class)->compare_property (sett_info,
+	                                                                               property_idx,
+	                                                                               setting,
+	                                                                               other,
+	                                                                               flags);
 }
 
+/*****************************************************************************/
+
 static void
-nm_setting_team_port_init (NMSettingTeamPort *setting)
+get_property (GObject *object, guint prop_id,
+              GValue *value, GParamSpec *pspec)
 {
+	NMSettingTeamPort *setting = NM_SETTING_TEAM_PORT (object);
 	NMSettingTeamPortPrivate *priv = NM_SETTING_TEAM_PORT_GET_PRIVATE (setting);
 
-	priv->queue_id = NM_SETTING_TEAM_PORT_QUEUE_ID_DEFAULT;
-	priv->lacp_prio = NM_SETTING_TEAM_PORT_LACP_PRIO_DEFAULT;
-	priv->link_watchers = g_ptr_array_new_with_free_func ((GDestroyNotify) nm_team_link_watcher_unref);
+	switch (prop_id) {
+	case PROP_CONFIG:
+		g_value_set_string (value, nm_setting_team_port_get_config (setting));
+		break;
+	case PROP_QUEUE_ID:
+		g_value_set_int (value, priv->queue_id);
+		break;
+	case PROP_PRIO:
+		g_value_set_int (value, priv->prio);
+		break;
+	case PROP_STICKY:
+		g_value_set_boolean (value, priv->sticky);
+		break;
+	case PROP_LACP_PRIO:
+		g_value_set_int (value, priv->lacp_prio);
+		break;
+	case PROP_LACP_KEY:
+		g_value_set_int (value, priv->lacp_key);
+		break;
+	case PROP_LINK_WATCHERS:
+		g_value_take_boxed (value, _nm_utils_copy_array (priv->link_watchers,
+		                                                 (NMUtilsCopyFunc) nm_team_link_watcher_dup,
+		                                                 (GDestroyNotify) nm_team_link_watcher_unref));
+		break;
+	default:
+		G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+		break;
+	}
 }
 
-#define JSON_TO_VAL(typ, id)   _nm_utils_json_extract_##typ (priv->config, _prop_to_keys[id], TRUE)
-
 static void
 set_property (GObject *object, guint prop_id,
               const GValue *value, GParamSpec *pspec)
@@ -465,6 +501,8 @@ set_property (GObject *object, guint prop_id,
 	const GValue *align_value = NULL;
 	gboolean align_config = FALSE;
 
+#define JSON_TO_VAL(typ, id)   _nm_utils_json_extract_##typ (priv->config, _prop_to_keys[id], TRUE)
+
 	switch (prop_id) {
 	case PROP_CONFIG:
 		g_free (priv->config);
@@ -536,41 +574,29 @@ set_property (GObject *object, guint prop_id,
 		_nm_utils_json_append_gvalue (&priv->config, _prop_to_keys[prop_id], align_value);
 }
 
+/*****************************************************************************/
+
 static void
-get_property (GObject *object, guint prop_id,
-              GValue *value, GParamSpec *pspec)
+nm_setting_team_port_init (NMSettingTeamPort *setting)
 {
-	NMSettingTeamPort *setting = NM_SETTING_TEAM_PORT (object);
 	NMSettingTeamPortPrivate *priv = NM_SETTING_TEAM_PORT_GET_PRIVATE (setting);
 
-	switch (prop_id) {
-	case PROP_CONFIG:
-		g_value_set_string (value, nm_setting_team_port_get_config (setting));
-		break;
-	case PROP_QUEUE_ID:
-		g_value_set_int (value, priv->queue_id);
-		break;
-	case PROP_PRIO:
-		g_value_set_int (value, priv->prio);
-		break;
-	case PROP_STICKY:
-		g_value_set_boolean (value, priv->sticky);
-		break;
-	case PROP_LACP_PRIO:
-		g_value_set_int (value, priv->lacp_prio);
-		break;
-	case PROP_LACP_KEY:
-		g_value_set_int (value, priv->lacp_key);
-		break;
-	case PROP_LINK_WATCHERS:
-		g_value_take_boxed (value, _nm_utils_copy_array (priv->link_watchers,
-		                                                 (NMUtilsCopyFunc) nm_team_link_watcher_dup,
-		                                                 (GDestroyNotify) nm_team_link_watcher_unref));
-		break;
-	default:
-		G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
-		break;
-	}
+	priv->queue_id = NM_SETTING_TEAM_PORT_QUEUE_ID_DEFAULT;
+	priv->lacp_prio = NM_SETTING_TEAM_PORT_LACP_PRIO_DEFAULT;
+	priv->link_watchers = g_ptr_array_new_with_free_func ((GDestroyNotify) nm_team_link_watcher_unref);
+}
+
+/**
+ * nm_setting_team_port_new:
+ *
+ * Creates a new #NMSettingTeamPort object with default values.
+ *
+ * Returns: (transfer full): the new empty #NMSettingTeamPort object
+ **/
+NMSetting *
+nm_setting_team_port_new (void)
+{
+	return (NMSetting *) g_object_new (NM_TYPE_SETTING_TEAM_PORT, NULL);
 }
 
 static void
@@ -593,8 +619,8 @@ nm_setting_team_port_class_init (NMSettingTeamPortClass *klass)
 
 	g_type_class_add_private (klass, sizeof (NMSettingTeamPortPrivate));
 
-	object_class->set_property     = set_property;
 	object_class->get_property     = get_property;
+	object_class->set_property     = set_property;
 	object_class->finalize         = finalize;
 
 	setting_class->compare_property = compare_property;
@@ -614,13 +640,12 @@ nm_setting_team_port_class_init (NMSettingTeamPortClass *klass)
 	 * description: Team port configuration in JSON. See man teamd.conf for details.
 	 * ---end---
 	 */
-	g_object_class_install_property
-		(object_class, PROP_CONFIG,
-		 g_param_spec_string (NM_SETTING_TEAM_PORT_CONFIG, "", "",
-		                      NULL,
-		                      G_PARAM_READWRITE |
-		                      NM_SETTING_PARAM_INFERRABLE |
-		                      G_PARAM_STATIC_STRINGS));
+	obj_properties[PROP_CONFIG] =
+	    g_param_spec_string (NM_SETTING_TEAM_PORT_CONFIG, "", "",
+	                         NULL,
+	                         G_PARAM_READWRITE |
+	                         NM_SETTING_PARAM_INFERRABLE |
+	                         G_PARAM_STATIC_STRINGS);
 
 	/**
 	 * NMSettingTeamPort:queue-id:
@@ -630,12 +655,11 @@ nm_setting_team_port_class_init (NMSettingTeamPortClass *klass)
 	 *
 	 * Since: 1.12
 	 **/
-	g_object_class_install_property
-		(object_class, PROP_QUEUE_ID,
-		 g_param_spec_int (NM_SETTING_TEAM_PORT_QUEUE_ID, "", "",
-		                   G_MININT32, G_MAXINT32, 0,
-		                   G_PARAM_READWRITE |
-		                   G_PARAM_STATIC_STRINGS));
+	obj_properties[PROP_QUEUE_ID] =
+	    g_param_spec_int (NM_SETTING_TEAM_PORT_QUEUE_ID, "", "",
+	                      G_MININT32, G_MAXINT32, 0,
+	                      G_PARAM_READWRITE |
+	                      G_PARAM_STATIC_STRINGS);
 
 	/**
 	 * NMSettingTeamPort:prio:
@@ -644,12 +668,11 @@ nm_setting_team_port_class_init (NMSettingTeamPortClass *klass)
 	 *
 	 * Since: 1.12
 	 **/
-	g_object_class_install_property
-		(object_class, PROP_PRIO,
-		 g_param_spec_int (NM_SETTING_TEAM_PORT_PRIO, "", "",
-		                   G_MININT32, G_MAXINT32, 0,
-		                   G_PARAM_READWRITE |
-		                   G_PARAM_STATIC_STRINGS));
+	obj_properties[PROP_PRIO] =
+	    g_param_spec_int (NM_SETTING_TEAM_PORT_PRIO, "", "",
+	                      G_MININT32, G_MAXINT32, 0,
+	                      G_PARAM_READWRITE |
+	                      G_PARAM_STATIC_STRINGS);
 
 	/**
 	 * NMSettingTeamPort:sticky:
@@ -658,12 +681,11 @@ nm_setting_team_port_class_init (NMSettingTeamPortClass *klass)
 	 *
 	 * Since: 1.12
 	 **/
-	g_object_class_install_property
-		(object_class, PROP_STICKY,
-		 g_param_spec_boolean (NM_SETTING_TEAM_PORT_STICKY, "", "",
-		                       FALSE,
-		                       G_PARAM_READWRITE |
-		                       G_PARAM_STATIC_STRINGS));
+	obj_properties[PROP_STICKY] =
+	    g_param_spec_boolean (NM_SETTING_TEAM_PORT_STICKY, "", "",
+	                          FALSE,
+	                          G_PARAM_READWRITE |
+	                          G_PARAM_STATIC_STRINGS);
 
 	/**
 	 * NMSettingTeamPort:lacp-prio:
@@ -672,12 +694,11 @@ nm_setting_team_port_class_init (NMSettingTeamPortClass *klass)
 	 *
 	 * Since: 1.12
 	 **/
-	g_object_class_install_property
-		(object_class, PROP_LACP_PRIO,
-		 g_param_spec_int (NM_SETTING_TEAM_PORT_LACP_PRIO, "", "",
-		                   G_MININT32, G_MAXINT32, 0,
-		                   G_PARAM_READWRITE |
-		                   G_PARAM_STATIC_STRINGS));
+	obj_properties[PROP_LACP_PRIO] =
+	    g_param_spec_int (NM_SETTING_TEAM_PORT_LACP_PRIO, "", "",
+	                      G_MININT32, G_MAXINT32, 0,
+	                      G_PARAM_READWRITE |
+	                      G_PARAM_STATIC_STRINGS);
 
 	/**
 	 * NMSettingTeamPort:lacp-key:
@@ -686,12 +707,11 @@ nm_setting_team_port_class_init (NMSettingTeamPortClass *klass)
 	 *
 	 * Since: 1.12
 	 **/
-	g_object_class_install_property
-		(object_class, PROP_LACP_KEY,
-		 g_param_spec_int (NM_SETTING_TEAM_PORT_LACP_KEY, "", "",
-		                   G_MININT32, G_MAXINT32, 0,
-		                   G_PARAM_READWRITE |
-		                   G_PARAM_STATIC_STRINGS));
+	obj_properties[PROP_LACP_KEY] =
+	    g_param_spec_int (NM_SETTING_TEAM_PORT_LACP_KEY, "", "",
+	                      G_MININT32, G_MAXINT32, 0,
+	                      G_PARAM_READWRITE |
+	                      G_PARAM_STATIC_STRINGS);
 
 	/**
 	 * NMSettingTeamPort:link-watchers: (type GPtrArray(NMTeamLinkWatcher))
@@ -703,24 +723,24 @@ nm_setting_team_port_class_init (NMSettingTeamPortClass *klass)
 	 * Available keys are:   ethtool: 'delay-up', 'delay-down', 'init-wait';
 	 * nsna_ping: 'init-wait', 'interval', 'missed-max', 'target-host';
 	 * arp_ping: all the ones in nsna_ping and 'source-host', 'validate-active',
-	 * 'validate-incative', 'send-always'. See teamd.conf man for more details.
+	 * 'validate-inactive', 'send-always'. See teamd.conf man for more details.
 	 *
 	 * Since: 1.12
 	 **/
-	g_object_class_install_property
-		(object_class, PROP_LINK_WATCHERS,
-		 g_param_spec_boxed (NM_SETTING_TEAM_PORT_LINK_WATCHERS, "", "",
-		                     G_TYPE_PTR_ARRAY,
-		                     G_PARAM_READWRITE |
-		                     G_PARAM_STATIC_STRINGS));
+	obj_properties[PROP_LINK_WATCHERS] =
+	    g_param_spec_boxed (NM_SETTING_TEAM_PORT_LINK_WATCHERS, "", "",
+	                        G_TYPE_PTR_ARRAY,
+	                        G_PARAM_READWRITE |
+	                        G_PARAM_STATIC_STRINGS);
 
 	_properties_override_add_transform (properties_override,
-	                                    g_object_class_find_property (G_OBJECT_CLASS (setting_class),
-	                                                                  NM_SETTING_TEAM_PORT_LINK_WATCHERS),
+	                                    obj_properties[PROP_LINK_WATCHERS],
 	                                    G_VARIANT_TYPE ("aa{sv}"),
 	                                    team_link_watchers_to_dbus,
 	                                    team_link_watchers_from_dbus);
 
+	g_object_class_install_properties (object_class, _PROPERTY_ENUMS_LAST, obj_properties);
+
 	_nm_setting_class_commit_full (setting_class, NM_META_SETTING_TYPE_TEAM_PORT,
 	                               NULL, properties_override);
 }
diff --git a/libnm-core/nm-setting-team.c b/libnm-core/nm-setting-team.c
index 3d151462..3161c05f 100644
--- a/libnm-core/nm-setting-team.c
+++ b/libnm-core/nm-setting-team.c
@@ -21,10 +21,11 @@
 
 #include "nm-default.h"
 
+#include "nm-setting-team.h"
+
 #include <string.h>
 #include <stdlib.h>
 
-#include "nm-setting-team.h"
 #include "nm-utils.h"
 #include "nm-utils-private.h"
 #include "nm-connection-private.h"
@@ -83,6 +84,7 @@ struct NMTeamLinkWatcher {
 			int init_wait;
 			int interval;
 			int missed_max;
+			int vlanid;
 			char *target_host;
 			char *source_host;
 			NMTeamLinkWatcherArpPingFlags flags;
@@ -233,6 +235,45 @@ nm_team_link_watcher_new_arp_ping (int init_wait,
                                    NMTeamLinkWatcherArpPingFlags flags,
                                    GError **error)
 {
+	return nm_team_link_watcher_new_arp_ping2 (init_wait,
+	                                           interval,
+	                                           missed_max,
+	                                           -1,
+	                                           target_host,
+	                                           source_host,
+	                                           flags,
+	                                           error);
+}
+
+/**
+ * nm_team_link_watcher_new_arp_ping2:
+ * @init_wait: init_wait value
+ * @interval: interval value
+ * @missed_max: missed_max value
+ * @vlanid: vlanid value
+ * @target_host: the host name or the ip address that will be used as destination
+ *   address in the arp request
+ * @source_host: the host name or the ip address that will be used as source
+ *   address in the arp request
+ * @flags: the watcher #NMTeamLinkWatcherArpPingFlags
+ * @error: (out) (allow-none): location to store the error on failure
+ *
+ * Creates a new arp_ping #NMTeamLinkWatcher object
+ *
+ * Returns: (transfer full): the new #NMTeamLinkWatcher object, or %NULL on error
+ *
+ * Since: 1.16
+ **/
+NMTeamLinkWatcher *
+nm_team_link_watcher_new_arp_ping2 (int init_wait,
+                                    int interval,
+                                    int missed_max,
+                                    int vlanid,
+                                    const char *target_host,
+                                    const char *source_host,
+                                    NMTeamLinkWatcherArpPingFlags flags,
+                                    GError **error)
+{
 	NMTeamLinkWatcher *watcher;
 	const char *val_fail = NULL;
 
@@ -255,11 +296,11 @@ nm_team_link_watcher_new_arp_ping (int init_wait,
 		return NULL;
 	}
 
-	if (init_wait < 0 || !_NM_INT_LE_MAXINT32 (init_wait))
+	else if (init_wait < 0 || !_NM_INT_LE_MAXINT32 (init_wait))
 		val_fail = "init-wait";
-	if (interval < 0 || !_NM_INT_LE_MAXINT32 (interval))
+	else if (interval < 0 || !_NM_INT_LE_MAXINT32 (interval))
 		val_fail = "interval";
-	if (missed_max < 0 || !_NM_INT_LE_MAXINT32 (missed_max))
+	else if (missed_max < 0 || !_NM_INT_LE_MAXINT32 (missed_max))
 		val_fail = "missed-max";
 	if (val_fail) {
 		g_set_error (error, NM_CONNECTION_ERROR, NM_CONNECTION_ERROR_FAILED,
@@ -267,6 +308,12 @@ nm_team_link_watcher_new_arp_ping (int init_wait,
 		return NULL;
 	}
 
+	if (vlanid < -1 || vlanid > 4094) {
+		g_set_error_literal (error, NM_CONNECTION_ERROR, NM_CONNECTION_ERROR_FAILED,
+		                     _("vlanid is out of range [-1, 4094]"));
+		return NULL;
+	}
+
 	watcher = g_slice_new0 (NMTeamLinkWatcher);
 	watcher->refcount = 1;
 
@@ -277,6 +324,7 @@ nm_team_link_watcher_new_arp_ping (int init_wait,
 	watcher->arp_ping.target_host = g_strdup (target_host);
 	watcher->arp_ping.source_host = g_strdup (source_host);
 	watcher->arp_ping.flags = flags;
+	watcher->arp_ping.vlanid = vlanid;
 
 	return watcher;
 }
@@ -342,6 +390,7 @@ nm_team_link_watcher_equal (NMTeamLinkWatcher *watcher, NMTeamLinkWatcher *other
 	    || watcher->arp_ping.init_wait != other->arp_ping.init_wait
 	    || watcher->arp_ping.interval != other->arp_ping.interval
 	    || watcher->arp_ping.missed_max != other->arp_ping.missed_max
+	    || watcher->arp_ping.vlanid != other->arp_ping.vlanid
 	    || watcher->arp_ping.flags != other->arp_ping.flags)
 		return FALSE;
 
@@ -377,12 +426,13 @@ nm_team_link_watcher_dup (NMTeamLinkWatcher *watcher)
 		                                           NULL);
 		break;
 	case LINK_WATCHER_ARP_PING:
-		return nm_team_link_watcher_new_arp_ping (watcher->arp_ping.init_wait,
-		                                          watcher->arp_ping.interval,
-		                                          watcher->arp_ping.missed_max,
-		                                          watcher->arp_ping.target_host,
-		                                          watcher->arp_ping.source_host,
-		                                          watcher->arp_ping.flags,
+		return nm_team_link_watcher_new_arp_ping2 (watcher->arp_ping.init_wait,
+		                                           watcher->arp_ping.interval,
+		                                           watcher->arp_ping.missed_max,
+		                                           watcher->arp_ping.vlanid,
+		                                           watcher->arp_ping.target_host,
+		                                           watcher->arp_ping.source_host,
+		                                           watcher->arp_ping.flags,
 		                                          NULL);
 	default:
 		g_assert_not_reached ();
@@ -411,7 +461,7 @@ nm_team_link_watcher_get_name (NMTeamLinkWatcher *watcher)
  * @watcher: the #NMTeamLinkWatcher
  *
  * Gets the delay_up interval (in milliseconds) that elapses between the link
- * coming up and the runner beeing notified about it.
+ * coming up and the runner being notified about it.
  *
  * Since: 1.12
  **/
@@ -430,7 +480,7 @@ nm_team_link_watcher_get_delay_up (NMTeamLinkWatcher *watcher)
  * @watcher: the #NMTeamLinkWatcher
  *
  * Gets the delay_down interval (in milliseconds) that elapses between the link
- * going down and the runner beeing notified about it.
+ * going down and the runner being notified about it.
  *
  * Since: 1.12
  **/
@@ -507,6 +557,24 @@ nm_team_link_watcher_get_missed_max (NMTeamLinkWatcher *watcher)
 }
 
 /**
+ * nm_team_link_watcher_get_vlanid:
+ * @watcher: the #NMTeamLinkWatcher
+ *
+ * Gets the VLAN tag ID to be used to outgoing link probes
+ *
+ * Since: 1.16
+ **/
+int
+nm_team_link_watcher_get_vlanid (NMTeamLinkWatcher *watcher)
+{
+	_CHECK_WATCHER (watcher, -1);
+
+	if (watcher->type != LINK_WATCHER_ARP_PING)
+		return -1;
+	return watcher->arp_ping.vlanid;
+}
+
+/**
  * nm_team_link_watcher_get_target_host:
  * @watcher: the #NMTeamLinkWatcher
  *
@@ -557,32 +625,8 @@ nm_team_link_watcher_get_flags (NMTeamLinkWatcher *watcher)
 
 /*****************************************************************************/
 
-G_DEFINE_TYPE (NMSettingTeam, nm_setting_team, NM_TYPE_SETTING)
-
-#define NM_SETTING_TEAM_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), NM_TYPE_SETTING_TEAM, NMSettingTeamPrivate))
-
-typedef struct {
-	char *config;
-	int notify_peers_count;
-	int notify_peers_interval;
-	int mcast_rejoin_count;
-	int mcast_rejoin_interval;
-	char *runner;
-	char *runner_hwaddr_policy;
-	GPtrArray *runner_tx_hash;
-	char *runner_tx_balancer;
-	int runner_tx_balancer_interval;
-	gboolean runner_active;
-	gboolean runner_fast_rate;
-	int runner_sys_prio;
-	int runner_min_ports;
-	char *runner_agg_select_policy;
-	GPtrArray *link_watchers; /* Array of NMTeamLinkWatcher */
-} NMSettingTeamPrivate;
-
 /* Keep aligned with _prop_to_keys[] */
-enum {
-	PROP_0,
+NM_GOBJECT_PROPERTIES_DEFINE (NMSettingTeam,
 	PROP_CONFIG,
 	PROP_NOTIFY_PEERS_COUNT,
 	PROP_NOTIFY_PEERS_INTERVAL,
@@ -599,12 +643,10 @@ enum {
 	PROP_RUNNER_MIN_PORTS,
 	PROP_RUNNER_AGG_SELECT_POLICY,
 	PROP_LINK_WATCHERS,
-	LAST_PROP
-};
+);
 
 /* Keep aligned with team properties enum */
-static const _NMUtilsTeamPropertyKeys _prop_to_keys[LAST_PROP] = {
-	[PROP_0] =                           { NULL, NULL, NULL, 0 },
+static const _NMUtilsTeamPropertyKeys _prop_to_keys[_PROPERTY_ENUMS_LAST] = {
 	[PROP_CONFIG] =                      { NULL, NULL, NULL, 0 },
 	[PROP_NOTIFY_PEERS_COUNT] =          { "notify_peers", "count", NULL, 0 },
 	[PROP_NOTIFY_PEERS_INTERVAL] =       { "notify_peers", "interval", NULL, 0 },
@@ -624,18 +666,30 @@ static const _NMUtilsTeamPropertyKeys _prop_to_keys[LAST_PROP] = {
 	[PROP_LINK_WATCHERS] =               { "link_watch", NULL, NULL, 0 }
 };
 
-/**
- * nm_setting_team_new:
- *
- * Creates a new #NMSettingTeam object with default values.
- *
- * Returns: (transfer full): the new empty #NMSettingTeam object
- **/
-NMSetting *
-nm_setting_team_new (void)
-{
-	return (NMSetting *) g_object_new (NM_TYPE_SETTING_TEAM, NULL);
-}
+typedef struct {
+	char *config;
+	int notify_peers_count;
+	int notify_peers_interval;
+	int mcast_rejoin_count;
+	int mcast_rejoin_interval;
+	char *runner;
+	char *runner_hwaddr_policy;
+	GPtrArray *runner_tx_hash;
+	char *runner_tx_balancer;
+	int runner_tx_balancer_interval;
+	gboolean runner_active;
+	gboolean runner_fast_rate;
+	int runner_sys_prio;
+	int runner_min_ports;
+	char *runner_agg_select_policy;
+	GPtrArray *link_watchers; /* Array of NMTeamLinkWatcher */
+} NMSettingTeamPrivate;
+
+G_DEFINE_TYPE (NMSettingTeam, nm_setting_team, NM_TYPE_SETTING)
+
+#define NM_SETTING_TEAM_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), NM_TYPE_SETTING_TEAM, NMSettingTeamPrivate))
+
+/*****************************************************************************/
 
 /**
  * nm_setting_team_get_config:
@@ -884,7 +938,7 @@ nm_setting_team_remove_runner_tx_hash_by_value (NMSettingTeam *setting,
 	for (i = 0; i < priv->runner_tx_hash->len; i++) {
 		if (nm_streq (txhash, priv->runner_tx_hash->pdata[i])) {
 			g_ptr_array_remove_index (priv->runner_tx_hash, i);
-			g_object_notify (G_OBJECT (setting), NM_SETTING_TEAM_RUNNER_TX_HASH);
+			_notify (setting, PROP_RUNNER_TX_HASH);
 			return TRUE;
 		}
 	}
@@ -947,7 +1001,7 @@ nm_setting_team_remove_runner_tx_hash (NMSettingTeam *setting, guint idx)
 	g_return_if_fail (idx < priv->runner_tx_hash->len);
 
 	g_ptr_array_remove_index (priv->runner_tx_hash, idx);
-	g_object_notify (G_OBJECT (setting), NM_SETTING_TEAM_RUNNER_TX_HASH);
+	_notify (setting, PROP_RUNNER_TX_HASH);
 }
 
 /**
@@ -980,7 +1034,7 @@ nm_setting_team_add_runner_tx_hash (NMSettingTeam *setting, const char *txhash)
 	}
 
 	g_ptr_array_add (priv->runner_tx_hash, g_strdup (txhash));
-	g_object_notify (G_OBJECT (setting), NM_SETTING_TEAM_RUNNER_TX_HASH);
+	_notify (setting, PROP_RUNNER_TX_HASH);
 	return TRUE;
 }
 
@@ -1050,7 +1104,7 @@ nm_setting_team_add_link_watcher (NMSettingTeam *setting,
 	}
 
 	g_ptr_array_add (priv->link_watchers, nm_team_link_watcher_dup (link_watcher));
-	g_object_notify (G_OBJECT (setting), NM_SETTING_TEAM_LINK_WATCHERS);
+	_notify (setting, PROP_LINK_WATCHERS);
 	return TRUE;
 }
 
@@ -1072,7 +1126,7 @@ nm_setting_team_remove_link_watcher (NMSettingTeam *setting, guint idx)
 	g_return_if_fail (idx < priv->link_watchers->len);
 
 	g_ptr_array_remove_index (priv->link_watchers, idx);
-	g_object_notify (G_OBJECT (setting), NM_SETTING_TEAM_LINK_WATCHERS);
+	_notify (setting, PROP_LINK_WATCHERS);
 }
 
 /**
@@ -1098,7 +1152,7 @@ nm_setting_team_remove_link_watcher_by_value (NMSettingTeam *setting,
 	for (i = 0; i < priv->link_watchers->len; i++) {
 		if (nm_team_link_watcher_equal (priv->link_watchers->pdata[i], link_watcher)) {
 			g_ptr_array_remove_index (priv->link_watchers, i);
-			g_object_notify (G_OBJECT (setting), NM_SETTING_TEAM_LINK_WATCHERS);
+			_notify (setting, PROP_LINK_WATCHERS);
 			return TRUE;
 		}
 	}
@@ -1121,7 +1175,7 @@ nm_setting_team_clear_link_watchers (NMSettingTeam *setting) {
 
 	if (priv->link_watchers->len != 0) {
 		g_ptr_array_set_size (priv->link_watchers, 0);
-		g_object_notify (G_OBJECT (setting), NM_SETTING_TEAM_LINK_WATCHERS);
+		_notify (setting, PROP_LINK_WATCHERS);
 	}
 }
 
@@ -1230,38 +1284,33 @@ verify (NMSetting *setting, NMConnection *connection, GError **error)
 	return TRUE;
 }
 
-static gboolean
-compare_property (NMSetting *setting,
+static NMTernary
+compare_property (const NMSettInfoSetting *sett_info,
+                  guint property_idx,
+                  NMSetting *setting,
                   NMSetting *other,
-                  const GParamSpec *prop_spec,
                   NMSettingCompareFlags flags)
 {
 	NMSettingTeamPrivate *a_priv, *b_priv;
-	NMSettingClass *setting_class;
 	guint i, j;
 
-	/* If we are trying to match a connection in order to assume it (and thus
-	 * @flags contains INFERRABLE), use the "relaxed" matching for team
-	 * configuration. Otherwise, for all other purposes (including connection
-	 * comparison before an update), resort to the default string comparison.
-	 */
-	if (   NM_FLAGS_HAS (flags, NM_SETTING_COMPARE_FLAG_INFERRABLE)
-	    && nm_streq0 (prop_spec->name, NM_SETTING_TEAM_CONFIG)) {
-		return _nm_utils_team_config_equal (NM_SETTING_TEAM_GET_PRIVATE (setting)->config,
-		                                    NM_SETTING_TEAM_GET_PRIVATE (other)->config,
-		                                    FALSE);
-	}
-	if (nm_streq0 (prop_spec->name, NM_SETTING_TEAM_LINK_WATCHERS)) {
-		a_priv = NM_SETTING_TEAM_GET_PRIVATE (setting);
-		b_priv = NM_SETTING_TEAM_GET_PRIVATE (other);
+	if (nm_streq (sett_info->property_infos[property_idx].name, NM_SETTING_TEAM_LINK_WATCHERS)) {
 
-		if (a_priv->link_watchers->len != b_priv->link_watchers->len)
-			return FALSE;
-		for (i = 0; i < a_priv->link_watchers->len; i++) {
-			for (j = 0; j < b_priv->link_watchers->len; j++) {
-				if (nm_team_link_watcher_equal (a_priv->link_watchers->pdata[i],
-				                                b_priv->link_watchers->pdata[j])) {
-					break;
+		if (NM_FLAGS_HAS (flags, NM_SETTING_COMPARE_FLAG_INFERRABLE))
+			return NM_TERNARY_DEFAULT;
+
+		if (other) {
+			a_priv = NM_SETTING_TEAM_GET_PRIVATE (setting);
+			b_priv = NM_SETTING_TEAM_GET_PRIVATE (other);
+
+			if (a_priv->link_watchers->len != b_priv->link_watchers->len)
+				return FALSE;
+			for (i = 0; i < a_priv->link_watchers->len; i++) {
+				for (j = 0; j < b_priv->link_watchers->len; j++) {
+					if (nm_team_link_watcher_equal (a_priv->link_watchers->pdata[i],
+					                                b_priv->link_watchers->pdata[j])) {
+						break;
+					}
 				}
 				if (j == b_priv->link_watchers->len)
 					return FALSE;
@@ -1270,37 +1319,32 @@ compare_property (NMSetting *setting,
 		return TRUE;
 	}
 
-	setting_class = NM_SETTING_CLASS (nm_setting_team_parent_class);
-	return setting_class->compare_property (setting, other, prop_spec, flags);
-}
-
-static void
-nm_setting_team_init (NMSettingTeam *setting)
-{
-	NMSettingTeamPrivate *priv = NM_SETTING_TEAM_GET_PRIVATE (setting);
-
-	priv->runner = g_strdup (NM_SETTING_TEAM_RUNNER_ROUNDROBIN);
-	priv->runner_tx_balancer_interval = -1;
-	priv->runner_sys_prio = -1;
-	priv->runner_min_ports = -1;
-	priv->link_watchers = g_ptr_array_new_with_free_func ((GDestroyNotify) nm_team_link_watcher_unref);
-}
+	if (nm_streq (sett_info->property_infos[property_idx].name, NM_SETTING_TEAM_CONFIG)) {
+		if (other) {
+			a_priv = NM_SETTING_TEAM_GET_PRIVATE (setting);
+			b_priv = NM_SETTING_TEAM_GET_PRIVATE (other);
+
+			if (NM_FLAGS_HAS (flags, NM_SETTING_COMPARE_FLAG_INFERRABLE)) {
+				/* If we are trying to match a connection in order to assume it (and thus
+				 * @flags contains INFERRABLE), use the "relaxed" matching for team
+				 * configuration. Otherwise, for all other purposes (including connection
+				 * comparison before an update), resort to the default string comparison. */
+				return _nm_utils_team_config_equal (a_priv->config,
+				                                    b_priv->config,
+				                                    TRUE);
+			}
 
-static void
-finalize (GObject *object)
-{
-	NMSettingTeamPrivate *priv = NM_SETTING_TEAM_GET_PRIVATE (object);
+			return nm_streq0 (a_priv->config, b_priv->config);
+		}
 
-	g_free (priv->config);
-	g_free (priv->runner);
-	g_free (priv->runner_hwaddr_policy);
-	g_free (priv->runner_tx_balancer);
-	g_free (priv->runner_agg_select_policy);
-	if (priv->runner_tx_hash)
-		g_ptr_array_unref (priv->runner_tx_hash);
-	g_ptr_array_unref (priv->link_watchers);
+		return TRUE;
+	}
 
-	G_OBJECT_CLASS (nm_setting_team_parent_class)->finalize (object);
+	return NM_SETTING_CLASS (nm_setting_team_parent_class)->compare_property (sett_info,
+	                                                                          property_idx,
+	                                                                          setting,
+	                                                                          other,
+	                                                                          flags);
 }
 
 #define JSON_TO_VAL(typ, id)   _nm_utils_json_extract_##typ (priv->config, _prop_to_keys[id], FALSE)
@@ -1347,6 +1391,73 @@ _align_team_properties (NMSettingTeam *setting)
 	priv->link_watchers = JSON_TO_VAL (ptr_array, PROP_LINK_WATCHERS);
 }
 
+/*****************************************************************************/
+
+static void
+get_property (GObject *object, guint prop_id,
+              GValue *value, GParamSpec *pspec)
+{
+	NMSettingTeam *setting = NM_SETTING_TEAM (object);
+	NMSettingTeamPrivate *priv = NM_SETTING_TEAM_GET_PRIVATE (setting);
+
+	switch (prop_id) {
+	case PROP_CONFIG:
+		g_value_set_string (value, nm_setting_team_get_config (setting));
+		break;
+	case PROP_NOTIFY_PEERS_COUNT:
+		g_value_set_int (value, priv->notify_peers_count);
+		break;
+	case PROP_NOTIFY_PEERS_INTERVAL:
+		g_value_set_int (value, priv->notify_peers_interval);
+		break;
+	case PROP_MCAST_REJOIN_COUNT:
+		g_value_set_int (value, priv->mcast_rejoin_count);
+		break;
+	case PROP_MCAST_REJOIN_INTERVAL:
+		g_value_set_int (value, priv->mcast_rejoin_interval);
+		break;
+	case PROP_RUNNER:
+		g_value_set_string (value, nm_setting_team_get_runner (setting));
+		break;
+	case PROP_RUNNER_HWADDR_POLICY:
+		g_value_set_string (value, nm_setting_team_get_runner_hwaddr_policy (setting));
+		break;
+	case PROP_RUNNER_TX_HASH:
+		g_value_take_boxed (value, priv->runner_tx_hash ?
+		                    _nm_utils_ptrarray_to_strv (priv->runner_tx_hash): NULL);
+		break;
+	case PROP_RUNNER_TX_BALANCER:
+		g_value_set_string (value, nm_setting_team_get_runner_tx_balancer (setting));
+		break;
+	case PROP_RUNNER_TX_BALANCER_INTERVAL:
+		g_value_set_int (value, priv->runner_tx_balancer_interval);
+		break;
+	case PROP_RUNNER_ACTIVE:
+		g_value_set_boolean (value, nm_setting_team_get_runner_active (setting));
+		break;
+	case PROP_RUNNER_FAST_RATE:
+		g_value_set_boolean (value, nm_setting_team_get_runner_fast_rate (setting));
+		break;
+	case PROP_RUNNER_SYS_PRIO:
+		g_value_set_int (value, priv->runner_sys_prio);
+		break;
+	case PROP_RUNNER_MIN_PORTS:
+		g_value_set_int (value, priv->runner_min_ports);
+		break;
+	case PROP_RUNNER_AGG_SELECT_POLICY:
+		g_value_set_string (value, nm_setting_team_get_runner_agg_select_policy (setting));
+		break;
+	case PROP_LINK_WATCHERS:
+		g_value_take_boxed (value, _nm_utils_copy_array (priv->link_watchers,
+		                                                 (NMUtilsCopyFunc) nm_team_link_watcher_dup,
+		                                                 (GDestroyNotify) nm_team_link_watcher_unref));
+		break;
+	default:
+		G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+		break;
+	}
+}
+
 static void
 set_property (GObject *object, guint prop_id,
               const GValue *value, GParamSpec *pspec)
@@ -1490,69 +1601,48 @@ set_property (GObject *object, guint prop_id,
 	}
 }
 
+/*****************************************************************************/
+
 static void
-get_property (GObject *object, guint prop_id,
-              GValue *value, GParamSpec *pspec)
+nm_setting_team_init (NMSettingTeam *setting)
 {
-	NMSettingTeam *setting = NM_SETTING_TEAM (object);
 	NMSettingTeamPrivate *priv = NM_SETTING_TEAM_GET_PRIVATE (setting);
 
-	switch (prop_id) {
-	case PROP_CONFIG:
-		g_value_set_string (value, nm_setting_team_get_config (setting));
-		break;
-	case PROP_NOTIFY_PEERS_COUNT:
-		g_value_set_int (value, priv->notify_peers_count);
-		break;
-	case PROP_NOTIFY_PEERS_INTERVAL:
-		g_value_set_int (value, priv->notify_peers_interval);
-		break;
-	case PROP_MCAST_REJOIN_COUNT:
-		g_value_set_int (value, priv->mcast_rejoin_count);
-		break;
-	case PROP_MCAST_REJOIN_INTERVAL:
-		g_value_set_int (value, priv->mcast_rejoin_interval);
-		break;
-	case PROP_RUNNER:
-		g_value_set_string (value, nm_setting_team_get_runner (setting));
-		break;
-	case PROP_RUNNER_HWADDR_POLICY:
-		g_value_set_string (value, nm_setting_team_get_runner_hwaddr_policy (setting));
-		break;
-	case PROP_RUNNER_TX_HASH:
-		g_value_take_boxed (value, priv->runner_tx_hash ?
-		                    _nm_utils_ptrarray_to_strv (priv->runner_tx_hash): NULL);
-		break;
-	case PROP_RUNNER_TX_BALANCER:
-		g_value_set_string (value, nm_setting_team_get_runner_tx_balancer (setting));
-		break;
-	case PROP_RUNNER_TX_BALANCER_INTERVAL:
-		g_value_set_int (value, priv->runner_tx_balancer_interval);
-		break;
-	case PROP_RUNNER_ACTIVE:
-		g_value_set_boolean (value, nm_setting_team_get_runner_active (setting));
-		break;
-	case PROP_RUNNER_FAST_RATE:
-		g_value_set_boolean (value, nm_setting_team_get_runner_fast_rate (setting));
-		break;
-	case PROP_RUNNER_SYS_PRIO:
-		g_value_set_int (value, priv->runner_sys_prio);
-		break;
-	case PROP_RUNNER_MIN_PORTS:
-		g_value_set_int (value, priv->runner_min_ports);
-		break;
-	case PROP_RUNNER_AGG_SELECT_POLICY:
-		g_value_set_string (value, nm_setting_team_get_runner_agg_select_policy (setting));
-		break;
-	case PROP_LINK_WATCHERS:
-		g_value_take_boxed (value, _nm_utils_copy_array (priv->link_watchers,
-		                                                 (NMUtilsCopyFunc) nm_team_link_watcher_dup,
-		                                                 (GDestroyNotify) nm_team_link_watcher_unref));
-		break;
-	default:
-		G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
-		break;
-	}
+	priv->runner = g_strdup (NM_SETTING_TEAM_RUNNER_ROUNDROBIN);
+	priv->runner_tx_balancer_interval = -1;
+	priv->runner_sys_prio = -1;
+	priv->runner_min_ports = -1;
+	priv->link_watchers = g_ptr_array_new_with_free_func ((GDestroyNotify) nm_team_link_watcher_unref);
+}
+
+/**
+ * nm_setting_team_new:
+ *
+ * Creates a new #NMSettingTeam object with default values.
+ *
+ * Returns: (transfer full): the new empty #NMSettingTeam object
+ **/
+NMSetting *
+nm_setting_team_new (void)
+{
+	return (NMSetting *) g_object_new (NM_TYPE_SETTING_TEAM, NULL);
+}
+
+static void
+finalize (GObject *object)
+{
+	NMSettingTeamPrivate *priv = NM_SETTING_TEAM_GET_PRIVATE (object);
+
+	g_free (priv->config);
+	g_free (priv->runner);
+	g_free (priv->runner_hwaddr_policy);
+	g_free (priv->runner_tx_balancer);
+	g_free (priv->runner_agg_select_policy);
+	if (priv->runner_tx_hash)
+		g_ptr_array_unref (priv->runner_tx_hash);
+	g_ptr_array_unref (priv->link_watchers);
+
+	G_OBJECT_CLASS (nm_setting_team_parent_class)->finalize (object);
 }
 
 static void
@@ -1564,8 +1654,8 @@ nm_setting_team_class_init (NMSettingTeamClass *klass)
 
 	g_type_class_add_private (klass, sizeof (NMSettingTeamPrivate));
 
-	object_class->set_property     = set_property;
 	object_class->get_property     = get_property;
+	object_class->set_property     = set_property;
 	object_class->finalize         = finalize;
 
 	setting_class->compare_property = compare_property;
@@ -1585,13 +1675,12 @@ nm_setting_team_class_init (NMSettingTeamClass *klass)
 	 * description: Team configuration in JSON. See man teamd.conf for details.
 	 * ---end---
 	 */
-	g_object_class_install_property
-		(object_class, PROP_CONFIG,
-		 g_param_spec_string (NM_SETTING_TEAM_CONFIG, "", "",
-		                      NULL,
-		                      G_PARAM_READWRITE |
-		                      NM_SETTING_PARAM_INFERRABLE |
-		                      G_PARAM_STATIC_STRINGS));
+	obj_properties[PROP_CONFIG] =
+	    g_param_spec_string (NM_SETTING_TEAM_CONFIG, "", "",
+	                         NULL,
+	                         G_PARAM_READWRITE |
+	                         NM_SETTING_PARAM_INFERRABLE |
+	                         G_PARAM_STATIC_STRINGS);
 
 	/**
 	 * NMSettingTeam:notify-peers-count:
@@ -1600,12 +1689,11 @@ nm_setting_team_class_init (NMSettingTeamClass *klass)
 	 *
 	 * Since: 1.12
 	 **/
-	g_object_class_install_property
-		(object_class, PROP_NOTIFY_PEERS_COUNT,
-		 g_param_spec_int (NM_SETTING_TEAM_NOTIFY_PEERS_COUNT, "", "",
-		                   G_MININT32, G_MAXINT32, 0,
-		                   G_PARAM_READWRITE |
-		                   G_PARAM_STATIC_STRINGS));
+	obj_properties[PROP_NOTIFY_PEERS_COUNT] =
+	    g_param_spec_int (NM_SETTING_TEAM_NOTIFY_PEERS_COUNT, "", "",
+	                      G_MININT32, G_MAXINT32, 0,
+	                      G_PARAM_READWRITE |
+	                      G_PARAM_STATIC_STRINGS);
 
 	/**
 	 * NMSettingTeam:notify-peers-interval:
@@ -1614,12 +1702,11 @@ nm_setting_team_class_init (NMSettingTeamClass *klass)
 	 *
 	 * Since: 1.12
 	 **/
-	g_object_class_install_property
-		(object_class, PROP_NOTIFY_PEERS_INTERVAL,
-		 g_param_spec_int (NM_SETTING_TEAM_NOTIFY_PEERS_INTERVAL, "", "",
-		                   G_MININT32, G_MAXINT32, 0,
-		                   G_PARAM_READWRITE |
-		                   G_PARAM_STATIC_STRINGS));
+	obj_properties[PROP_NOTIFY_PEERS_INTERVAL] =
+	    g_param_spec_int (NM_SETTING_TEAM_NOTIFY_PEERS_INTERVAL, "", "",
+	                      G_MININT32, G_MAXINT32, 0,
+	                      G_PARAM_READWRITE |
+	                      G_PARAM_STATIC_STRINGS);
 
 	/**
 	 * NMSettingTeam:mcast-rejoin-count:
@@ -1628,12 +1715,11 @@ nm_setting_team_class_init (NMSettingTeamClass *klass)
 	 *
 	 * Since: 1.12
 	 **/
-	g_object_class_install_property
-		(object_class, PROP_MCAST_REJOIN_COUNT,
-		 g_param_spec_int (NM_SETTING_TEAM_MCAST_REJOIN_COUNT, "", "",
-		                   G_MININT32, G_MAXINT32, 0,
-		                   G_PARAM_READWRITE |
-		                   G_PARAM_STATIC_STRINGS));
+	obj_properties[PROP_MCAST_REJOIN_COUNT] =
+	    g_param_spec_int (NM_SETTING_TEAM_MCAST_REJOIN_COUNT, "", "",
+	                      G_MININT32, G_MAXINT32, 0,
+	                      G_PARAM_READWRITE |
+	                      G_PARAM_STATIC_STRINGS);
 
 	/**
 	 * NMSettingTeam:mcast-rejoin-interval:
@@ -1642,12 +1728,11 @@ nm_setting_team_class_init (NMSettingTeamClass *klass)
 	 *
 	 * Since: 1.12
 	 **/
-	g_object_class_install_property
-		(object_class, PROP_MCAST_REJOIN_INTERVAL,
-		 g_param_spec_int (NM_SETTING_TEAM_MCAST_REJOIN_INTERVAL, "", "",
-		                   G_MININT32, G_MAXINT32, 0,
-		                   G_PARAM_READWRITE |
-		                   G_PARAM_STATIC_STRINGS));
+	obj_properties[PROP_MCAST_REJOIN_INTERVAL] =
+	    g_param_spec_int (NM_SETTING_TEAM_MCAST_REJOIN_INTERVAL, "", "",
+	                      G_MININT32, G_MAXINT32, 0,
+	                      G_PARAM_READWRITE |
+	                      G_PARAM_STATIC_STRINGS);
 
 	/**
 	 * NMSettingTeam:runner:
@@ -1662,12 +1747,11 @@ nm_setting_team_class_init (NMSettingTeamClass *klass)
 	 *
 	 * Since: 1.12
 	 **/
-	g_object_class_install_property
-		(object_class, PROP_RUNNER,
-		 g_param_spec_string (NM_SETTING_TEAM_RUNNER, "", "",
-		                      NULL,
-		                      G_PARAM_READWRITE |
-		                      G_PARAM_STATIC_STRINGS));
+	obj_properties[PROP_RUNNER] =
+	    g_param_spec_string (NM_SETTING_TEAM_RUNNER, "", "",
+	                         NULL,
+	                         G_PARAM_READWRITE |
+	                         G_PARAM_STATIC_STRINGS);
 
 	/**
 	 * NMSettingTeam:runner-hwaddr-policy:
@@ -1676,12 +1760,11 @@ nm_setting_team_class_init (NMSettingTeamClass *klass)
 	 *
 	 * Since: 1.12
 	 **/
-	g_object_class_install_property
-		(object_class, PROP_RUNNER_HWADDR_POLICY,
-		 g_param_spec_string (NM_SETTING_TEAM_RUNNER_HWADDR_POLICY, "", "",
-		                      NULL,
-		                      G_PARAM_READWRITE |
-		                      G_PARAM_STATIC_STRINGS));
+	obj_properties[PROP_RUNNER_HWADDR_POLICY] =
+	    g_param_spec_string (NM_SETTING_TEAM_RUNNER_HWADDR_POLICY, "", "",
+	                         NULL,
+	                         G_PARAM_READWRITE |
+	                         G_PARAM_STATIC_STRINGS);
 
 	/**
 	 * NMSettingTeam:runner-tx-hash:
@@ -1690,13 +1773,12 @@ nm_setting_team_class_init (NMSettingTeamClass *klass)
 	 *
 	 * Since: 1.12
 	 **/
-	g_object_class_install_property
-		(object_class, PROP_RUNNER_TX_HASH,
-		 g_param_spec_boxed (NM_SETTING_TEAM_RUNNER_TX_HASH, "", "",
-		                     G_TYPE_STRV,
+	obj_properties[PROP_RUNNER_TX_HASH] =
+	    g_param_spec_boxed (NM_SETTING_TEAM_RUNNER_TX_HASH, "", "",
+	                        G_TYPE_STRV,
 	                             G_PARAM_READWRITE |
-		                     NM_SETTING_PARAM_INFERRABLE |
-	                             G_PARAM_STATIC_STRINGS));
+	                        NM_SETTING_PARAM_INFERRABLE |
+	                             G_PARAM_STATIC_STRINGS);
 
 	/**
 	 * NMSettingTeam:runner-tx-balancer:
@@ -1705,12 +1787,11 @@ nm_setting_team_class_init (NMSettingTeamClass *klass)
 	 *
 	 * Since: 1.12
 	 **/
-	g_object_class_install_property
-		(object_class, PROP_RUNNER_TX_BALANCER,
-		 g_param_spec_string (NM_SETTING_TEAM_RUNNER_TX_BALANCER, "", "",
-		                      NULL,
-		                      G_PARAM_READWRITE |
-		                      G_PARAM_STATIC_STRINGS));
+	obj_properties[PROP_RUNNER_TX_BALANCER] =
+	    g_param_spec_string (NM_SETTING_TEAM_RUNNER_TX_BALANCER, "", "",
+	                         NULL,
+	                         G_PARAM_READWRITE |
+	                         G_PARAM_STATIC_STRINGS);
 
 	/**
 	 * NMSettingTeam:runner-tx-balancer-interval:
@@ -1719,12 +1800,11 @@ nm_setting_team_class_init (NMSettingTeamClass *klass)
 	 *
 	 * Since: 1.12
 	 **/
-	g_object_class_install_property
-		(object_class, PROP_RUNNER_TX_BALANCER_INTERVAL,
-		 g_param_spec_int (NM_SETTING_TEAM_RUNNER_TX_BALANCER_INTERVAL, "", "",
-		                   G_MININT32, G_MAXINT32, 0,
-		                   G_PARAM_READWRITE |
-		                   G_PARAM_STATIC_STRINGS));
+	obj_properties[PROP_RUNNER_TX_BALANCER_INTERVAL] =
+	    g_param_spec_int (NM_SETTING_TEAM_RUNNER_TX_BALANCER_INTERVAL, "", "",
+	                      G_MININT32, G_MAXINT32, 0,
+	                      G_PARAM_READWRITE |
+	                      G_PARAM_STATIC_STRINGS);
 
 	/**
 	 * NMSettingTeam:runner-active:
@@ -1733,12 +1813,11 @@ nm_setting_team_class_init (NMSettingTeamClass *klass)
 	 *
 	 * Since: 1.12
 	 **/
-	g_object_class_install_property
-		(object_class, PROP_RUNNER_ACTIVE,
-		 g_param_spec_boolean (NM_SETTING_TEAM_RUNNER_ACTIVE, "", "",
-		                       FALSE,
-		                       G_PARAM_READWRITE |
-		                       G_PARAM_STATIC_STRINGS));
+	obj_properties[PROP_RUNNER_ACTIVE] =
+	    g_param_spec_boolean (NM_SETTING_TEAM_RUNNER_ACTIVE, "", "",
+	                          FALSE,
+	                          G_PARAM_READWRITE |
+	                          G_PARAM_STATIC_STRINGS);
 
 	/**
 	 * NMSettingTeam:runner-fast-rate:
@@ -1747,12 +1826,11 @@ nm_setting_team_class_init (NMSettingTeamClass *klass)
 	 *
 	 * Since: 1.12
 	 **/
-	g_object_class_install_property
-		(object_class, PROP_RUNNER_FAST_RATE,
-		 g_param_spec_boolean (NM_SETTING_TEAM_RUNNER_FAST_RATE, "", "",
-		                       FALSE,
-		                       G_PARAM_READWRITE |
-		                       G_PARAM_STATIC_STRINGS));
+	obj_properties[PROP_RUNNER_FAST_RATE] =
+	    g_param_spec_boolean (NM_SETTING_TEAM_RUNNER_FAST_RATE, "", "",
+	                          FALSE,
+	                          G_PARAM_READWRITE |
+	                          G_PARAM_STATIC_STRINGS);
 
 	/**
 	 * NMSettingTeam:runner-sys-prio:
@@ -1761,12 +1839,11 @@ nm_setting_team_class_init (NMSettingTeamClass *klass)
 	 *
 	 * Since: 1.12
 	 **/
-	g_object_class_install_property
-		(object_class, PROP_RUNNER_SYS_PRIO,
-		 g_param_spec_int (NM_SETTING_TEAM_RUNNER_SYS_PRIO, "", "",
-		                   G_MININT32, G_MAXINT32, 0,
-		                   G_PARAM_READWRITE |
-		                   G_PARAM_STATIC_STRINGS));
+	obj_properties[PROP_RUNNER_SYS_PRIO] =
+	    g_param_spec_int (NM_SETTING_TEAM_RUNNER_SYS_PRIO, "", "",
+	                      G_MININT32, G_MAXINT32, 0,
+	                      G_PARAM_READWRITE |
+	                      G_PARAM_STATIC_STRINGS);
 
 	/**
 	 * NMSettingTeam:runner-min-ports:
@@ -1775,12 +1852,11 @@ nm_setting_team_class_init (NMSettingTeamClass *klass)
 	 *
 	 * Since: 1.12
 	 **/
-	g_object_class_install_property
-		(object_class, PROP_RUNNER_MIN_PORTS,
-		 g_param_spec_int (NM_SETTING_TEAM_RUNNER_MIN_PORTS, "", "",
-		                   G_MININT32, G_MAXINT32, 0,
-		                   G_PARAM_READWRITE |
-		                   G_PARAM_STATIC_STRINGS));
+	obj_properties[PROP_RUNNER_MIN_PORTS] =
+	    g_param_spec_int (NM_SETTING_TEAM_RUNNER_MIN_PORTS, "", "",
+	                      G_MININT32, G_MAXINT32, 0,
+	                      G_PARAM_READWRITE |
+	                      G_PARAM_STATIC_STRINGS);
 
 	/**
 	 * NMSettingTeam:runner-agg-select-policy:
@@ -1789,12 +1865,11 @@ nm_setting_team_class_init (NMSettingTeamClass *klass)
 	 *
 	 * Since: 1.12
 	 **/
-	g_object_class_install_property
-		(object_class, PROP_RUNNER_AGG_SELECT_POLICY,
-		 g_param_spec_string (NM_SETTING_TEAM_RUNNER_AGG_SELECT_POLICY, "", "",
-		                      NULL,
-		                      G_PARAM_READWRITE |
-		                      G_PARAM_STATIC_STRINGS));
+	obj_properties[PROP_RUNNER_AGG_SELECT_POLICY] =
+	    g_param_spec_string (NM_SETTING_TEAM_RUNNER_AGG_SELECT_POLICY, "", "",
+	                         NULL,
+	                         G_PARAM_READWRITE |
+	                         G_PARAM_STATIC_STRINGS);
 
 	/**
 	 * NMSettingTeam:link-watchers: (type GPtrArray(NMTeamLinkWatcher))
@@ -1806,20 +1881,18 @@ nm_setting_team_class_init (NMSettingTeamClass *klass)
 	 * Available keys are:   ethtool: 'delay-up', 'delay-down', 'init-wait';
 	 * nsna_ping: 'init-wait', 'interval', 'missed-max', 'target-host';
 	 * arp_ping: all the ones in nsna_ping and 'source-host', 'validate-active',
-	 * 'validate-incative', 'send-always'. See teamd.conf man for more details.
+	 * 'validate-inactive', 'send-always'. See teamd.conf man for more details.
 	 *
 	 * Since: 1.12
 	 **/
-	g_object_class_install_property
-		(object_class, PROP_LINK_WATCHERS,
-		 g_param_spec_boxed (NM_SETTING_TEAM_LINK_WATCHERS, "", "",
-		                     G_TYPE_PTR_ARRAY,
-		                     G_PARAM_READWRITE |
-		                     G_PARAM_STATIC_STRINGS));
+	obj_properties[PROP_LINK_WATCHERS] =
+	    g_param_spec_boxed (NM_SETTING_TEAM_LINK_WATCHERS, "", "",
+	                        G_TYPE_PTR_ARRAY,
+	                        G_PARAM_READWRITE |
+	                        G_PARAM_STATIC_STRINGS);
 
 	_properties_override_add_transform (properties_override,
-	                                    g_object_class_find_property (G_OBJECT_CLASS (setting_class),
-	                                                                  NM_SETTING_TEAM_LINK_WATCHERS),
+	                                    obj_properties[PROP_LINK_WATCHERS],
 	                                    G_VARIANT_TYPE ("aa{sv}"),
 	                                    team_link_watchers_to_dbus,
 	                                    team_link_watchers_from_dbus);
@@ -1838,6 +1911,8 @@ nm_setting_team_class_init (NMSettingTeamClass *klass)
 	                                    _nm_setting_get_deprecated_virtual_interface_name,
 	                                    NULL);
 
+	g_object_class_install_properties (object_class, _PROPERTY_ENUMS_LAST, obj_properties);
+
 	_nm_setting_class_commit_full (setting_class, NM_META_SETTING_TYPE_TEAM,
 	                               NULL, properties_override);
 }
diff --git a/libnm-core/nm-setting-team.h b/libnm-core/nm-setting-team.h
index a600053a..5819feca 100644
--- a/libnm-core/nm-setting-team.h
+++ b/libnm-core/nm-setting-team.h
@@ -74,6 +74,15 @@ NMTeamLinkWatcher *nm_team_link_watcher_new_arp_ping (int init_wait,
                                                       const char *source_host,
                                                       NMTeamLinkWatcherArpPingFlags flags,
                                                       GError **error);
+NM_AVAILABLE_IN_1_16
+NMTeamLinkWatcher *nm_team_link_watcher_new_arp_ping2 (int init_wait,
+                                                       int interval,
+                                                       int missed_max,
+                                                       int vlanid,
+                                                       const char *target_host,
+                                                       const char *source_host,
+                                                       NMTeamLinkWatcherArpPingFlags flags,
+                                                       GError **error);
 NM_AVAILABLE_IN_1_12
 void nm_team_link_watcher_ref                    (NMTeamLinkWatcher *watcher);
 NM_AVAILABLE_IN_1_12
@@ -100,6 +109,8 @@ NM_AVAILABLE_IN_1_12
 const char *nm_team_link_watcher_get_source_host (NMTeamLinkWatcher *watcher);
 NM_AVAILABLE_IN_1_12
 NMTeamLinkWatcherArpPingFlags nm_team_link_watcher_get_flags (NMTeamLinkWatcher *watcher);
+NM_AVAILABLE_IN_1_16
+int nm_team_link_watcher_get_vlanid              (NMTeamLinkWatcher *watcher);
 
 #define NM_TYPE_SETTING_TEAM            (nm_setting_team_get_type ())
 #define NM_SETTING_TEAM(obj)            (G_TYPE_CHECK_INSTANCE_CAST ((obj), NM_TYPE_SETTING_TEAM, NMSettingTeam))
diff --git a/libnm-core/nm-setting-tun.c b/libnm-core/nm-setting-tun.c
index 3e033e25..348c9fc1 100644
--- a/libnm-core/nm-setting-tun.c
+++ b/libnm-core/nm-setting-tun.c
@@ -21,10 +21,11 @@
 
 #include "nm-default.h"
 
+#include "nm-setting-tun.h"
+
 #include <stdlib.h>
 #include <string.h>
 
-#include "nm-setting-tun.h"
 #include "nm-utils.h"
 #include "nm-setting-connection.h"
 #include "nm-setting-private.h"
@@ -38,9 +39,16 @@
  * necessary for connection to TUN/TAP interfaces.
  **/
 
-G_DEFINE_TYPE (NMSettingTun, nm_setting_tun, NM_TYPE_SETTING)
+/*****************************************************************************/
 
-#define NM_SETTING_TUN_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), NM_TYPE_SETTING_TUN, NMSettingTunPrivate))
+NM_GOBJECT_PROPERTIES_DEFINE_BASE (
+	PROP_MODE,
+	PROP_OWNER,
+	PROP_GROUP,
+	PROP_PI,
+	PROP_VNET_HDR,
+	PROP_MULTI_QUEUE,
+);
 
 typedef struct {
 	NMSettingTunMode mode;
@@ -51,31 +59,11 @@ typedef struct {
 	gboolean multi_queue;
 } NMSettingTunPrivate;
 
-enum {
-	PROP_0,
-	PROP_MODE,
-	PROP_OWNER,
-	PROP_GROUP,
-	PROP_PI,
-	PROP_VNET_HDR,
-	PROP_MULTI_QUEUE,
-	LAST_PROP
-};
+G_DEFINE_TYPE (NMSettingTun, nm_setting_tun, NM_TYPE_SETTING)
 
-/**
- * nm_setting_tun_new:
- *
- * Creates a new #NMSettingTun object with default values.
- *
- * Returns: (transfer full): the new empty #NMSettingTun object
- *
- * Since: 1.2
- **/
-NMSetting *
-nm_setting_tun_new (void)
-{
-	return (NMSetting *) g_object_new (NM_TYPE_SETTING_TUN, NULL);
-}
+#define NM_SETTING_TUN_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), NM_TYPE_SETTING_TUN, NMSettingTunPrivate))
+
+/*****************************************************************************/
 
 /**
  * nm_setting_tun_get_mode:
@@ -167,11 +155,6 @@ nm_setting_tun_get_multi_queue (NMSettingTun *setting)
 	return NM_SETTING_TUN_GET_PRIVATE (setting)->multi_queue;
 }
 
-static void
-nm_setting_tun_init (NMSettingTun *setting)
-{
-}
-
 static gboolean
 verify (NMSetting *setting, NMConnection *connection, GError **error)
 {
@@ -212,70 +195,94 @@ verify (NMSetting *setting, NMConnection *connection, GError **error)
 	return TRUE;
 }
 
+/*****************************************************************************/
+
 static void
-set_property (GObject *object, guint prop_id,
-              const GValue *value, GParamSpec *pspec)
+get_property (GObject *object, guint prop_id,
+              GValue *value, GParamSpec *pspec)
 {
 	NMSettingTun *setting = NM_SETTING_TUN (object);
 	NMSettingTunPrivate *priv = NM_SETTING_TUN_GET_PRIVATE (setting);
 
 	switch (prop_id) {
 	case PROP_MODE:
-		priv->mode = g_value_get_uint (value);
+		g_value_set_uint (value, priv->mode);
 		break;
 	case PROP_OWNER:
-		g_free (priv->owner);
-		priv->owner = g_value_dup_string (value);
+		g_value_set_string (value, priv->owner);
 		break;
 	case PROP_GROUP:
-		g_free (priv->group);
-		priv->group = g_value_dup_string (value);
+		g_value_set_string (value, priv->group);
 		break;
 	case PROP_PI:
-		priv->pi = g_value_get_boolean (value);
+		g_value_set_boolean (value, priv->pi);
 		break;
 	case PROP_VNET_HDR:
-		priv->vnet_hdr = g_value_get_boolean (value);
+		g_value_set_boolean (value, priv->vnet_hdr);
 		break;
 	case PROP_MULTI_QUEUE:
-		priv->multi_queue = g_value_get_boolean (value);
+		g_value_set_boolean (value, priv->multi_queue);
 		break;
 	default:
 		G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
 		break;
 	}
 }
+
 static void
-get_property (GObject *object, guint prop_id,
-              GValue *value, GParamSpec *pspec)
+set_property (GObject *object, guint prop_id,
+              const GValue *value, GParamSpec *pspec)
 {
 	NMSettingTun *setting = NM_SETTING_TUN (object);
 	NMSettingTunPrivate *priv = NM_SETTING_TUN_GET_PRIVATE (setting);
 
 	switch (prop_id) {
 	case PROP_MODE:
-		g_value_set_uint (value, priv->mode);
+		priv->mode = g_value_get_uint (value);
 		break;
 	case PROP_OWNER:
-		g_value_set_string (value, priv->owner);
+		g_free (priv->owner);
+		priv->owner = g_value_dup_string (value);
 		break;
 	case PROP_GROUP:
-		g_value_set_string (value, priv->group);
+		g_free (priv->group);
+		priv->group = g_value_dup_string (value);
 		break;
 	case PROP_PI:
-		g_value_set_boolean (value, priv->pi);
+		priv->pi = g_value_get_boolean (value);
 		break;
 	case PROP_VNET_HDR:
-		g_value_set_boolean (value, priv->vnet_hdr);
+		priv->vnet_hdr = g_value_get_boolean (value);
 		break;
 	case PROP_MULTI_QUEUE:
-		g_value_set_boolean (value, priv->multi_queue);
+		priv->multi_queue = g_value_get_boolean (value);
 		break;
 	default:
 		G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
 		break;
 	}
 }
+/*****************************************************************************/
+
+static void
+nm_setting_tun_init (NMSettingTun *setting)
+{
+}
+
+/**
+ * nm_setting_tun_new:
+ *
+ * Creates a new #NMSettingTun object with default values.
+ *
+ * Returns: (transfer full): the new empty #NMSettingTun object
+ *
+ * Since: 1.2
+ **/
+NMSetting *
+nm_setting_tun_new (void)
+{
+	return (NMSetting *) g_object_new (NM_TYPE_SETTING_TUN, NULL);
+}
 
 static void
 finalize (GObject *object)
@@ -297,8 +304,8 @@ nm_setting_tun_class_init (NMSettingTunClass *klass)
 
 	g_type_class_add_private (klass, sizeof (NMSettingTunPrivate));
 
-	object_class->set_property = set_property;
 	object_class->get_property = get_property;
+	object_class->set_property = set_property;
 	object_class->finalize     = finalize;
 
 	setting_class->verify = verify;
@@ -313,14 +320,13 @@ nm_setting_tun_class_init (NMSettingTunClass *klass)
 	 *
 	 * Since: 1.2
 	 */
-	g_object_class_install_property
-		(object_class, PROP_MODE,
-		 g_param_spec_uint (NM_SETTING_TUN_MODE, "", "",
-		                    0, G_MAXUINT, NM_SETTING_TUN_MODE_TUN,
-		                    G_PARAM_READWRITE |
-		                    G_PARAM_CONSTRUCT |
-		                    NM_SETTING_PARAM_INFERRABLE |
-		                    G_PARAM_STATIC_STRINGS));
+	obj_properties[PROP_MODE] =
+	    g_param_spec_uint (NM_SETTING_TUN_MODE, "", "",
+	                       0, G_MAXUINT, NM_SETTING_TUN_MODE_TUN,
+	                       G_PARAM_READWRITE |
+	                       G_PARAM_CONSTRUCT |
+	                       NM_SETTING_PARAM_INFERRABLE |
+	                       G_PARAM_STATIC_STRINGS);
 
 	/**
 	 * NMSettingTun:owner:
@@ -330,13 +336,12 @@ nm_setting_tun_class_init (NMSettingTunClass *klass)
 	 *
 	 * Since: 1.2
 	 */
-	g_object_class_install_property
-		(object_class, PROP_OWNER,
-		 g_param_spec_string (NM_SETTING_TUN_OWNER, "", "",
-		                      NULL,
-		                      G_PARAM_READWRITE |
-		                      NM_SETTING_PARAM_INFERRABLE |
-		                      G_PARAM_STATIC_STRINGS));
+	obj_properties[PROP_OWNER] =
+	    g_param_spec_string (NM_SETTING_TUN_OWNER, "", "",
+	                         NULL,
+	                         G_PARAM_READWRITE |
+	                         NM_SETTING_PARAM_INFERRABLE |
+	                         G_PARAM_STATIC_STRINGS);
 
 	/**
 	 * NMSettingTun:group:
@@ -346,13 +351,12 @@ nm_setting_tun_class_init (NMSettingTunClass *klass)
 	 *
 	 * Since: 1.2
 	 */
-	g_object_class_install_property
-		(object_class, PROP_GROUP,
-		 g_param_spec_string (NM_SETTING_TUN_GROUP, "", "",
-		                      NULL,
-		                      G_PARAM_READWRITE |
-		                      NM_SETTING_PARAM_INFERRABLE |
-		                      G_PARAM_STATIC_STRINGS));
+	obj_properties[PROP_GROUP] =
+	    g_param_spec_string (NM_SETTING_TUN_GROUP, "", "",
+	                         NULL,
+	                         G_PARAM_READWRITE |
+	                         NM_SETTING_PARAM_INFERRABLE |
+	                         G_PARAM_STATIC_STRINGS);
 
 	/**
 	 * NMSettingTun:pi:
@@ -362,13 +366,12 @@ nm_setting_tun_class_init (NMSettingTunClass *klass)
 	 *
 	 * Since: 1.2
 	 */
-	g_object_class_install_property
-		(object_class, PROP_PI,
-		 g_param_spec_boolean (NM_SETTING_TUN_PI, "", "",
-		                       FALSE,
-		                       G_PARAM_READWRITE |
-		                       NM_SETTING_PARAM_INFERRABLE |
-		                       G_PARAM_STATIC_STRINGS));
+	obj_properties[PROP_PI] =
+	    g_param_spec_boolean (NM_SETTING_TUN_PI, "", "",
+	                          FALSE,
+	                          G_PARAM_READWRITE |
+	                          NM_SETTING_PARAM_INFERRABLE |
+	                          G_PARAM_STATIC_STRINGS);
 
 	/**
 	 * NMSettingTun:vnet-hdr:
@@ -378,13 +381,12 @@ nm_setting_tun_class_init (NMSettingTunClass *klass)
 	 *
 	 * Since: 1.2
 	 */
-	g_object_class_install_property
-		(object_class, PROP_VNET_HDR,
-		 g_param_spec_boolean (NM_SETTING_TUN_VNET_HDR, "", "",
-		                       FALSE,
-		                       G_PARAM_READWRITE |
-		                       NM_SETTING_PARAM_INFERRABLE |
-		                       G_PARAM_STATIC_STRINGS));
+	obj_properties[PROP_VNET_HDR] =
+	    g_param_spec_boolean (NM_SETTING_TUN_VNET_HDR, "", "",
+	                          FALSE,
+	                          G_PARAM_READWRITE |
+	                          NM_SETTING_PARAM_INFERRABLE |
+	                          G_PARAM_STATIC_STRINGS);
 
 	/**
 	 * NMSettingTun:multi-queue:
@@ -396,13 +398,14 @@ nm_setting_tun_class_init (NMSettingTunClass *klass)
 	 *
 	 * Since: 1.2
 	 */
-	g_object_class_install_property
-		(object_class, PROP_MULTI_QUEUE,
-		 g_param_spec_boolean (NM_SETTING_TUN_MULTI_QUEUE, "", "",
-		                       FALSE,
-		                       G_PARAM_READWRITE |
-		                       NM_SETTING_PARAM_INFERRABLE |
-		                       G_PARAM_STATIC_STRINGS));
+	obj_properties[PROP_MULTI_QUEUE] =
+	    g_param_spec_boolean (NM_SETTING_TUN_MULTI_QUEUE, "", "",
+	                          FALSE,
+	                          G_PARAM_READWRITE |
+	                          NM_SETTING_PARAM_INFERRABLE |
+	                          G_PARAM_STATIC_STRINGS);
+
+	g_object_class_install_properties (object_class, _PROPERTY_ENUMS_LAST, obj_properties);
 
 	_nm_setting_class_commit (setting_class, NM_META_SETTING_TYPE_TUN);
 }
diff --git a/libnm-core/nm-setting-user.c b/libnm-core/nm-setting-user.c
index d72c9094..01ac671b 100644
--- a/libnm-core/nm-setting-user.c
+++ b/libnm-core/nm-setting-user.c
@@ -395,33 +395,34 @@ verify (NMSetting *setting, NMConnection *connection, GError **error)
 	return TRUE;
 }
 
-static gboolean
-compare_property (NMSetting *setting,
+static NMTernary
+compare_property (const NMSettInfoSetting *sett_info,
+                  guint property_idx,
+                  NMSetting *setting,
                   NMSetting *other,
-                  const GParamSpec *prop_spec,
                   NMSettingCompareFlags flags)
 {
 	NMSettingUserPrivate *priv, *pri2;
 
-	g_return_val_if_fail (NM_IS_SETTING_USER (setting), FALSE);
-	g_return_val_if_fail (NM_IS_SETTING_USER (other), FALSE);
-
-	if (!nm_streq0 (prop_spec->name, NM_SETTING_USER_DATA))
-		goto call_parent;
+	if (nm_streq (sett_info->property_infos[property_idx].name, NM_SETTING_USER_DATA)) {
 
-	priv = NM_SETTING_USER_GET_PRIVATE (NM_SETTING_USER (setting));
-	pri2 = NM_SETTING_USER_GET_PRIVATE (NM_SETTING_USER (other));
-
-	if (!nm_utils_hash_table_equal (priv->data, pri2->data, TRUE, g_str_equal))
-		return FALSE;
+		if (NM_FLAGS_HAS (flags, NM_SETTING_COMPARE_FLAG_INFERRABLE))
+			return NM_TERNARY_DEFAULT;
 
-	if (!nm_utils_hash_table_equal (priv->data_invalid, pri2->data_invalid, TRUE, g_str_equal))
-		return FALSE;
+		if (!other)
+			return TRUE;
 
-	return TRUE;
+		priv = NM_SETTING_USER_GET_PRIVATE (NM_SETTING_USER (setting));
+		pri2 = NM_SETTING_USER_GET_PRIVATE (NM_SETTING_USER (other));
+		return    nm_utils_hash_table_equal (priv->data, pri2->data, TRUE, g_str_equal)
+		       && nm_utils_hash_table_equal (priv->data_invalid, pri2->data_invalid, TRUE, g_str_equal);
+	}
 
-call_parent:
-	return NM_SETTING_CLASS (nm_setting_user_parent_class)->compare_property (setting, other, prop_spec, flags);
+	return NM_SETTING_CLASS (nm_setting_user_parent_class)->compare_property (sett_info,
+	                                                                          property_idx,
+	                                                                          setting,
+	                                                                          other,
+	                                                                          flags);
 }
 
 /*****************************************************************************/
@@ -549,8 +550,8 @@ nm_setting_user_class_init (NMSettingUserClass *klass)
 	NMSettingClass *setting_class = NM_SETTING_CLASS (klass);
 	GArray *properties_override = _nm_sett_info_property_override_create_array ();
 
-	object_class->set_property = set_property;
 	object_class->get_property = get_property;
+	object_class->set_property = set_property;
 	object_class->finalize     = finalize;
 
 	setting_class->compare_property = compare_property;
@@ -583,15 +584,14 @@ nm_setting_user_class_init (NMSettingUserClass *klass)
 	                        G_PARAM_READWRITE |
 	                        G_PARAM_STATIC_STRINGS);
 
-	g_object_class_install_properties (object_class, _PROPERTY_ENUMS_LAST, obj_properties);
-
 	_properties_override_add_transform (properties_override,
-	                                    g_object_class_find_property (G_OBJECT_CLASS (setting_class),
-	                                                                  NM_SETTING_USER_DATA),
+	                                    obj_properties[PROP_DATA],
 	                                    G_VARIANT_TYPE ("a{ss}"),
 	                                    _nm_utils_strdict_to_dbus,
 	                                    _nm_utils_strdict_from_dbus);
 
+	g_object_class_install_properties (object_class, _PROPERTY_ENUMS_LAST, obj_properties);
+
 	_nm_setting_class_commit_full (setting_class, NM_META_SETTING_TYPE_USER,
 	                               NULL, properties_override);
 }
diff --git a/libnm-core/nm-setting-vlan.c b/libnm-core/nm-setting-vlan.c
index 1b61da55..4eba1626 100644
--- a/libnm-core/nm-setting-vlan.c
+++ b/libnm-core/nm-setting-vlan.c
@@ -41,9 +41,15 @@
  * necessary for connection to VLAN interfaces.
  **/
 
-G_DEFINE_TYPE (NMSettingVlan, nm_setting_vlan, NM_TYPE_SETTING)
+/*****************************************************************************/
 
-#define NM_SETTING_VLAN_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), NM_TYPE_SETTING_VLAN, NMSettingVlanPrivate))
+NM_GOBJECT_PROPERTIES_DEFINE (NMSettingVlan,
+	PROP_PARENT,
+	PROP_ID,
+	PROP_FLAGS,
+	PROP_INGRESS_PRIORITY_MAP,
+	PROP_EGRESS_PRIORITY_MAP,
+);
 
 typedef struct {
 	char *parent;
@@ -53,33 +59,16 @@ typedef struct {
 	GSList *egress_priority_map;
 } NMSettingVlanPrivate;
 
-enum {
-	PROP_0,
-	PROP_PARENT,
-	PROP_ID,
-	PROP_FLAGS,
-	PROP_INGRESS_PRIORITY_MAP,
-	PROP_EGRESS_PRIORITY_MAP,
-	LAST_PROP
-};
+G_DEFINE_TYPE (NMSettingVlan, nm_setting_vlan, NM_TYPE_SETTING)
+
+#define NM_SETTING_VLAN_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), NM_TYPE_SETTING_VLAN, NMSettingVlanPrivate))
+
+/*****************************************************************************/
 
 #define MAX_SKB_PRIO   G_MAXUINT32
 #define MAX_8021P_PRIO 7  /* Max 802.1p priority */
 
 /**
- * nm_setting_vlan_new:
- *
- * Creates a new #NMSettingVlan object with default values.
- *
- * Returns: (transfer full): the new empty #NMSettingVlan object
- **/
-NMSetting *
-nm_setting_vlan_new (void)
-{
-	return (NMSetting *) g_object_new (NM_TYPE_SETTING_VLAN, NULL);
-}
-
-/**
  * nm_setting_vlan_get_parent:
  * @setting: the #NMSettingVlan
  *
@@ -214,10 +203,10 @@ set_map (NMSettingVlan *self, NMVlanPriorityMap map, GSList *list)
 
 	if (map == NM_VLAN_INGRESS_MAP) {
 		NM_SETTING_VLAN_GET_PRIVATE (self)->ingress_priority_map = list;
-		g_object_notify (G_OBJECT (self), NM_SETTING_VLAN_INGRESS_PRIORITY_MAP);
+		_notify (self, PROP_INGRESS_PRIORITY_MAP);
 	} else if (map == NM_VLAN_EGRESS_MAP) {
 		NM_SETTING_VLAN_GET_PRIVATE (self)->egress_priority_map = list;
-		g_object_notify (G_OBJECT (self), NM_SETTING_VLAN_EGRESS_PRIORITY_MAP);
+		_notify (self, PROP_EGRESS_PRIORITY_MAP);
 	} else
 		g_assert_not_reached ();
 }
@@ -273,9 +262,9 @@ nm_setting_vlan_add_priority_str (NMSettingVlan *setting,
 	if (check_replace_duplicate_priority (list, item->from, item->to)) {
 		g_free (item);
 		if (map == NM_VLAN_INGRESS_MAP)
-			g_object_notify (G_OBJECT (setting), NM_SETTING_VLAN_INGRESS_PRIORITY_MAP);
+			_notify (setting, PROP_INGRESS_PRIORITY_MAP);
 		else
-			g_object_notify (G_OBJECT (setting), NM_SETTING_VLAN_EGRESS_PRIORITY_MAP);
+			_notify (setting, PROP_EGRESS_PRIORITY_MAP);
 		return TRUE;
 	}
 
@@ -377,9 +366,9 @@ nm_setting_vlan_add_priority (NMSettingVlan *setting,
 	list = get_map (setting, map);
 	if (check_replace_duplicate_priority (list, from, to)) {
 		if (map == NM_VLAN_INGRESS_MAP)
-			g_object_notify (G_OBJECT (setting), NM_SETTING_VLAN_INGRESS_PRIORITY_MAP);
+			_notify (setting, PROP_INGRESS_PRIORITY_MAP);
 		else
-			g_object_notify (G_OBJECT (setting), NM_SETTING_VLAN_EGRESS_PRIORITY_MAP);
+			_notify (setting, PROP_EGRESS_PRIORITY_MAP);
 		return TRUE;
 	}
 
@@ -593,11 +582,6 @@ nm_setting_vlan_clear_priorities (NMSettingVlan *setting, NMVlanPriorityMap map)
 
 /*****************************************************************************/
 
-static void
-nm_setting_vlan_init (NMSettingVlan *setting)
-{
-}
-
 static int
 verify (NMSetting *setting, NMConnection *connection, GError **error)
 {
@@ -736,38 +720,6 @@ priority_strv_to_maplist (NMVlanPriorityMap map, char **strv)
 	return g_slist_sort (list, prio_map_compare);
 }
 
-static void
-set_property (GObject *object, guint prop_id,
-              const GValue *value, GParamSpec *pspec)
-{
-	NMSettingVlan *setting = NM_SETTING_VLAN (object);
-	NMSettingVlanPrivate *priv = NM_SETTING_VLAN_GET_PRIVATE (setting);
-
-	switch (prop_id) {
-	case PROP_PARENT:
-		g_free (priv->parent);
-		priv->parent = g_value_dup_string (value);
-		break;
-	case PROP_ID:
-		priv->id = g_value_get_uint (value);
-		break;
-	case PROP_FLAGS:
-		priv->flags = g_value_get_flags (value);
-		break;
-	case PROP_INGRESS_PRIORITY_MAP:
-		g_slist_free_full (priv->ingress_priority_map, g_free);
-		priv->ingress_priority_map = priority_strv_to_maplist (NM_VLAN_INGRESS_MAP, g_value_get_boxed (value));
-		break;
-	case PROP_EGRESS_PRIORITY_MAP:
-		g_slist_free_full (priv->egress_priority_map, g_free);
-		priv->egress_priority_map = priority_strv_to_maplist (NM_VLAN_EGRESS_MAP, g_value_get_boxed (value));
-		break;
-	default:
-		G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
-		break;
-	}
-}
-
 static char **
 priority_maplist_to_strv (GSList *list)
 {
@@ -786,6 +738,8 @@ priority_maplist_to_strv (GSList *list)
 	return (char **) g_ptr_array_free (strv, FALSE);
 }
 
+/*****************************************************************************/
+
 static void
 get_property (GObject *object, guint prop_id,
               GValue *value, GParamSpec *pspec)
@@ -816,6 +770,58 @@ get_property (GObject *object, guint prop_id,
 }
 
 static void
+set_property (GObject *object, guint prop_id,
+              const GValue *value, GParamSpec *pspec)
+{
+	NMSettingVlan *setting = NM_SETTING_VLAN (object);
+	NMSettingVlanPrivate *priv = NM_SETTING_VLAN_GET_PRIVATE (setting);
+
+	switch (prop_id) {
+	case PROP_PARENT:
+		g_free (priv->parent);
+		priv->parent = g_value_dup_string (value);
+		break;
+	case PROP_ID:
+		priv->id = g_value_get_uint (value);
+		break;
+	case PROP_FLAGS:
+		priv->flags = g_value_get_flags (value);
+		break;
+	case PROP_INGRESS_PRIORITY_MAP:
+		g_slist_free_full (priv->ingress_priority_map, g_free);
+		priv->ingress_priority_map = priority_strv_to_maplist (NM_VLAN_INGRESS_MAP, g_value_get_boxed (value));
+		break;
+	case PROP_EGRESS_PRIORITY_MAP:
+		g_slist_free_full (priv->egress_priority_map, g_free);
+		priv->egress_priority_map = priority_strv_to_maplist (NM_VLAN_EGRESS_MAP, g_value_get_boxed (value));
+		break;
+	default:
+		G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+		break;
+	}
+}
+
+/*****************************************************************************/
+
+static void
+nm_setting_vlan_init (NMSettingVlan *setting)
+{
+}
+
+/**
+ * nm_setting_vlan_new:
+ *
+ * Creates a new #NMSettingVlan object with default values.
+ *
+ * Returns: (transfer full): the new empty #NMSettingVlan object
+ **/
+NMSetting *
+nm_setting_vlan_new (void)
+{
+	return (NMSetting *) g_object_new (NM_TYPE_SETTING_VLAN, NULL);
+}
+
+static void
 finalize (GObject *object)
 {
 	NMSettingVlan *setting = NM_SETTING_VLAN (object);
@@ -837,8 +843,8 @@ nm_setting_vlan_class_init (NMSettingVlanClass *klass)
 
 	g_type_class_add_private (klass, sizeof (NMSettingVlanPrivate));
 
-	object_class->set_property = set_property;
 	object_class->get_property = get_property;
+	object_class->set_property = set_property;
 	object_class->finalize     = finalize;
 
 	setting_class->verify = verify;
@@ -857,14 +863,13 @@ nm_setting_vlan_class_init (NMSettingVlanClass *klass)
 	 * description: Parent interface of the VLAN.
 	 * ---end---
 	 */
-	g_object_class_install_property
-		(object_class, PROP_PARENT,
-		 g_param_spec_string (NM_SETTING_VLAN_PARENT, "", "",
-		                      NULL,
-		                      G_PARAM_READWRITE |
-		                      G_PARAM_CONSTRUCT |
-		                      NM_SETTING_PARAM_INFERRABLE |
-		                      G_PARAM_STATIC_STRINGS));
+	obj_properties[PROP_PARENT] =
+	    g_param_spec_string (NM_SETTING_VLAN_PARENT, "", "",
+	                         NULL,
+	                         G_PARAM_READWRITE |
+	                         G_PARAM_CONSTRUCT |
+	                         NM_SETTING_PARAM_INFERRABLE |
+	                         G_PARAM_STATIC_STRINGS);
 
 	/**
 	 * NMSettingVlan:id:
@@ -878,14 +883,13 @@ nm_setting_vlan_class_init (NMSettingVlanClass *klass)
 	 * description: VLAN identifier.
 	 * ---end---
 	 */
-	g_object_class_install_property
-		(object_class, PROP_ID,
-		 g_param_spec_uint (NM_SETTING_VLAN_ID, "", "",
-		                    0, 4095, 0,
-		                    G_PARAM_READWRITE |
-		                    G_PARAM_CONSTRUCT |
-		                    NM_SETTING_PARAM_INFERRABLE |
-		                    G_PARAM_STATIC_STRINGS));
+	obj_properties[PROP_ID] =
+	    g_param_spec_uint (NM_SETTING_VLAN_ID, "", "",
+	                       0, 4095, 0,
+	                       G_PARAM_READWRITE |
+	                       G_PARAM_CONSTRUCT |
+	                       NM_SETTING_PARAM_INFERRABLE |
+	                       G_PARAM_STATIC_STRINGS);
 
 	/**
 	 * NMSettingVlan:flags:
@@ -909,19 +913,17 @@ nm_setting_vlan_class_init (NMSettingVlanClass *klass)
 	 * description: VLAN flags.
 	 * ---end---
 	 */
-	g_object_class_install_property
-		(object_class, PROP_FLAGS,
-		 g_param_spec_flags (NM_SETTING_VLAN_FLAGS, "", "",
-		                     NM_TYPE_VLAN_FLAGS,
-		                     NM_VLAN_FLAG_REORDER_HEADERS,
-		                     G_PARAM_READWRITE |
-		                     G_PARAM_CONSTRUCT |
-		                     NM_SETTING_PARAM_INFERRABLE |
-		                     G_PARAM_STATIC_STRINGS));
+	obj_properties[PROP_FLAGS] =
+	    g_param_spec_flags (NM_SETTING_VLAN_FLAGS, "", "",
+	                        NM_TYPE_VLAN_FLAGS,
+	                        NM_VLAN_FLAG_REORDER_HEADERS,
+	                        G_PARAM_READWRITE |
+	                        G_PARAM_CONSTRUCT |
+	                        NM_SETTING_PARAM_INFERRABLE |
+	                        G_PARAM_STATIC_STRINGS);
 
 	_properties_override_add_override (properties_override,
-	                                   g_object_class_find_property (G_OBJECT_CLASS (setting_class),
-	                                                                 NM_SETTING_VLAN_FLAGS),
+	                                   obj_properties[PROP_FLAGS],
 	                                   NULL,
 	                                   _override_flags_get,
 	                                   NULL,
@@ -941,13 +943,12 @@ nm_setting_vlan_class_init (NMSettingVlanClass *klass)
 	 * example: VLAN_INGRESS_PRIORITY_MAP=4:2,3:5
 	 * ---end---
 	 */
-	g_object_class_install_property
-		(object_class, PROP_INGRESS_PRIORITY_MAP,
-		 g_param_spec_boxed (NM_SETTING_VLAN_INGRESS_PRIORITY_MAP, "", "",
-		                     G_TYPE_STRV,
-		                     G_PARAM_READWRITE |
-		                     NM_SETTING_PARAM_INFERRABLE |
-		                     G_PARAM_STATIC_STRINGS));
+	obj_properties[PROP_INGRESS_PRIORITY_MAP] =
+	    g_param_spec_boxed (NM_SETTING_VLAN_INGRESS_PRIORITY_MAP, "", "",
+	                        G_TYPE_STRV,
+	                        G_PARAM_READWRITE |
+	                        NM_SETTING_PARAM_INFERRABLE |
+	                        G_PARAM_STATIC_STRINGS);
 
 	/**
 	 * NMSettingVlan:egress-priority-map:
@@ -963,13 +964,12 @@ nm_setting_vlan_class_init (NMSettingVlanClass *klass)
 	 * example: VLAN_EGRESS_PRIORITY_MAP=5:4,4:1,3:7
 	 * ---end---
 	 */
-	g_object_class_install_property
-		(object_class, PROP_EGRESS_PRIORITY_MAP,
-		 g_param_spec_boxed (NM_SETTING_VLAN_EGRESS_PRIORITY_MAP, "", "",
-		                     G_TYPE_STRV,
-		                     G_PARAM_READWRITE |
-		                     NM_SETTING_PARAM_INFERRABLE |
-		                     G_PARAM_STATIC_STRINGS));
+	obj_properties[PROP_EGRESS_PRIORITY_MAP] =
+	    g_param_spec_boxed (NM_SETTING_VLAN_EGRESS_PRIORITY_MAP, "", "",
+	                        G_TYPE_STRV,
+	                        G_PARAM_READWRITE |
+	                        NM_SETTING_PARAM_INFERRABLE |
+	                        G_PARAM_STATIC_STRINGS);
 
 	/* ---ifcfg-rh---
 	 * property: interface-name
@@ -993,6 +993,8 @@ nm_setting_vlan_class_init (NMSettingVlanClass *klass)
 	                                    _nm_setting_get_deprecated_virtual_interface_name,
 	                                    NULL);
 
+	g_object_class_install_properties (object_class, _PROPERTY_ENUMS_LAST, obj_properties);
+
 	_nm_setting_class_commit_full (setting_class, NM_META_SETTING_TYPE_VLAN,
 	                               NULL, properties_override);
 }
diff --git a/libnm-core/nm-setting-vpn.c b/libnm-core/nm-setting-vpn.c
index fcbeec68..1371140e 100644
--- a/libnm-core/nm-setting-vpn.c
+++ b/libnm-core/nm-setting-vpn.c
@@ -21,13 +21,13 @@
 
 #include "nm-default.h"
 
+#include "nm-setting-vpn.h"
+
 #include <string.h>
 #include <errno.h>
 #include <stdlib.h>
 
 #include "nm-utils/nm-secret-utils.h"
-
-#include "nm-setting-vpn.h"
 #include "nm-utils.h"
 #include "nm-utils-private.h"
 #include "nm-setting-private.h"
@@ -45,9 +45,16 @@
  * properties.
  **/
 
-G_DEFINE_TYPE (NMSettingVpn, nm_setting_vpn, NM_TYPE_SETTING)
+/*****************************************************************************/
 
-#define NM_SETTING_VPN_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), NM_TYPE_SETTING_VPN, NMSettingVpnPrivate))
+NM_GOBJECT_PROPERTIES_DEFINE (NMSettingVpn,
+	PROP_SERVICE_TYPE,
+	PROP_USER_NAME,
+	PROP_PERSISTENT,
+	PROP_DATA,
+	PROP_SECRETS,
+	PROP_TIMEOUT,
+);
 
 typedef struct {
 	char *service_type;
@@ -85,30 +92,11 @@ typedef struct {
 	guint32 timeout;
 } NMSettingVpnPrivate;
 
-enum {
-	PROP_0,
-	PROP_SERVICE_TYPE,
-	PROP_USER_NAME,
-	PROP_PERSISTENT,
-	PROP_DATA,
-	PROP_SECRETS,
-	PROP_TIMEOUT,
+G_DEFINE_TYPE (NMSettingVpn, nm_setting_vpn, NM_TYPE_SETTING)
 
-	LAST_PROP
-};
+#define NM_SETTING_VPN_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), NM_TYPE_SETTING_VPN, NMSettingVpnPrivate))
 
-/**
- * nm_setting_vpn_new:
- *
- * Creates a new #NMSettingVpn object with default values.
- *
- * Returns: (transfer full): the new empty #NMSettingVpn object
- **/
-NMSetting *
-nm_setting_vpn_new (void)
-{
-	return (NMSetting *) g_object_new (NM_TYPE_SETTING_VPN, NULL);
-}
+/*****************************************************************************/
 
 /**
  * nm_setting_vpn_get_service_type:
@@ -194,7 +182,7 @@ nm_setting_vpn_add_data_item (NMSettingVpn *setting,
 
 	g_hash_table_insert (NM_SETTING_VPN_GET_PRIVATE (setting)->data,
 	                     g_strdup (key), g_strdup (item));
-	g_object_notify (G_OBJECT (setting), NM_SETTING_VPN_DATA);
+	_notify (setting, PROP_DATA);
 }
 
 /**
@@ -259,7 +247,7 @@ nm_setting_vpn_remove_data_item (NMSettingVpn *setting, const char *key)
 
 	found = g_hash_table_remove (NM_SETTING_VPN_GET_PRIVATE (setting)->data, key);
 	if (found)
-		g_object_notify (G_OBJECT (setting), NM_SETTING_VPN_DATA);
+		_notify (setting, PROP_DATA);
 	return found;
 }
 
@@ -371,7 +359,7 @@ nm_setting_vpn_add_secret (NMSettingVpn *setting,
 
 	g_hash_table_insert (NM_SETTING_VPN_GET_PRIVATE (setting)->secrets,
 	                     g_strdup (key), g_strdup (secret));
-	g_object_notify (G_OBJECT (setting), NM_SETTING_VPN_SECRETS);
+	_notify (setting, PROP_SECRETS);
 }
 
 /**
@@ -436,7 +424,7 @@ nm_setting_vpn_remove_secret (NMSettingVpn *setting, const char *key)
 
 	found = g_hash_table_remove (NM_SETTING_VPN_GET_PRIVATE (setting)->secrets, key);
 	if (found)
-		g_object_notify (G_OBJECT (setting), NM_SETTING_VPN_SECRETS);
+		_notify (setting, PROP_SECRETS);
 	return found;
 }
 
@@ -461,6 +449,66 @@ nm_setting_vpn_foreach_secret (NMSettingVpn *setting,
 	foreach_item_helper (setting, TRUE, func, user_data);
 }
 
+gboolean
+_nm_setting_vpn_aggregate (NMSettingVpn *setting,
+                           NMConnectionAggregateType type,
+                           gpointer arg)
+{
+	NMSettingVpnPrivate *priv;
+	NMSettingSecretFlags secret_flags;
+	const char *key_name;
+	GHashTableIter iter;
+
+	g_return_val_if_fail (NM_IS_SETTING_VPN (setting), FALSE);
+
+	priv = NM_SETTING_VPN_GET_PRIVATE (setting);
+
+	switch (type) {
+
+	case NM_CONNECTION_AGGREGATE_ANY_SECRETS:
+		if (g_hash_table_size (priv->secrets) > 0) {
+			*((gboolean *) arg) = TRUE;
+			return TRUE;
+		}
+		return FALSE;
+
+	case NM_CONNECTION_AGGREGATE_ANY_SYSTEM_SECRET_FLAGS:
+
+		g_hash_table_iter_init (&iter, priv->secrets);
+		while (g_hash_table_iter_next (&iter, (gpointer *) &key_name, NULL)) {
+			if (!nm_setting_get_secret_flags (NM_SETTING (setting), key_name, &secret_flags, NULL))
+				nm_assert_not_reached ();
+			if (secret_flags == NM_SETTING_SECRET_FLAG_NONE) {
+				*((gboolean *) arg) = TRUE;
+				return TRUE;
+			}
+		}
+
+		/* Ok, we have no secrets with system-secret flags.
+		 * But do we have any secret-flags (without secrets) that indicate system secrets? */
+		g_hash_table_iter_init (&iter, priv->data);
+		while (g_hash_table_iter_next (&iter, (gpointer *) &key_name, NULL)) {
+			gs_free char *secret_name = NULL;
+
+			if (!g_str_has_suffix (key_name, "-flags"))
+				continue;
+			secret_name = g_strndup (key_name, strlen (key_name) - NM_STRLEN ("-flags"));
+			if (secret_name[0] == '\0')
+				continue;
+			if (!nm_setting_get_secret_flags (NM_SETTING (setting), secret_name, &secret_flags, NULL))
+				nm_assert_not_reached ();
+			if (secret_flags == NM_SETTING_SECRET_FLAG_NONE) {
+				*((gboolean *) arg) = TRUE;
+				return TRUE;
+			}
+		}
+
+		return FALSE;
+	}
+
+	g_return_val_if_reached (FALSE);
+}
+
 /**
  * nm_setting_vpn_get_timeout:
  * @setting: the #NMSettingVpn
@@ -634,7 +682,7 @@ update_one_secret (NMSetting *setting, const char *key, GVariant *value, GError
 	}
 
 	if (success == NM_SETTING_UPDATE_SECRET_SUCCESS_MODIFIED)
-		g_object_notify (G_OBJECT (setting), NM_SETTING_VPN_SECRETS);
+		_notify (NM_SETTING_VPN (setting), PROP_SECRETS);
 
 	return success;
 }
@@ -642,48 +690,59 @@ update_one_secret (NMSetting *setting, const char *key, GVariant *value, GError
 static gboolean
 get_secret_flags (NMSetting *setting,
                   const char *secret_name,
-                  gboolean verify_secret,
                   NMSettingSecretFlags *out_flags,
                   GError **error)
 {
 	NMSettingVpnPrivate *priv = NM_SETTING_VPN_GET_PRIVATE (setting);
-	gs_free char *flags_key = NULL;
-	gpointer val;
-	unsigned long tmp;
-	NMSettingSecretFlags flags = NM_SETTING_SECRET_FLAG_NONE;
-
-	flags_key = g_strdup_printf ("%s-flags", secret_name);
-	if (g_hash_table_lookup_extended (priv->data, flags_key, NULL, &val)) {
-		errno = 0;
-		tmp = strtoul ((const char *) val, NULL, 10);
-		if ((errno != 0) || (tmp > NM_SETTING_SECRET_FLAGS_ALL)) {
-			g_set_error (error,
-			             NM_CONNECTION_ERROR,
-			             NM_CONNECTION_ERROR_INVALID_PROPERTY,
-			             _("failed to convert value '%s' to uint"),
-			             (const char *) val);
+	gs_free char *flags_key_free = NULL;
+	const char *flags_key;
+	const char *flags_val;
+	gint64 i64;
+
+	flags_key = nm_construct_name_a ("%s-flags", secret_name, &flags_key_free);
+
+	if (!g_hash_table_lookup_extended (priv->data, flags_key, NULL, (gpointer *) &flags_val)) {
+		NM_SET_OUT (out_flags, NM_SETTING_SECRET_FLAG_NONE);
+
+		/* having no secret flag for the secret is fine, as long as there
+		 * is the secret itself... */
+		if (!g_hash_table_contains (priv->secrets, secret_name)) {
+			g_set_error_literal (error,
+			                     NM_CONNECTION_ERROR,
+			                     NM_CONNECTION_ERROR_PROPERTY_NOT_SECRET,
+			                     _("secret flags property not found"));
 			g_prefix_error (error, "%s.%s: ", NM_SETTING_VPN_SETTING_NAME, flags_key);
 			return FALSE;
 		}
-		flags = (NMSettingSecretFlags) tmp;
+		return TRUE;
 	}
 
-	if (out_flags)
-		*out_flags = flags;
+	i64 = _nm_utils_ascii_str_to_int64 (flags_val, 10, 0, NM_SETTING_SECRET_FLAGS_ALL, -1);
+	if (   i64 == -1
+	    || !_nm_setting_secret_flags_valid (i64)) {
+		/* The flags keys is set to an unexpected value. That is a configuration
+		 * error. Note that keys named "*-flags" are reserved for secrets. The user
+		 * must not use this for anything but secret flags. Hence, we cannot fail
+		 * to read the secret, we pretend that the secret flag is set to the default
+		 * NM_SETTING_SECRET_FLAG_NONE. */
+		NM_SET_OUT (out_flags, NM_SETTING_SECRET_FLAG_NONE);
+		return TRUE;
+	}
+
+	NM_SET_OUT (out_flags, (NMSettingSecretFlags) i64);
 	return TRUE;
 }
 
 static gboolean
 set_secret_flags (NMSetting *setting,
                   const char *secret_name,
-                  gboolean verify_secret,
                   NMSettingSecretFlags flags,
                   GError **error)
 {
 	g_hash_table_insert (NM_SETTING_VPN_GET_PRIVATE (setting)->data,
 	                     g_strdup_printf ("%s-flags", secret_name),
 	                     g_strdup_printf ("%u", flags));
-	g_object_notify (G_OBJECT (setting), NM_SETTING_VPN_SECRETS);
+	_notify (NM_SETTING_VPN (setting), PROP_SECRETS);
 	return TRUE;
 }
 
@@ -694,131 +753,143 @@ need_secrets (NMSetting *setting)
 	return g_ptr_array_sized_new (1);
 }
 
-static gboolean
-_compare_secrets (NMSettingVpn *a,
-                  NMSettingVpn *b,
-                  NMSettingCompareFlags flags)
+static NMTernary
+compare_property_secrets (NMSettingVpn *a,
+                          NMSettingVpn *b,
+                          NMSettingCompareFlags flags)
 {
-	GHashTable *a_secrets;
 	GHashTableIter iter;
 	const char *key, *val;
+	int run;
 
-	a_secrets = NM_SETTING_VPN_GET_PRIVATE (a)->secrets;
-	g_hash_table_iter_init (&iter, a_secrets);
-	while (g_hash_table_iter_next (&iter, (gpointer) &key, (gpointer) &val)) {
-		NMSettingSecretFlags a_secret_flags = NM_SETTING_SECRET_FLAG_NONE;
-		NMSettingSecretFlags b_secret_flags = NM_SETTING_SECRET_FLAG_NONE;
+	if (NM_FLAGS_HAS (flags, NM_SETTING_COMPARE_FLAG_FUZZY))
+		return NM_TERNARY_DEFAULT;
+	if (NM_FLAGS_HAS (flags, NM_SETTING_COMPARE_FLAG_IGNORE_SECRETS))
+		return NM_TERNARY_DEFAULT;
 
-		nm_setting_get_secret_flags (NM_SETTING (a), key, &a_secret_flags, NULL);
-		nm_setting_get_secret_flags (NM_SETTING (b), key, &b_secret_flags, NULL);
+	if (!b)
+		return TRUE;
 
-		/* If the secret flags aren't the same, the settings aren't the same */
-		if (a_secret_flags != b_secret_flags)
-			return FALSE;
+	for (run = 0; run < 2; run++) {
+		NMSettingVpn *current_a = (run == 0) ? a : b;
+		NMSettingVpn *current_b = (run == 0) ? b : a;
 
-		if (   (flags & NM_SETTING_COMPARE_FLAG_IGNORE_AGENT_OWNED_SECRETS)
-		    && (a_secret_flags & NM_SETTING_SECRET_FLAG_AGENT_OWNED))
-			continue;
+		g_hash_table_iter_init (&iter, NM_SETTING_VPN_GET_PRIVATE (current_a)->secrets);
+		while (g_hash_table_iter_next (&iter, (gpointer) &key, (gpointer) &val)) {
 
-		if (   (flags & NM_SETTING_COMPARE_FLAG_IGNORE_NOT_SAVED_SECRETS)
-		    && (a_secret_flags & NM_SETTING_SECRET_FLAG_NOT_SAVED))
-			continue;
+			if (nm_streq0 (val, nm_setting_vpn_get_secret (current_b, key)))
+				continue;
+			if (!_nm_setting_should_compare_secret_property (NM_SETTING (current_a),
+			                                                 NM_SETTING (current_b),
+			                                                 key,
+			                                                 flags))
+				continue;
 
-		/* Now compare the values themselves */
-		if (g_strcmp0 (val, nm_setting_vpn_get_secret (b, key)) != 0)
 			return FALSE;
+		}
 	}
 
 	return TRUE;
 }
 
-static gboolean
-compare_one_secret (NMSettingVpn *a,
-                    NMSettingVpn *b,
-                    NMSettingCompareFlags flags)
-{
-	if (!_compare_secrets (a, b, flags))
-		return FALSE;
-	if (!_compare_secrets (b, a, flags))
-		return FALSE;
-
-	return TRUE;
-}
-
-static gboolean
-compare_property (NMSetting *setting,
+static NMTernary
+compare_property (const NMSettInfoSetting *sett_info,
+                  guint property_idx,
+                  NMSetting *setting,
                   NMSetting *other,
-                  const GParamSpec *prop_spec,
                   NMSettingCompareFlags flags)
 {
-	gboolean same;
-
-	/* We only need to treat the 'secrets' property specially */
-	if (g_strcmp0 (prop_spec->name, NM_SETTING_VPN_SECRETS) != 0)
-		return NM_SETTING_CLASS (nm_setting_vpn_parent_class)->compare_property (setting, other, prop_spec, flags);
-
-	/* Compare A to B to ensure everything in A is found in B */
-	same = compare_one_secret (NM_SETTING_VPN (setting), NM_SETTING_VPN (other), flags);
-	if (same) {
-		/* And then B to A to ensure everything in B is also found in A */
-		same = compare_one_secret (NM_SETTING_VPN (other), NM_SETTING_VPN (setting), flags);
+	if (nm_streq (sett_info->property_infos[property_idx].name, NM_SETTING_VPN_SECRETS)) {
+		if (NM_FLAGS_HAS (flags, NM_SETTING_COMPARE_FLAG_INFERRABLE))
+			return NM_TERNARY_DEFAULT;
+		return compare_property_secrets (NM_SETTING_VPN (setting), NM_SETTING_VPN (other), flags);
 	}
 
-	return same;
+	return NM_SETTING_CLASS (nm_setting_vpn_parent_class)->compare_property (sett_info,
+	                                                                         property_idx,
+	                                                                         setting,
+	                                                                         other,
+	                                                                         flags);
 }
 
 static gboolean
-clear_secrets_with_flags (NMSetting *setting,
-                          GParamSpec *pspec,
-                          NMSettingClearSecretsWithFlagsFn func,
-                          gpointer user_data)
+clear_secrets (const NMSettInfoSetting *sett_info,
+               guint property_idx,
+               NMSetting *setting,
+               NMSettingClearSecretsWithFlagsFn func,
+               gpointer user_data)
 {
 	NMSettingVpnPrivate *priv = NM_SETTING_VPN_GET_PRIVATE (setting);
+	GParamSpec *prop_spec = sett_info->property_infos[property_idx].param_spec;
 	GHashTableIter iter;
 	const char *secret;
 	gboolean changed = TRUE;
 
-	if (priv->secrets == NULL)
+	if (   !prop_spec
+	    || !NM_FLAGS_HAS (prop_spec->flags, NM_SETTING_PARAM_SECRET))
+		return FALSE;
+
+	nm_assert (nm_streq (prop_spec->name, NM_SETTING_VPN_SECRETS));
+
+	if (!priv->secrets)
 		return FALSE;
 
-	/* Iterate through secrets hash and check each entry */
 	g_hash_table_iter_init (&iter, priv->secrets);
 	while (g_hash_table_iter_next (&iter, (gpointer) &secret, NULL)) {
-		NMSettingSecretFlags flags = NM_SETTING_SECRET_FLAG_NONE;
 
-		nm_setting_get_secret_flags (setting, secret, &flags, NULL);
-		if (func (setting, pspec->name, flags, user_data) == TRUE) {
-			g_hash_table_iter_remove (&iter);
-			changed = TRUE;
-		}
+		if (func) {
+			NMSettingSecretFlags flags = NM_SETTING_SECRET_FLAG_NONE;
+
+			if (!nm_setting_get_secret_flags (setting, secret, &flags, NULL))
+				nm_assert_not_reached ();
+
+			if (!func (setting, secret, flags, user_data))
+				continue;
+		} else
+			nm_assert (nm_setting_get_secret_flags (setting, secret, NULL, NULL));
+
+		g_hash_table_iter_remove (&iter);
+		changed = TRUE;
 	}
 
 	if (changed)
-		g_object_notify (G_OBJECT (setting), NM_SETTING_VPN_SECRETS);
+		_notify (NM_SETTING_VPN (setting), PROP_SECRETS);
 
 	return changed;
 }
 
-static void
-nm_setting_vpn_init (NMSettingVpn *setting)
-{
-	NMSettingVpnPrivate *priv = NM_SETTING_VPN_GET_PRIVATE (setting);
-
-	priv->data = g_hash_table_new_full (nm_str_hash, g_str_equal, g_free, g_free);
-	priv->secrets = g_hash_table_new_full (nm_str_hash, g_str_equal, g_free, (GDestroyNotify) nm_free_secret);
-}
+/*****************************************************************************/
 
 static void
-finalize (GObject *object)
+get_property (GObject *object, guint prop_id,
+              GValue *value, GParamSpec *pspec)
 {
-	NMSettingVpnPrivate *priv = NM_SETTING_VPN_GET_PRIVATE (object);
-
-	g_free (priv->service_type);
-	g_free (priv->user_name);
-	g_hash_table_destroy (priv->data);
-	g_hash_table_destroy (priv->secrets);
+	NMSettingVpn *setting = NM_SETTING_VPN (object);
+	NMSettingVpnPrivate *priv = NM_SETTING_VPN_GET_PRIVATE (setting);
 
-	G_OBJECT_CLASS (nm_setting_vpn_parent_class)->finalize (object);
+	switch (prop_id) {
+	case PROP_SERVICE_TYPE:
+		g_value_set_string (value, nm_setting_vpn_get_service_type (setting));
+		break;
+	case PROP_USER_NAME:
+		g_value_set_string (value, nm_setting_vpn_get_user_name (setting));
+		break;
+	case PROP_PERSISTENT:
+		g_value_set_boolean (value, priv->persistent);
+		break;
+	case PROP_DATA:
+		g_value_take_boxed (value, _nm_utils_copy_strdict (priv->data));
+		break;
+	case PROP_SECRETS:
+		g_value_take_boxed (value, _nm_utils_copy_strdict (priv->secrets));
+		break;
+	case PROP_TIMEOUT:
+		g_value_set_uint (value, nm_setting_vpn_get_timeout (setting));
+		break;
+	default:
+		G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+		break;
+	}
 }
 
 static void
@@ -856,36 +927,41 @@ set_property (GObject *object, guint prop_id,
 	}
 }
 
+/*****************************************************************************/
+
 static void
-get_property (GObject *object, guint prop_id,
-              GValue *value, GParamSpec *pspec)
+nm_setting_vpn_init (NMSettingVpn *setting)
 {
-	NMSettingVpn *setting = NM_SETTING_VPN (object);
 	NMSettingVpnPrivate *priv = NM_SETTING_VPN_GET_PRIVATE (setting);
 
-	switch (prop_id) {
-	case PROP_SERVICE_TYPE:
-		g_value_set_string (value, nm_setting_vpn_get_service_type (setting));
-		break;
-	case PROP_USER_NAME:
-		g_value_set_string (value, nm_setting_vpn_get_user_name (setting));
-		break;
-	case PROP_PERSISTENT:
-		g_value_set_boolean (value, priv->persistent);
-		break;
-	case PROP_DATA:
-		g_value_take_boxed (value, _nm_utils_copy_strdict (priv->data));
-		break;
-	case PROP_SECRETS:
-		g_value_take_boxed (value, _nm_utils_copy_strdict (priv->secrets));
-		break;
-	case PROP_TIMEOUT:
-		g_value_set_uint (value, nm_setting_vpn_get_timeout (setting));
-		break;
-	default:
-		G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
-		break;
-	}
+	priv->data = g_hash_table_new_full (nm_str_hash, g_str_equal, g_free, g_free);
+	priv->secrets = g_hash_table_new_full (nm_str_hash, g_str_equal, g_free, (GDestroyNotify) nm_free_secret);
+}
+
+/**
+ * nm_setting_vpn_new:
+ *
+ * Creates a new #NMSettingVpn object with default values.
+ *
+ * Returns: (transfer full): the new empty #NMSettingVpn object
+ **/
+NMSetting *
+nm_setting_vpn_new (void)
+{
+	return (NMSetting *) g_object_new (NM_TYPE_SETTING_VPN, NULL);
+}
+
+static void
+finalize (GObject *object)
+{
+	NMSettingVpnPrivate *priv = NM_SETTING_VPN_GET_PRIVATE (object);
+
+	g_free (priv->service_type);
+	g_free (priv->user_name);
+	g_hash_table_destroy (priv->data);
+	g_hash_table_destroy (priv->secrets);
+
+	G_OBJECT_CLASS (nm_setting_vpn_parent_class)->finalize (object);
 }
 
 static void
@@ -897,17 +973,17 @@ nm_setting_vpn_class_init (NMSettingVpnClass *klass)
 
 	g_type_class_add_private (klass, sizeof (NMSettingVpnPrivate));
 
-	object_class->set_property = set_property;
 	object_class->get_property = get_property;
+	object_class->set_property = set_property;
 	object_class->finalize     = finalize;
 
-	setting_class->verify                   = verify;
-	setting_class->update_one_secret        = update_one_secret;
-	setting_class->get_secret_flags         = get_secret_flags;
-	setting_class->set_secret_flags         = set_secret_flags;
-	setting_class->need_secrets             = need_secrets;
-	setting_class->compare_property         = compare_property;
-	setting_class->clear_secrets_with_flags = clear_secrets_with_flags;
+	setting_class->verify            = verify;
+	setting_class->update_one_secret = update_one_secret;
+	setting_class->get_secret_flags  = get_secret_flags;
+	setting_class->set_secret_flags  = set_secret_flags;
+	setting_class->need_secrets      = need_secrets;
+	setting_class->compare_property  = compare_property;
+	setting_class->clear_secrets     = clear_secrets;
 
 	/**
 	 * NMSettingVpn:service-type:
@@ -916,12 +992,11 @@ nm_setting_vpn_class_init (NMSettingVpnClass *klass)
 	 * its network.  i.e. org.freedesktop.NetworkManager.vpnc for the vpnc
 	 * plugin.
 	 **/
-	g_object_class_install_property
-		(object_class, PROP_SERVICE_TYPE,
-		 g_param_spec_string (NM_SETTING_VPN_SERVICE_TYPE, "", "",
-		                      NULL,
-		                      G_PARAM_READWRITE |
-		                      G_PARAM_STATIC_STRINGS));
+	obj_properties[PROP_SERVICE_TYPE] =
+	    g_param_spec_string (NM_SETTING_VPN_SERVICE_TYPE, "", "",
+	                         NULL,
+	                         G_PARAM_READWRITE |
+	                         G_PARAM_STATIC_STRINGS);
 
 	/**
 	 * NMSettingVpn:user-name:
@@ -933,12 +1008,11 @@ nm_setting_vpn_class_init (NMSettingVpnClass *klass)
 	 * will automatically supply the username of the user which requested the
 	 * VPN connection.
 	 **/
-	g_object_class_install_property
-		(object_class, PROP_USER_NAME,
-		 g_param_spec_string (NM_SETTING_VPN_USER_NAME, "", "",
-		                      NULL,
-		                      G_PARAM_READWRITE |
-		                      G_PARAM_STATIC_STRINGS));
+	obj_properties[PROP_USER_NAME] =
+	    g_param_spec_string (NM_SETTING_VPN_USER_NAME, "", "",
+	                         NULL,
+	                         G_PARAM_READWRITE |
+	                         G_PARAM_STATIC_STRINGS);
 
 	/**
 	 * NMSettingVpn:persistent:
@@ -947,12 +1021,11 @@ nm_setting_vpn_class_init (NMSettingVpnClass *klass)
 	 * the VPN will attempt to stay connected across link changes and outages,
 	 * until explicitly disconnected.
 	 **/
-	g_object_class_install_property
-		(object_class, PROP_PERSISTENT,
-		 g_param_spec_boolean (NM_SETTING_VPN_PERSISTENT, "", "",
-		                       FALSE,
-		                       G_PARAM_READWRITE |
-		                       G_PARAM_STATIC_STRINGS));
+	obj_properties[PROP_PERSISTENT] =
+	    g_param_spec_boolean (NM_SETTING_VPN_PERSISTENT, "", "",
+	                          FALSE,
+	                          G_PARAM_READWRITE |
+	                          G_PARAM_STATIC_STRINGS);
 
 	/**
 	 * NMSettingVpn:data: (type GHashTable(utf8,utf8)):
@@ -968,16 +1041,14 @@ nm_setting_vpn_class_init (NMSettingVpnClass *klass)
 	 * example: remote=ovpn.corp.com cipher=AES-256-CBC username=joe
 	 * ---end---
 	 */
-	g_object_class_install_property
-		(object_class, PROP_DATA,
-		 g_param_spec_boxed (NM_SETTING_VPN_DATA, "", "",
-		                     G_TYPE_HASH_TABLE,
-		                     G_PARAM_READWRITE |
-		                     G_PARAM_STATIC_STRINGS));
+	obj_properties[PROP_DATA] =
+	    g_param_spec_boxed (NM_SETTING_VPN_DATA, "", "",
+	                        G_TYPE_HASH_TABLE,
+	                        G_PARAM_READWRITE |
+	                        G_PARAM_STATIC_STRINGS);
 
 	_properties_override_add_transform (properties_override,
-	                                    g_object_class_find_property (G_OBJECT_CLASS (setting_class),
-	                                                                  NM_SETTING_VPN_DATA),
+	                                    obj_properties[PROP_DATA],
 	                                    G_VARIANT_TYPE ("a{ss}"),
 	                                    _nm_utils_strdict_to_dbus,
 	                                    _nm_utils_strdict_from_dbus);
@@ -996,17 +1067,15 @@ nm_setting_vpn_class_init (NMSettingVpnClass *klass)
 	 * example: password=Popocatepetl
 	 * ---end---
 	 */
-	g_object_class_install_property
-		(object_class, PROP_SECRETS,
-		 g_param_spec_boxed (NM_SETTING_VPN_SECRETS, "", "",
-		                     G_TYPE_HASH_TABLE,
-		                     G_PARAM_READWRITE |
-		                     NM_SETTING_PARAM_SECRET |
-		                     G_PARAM_STATIC_STRINGS));
+	obj_properties[PROP_SECRETS] =
+	    g_param_spec_boxed (NM_SETTING_VPN_SECRETS, "", "",
+	                        G_TYPE_HASH_TABLE,
+	                        G_PARAM_READWRITE |
+	                        NM_SETTING_PARAM_SECRET |
+	                        G_PARAM_STATIC_STRINGS);
 
 	_properties_override_add_transform (properties_override,
-	                                    g_object_class_find_property (G_OBJECT_CLASS (setting_class),
-	                                                                  NM_SETTING_VPN_SECRETS),
+	                                    obj_properties[PROP_SECRETS],
 	                                    G_VARIANT_TYPE ("a{ss}"),
 	                                    _nm_utils_strdict_to_dbus,
 	                                    _nm_utils_strdict_from_dbus);
@@ -1022,12 +1091,13 @@ nm_setting_vpn_class_init (NMSettingVpnClass *klass)
 	 *
 	 * Since: 1.2
 	 **/
-	g_object_class_install_property
-		(object_class, PROP_TIMEOUT,
-		 g_param_spec_uint (NM_SETTING_VPN_TIMEOUT, "", "",
-		                    0, G_MAXUINT32, 0,
-		                    G_PARAM_READWRITE |
-		                    G_PARAM_STATIC_STRINGS));
+	obj_properties[PROP_TIMEOUT] =
+	    g_param_spec_uint (NM_SETTING_VPN_TIMEOUT, "", "",
+	                       0, G_MAXUINT32, 0,
+	                       G_PARAM_READWRITE |
+	                       G_PARAM_STATIC_STRINGS);
+
+	g_object_class_install_properties (object_class, _PROPERTY_ENUMS_LAST, obj_properties);
 
 	_nm_setting_class_commit_full (setting_class, NM_META_SETTING_TYPE_VPN,
 	                               NULL, properties_override);
diff --git a/libnm-core/nm-setting-vxlan.c b/libnm-core/nm-setting-vxlan.c
index d00c5a7a..0c21be27 100644
--- a/libnm-core/nm-setting-vxlan.c
+++ b/libnm-core/nm-setting-vxlan.c
@@ -21,10 +21,11 @@
 
 #include "nm-default.h"
 
+#include "nm-setting-vxlan.h"
+
 #include <stdlib.h>
 #include <string.h>
 
-#include "nm-setting-vxlan.h"
 #include "nm-utils.h"
 #include "nm-setting-private.h"
 
@@ -36,9 +37,28 @@
  * necessary for connection to VXLAN interfaces.
  **/
 
-G_DEFINE_TYPE (NMSettingVxlan, nm_setting_vxlan, NM_TYPE_SETTING)
+#define DST_PORT_DEFAULT   8472
 
-#define NM_SETTING_VXLAN_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), NM_TYPE_SETTING_VXLAN, NMSettingVxlanPrivate))
+/*****************************************************************************/
+
+NM_GOBJECT_PROPERTIES_DEFINE_BASE (
+	PROP_PARENT,
+	PROP_ID,
+	PROP_LOCAL,
+	PROP_REMOTE,
+	PROP_SOURCE_PORT_MIN,
+	PROP_SOURCE_PORT_MAX,
+	PROP_DESTINATION_PORT,
+	PROP_TOS,
+	PROP_TTL,
+	PROP_AGEING,
+	PROP_LIMIT,
+	PROP_LEARNING,
+	PROP_PROXY,
+	PROP_RSC,
+	PROP_L2_MISS,
+	PROP_L3_MISS,
+);
 
 typedef struct {
 	char *parent;
@@ -59,44 +79,11 @@ typedef struct {
 	gboolean l3_miss;
 } NMSettingVxlanPrivate;
 
-enum {
-	PROP_0,
-	PROP_PARENT,
-	PROP_ID,
-	PROP_LOCAL,
-	PROP_REMOTE,
-	PROP_SOURCE_PORT_MIN,
-	PROP_SOURCE_PORT_MAX,
-	PROP_DESTINATION_PORT,
-	PROP_TOS,
-	PROP_TTL,
-	PROP_AGEING,
-	PROP_LIMIT,
-	PROP_LEARNING,
-	PROP_PROXY,
-	PROP_RSC,
-	PROP_L2_MISS,
-	PROP_L3_MISS,
-
-	LAST_PROP
-};
+G_DEFINE_TYPE (NMSettingVxlan, nm_setting_vxlan, NM_TYPE_SETTING)
 
-#define DST_PORT_DEFAULT   8472
+#define NM_SETTING_VXLAN_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), NM_TYPE_SETTING_VXLAN, NMSettingVxlanPrivate))
 
-/**
- * nm_setting_vxlan_new:
- *
- * Creates a new #NMSettingVxlan object with default values.
- *
- * Returns: (transfer full): the new empty #NMSettingVxlan object
- *
- * Since: 1.2
- **/
-NMSetting *
-nm_setting_vxlan_new (void)
-{
-	return (NMSetting *) g_object_new (NM_TYPE_SETTING_VXLAN, NULL);
-}
+/*****************************************************************************/
 
 /**
  * nm_setting_vxlan_get_parent:
@@ -340,11 +327,6 @@ nm_setting_vxlan_get_l3_miss (NMSettingVxlan *setting)
 
 /*****************************************************************************/
 
-static void
-nm_setting_vxlan_init (NMSettingVxlan *setting)
-{
-}
-
 static gboolean
 verify (NMSetting *setting, NMConnection *connection, GError **error)
 {
@@ -422,64 +404,63 @@ verify (NMSetting *setting, NMConnection *connection, GError **error)
 	return TRUE;
 }
 
+/*****************************************************************************/
+
 static void
-set_property (GObject *object, guint prop_id,
-              const GValue *value, GParamSpec *pspec)
+get_property (GObject *object, guint prop_id,
+              GValue *value, GParamSpec *pspec)
 {
 	NMSettingVxlan *setting = NM_SETTING_VXLAN (object);
 	NMSettingVxlanPrivate *priv = NM_SETTING_VXLAN_GET_PRIVATE (setting);
 
 	switch (prop_id) {
 	case PROP_PARENT:
-		g_free (priv->parent);
-		priv->parent = g_value_dup_string (value);
+		g_value_set_string (value, priv->parent);
 		break;
 	case PROP_ID:
-		priv->id = g_value_get_uint (value);
+		g_value_set_uint (value, priv->id);
 		break;
 	case PROP_LOCAL:
-		g_free (priv->local);
-		priv->local = g_value_dup_string (value);
+		g_value_set_string (value, priv->local);
 		break;
 	case PROP_REMOTE:
-		g_free (priv->remote);
-		priv->remote = g_value_dup_string (value);
+		g_value_set_string (value, priv->remote);
 		break;
 	case PROP_SOURCE_PORT_MIN:
-		priv->source_port_min = g_value_get_uint (value);
+		g_value_set_uint (value, priv->source_port_min);
 		break;
 	case PROP_SOURCE_PORT_MAX:
-		priv->source_port_max = g_value_get_uint (value);
+		g_value_set_uint (value, priv->source_port_max);
 		break;
 	case PROP_DESTINATION_PORT:
-		priv->destination_port = g_value_get_uint (value);
+		g_value_set_uint (value, priv->destination_port);
 		break;
 	case PROP_TOS:
-		priv->tos = g_value_get_uint (value);
+		g_value_set_uint (value, priv->tos);
 		break;
 	case PROP_AGEING:
-		priv->ageing = g_value_get_uint (value);
+		g_value_set_uint (value, priv->ageing);
 		break;
 	case PROP_LIMIT:
-		priv->limit = g_value_get_uint (value);
+		g_value_set_uint (value, priv->limit);
 		break;
 	case PROP_PROXY:
-		priv->proxy = g_value_get_boolean (value);
+		g_value_set_boolean (value, priv->proxy);
 		break;
 	case PROP_TTL:
-		priv->ttl = g_value_get_uint (value);
+		g_value_set_uint (value, priv->ttl);
 		break;
 	case PROP_LEARNING:
-		priv->learning = g_value_get_boolean (value);
+		g_value_set_boolean (value, priv->learning);
 		break;
 	case PROP_RSC:
-		priv->rsc = g_value_get_boolean (value);
+		g_value_set_boolean (value, priv->rsc);
 		break;
 	case PROP_L2_MISS:
-		priv->l2_miss = g_value_get_boolean (value);
+		g_value_set_boolean (value, priv->l2_miss);
 		break;
 	case PROP_L3_MISS:
-		priv->l3_miss = g_value_get_boolean (value);
+		g_value_set_boolean (value, priv->l3_miss);
 		break;
 	default:
 		G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
@@ -488,60 +469,63 @@ set_property (GObject *object, guint prop_id,
 }
 
 static void
-get_property (GObject *object, guint prop_id,
-              GValue *value, GParamSpec *pspec)
+set_property (GObject *object, guint prop_id,
+              const GValue *value, GParamSpec *pspec)
 {
 	NMSettingVxlan *setting = NM_SETTING_VXLAN (object);
 	NMSettingVxlanPrivate *priv = NM_SETTING_VXLAN_GET_PRIVATE (setting);
 
 	switch (prop_id) {
 	case PROP_PARENT:
-		g_value_set_string (value, priv->parent);
+		g_free (priv->parent);
+		priv->parent = g_value_dup_string (value);
 		break;
 	case PROP_ID:
-		g_value_set_uint (value, priv->id);
+		priv->id = g_value_get_uint (value);
 		break;
 	case PROP_LOCAL:
-		g_value_set_string (value, priv->local);
+		g_free (priv->local);
+		priv->local = g_value_dup_string (value);
 		break;
 	case PROP_REMOTE:
-		g_value_set_string (value, priv->remote);
+		g_free (priv->remote);
+		priv->remote = g_value_dup_string (value);
 		break;
 	case PROP_SOURCE_PORT_MIN:
-		g_value_set_uint (value, priv->source_port_min);
+		priv->source_port_min = g_value_get_uint (value);
 		break;
 	case PROP_SOURCE_PORT_MAX:
-		g_value_set_uint (value, priv->source_port_max);
+		priv->source_port_max = g_value_get_uint (value);
 		break;
 	case PROP_DESTINATION_PORT:
-		g_value_set_uint (value, priv->destination_port);
+		priv->destination_port = g_value_get_uint (value);
 		break;
 	case PROP_TOS:
-		g_value_set_uint (value, priv->tos);
+		priv->tos = g_value_get_uint (value);
 		break;
 	case PROP_AGEING:
-		g_value_set_uint (value, priv->ageing);
+		priv->ageing = g_value_get_uint (value);
 		break;
 	case PROP_LIMIT:
-		g_value_set_uint (value, priv->limit);
+		priv->limit = g_value_get_uint (value);
 		break;
 	case PROP_PROXY:
-		g_value_set_boolean (value, priv->proxy);
+		priv->proxy = g_value_get_boolean (value);
 		break;
 	case PROP_TTL:
-		g_value_set_uint (value, priv->ttl);
+		priv->ttl = g_value_get_uint (value);
 		break;
 	case PROP_LEARNING:
-		g_value_set_boolean (value, priv->learning);
+		priv->learning = g_value_get_boolean (value);
 		break;
 	case PROP_RSC:
-		g_value_set_boolean (value, priv->rsc);
+		priv->rsc = g_value_get_boolean (value);
 		break;
 	case PROP_L2_MISS:
-		g_value_set_boolean (value, priv->l2_miss);
+		priv->l2_miss = g_value_get_boolean (value);
 		break;
 	case PROP_L3_MISS:
-		g_value_set_boolean (value, priv->l3_miss);
+		priv->l3_miss = g_value_get_boolean (value);
 		break;
 	default:
 		G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
@@ -549,6 +533,28 @@ get_property (GObject *object, guint prop_id,
 	}
 }
 
+/*****************************************************************************/
+
+static void
+nm_setting_vxlan_init (NMSettingVxlan *setting)
+{
+}
+
+/**
+ * nm_setting_vxlan_new:
+ *
+ * Creates a new #NMSettingVxlan object with default values.
+ *
+ * Returns: (transfer full): the new empty #NMSettingVxlan object
+ *
+ * Since: 1.2
+ **/
+NMSetting *
+nm_setting_vxlan_new (void)
+{
+	return (NMSetting *) g_object_new (NM_TYPE_SETTING_VXLAN, NULL);
+}
+
 static void
 finalize (GObject *object)
 {
@@ -570,8 +576,8 @@ nm_setting_vxlan_class_init (NMSettingVxlanClass *klass)
 
 	g_type_class_add_private (klass, sizeof (NMSettingVxlanPrivate));
 
-	object_class->set_property = set_property;
 	object_class->get_property = get_property;
+	object_class->set_property = set_property;
 	object_class->finalize     = finalize;
 
 	setting_class->verify = verify;
@@ -583,14 +589,13 @@ nm_setting_vxlan_class_init (NMSettingVxlanClass *klass)
 	 *
 	 * Since: 1.2
 	 **/
-	g_object_class_install_property
-		(object_class, PROP_PARENT,
-		 g_param_spec_string (NM_SETTING_VXLAN_PARENT, "", "",
-		                      NULL,
-		                      G_PARAM_READWRITE |
-		                      G_PARAM_CONSTRUCT |
-		                      NM_SETTING_PARAM_INFERRABLE |
-		                      G_PARAM_STATIC_STRINGS));
+	obj_properties[PROP_PARENT] =
+	    g_param_spec_string (NM_SETTING_VXLAN_PARENT, "", "",
+	                         NULL,
+	                         G_PARAM_READWRITE |
+	                         G_PARAM_CONSTRUCT |
+	                         NM_SETTING_PARAM_INFERRABLE |
+	                         G_PARAM_STATIC_STRINGS);
 	/**
 	 * NMSettingVxlan:id:
 	 *
@@ -599,14 +604,13 @@ nm_setting_vxlan_class_init (NMSettingVxlanClass *klass)
 	 *
 	 * Since: 1.2
 	 **/
-	g_object_class_install_property
-		(object_class, PROP_ID,
-		 g_param_spec_uint (NM_SETTING_VXLAN_ID, "", "",
-		                    0, (1 << 24) - 1, 0,
-		                    G_PARAM_READWRITE |
-		                    G_PARAM_CONSTRUCT |
-		                    NM_SETTING_PARAM_INFERRABLE |
-		                    G_PARAM_STATIC_STRINGS));
+	obj_properties[PROP_ID] =
+	    g_param_spec_uint (NM_SETTING_VXLAN_ID, "", "",
+	                       0, (1 << 24) - 1, 0,
+	                       G_PARAM_READWRITE |
+	                       G_PARAM_CONSTRUCT |
+	                       NM_SETTING_PARAM_INFERRABLE |
+	                       G_PARAM_STATIC_STRINGS);
 
 	/**
 	 * NMSettingVxlan:local:
@@ -615,14 +619,13 @@ nm_setting_vxlan_class_init (NMSettingVxlanClass *klass)
 	 *
 	 * Since: 1.2
 	 **/
-	g_object_class_install_property
-		(object_class, PROP_LOCAL,
-		 g_param_spec_string (NM_SETTING_VXLAN_LOCAL, "", "",
-		                      NULL,
-		                      G_PARAM_READWRITE |
-		                      G_PARAM_CONSTRUCT |
-		                      NM_SETTING_PARAM_INFERRABLE |
-		                      G_PARAM_STATIC_STRINGS));
+	obj_properties[PROP_LOCAL] =
+	    g_param_spec_string (NM_SETTING_VXLAN_LOCAL, "", "",
+	                         NULL,
+	                         G_PARAM_READWRITE |
+	                         G_PARAM_CONSTRUCT |
+	                         NM_SETTING_PARAM_INFERRABLE |
+	                         G_PARAM_STATIC_STRINGS);
 
 	/**
 	 * NMSettingVxlan:remote:
@@ -633,14 +636,13 @@ nm_setting_vxlan_class_init (NMSettingVxlanClass *klass)
 	 *
 	 * Since: 1.2
 	 **/
-	g_object_class_install_property
-		(object_class, PROP_REMOTE,
-		 g_param_spec_string (NM_SETTING_VXLAN_REMOTE, "", "",
-		                      NULL,
-		                      G_PARAM_READWRITE |
-		                      G_PARAM_CONSTRUCT |
-		                      NM_SETTING_PARAM_INFERRABLE |
-		                      G_PARAM_STATIC_STRINGS));
+	obj_properties[PROP_REMOTE] =
+	    g_param_spec_string (NM_SETTING_VXLAN_REMOTE, "", "",
+	                         NULL,
+	                         G_PARAM_READWRITE |
+	                         G_PARAM_CONSTRUCT |
+	                         NM_SETTING_PARAM_INFERRABLE |
+	                         G_PARAM_STATIC_STRINGS);
 
 	/**
 	 * NMSettingVxlan:source-port-min:
@@ -650,14 +652,13 @@ nm_setting_vxlan_class_init (NMSettingVxlanClass *klass)
 	 *
 	 * Since: 1.2
 	 **/
-	g_object_class_install_property
-		(object_class, PROP_SOURCE_PORT_MIN,
-		 g_param_spec_uint (NM_SETTING_VXLAN_SOURCE_PORT_MIN, "", "",
-		                    0, G_MAXUINT16, 0,
-		                    G_PARAM_READWRITE |
-		                    G_PARAM_CONSTRUCT |
-		                    NM_SETTING_PARAM_INFERRABLE |
-		                    G_PARAM_STATIC_STRINGS));
+	obj_properties[PROP_SOURCE_PORT_MIN] =
+	    g_param_spec_uint (NM_SETTING_VXLAN_SOURCE_PORT_MIN, "", "",
+	                       0, G_MAXUINT16, 0,
+	                       G_PARAM_READWRITE |
+	                       G_PARAM_CONSTRUCT |
+	                       NM_SETTING_PARAM_INFERRABLE |
+	                       G_PARAM_STATIC_STRINGS);
 
 	/**
 	 * NMSettingVxlan:source-port-max:
@@ -667,14 +668,13 @@ nm_setting_vxlan_class_init (NMSettingVxlanClass *klass)
 	 *
 	 * Since: 1.2
 	 **/
-	g_object_class_install_property
-		(object_class, PROP_SOURCE_PORT_MAX,
-		 g_param_spec_uint (NM_SETTING_VXLAN_SOURCE_PORT_MAX, "", "",
-		                    0, G_MAXUINT16, 0,
-		                    G_PARAM_READWRITE |
-		                    G_PARAM_CONSTRUCT |
-		                    NM_SETTING_PARAM_INFERRABLE |
-		                    G_PARAM_STATIC_STRINGS));
+	obj_properties[PROP_SOURCE_PORT_MAX] =
+	    g_param_spec_uint (NM_SETTING_VXLAN_SOURCE_PORT_MAX, "", "",
+	                       0, G_MAXUINT16, 0,
+	                       G_PARAM_READWRITE |
+	                       G_PARAM_CONSTRUCT |
+	                       NM_SETTING_PARAM_INFERRABLE |
+	                       G_PARAM_STATIC_STRINGS);
 
 	/**
 	 * NMSettingVxlan:destination-port:
@@ -684,14 +684,13 @@ nm_setting_vxlan_class_init (NMSettingVxlanClass *klass)
 	 *
 	 * Since: 1.2
 	 **/
-	g_object_class_install_property
-		(object_class, PROP_DESTINATION_PORT,
-		 g_param_spec_uint (NM_SETTING_VXLAN_DESTINATION_PORT, "", "",
-		                    0, G_MAXUINT16, DST_PORT_DEFAULT,
-		                    G_PARAM_READWRITE |
-		                    G_PARAM_CONSTRUCT |
-		                    NM_SETTING_PARAM_INFERRABLE |
-		                    G_PARAM_STATIC_STRINGS));
+	obj_properties[PROP_DESTINATION_PORT] =
+	    g_param_spec_uint (NM_SETTING_VXLAN_DESTINATION_PORT, "", "",
+	                       0, G_MAXUINT16, DST_PORT_DEFAULT,
+	                       G_PARAM_READWRITE |
+	                       G_PARAM_CONSTRUCT |
+	                       NM_SETTING_PARAM_INFERRABLE |
+	                       G_PARAM_STATIC_STRINGS);
 
 	/**
 	 * NMSettingVxlan:ageing:
@@ -700,14 +699,13 @@ nm_setting_vxlan_class_init (NMSettingVxlanClass *klass)
 	 *
 	 * Since: 1.2
 	 **/
-	g_object_class_install_property
-		(object_class, PROP_AGEING,
-		 g_param_spec_uint (NM_SETTING_VXLAN_AGEING, "", "",
-		                    0, G_MAXUINT32, 300,
-		                    G_PARAM_READWRITE |
-		                    G_PARAM_CONSTRUCT |
-		                    NM_SETTING_PARAM_INFERRABLE |
-		                    G_PARAM_STATIC_STRINGS));
+	obj_properties[PROP_AGEING] =
+	    g_param_spec_uint (NM_SETTING_VXLAN_AGEING, "", "",
+	                       0, G_MAXUINT32, 300,
+	                       G_PARAM_READWRITE |
+	                       G_PARAM_CONSTRUCT |
+	                       NM_SETTING_PARAM_INFERRABLE |
+	                       G_PARAM_STATIC_STRINGS);
 
 	/**
 	 * NMSettingVxlan:limit:
@@ -717,14 +715,13 @@ nm_setting_vxlan_class_init (NMSettingVxlanClass *klass)
 	 *
 	 * Since: 1.2
 	 **/
-	g_object_class_install_property
-		(object_class, PROP_LIMIT,
-		 g_param_spec_uint (NM_SETTING_VXLAN_LIMIT, "", "",
-		                    0, G_MAXUINT32, 0,
-		                    G_PARAM_READWRITE |
-		                    G_PARAM_CONSTRUCT |
-		                    NM_SETTING_PARAM_INFERRABLE |
-		                    G_PARAM_STATIC_STRINGS));
+	obj_properties[PROP_LIMIT] =
+	    g_param_spec_uint (NM_SETTING_VXLAN_LIMIT, "", "",
+	                       0, G_MAXUINT32, 0,
+	                       G_PARAM_READWRITE |
+	                       G_PARAM_CONSTRUCT |
+	                       NM_SETTING_PARAM_INFERRABLE |
+	                       G_PARAM_STATIC_STRINGS);
 
 	/**
 	 * NMSettingVxlan:tos:
@@ -733,14 +730,13 @@ nm_setting_vxlan_class_init (NMSettingVxlanClass *klass)
 	 *
 	 * Since: 1.2
 	 **/
-	g_object_class_install_property
-		(object_class, PROP_TOS,
-		 g_param_spec_uint (NM_SETTING_VXLAN_TOS, "", "",
-		                    0, 255, 0,
-		                    G_PARAM_READWRITE |
-		                    G_PARAM_CONSTRUCT |
-		                    NM_SETTING_PARAM_INFERRABLE |
-		                    G_PARAM_STATIC_STRINGS));
+	obj_properties[PROP_TOS] =
+	    g_param_spec_uint (NM_SETTING_VXLAN_TOS, "", "",
+	                       0, 255, 0,
+	                       G_PARAM_READWRITE |
+	                       G_PARAM_CONSTRUCT |
+	                       NM_SETTING_PARAM_INFERRABLE |
+	                       G_PARAM_STATIC_STRINGS);
 
 	/**
 	 * NMSettingVxlan:ttl:
@@ -749,14 +745,13 @@ nm_setting_vxlan_class_init (NMSettingVxlanClass *klass)
 	 *
 	 * Since: 1.2
 	 **/
-	g_object_class_install_property
-		(object_class, PROP_TTL,
-		 g_param_spec_uint (NM_SETTING_VXLAN_TTL, "", "",
-		                    0, 255, 0,
-		                    G_PARAM_READWRITE |
-		                    G_PARAM_CONSTRUCT |
-		                    NM_SETTING_PARAM_INFERRABLE |
-		                    G_PARAM_STATIC_STRINGS));
+	obj_properties[PROP_TTL] =
+	    g_param_spec_uint (NM_SETTING_VXLAN_TTL, "", "",
+	                       0, 255, 0,
+	                       G_PARAM_READWRITE |
+	                       G_PARAM_CONSTRUCT |
+	                       NM_SETTING_PARAM_INFERRABLE |
+	                       G_PARAM_STATIC_STRINGS);
 
 	/**
 	 * NMSettingVxlan:proxy:
@@ -765,14 +760,13 @@ nm_setting_vxlan_class_init (NMSettingVxlanClass *klass)
 	 *
 	 * Since: 1.2
 	 **/
-	g_object_class_install_property
-		(object_class, PROP_PROXY,
-		 g_param_spec_boolean (NM_SETTING_VXLAN_PROXY, "", "",
-		                       FALSE,
-		                       G_PARAM_READWRITE |
-		                       G_PARAM_CONSTRUCT |
-		                       NM_SETTING_PARAM_INFERRABLE |
-		                       G_PARAM_STATIC_STRINGS));
+	obj_properties[PROP_PROXY] =
+	    g_param_spec_boolean (NM_SETTING_VXLAN_PROXY, "", "",
+	                          FALSE,
+	                          G_PARAM_READWRITE |
+	                          G_PARAM_CONSTRUCT |
+	                          NM_SETTING_PARAM_INFERRABLE |
+	                          G_PARAM_STATIC_STRINGS);
 
 	/**
 	 * NMSettingVxlan:learning:
@@ -782,14 +776,13 @@ nm_setting_vxlan_class_init (NMSettingVxlanClass *klass)
 	 *
 	 * Since: 1.2
 	 **/
-	g_object_class_install_property
-		(object_class, PROP_LEARNING,
-		 g_param_spec_boolean (NM_SETTING_VXLAN_LEARNING, "", "",
-		                       TRUE,
-		                       G_PARAM_READWRITE |
-		                       G_PARAM_CONSTRUCT |
-		                       NM_SETTING_PARAM_INFERRABLE |
-		                       G_PARAM_STATIC_STRINGS));
+	obj_properties[PROP_LEARNING] =
+	    g_param_spec_boolean (NM_SETTING_VXLAN_LEARNING, "", "",
+	                          TRUE,
+	                          G_PARAM_READWRITE |
+	                          G_PARAM_CONSTRUCT |
+	                          NM_SETTING_PARAM_INFERRABLE |
+	                          G_PARAM_STATIC_STRINGS);
 	/**
 	 * NMSettingVxlan:rsc:
 	 *
@@ -797,14 +790,13 @@ nm_setting_vxlan_class_init (NMSettingVxlanClass *klass)
 	 *
 	 * Since: 1.2
 	 **/
-	g_object_class_install_property
-		(object_class, PROP_RSC,
-		 g_param_spec_boolean (NM_SETTING_VXLAN_RSC, "", "",
-		                       FALSE,
-		                       G_PARAM_READWRITE |
-		                       G_PARAM_CONSTRUCT |
-		                       NM_SETTING_PARAM_INFERRABLE |
-		                       G_PARAM_STATIC_STRINGS));
+	obj_properties[PROP_RSC] =
+	    g_param_spec_boolean (NM_SETTING_VXLAN_RSC, "", "",
+	                          FALSE,
+	                          G_PARAM_READWRITE |
+	                          G_PARAM_CONSTRUCT |
+	                          NM_SETTING_PARAM_INFERRABLE |
+	                          G_PARAM_STATIC_STRINGS);
 	/**
 	 * NMSettingVxlan:l2-miss:
 	 *
@@ -812,14 +804,13 @@ nm_setting_vxlan_class_init (NMSettingVxlanClass *klass)
 	 *
 	 * Since: 1.2
 	 **/
-	g_object_class_install_property
-		(object_class, PROP_L2_MISS,
-		 g_param_spec_boolean (NM_SETTING_VXLAN_L2_MISS, "", "",
-		                       FALSE,
-		                       G_PARAM_READWRITE |
-		                       G_PARAM_CONSTRUCT |
-		                       NM_SETTING_PARAM_INFERRABLE |
-		                       G_PARAM_STATIC_STRINGS));
+	obj_properties[PROP_L2_MISS] =
+	    g_param_spec_boolean (NM_SETTING_VXLAN_L2_MISS, "", "",
+	                          FALSE,
+	                          G_PARAM_READWRITE |
+	                          G_PARAM_CONSTRUCT |
+	                          NM_SETTING_PARAM_INFERRABLE |
+	                          G_PARAM_STATIC_STRINGS);
 
 	/**
 	 * NMSettingVxlan:l3-miss:
@@ -828,14 +819,15 @@ nm_setting_vxlan_class_init (NMSettingVxlanClass *klass)
 	 *
 	 * Since: 1.2
 	 **/
-	g_object_class_install_property
-		(object_class, PROP_L3_MISS,
-		 g_param_spec_boolean (NM_SETTING_VXLAN_L3_MISS, "", "",
-		                       FALSE,
-		                       G_PARAM_READWRITE |
-		                       G_PARAM_CONSTRUCT |
-		                       NM_SETTING_PARAM_INFERRABLE |
-		                       G_PARAM_STATIC_STRINGS));
+	obj_properties[PROP_L3_MISS] =
+	    g_param_spec_boolean (NM_SETTING_VXLAN_L3_MISS, "", "",
+	                          FALSE,
+	                          G_PARAM_READWRITE |
+	                          G_PARAM_CONSTRUCT |
+	                          NM_SETTING_PARAM_INFERRABLE |
+	                          G_PARAM_STATIC_STRINGS);
+
+	g_object_class_install_properties (object_class, _PROPERTY_ENUMS_LAST, obj_properties);
 
 	_nm_setting_class_commit (setting_class, NM_META_SETTING_TYPE_VXLAN);
 }
diff --git a/libnm-core/nm-setting-wimax.c b/libnm-core/nm-setting-wimax.c
index 4c1a572e..aa574a56 100644
--- a/libnm-core/nm-setting-wimax.c
+++ b/libnm-core/nm-setting-wimax.c
@@ -22,10 +22,11 @@
 
 #include "nm-default.h"
 
+#include "nm-setting-wimax.h"
+
 #include <string.h>
 #include <net/ethernet.h>
 
-#include "nm-setting-wimax.h"
 #include "nm-setting-private.h"
 #include "nm-utils.h"
 #include "nm-utils-private.h"
@@ -42,37 +43,23 @@
  * connections cannot be activated.
  **/
 
-G_DEFINE_TYPE (NMSettingWimax, nm_setting_wimax, NM_TYPE_SETTING)
+/*****************************************************************************/
 
-#define NM_SETTING_WIMAX_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), NM_TYPE_SETTING_WIMAX, NMSettingWimaxPrivate))
+NM_GOBJECT_PROPERTIES_DEFINE_BASE (
+	PROP_NETWORK_NAME,
+	PROP_MAC_ADDRESS,
+);
 
 typedef struct {
 	char *network_name;
 	char *mac_address;
 } NMSettingWimaxPrivate;
 
-enum {
-	PROP_0,
-	PROP_NETWORK_NAME,
-	PROP_MAC_ADDRESS,
+G_DEFINE_TYPE (NMSettingWimax, nm_setting_wimax, NM_TYPE_SETTING)
 
-	LAST_PROP
-};
+#define NM_SETTING_WIMAX_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), NM_TYPE_SETTING_WIMAX, NMSettingWimaxPrivate))
 
-/**
- * nm_setting_wimax_new:
- *
- * Creates a new #NMSettingWimax object with default values.
- *
- * Returns: the new empty #NMSettingWimax object
- *
- * Deprecated: 1.2: WiMAX is no longer supported.
- **/
-NMSetting *
-nm_setting_wimax_new (void)
-{
-	return (NMSetting *) g_object_new (NM_TYPE_SETTING_WIMAX, NULL);
-}
+/*****************************************************************************/
 
 /**
  * nm_setting_wimax_get_network_name:
@@ -147,20 +134,25 @@ verify (NMSetting *setting, NMConnection *connection, GError **error)
 	return TRUE;
 }
 
-static void
-nm_setting_wimax_init (NMSettingWimax *setting)
-{
-}
+/*****************************************************************************/
 
 static void
-finalize (GObject *object)
+get_property (GObject *object, guint prop_id,
+              GValue *value, GParamSpec *pspec)
 {
-	NMSettingWimaxPrivate *priv = NM_SETTING_WIMAX_GET_PRIVATE (object);
-
-	g_free (priv->network_name);
-	g_free (priv->mac_address);
+	NMSettingWimax *setting = NM_SETTING_WIMAX (object);
 
-	G_OBJECT_CLASS (nm_setting_wimax_parent_class)->finalize (object);
+	switch (prop_id) {
+	case PROP_NETWORK_NAME:
+		g_value_set_string (value, nm_setting_wimax_get_network_name (setting));
+		break;
+	case PROP_MAC_ADDRESS:
+		g_value_set_string (value, nm_setting_wimax_get_mac_address (setting));
+		break;
+	default:
+		G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+		break;
+	}
 }
 
 static void
@@ -185,23 +177,37 @@ set_property (GObject *object, guint prop_id,
 	}
 }
 
+/*****************************************************************************/
+
 static void
-get_property (GObject *object, guint prop_id,
-              GValue *value, GParamSpec *pspec)
+nm_setting_wimax_init (NMSettingWimax *setting)
 {
-	NMSettingWimax *setting = NM_SETTING_WIMAX (object);
+}
 
-	switch (prop_id) {
-	case PROP_NETWORK_NAME:
-		g_value_set_string (value, nm_setting_wimax_get_network_name (setting));
-		break;
-	case PROP_MAC_ADDRESS:
-		g_value_set_string (value, nm_setting_wimax_get_mac_address (setting));
-		break;
-	default:
-		G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
-		break;
-	}
+/**
+ * nm_setting_wimax_new:
+ *
+ * Creates a new #NMSettingWimax object with default values.
+ *
+ * Returns: the new empty #NMSettingWimax object
+ *
+ * Deprecated: 1.2: WiMAX is no longer supported.
+ **/
+NMSetting *
+nm_setting_wimax_new (void)
+{
+	return (NMSetting *) g_object_new (NM_TYPE_SETTING_WIMAX, NULL);
+}
+
+static void
+finalize (GObject *object)
+{
+	NMSettingWimaxPrivate *priv = NM_SETTING_WIMAX_GET_PRIVATE (object);
+
+	g_free (priv->network_name);
+	g_free (priv->mac_address);
+
+	G_OBJECT_CLASS (nm_setting_wimax_parent_class)->finalize (object);
 }
 
 static void
@@ -213,8 +219,8 @@ nm_setting_wimax_class_init (NMSettingWimaxClass *klass)
 
 	g_type_class_add_private (klass, sizeof (NMSettingWimaxPrivate));
 
-	object_class->set_property = set_property;
 	object_class->get_property = get_property;
+	object_class->set_property = set_property;
 	object_class->finalize     = finalize;
 
 	setting_class->verify = verify;
@@ -227,12 +233,11 @@ nm_setting_wimax_class_init (NMSettingWimaxClass *klass)
 	 *
 	 * Deprecated: 1.2: WiMAX is no longer supported.
 	 **/
-	g_object_class_install_property
-		(object_class, PROP_NETWORK_NAME,
-		 g_param_spec_string (NM_SETTING_WIMAX_NETWORK_NAME, "", "",
-		                      NULL,
-		                      G_PARAM_READWRITE |
-		                      G_PARAM_STATIC_STRINGS));
+	obj_properties[PROP_NETWORK_NAME] =
+	    g_param_spec_string (NM_SETTING_WIMAX_NETWORK_NAME, "", "",
+	                         NULL,
+	                         G_PARAM_READWRITE |
+	                         G_PARAM_STATIC_STRINGS);
 
 	/**
 	 * NMSettingWimax:mac-address:
@@ -243,20 +248,20 @@ nm_setting_wimax_class_init (NMSettingWimaxClass *klass)
 	 *
 	 * Deprecated: 1.2: WiMAX is no longer supported.
 	 **/
-	g_object_class_install_property
-		(object_class, PROP_MAC_ADDRESS,
-		 g_param_spec_string (NM_SETTING_WIMAX_MAC_ADDRESS, "", "",
-		                      NULL,
-		                      G_PARAM_READWRITE |
-		                      G_PARAM_STATIC_STRINGS));
+	obj_properties[PROP_MAC_ADDRESS] =
+	    g_param_spec_string (NM_SETTING_WIMAX_MAC_ADDRESS, "", "",
+	                         NULL,
+	                         G_PARAM_READWRITE |
+	                         G_PARAM_STATIC_STRINGS);
 
 	_properties_override_add_transform (properties_override,
-	                                    g_object_class_find_property (G_OBJECT_CLASS (setting_class),
-	                                                                  NM_SETTING_WIMAX_MAC_ADDRESS),
+	                                    obj_properties[PROP_MAC_ADDRESS],
 	                                    G_VARIANT_TYPE_BYTESTRING,
 	                                    _nm_utils_hwaddr_to_dbus,
 	                                    _nm_utils_hwaddr_from_dbus);
 
+	g_object_class_install_properties (object_class, _PROPERTY_ENUMS_LAST, obj_properties);
+
 	_nm_setting_class_commit_full (setting_class, NM_META_SETTING_TYPE_WIMAX,
 	                               NULL, properties_override);
 }
diff --git a/libnm-core/nm-setting-wired.c b/libnm-core/nm-setting-wired.c
index baa40cc4..ef994255 100644
--- a/libnm-core/nm-setting-wired.c
+++ b/libnm-core/nm-setting-wired.c
@@ -40,9 +40,24 @@
  * necessary for connection to Ethernet networks.
  **/
 
-G_DEFINE_TYPE (NMSettingWired, nm_setting_wired, NM_TYPE_SETTING)
+/*****************************************************************************/
 
-#define NM_SETTING_WIRED_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), NM_TYPE_SETTING_WIRED, NMSettingWiredPrivate))
+NM_GOBJECT_PROPERTIES_DEFINE (NMSettingWired,
+	PROP_PORT,
+	PROP_SPEED,
+	PROP_DUPLEX,
+	PROP_AUTO_NEGOTIATE,
+	PROP_MAC_ADDRESS,
+	PROP_CLONED_MAC_ADDRESS,
+	PROP_GENERATE_MAC_ADDRESS_MASK,
+	PROP_MAC_ADDRESS_BLACKLIST,
+	PROP_MTU,
+	PROP_S390_SUBCHANNELS,
+	PROP_S390_NETTYPE,
+	PROP_S390_OPTIONS,
+	PROP_WAKE_ON_LAN,
+	PROP_WAKE_ON_LAN_PASSWORD,
+);
 
 typedef struct {
 	char *port;
@@ -61,25 +76,11 @@ typedef struct {
 	char *wol_password;
 } NMSettingWiredPrivate;
 
-enum {
-	PROP_0,
-	PROP_PORT,
-	PROP_SPEED,
-	PROP_DUPLEX,
-	PROP_AUTO_NEGOTIATE,
-	PROP_MAC_ADDRESS,
-	PROP_CLONED_MAC_ADDRESS,
-	PROP_GENERATE_MAC_ADDRESS_MASK,
-	PROP_MAC_ADDRESS_BLACKLIST,
-	PROP_MTU,
-	PROP_S390_SUBCHANNELS,
-	PROP_S390_NETTYPE,
-	PROP_S390_OPTIONS,
-	PROP_WAKE_ON_LAN,
-	PROP_WAKE_ON_LAN_PASSWORD,
+G_DEFINE_TYPE (NMSettingWired, nm_setting_wired, NM_TYPE_SETTING)
 
-	LAST_PROP
-};
+#define NM_SETTING_WIRED_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), NM_TYPE_SETTING_WIRED, NMSettingWiredPrivate))
+
+/*****************************************************************************/
 
 static const char *valid_s390_opts[] = {
 	"portno", "layer2", "portname", "protocol", "priority_queueing",
@@ -92,19 +93,6 @@ static const char *valid_s390_opts[] = {
 };
 
 /**
- * nm_setting_wired_new:
- *
- * Creates a new #NMSettingWired object with default values.
- *
- * Returns: (transfer full): the new empty #NMSettingWired object
- **/
-NMSetting *
-nm_setting_wired_new (void)
-{
-	return (NMSetting *) g_object_new (NM_TYPE_SETTING_WIRED, NULL);
-}
-
-/**
  * nm_setting_wired_get_port:
  * @setting: the #NMSettingWired
  *
@@ -288,7 +276,7 @@ nm_setting_wired_add_mac_blacklist_item (NMSettingWired *setting, const char *ma
 
 	mac = nm_utils_hwaddr_canonical (mac, ETH_ALEN);
 	g_array_append_val (priv->mac_address_blacklist, mac);
-	g_object_notify (G_OBJECT (setting), NM_SETTING_WIRED_MAC_ADDRESS_BLACKLIST);
+	_notify (setting, PROP_MAC_ADDRESS_BLACKLIST);
 	return TRUE;
 }
 
@@ -310,7 +298,7 @@ nm_setting_wired_remove_mac_blacklist_item (NMSettingWired *setting, guint32 idx
 	g_return_if_fail (idx < priv->mac_address_blacklist->len);
 
 	g_array_remove_index (priv->mac_address_blacklist, idx);
-	g_object_notify (G_OBJECT (setting), NM_SETTING_WIRED_MAC_ADDRESS_BLACKLIST);
+	_notify (setting, PROP_MAC_ADDRESS_BLACKLIST);
 }
 
 /**
@@ -338,7 +326,7 @@ nm_setting_wired_remove_mac_blacklist_item_by_value (NMSettingWired *setting, co
 		candidate = g_array_index (priv->mac_address_blacklist, char *, i);
 		if (!nm_utils_hwaddr_matches (mac, -1, candidate, -1)) {
 			g_array_remove_index (priv->mac_address_blacklist, i);
-			g_object_notify (G_OBJECT (setting), NM_SETTING_WIRED_MAC_ADDRESS_BLACKLIST);
+			_notify (setting, PROP_MAC_ADDRESS_BLACKLIST);
 			return TRUE;
 		}
 	}
@@ -357,7 +345,7 @@ nm_setting_wired_clear_mac_blacklist_items (NMSettingWired *setting)
 	g_return_if_fail (NM_IS_SETTING_WIRED (setting));
 
 	g_array_set_size (NM_SETTING_WIRED_GET_PRIVATE (setting)->mac_address_blacklist, 0);
-	g_object_notify (G_OBJECT (setting), NM_SETTING_WIRED_MAC_ADDRESS_BLACKLIST);
+	_notify (setting, PROP_MAC_ADDRESS_BLACKLIST);
 }
 
 /**
@@ -530,7 +518,7 @@ nm_setting_wired_add_s390_option (NMSettingWired *setting,
 	g_hash_table_insert (NM_SETTING_WIRED_GET_PRIVATE (setting)->s390_options,
 	                     g_strdup (key),
 	                     g_strdup (value));
-	g_object_notify (G_OBJECT (setting), NM_SETTING_WIRED_S390_OPTIONS);
+	_notify (setting, PROP_S390_OPTIONS);
 	return TRUE;
 }
 
@@ -557,7 +545,7 @@ nm_setting_wired_remove_s390_option (NMSettingWired *setting,
 
 	found = g_hash_table_remove (NM_SETTING_WIRED_GET_PRIVATE (setting)->s390_options, key);
 	if (found)
-		g_object_notify (G_OBJECT (setting), NM_SETTING_WIRED_S390_OPTIONS);
+		_notify (setting, PROP_S390_OPTIONS);
 	return found;
 }
 
@@ -775,21 +763,25 @@ verify (NMSetting *setting, NMConnection *connection, GError **error)
 	return TRUE;
 }
 
-static gboolean
-compare_property (NMSetting *setting,
+static NMTernary
+compare_property (const NMSettInfoSetting *sett_info,
+                  guint property_idx,
+                  NMSetting *setting,
                   NMSetting *other,
-                  const GParamSpec *prop_spec,
                   NMSettingCompareFlags flags)
 {
-	NMSettingClass *setting_class;
 
-	if (nm_streq (prop_spec->name, NM_SETTING_WIRED_CLONED_MAC_ADDRESS)) {
-		return nm_streq0 (NM_SETTING_WIRED_GET_PRIVATE (setting)->cloned_mac_address,
-		                  NM_SETTING_WIRED_GET_PRIVATE (other)->cloned_mac_address);
+	if (nm_streq (sett_info->property_infos[property_idx].name, NM_SETTING_WIRED_CLONED_MAC_ADDRESS)) {
+		return    !other
+		       || nm_streq0 (NM_SETTING_WIRED_GET_PRIVATE (setting)->cloned_mac_address,
+		                     NM_SETTING_WIRED_GET_PRIVATE (other)->cloned_mac_address);
 	}
 
-	setting_class = NM_SETTING_CLASS (nm_setting_wired_parent_class);
-	return setting_class->compare_property (setting, other, prop_spec, flags);
+	return NM_SETTING_CLASS (nm_setting_wired_parent_class)->compare_property (sett_info,
+	                                                                           property_idx,
+	                                                                           setting,
+	                                                                           other,
+	                                                                           flags);
 }
 
 static GVariant *
@@ -806,40 +798,62 @@ clear_blacklist_item (char **item_p)
 	g_free (*item_p);
 }
 
-static void
-nm_setting_wired_init (NMSettingWired *setting)
-{
-	NMSettingWiredPrivate *priv = NM_SETTING_WIRED_GET_PRIVATE (setting);
-
-	priv->s390_options = g_hash_table_new_full (nm_str_hash, g_str_equal, g_free, g_free);
-
-	/* We use GArray rather than GPtrArray so it will automatically be NULL-terminated */
-	priv->mac_address_blacklist = g_array_new (TRUE, FALSE, sizeof (char *));
-	g_array_set_clear_func (priv->mac_address_blacklist, (GDestroyNotify) clear_blacklist_item);
-}
+/*****************************************************************************/
 
 static void
-finalize (GObject *object)
+get_property (GObject *object, guint prop_id,
+              GValue *value, GParamSpec *pspec)
 {
-	NMSettingWiredPrivate *priv = NM_SETTING_WIRED_GET_PRIVATE (object);
-
-	g_free (priv->port);
-	g_free (priv->duplex);
-	g_free (priv->s390_nettype);
-
-	g_hash_table_destroy (priv->s390_options);
-
-	g_free (priv->device_mac_address);
-	g_free (priv->cloned_mac_address);
-	g_free (priv->generate_mac_address_mask);
-	g_array_unref (priv->mac_address_blacklist);
-
-	if (priv->s390_subchannels)
-		g_strfreev (priv->s390_subchannels);
-
-	g_free (priv->wol_password);
+	NMSettingWired *setting = NM_SETTING_WIRED (object);
+	NMSettingWiredPrivate *priv = NM_SETTING_WIRED_GET_PRIVATE (setting);
 
-	G_OBJECT_CLASS (nm_setting_wired_parent_class)->finalize (object);
+	switch (prop_id) {
+	case PROP_PORT:
+		g_value_set_string (value, nm_setting_wired_get_port (setting));
+		break;
+	case PROP_SPEED:
+		g_value_set_uint (value, nm_setting_wired_get_speed (setting));
+		break;
+	case PROP_DUPLEX:
+		g_value_set_string (value, nm_setting_wired_get_duplex (setting));
+		break;
+	case PROP_AUTO_NEGOTIATE:
+		g_value_set_boolean (value, nm_setting_wired_get_auto_negotiate (setting));
+		break;
+	case PROP_MAC_ADDRESS:
+		g_value_set_string (value, nm_setting_wired_get_mac_address (setting));
+		break;
+	case PROP_CLONED_MAC_ADDRESS:
+		g_value_set_string (value, nm_setting_wired_get_cloned_mac_address (setting));
+		break;
+	case PROP_GENERATE_MAC_ADDRESS_MASK:
+		g_value_set_string (value, nm_setting_wired_get_generate_mac_address_mask (setting));
+		break;
+	case PROP_MAC_ADDRESS_BLACKLIST:
+		g_value_set_boxed (value, (char **) priv->mac_address_blacklist->data);
+		break;
+	case PROP_MTU:
+		g_value_set_uint (value, nm_setting_wired_get_mtu (setting));
+		break;
+	case PROP_S390_SUBCHANNELS:
+		g_value_set_boxed (value, priv->s390_subchannels);
+		break;
+	case PROP_S390_NETTYPE:
+		g_value_set_string (value, nm_setting_wired_get_s390_nettype (setting));
+		break;
+	case PROP_S390_OPTIONS:
+		g_value_take_boxed (value, _nm_utils_copy_strdict (priv->s390_options));
+		break;
+	case PROP_WAKE_ON_LAN:
+		g_value_set_uint (value, priv->wol);
+		break;
+	case PROP_WAKE_ON_LAN_PASSWORD:
+		g_value_set_string (value, priv->wol_password);
+		break;
+	default:
+		G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+		break;
+	}
 }
 
 static void
@@ -919,60 +933,55 @@ set_property (GObject *object, guint prop_id,
 	}
 }
 
+/*****************************************************************************/
+
 static void
-get_property (GObject *object, guint prop_id,
-              GValue *value, GParamSpec *pspec)
+nm_setting_wired_init (NMSettingWired *setting)
 {
-	NMSettingWired *setting = NM_SETTING_WIRED (object);
 	NMSettingWiredPrivate *priv = NM_SETTING_WIRED_GET_PRIVATE (setting);
 
-	switch (prop_id) {
-	case PROP_PORT:
-		g_value_set_string (value, nm_setting_wired_get_port (setting));
-		break;
-	case PROP_SPEED:
-		g_value_set_uint (value, nm_setting_wired_get_speed (setting));
-		break;
-	case PROP_DUPLEX:
-		g_value_set_string (value, nm_setting_wired_get_duplex (setting));
-		break;
-	case PROP_AUTO_NEGOTIATE:
-		g_value_set_boolean (value, nm_setting_wired_get_auto_negotiate (setting));
-		break;
-	case PROP_MAC_ADDRESS:
-		g_value_set_string (value, nm_setting_wired_get_mac_address (setting));
-		break;
-	case PROP_CLONED_MAC_ADDRESS:
-		g_value_set_string (value, nm_setting_wired_get_cloned_mac_address (setting));
-		break;
-	case PROP_GENERATE_MAC_ADDRESS_MASK:
-		g_value_set_string (value, nm_setting_wired_get_generate_mac_address_mask (setting));
-		break;
-	case PROP_MAC_ADDRESS_BLACKLIST:
-		g_value_set_boxed (value, (char **) priv->mac_address_blacklist->data);
-		break;
-	case PROP_MTU:
-		g_value_set_uint (value, nm_setting_wired_get_mtu (setting));
-		break;
-	case PROP_S390_SUBCHANNELS:
-		g_value_set_boxed (value, priv->s390_subchannels);
-		break;
-	case PROP_S390_NETTYPE:
-		g_value_set_string (value, nm_setting_wired_get_s390_nettype (setting));
-		break;
-	case PROP_S390_OPTIONS:
-		g_value_take_boxed (value, _nm_utils_copy_strdict (priv->s390_options));
-		break;
-	case PROP_WAKE_ON_LAN:
-		g_value_set_uint (value, priv->wol);
-		break;
-	case PROP_WAKE_ON_LAN_PASSWORD:
-		g_value_set_string (value, priv->wol_password);
-		break;
-	default:
-		G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
-		break;
-	}
+	priv->s390_options = g_hash_table_new_full (nm_str_hash, g_str_equal, g_free, g_free);
+
+	/* We use GArray rather than GPtrArray so it will automatically be NULL-terminated */
+	priv->mac_address_blacklist = g_array_new (TRUE, FALSE, sizeof (char *));
+	g_array_set_clear_func (priv->mac_address_blacklist, (GDestroyNotify) clear_blacklist_item);
+}
+
+/**
+ * nm_setting_wired_new:
+ *
+ * Creates a new #NMSettingWired object with default values.
+ *
+ * Returns: (transfer full): the new empty #NMSettingWired object
+ **/
+NMSetting *
+nm_setting_wired_new (void)
+{
+	return (NMSetting *) g_object_new (NM_TYPE_SETTING_WIRED, NULL);
+}
+
+static void
+finalize (GObject *object)
+{
+	NMSettingWiredPrivate *priv = NM_SETTING_WIRED_GET_PRIVATE (object);
+
+	g_free (priv->port);
+	g_free (priv->duplex);
+	g_free (priv->s390_nettype);
+
+	g_hash_table_destroy (priv->s390_options);
+
+	g_free (priv->device_mac_address);
+	g_free (priv->cloned_mac_address);
+	g_free (priv->generate_mac_address_mask);
+	g_array_unref (priv->mac_address_blacklist);
+
+	if (priv->s390_subchannels)
+		g_strfreev (priv->s390_subchannels);
+
+	g_free (priv->wol_password);
+
+	G_OBJECT_CLASS (nm_setting_wired_parent_class)->finalize (object);
 }
 
 static void
@@ -984,8 +993,8 @@ nm_setting_wired_class_init (NMSettingWiredClass *klass)
 
 	g_type_class_add_private (klass, sizeof (NMSettingWiredPrivate));
 
-	object_class->set_property = set_property;
 	object_class->get_property = get_property;
+	object_class->set_property = set_property;
 	object_class->finalize     = finalize;
 
 	setting_class->verify           = verify;
@@ -1005,12 +1014,11 @@ nm_setting_wired_class_init (NMSettingWiredClass *klass)
 	 * description: The property is not saved by the plugin.
 	 * ---end---
 	 */
-	g_object_class_install_property
-		(object_class, PROP_PORT,
-		 g_param_spec_string (NM_SETTING_WIRED_PORT, "", "",
-		                      NULL,
-		                      G_PARAM_READWRITE |
-		                      G_PARAM_STATIC_STRINGS));
+	obj_properties[PROP_PORT] =
+	    g_param_spec_string (NM_SETTING_WIRED_PORT, "", "",
+	                         NULL,
+	                         G_PARAM_READWRITE |
+	                         G_PARAM_STATIC_STRINGS);
 
 	/**
 	 * NMSettingWired:speed:
@@ -1036,13 +1044,12 @@ nm_setting_wired_class_init (NMSettingWiredClass *klass)
 	 *    parameter in the ETHTOOL_OPTS variable.
 	 * ---end---
 	 */
-	g_object_class_install_property
-		(object_class, PROP_SPEED,
-		 g_param_spec_uint (NM_SETTING_WIRED_SPEED, "", "",
-		                    0, G_MAXUINT32, 0,
-		                    G_PARAM_READWRITE |
-		                    G_PARAM_CONSTRUCT |
-		                    G_PARAM_STATIC_STRINGS));
+	obj_properties[PROP_SPEED] =
+	    g_param_spec_uint (NM_SETTING_WIRED_SPEED, "", "",
+	                       0, G_MAXUINT32, 0,
+	                       G_PARAM_READWRITE |
+	                       G_PARAM_CONSTRUCT |
+	                       G_PARAM_STATIC_STRINGS);
 
 	/**
 	 * NMSettingWired:duplex:
@@ -1067,12 +1074,11 @@ nm_setting_wired_class_init (NMSettingWiredClass *klass)
 	 *    "duplex" parameter in the ETHOOL_OPTS variable.
 	 * ---end---
 	 */
-	g_object_class_install_property
-		(object_class, PROP_DUPLEX,
-		 g_param_spec_string (NM_SETTING_WIRED_DUPLEX, "", "",
-		                      NULL,
-		                      G_PARAM_READWRITE |
-		                      G_PARAM_STATIC_STRINGS));
+	obj_properties[PROP_DUPLEX] =
+	    g_param_spec_string (NM_SETTING_WIRED_DUPLEX, "", "",
+	                         NULL,
+	                         G_PARAM_READWRITE |
+	                         G_PARAM_STATIC_STRINGS);
 
 	/**
 	 * NMSettingWired:auto-negotiate:
@@ -1094,17 +1100,15 @@ nm_setting_wired_class_init (NMSettingWiredClass *klass)
 	 *    "speed" and "duplex" parameters (skips link configuration).
 	 * ---end---
 	 */
-	g_object_class_install_property
-		(object_class, PROP_AUTO_NEGOTIATE,
-		 g_param_spec_boolean (NM_SETTING_WIRED_AUTO_NEGOTIATE, "", "",
-		                       FALSE,
-		                       G_PARAM_READWRITE |
-		                       G_PARAM_CONSTRUCT |
-		                       G_PARAM_STATIC_STRINGS));
+	obj_properties[PROP_AUTO_NEGOTIATE] =
+	    g_param_spec_boolean (NM_SETTING_WIRED_AUTO_NEGOTIATE, "", "",
+	                          FALSE,
+	                          G_PARAM_READWRITE |
+	                          G_PARAM_CONSTRUCT |
+	                          G_PARAM_STATIC_STRINGS);
 
 	_properties_override_add_override (properties_override,
-	                                   g_object_class_find_property (G_OBJECT_CLASS (setting_class),
-	                                                                 NM_SETTING_WIRED_AUTO_NEGOTIATE),
+	                                   obj_properties[PROP_AUTO_NEGOTIATE],
 	                                   G_VARIANT_TYPE_BOOLEAN,
 	                                   _override_autoneg_get,
 	                                   NULL,
@@ -1134,17 +1138,15 @@ nm_setting_wired_class_init (NMSettingWiredClass *klass)
 	 *    permanent MAC address exists, the MAC address initially configured on the device.
 	 * ---end---
 	 */
-	g_object_class_install_property
-		(object_class, PROP_MAC_ADDRESS,
-		 g_param_spec_string (NM_SETTING_WIRED_MAC_ADDRESS, "", "",
-		                      NULL,
-		                      G_PARAM_READWRITE |
-		                      NM_SETTING_PARAM_INFERRABLE |
-		                      G_PARAM_STATIC_STRINGS));
+	obj_properties[PROP_MAC_ADDRESS] =
+	    g_param_spec_string (NM_SETTING_WIRED_MAC_ADDRESS, "", "",
+	                         NULL,
+	                         G_PARAM_READWRITE |
+	                         NM_SETTING_PARAM_INFERRABLE |
+	                         G_PARAM_STATIC_STRINGS);
 
 	_properties_override_add_transform (properties_override,
-	                                    g_object_class_find_property (G_OBJECT_CLASS (setting_class),
-	                                                                  NM_SETTING_WIRED_MAC_ADDRESS),
+	                                    obj_properties[PROP_MAC_ADDRESS],
 	                                    G_VARIANT_TYPE_BYTESTRING,
 	                                    _nm_utils_hwaddr_to_dbus,
 	                                    _nm_utils_hwaddr_from_dbus);
@@ -1192,17 +1194,15 @@ nm_setting_wired_class_init (NMSettingWiredClass *klass)
 	 *    For libnm and nmcli, this field is called "cloned-mac-address".
 	 * ---end---
 	 */
-	g_object_class_install_property
-		(object_class, PROP_CLONED_MAC_ADDRESS,
-		 g_param_spec_string (NM_SETTING_WIRED_CLONED_MAC_ADDRESS, "", "",
-		                      NULL,
-		                      G_PARAM_READWRITE |
-		                      NM_SETTING_PARAM_INFERRABLE |
-		                      G_PARAM_STATIC_STRINGS));
+	obj_properties[PROP_CLONED_MAC_ADDRESS] =
+	    g_param_spec_string (NM_SETTING_WIRED_CLONED_MAC_ADDRESS, "", "",
+	                         NULL,
+	                         G_PARAM_READWRITE |
+	                         NM_SETTING_PARAM_INFERRABLE |
+	                         G_PARAM_STATIC_STRINGS);
 
 	_properties_override_add_override (properties_override,
-	                                     g_object_class_find_property (G_OBJECT_CLASS (setting_class),
-	                                                                   NM_SETTING_WIRED_CLONED_MAC_ADDRESS),
+	                                     obj_properties[PROP_CLONED_MAC_ADDRESS],
 	                                     G_VARIANT_TYPE_BYTESTRING,
 	                                     _nm_utils_hwaddr_cloned_get,
 	                                     _nm_utils_hwaddr_cloned_set,
@@ -1215,7 +1215,7 @@ nm_setting_wired_class_init (NMSettingWiredClass *klass)
 	 *   a hardware address in ASCII representation, or one of the special values
 	 *   "preserve", "permanent", "random" or "stable".
 	 *   This field replaces the deprecated "cloned-mac-address" on D-Bus, which
-	 *   can only contain explict hardware addresses. Note that this property
+	 *   can only contain explicit hardware addresses. Note that this property
 	 *   only exists in D-Bus API. libnm and nmcli continue to call this property
 	 *   "cloned-mac-address".
 	 * ---end---
@@ -1265,13 +1265,12 @@ nm_setting_wired_class_init (NMSettingWiredClass *klass)
 	 *   cloned-mac-address.
 	 * ---end---
 	 */
-	g_object_class_install_property
-	    (object_class, PROP_GENERATE_MAC_ADDRESS_MASK,
+	obj_properties[PROP_GENERATE_MAC_ADDRESS_MASK] =
 	     g_param_spec_string (NM_SETTING_WIRED_GENERATE_MAC_ADDRESS_MASK, "", "",
 	                          NULL,
 	                          G_PARAM_READWRITE |
 	                          NM_SETTING_PARAM_FUZZY_IGNORE |
-	                          G_PARAM_STATIC_STRINGS));
+	                          G_PARAM_STATIC_STRINGS);
 
 	/**
 	 * NMSettingWired:mac-address-blacklist:
@@ -1295,13 +1294,12 @@ nm_setting_wired_class_init (NMSettingWiredClass *klass)
 	 * example: HWADDR_BLACKLIST="00:22:68:11:69:08 00:11:22:11:44:55"
 	 * ---end---
 	 */
-	g_object_class_install_property
-		(object_class, PROP_MAC_ADDRESS_BLACKLIST,
-		 g_param_spec_boxed (NM_SETTING_WIRED_MAC_ADDRESS_BLACKLIST, "", "",
-		                     G_TYPE_STRV,
-		                     G_PARAM_READWRITE |
-		                     NM_SETTING_PARAM_FUZZY_IGNORE |
-		                     G_PARAM_STATIC_STRINGS));
+	obj_properties[PROP_MAC_ADDRESS_BLACKLIST] =
+	    g_param_spec_boxed (NM_SETTING_WIRED_MAC_ADDRESS_BLACKLIST, "", "",
+	                        G_TYPE_STRV,
+	                        G_PARAM_READWRITE |
+	                        NM_SETTING_PARAM_FUZZY_IGNORE |
+	                        G_PARAM_STATIC_STRINGS);
 
 	/**
 	 * NMSettingWired:mtu:
@@ -1315,14 +1313,13 @@ nm_setting_wired_class_init (NMSettingWiredClass *klass)
 	 * description: MTU of the interface.
 	 * ---end---
 	 */
-	g_object_class_install_property
-		(object_class, PROP_MTU,
-		 g_param_spec_uint (NM_SETTING_WIRED_MTU, "", "",
-		                    0, G_MAXUINT32, 0,
-		                    G_PARAM_READWRITE |
-		                    G_PARAM_CONSTRUCT |
-		                    NM_SETTING_PARAM_FUZZY_IGNORE |
-		                    G_PARAM_STATIC_STRINGS));
+	obj_properties[PROP_MTU] =
+	    g_param_spec_uint (NM_SETTING_WIRED_MTU, "", "",
+	                       0, G_MAXUINT32, 0,
+	                       G_PARAM_READWRITE |
+	                       G_PARAM_CONSTRUCT |
+	                       NM_SETTING_PARAM_FUZZY_IGNORE |
+	                       G_PARAM_STATIC_STRINGS);
 
 	/**
 	 * NMSettingWired:s390-subchannels:
@@ -1342,13 +1339,12 @@ nm_setting_wired_class_init (NMSettingWiredClass *klass)
 	 * example: SUBCHANNELS=0.0.b00a,0.0.b00b,0.0.b00c
 	 * ---end---
 	 */
-	g_object_class_install_property
-		(object_class, PROP_S390_SUBCHANNELS,
-		 g_param_spec_boxed (NM_SETTING_WIRED_S390_SUBCHANNELS, "", "",
-		                     G_TYPE_STRV,
-		                     G_PARAM_READWRITE |
-		                     NM_SETTING_PARAM_INFERRABLE |
-		                     G_PARAM_STATIC_STRINGS));
+	obj_properties[PROP_S390_SUBCHANNELS] =
+	    g_param_spec_boxed (NM_SETTING_WIRED_S390_SUBCHANNELS, "", "",
+	                        G_TYPE_STRV,
+	                        G_PARAM_READWRITE |
+	                        NM_SETTING_PARAM_INFERRABLE |
+	                        G_PARAM_STATIC_STRINGS);
 
 	/**
 	 * NMSettingWired:s390-nettype:
@@ -1364,13 +1360,12 @@ nm_setting_wired_class_init (NMSettingWiredClass *klass)
 	 * example: NETTYPE=qeth
 	 * ---end---
 	 */
-	g_object_class_install_property
-		(object_class, PROP_S390_NETTYPE,
-		 g_param_spec_string (NM_SETTING_WIRED_S390_NETTYPE, "", "",
-		                      NULL,
-		                      G_PARAM_READWRITE |
-		                      NM_SETTING_PARAM_INFERRABLE |
-		                      G_PARAM_STATIC_STRINGS));
+	obj_properties[PROP_S390_NETTYPE] =
+	    g_param_spec_string (NM_SETTING_WIRED_S390_NETTYPE, "", "",
+	                         NULL,
+	                         G_PARAM_READWRITE |
+	                         NM_SETTING_PARAM_INFERRABLE |
+	                         G_PARAM_STATIC_STRINGS);
 
 	/**
 	 * NMSettingWired:s390-options: (type GHashTable(utf8,utf8)):
@@ -1387,17 +1382,15 @@ nm_setting_wired_class_init (NMSettingWiredClass *klass)
 	 *   "portname" and "ctcprot" that have their own variables.
 	 * ---end---
 	 */
-	g_object_class_install_property
-		(object_class, PROP_S390_OPTIONS,
-		 g_param_spec_boxed (NM_SETTING_WIRED_S390_OPTIONS, "", "",
-		                     G_TYPE_HASH_TABLE,
-		                     G_PARAM_READWRITE |
-		                     NM_SETTING_PARAM_INFERRABLE |
-		                     G_PARAM_STATIC_STRINGS));
+	obj_properties[PROP_S390_OPTIONS] =
+	    g_param_spec_boxed (NM_SETTING_WIRED_S390_OPTIONS, "", "",
+	                        G_TYPE_HASH_TABLE,
+	                        G_PARAM_READWRITE |
+	                        NM_SETTING_PARAM_INFERRABLE |
+	                        G_PARAM_STATIC_STRINGS);
 
 	_properties_override_add_transform (properties_override,
-	                                    g_object_class_find_property (G_OBJECT_CLASS (setting_class),
-	                                                                  NM_SETTING_WIRED_S390_OPTIONS),
+	                                    obj_properties[PROP_S390_OPTIONS],
 	                                    G_VARIANT_TYPE ("a{ss}"),
 	                                    _nm_utils_strdict_to_dbus,
 	                                    _nm_utils_strdict_from_dbus);
@@ -1416,13 +1409,12 @@ nm_setting_wired_class_init (NMSettingWiredClass *klass)
 	 *
 	 * Since: 1.2
 	 **/
-	g_object_class_install_property
-		(object_class, PROP_WAKE_ON_LAN,
-		 g_param_spec_uint (NM_SETTING_WIRED_WAKE_ON_LAN, "", "",
-		                    0, G_MAXUINT32, NM_SETTING_WIRED_WAKE_ON_LAN_DEFAULT,
-		                    G_PARAM_CONSTRUCT |
-		                    G_PARAM_READWRITE |
-		                    G_PARAM_STATIC_STRINGS));
+	obj_properties[PROP_WAKE_ON_LAN] =
+	    g_param_spec_uint (NM_SETTING_WIRED_WAKE_ON_LAN, "", "",
+	                       0, G_MAXUINT32, NM_SETTING_WIRED_WAKE_ON_LAN_DEFAULT,
+	                       G_PARAM_CONSTRUCT |
+	                       G_PARAM_READWRITE |
+	                       G_PARAM_STATIC_STRINGS);
 
 	/**
 	 * NMSettingWired:wake-on-lan-password:
@@ -1433,12 +1425,13 @@ nm_setting_wired_class_init (NMSettingWiredClass *klass)
 	 *
 	 * Since: 1.2
 	 **/
-	g_object_class_install_property
-		(object_class, PROP_WAKE_ON_LAN_PASSWORD,
-		 g_param_spec_string (NM_SETTING_WIRED_WAKE_ON_LAN_PASSWORD, "", "",
-		                      NULL,
-		                      G_PARAM_READWRITE |
-		                      G_PARAM_STATIC_STRINGS));
+	obj_properties[PROP_WAKE_ON_LAN_PASSWORD] =
+	    g_param_spec_string (NM_SETTING_WIRED_WAKE_ON_LAN_PASSWORD, "", "",
+	                         NULL,
+	                         G_PARAM_READWRITE |
+	                         G_PARAM_STATIC_STRINGS);
+
+	g_object_class_install_properties (object_class, _PROPERTY_ENUMS_LAST, obj_properties);
 
 	_nm_setting_class_commit_full (setting_class, NM_META_SETTING_TYPE_WIRED,
 	                               NULL, properties_override);
diff --git a/libnm-core/nm-setting-wireless-security.c b/libnm-core/nm-setting-wireless-security.c
index d1527821..fe339d9e 100644
--- a/libnm-core/nm-setting-wireless-security.c
+++ b/libnm-core/nm-setting-wireless-security.c
@@ -22,9 +22,10 @@
 
 #include "nm-default.h"
 
+#include "nm-setting-wireless-security.h"
+
 #include <string.h>
 
-#include "nm-setting-wireless-security.h"
 #include "nm-setting-8021x.h"
 #include "nm-utils.h"
 #include "nm-utils-private.h"
@@ -53,9 +54,30 @@
  *       ISBN: 978-1587051548
  **/
 
-G_DEFINE_TYPE (NMSettingWirelessSecurity, nm_setting_wireless_security, NM_TYPE_SETTING)
+/*****************************************************************************/
 
-#define NM_SETTING_WIRELESS_SECURITY_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), NM_TYPE_SETTING_WIRELESS_SECURITY, NMSettingWirelessSecurityPrivate))
+NM_GOBJECT_PROPERTIES_DEFINE (NMSettingWirelessSecurity,
+	PROP_KEY_MGMT,
+	PROP_WEP_TX_KEYIDX,
+	PROP_AUTH_ALG,
+	PROP_PROTO,
+	PROP_PAIRWISE,
+	PROP_GROUP,
+	PROP_PMF,
+	PROP_LEAP_USERNAME,
+	PROP_WEP_KEY0,
+	PROP_WEP_KEY1,
+	PROP_WEP_KEY2,
+	PROP_WEP_KEY3,
+	PROP_WEP_KEY_FLAGS,
+	PROP_WEP_KEY_TYPE,
+	PROP_PSK,
+	PROP_PSK_FLAGS,
+	PROP_LEAP_PASSWORD,
+	PROP_LEAP_PASSWORD_FLAGS,
+	PROP_WPS_METHOD,
+	PROP_FILS,
+);
 
 typedef struct {
 	char *key_mgmt;
@@ -90,44 +112,11 @@ typedef struct {
 	NMSettingWirelessSecurityFils fils;
 } NMSettingWirelessSecurityPrivate;
 
-enum {
-	PROP_0,
-	PROP_KEY_MGMT,
-	PROP_WEP_TX_KEYIDX,
-	PROP_AUTH_ALG,
-	PROP_PROTO,
-	PROP_PAIRWISE,
-	PROP_GROUP,
-	PROP_PMF,
-	PROP_LEAP_USERNAME,
-	PROP_WEP_KEY0,
-	PROP_WEP_KEY1,
-	PROP_WEP_KEY2,
-	PROP_WEP_KEY3,
-	PROP_WEP_KEY_FLAGS,
-	PROP_WEP_KEY_TYPE,
-	PROP_PSK,
-	PROP_PSK_FLAGS,
-	PROP_LEAP_PASSWORD,
-	PROP_LEAP_PASSWORD_FLAGS,
-	PROP_WPS_METHOD,
-	PROP_FILS,
+G_DEFINE_TYPE (NMSettingWirelessSecurity, nm_setting_wireless_security, NM_TYPE_SETTING)
 
-	LAST_PROP
-};
+#define NM_SETTING_WIRELESS_SECURITY_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), NM_TYPE_SETTING_WIRELESS_SECURITY, NMSettingWirelessSecurityPrivate))
 
-/**
- * nm_setting_wireless_security_new:
- *
- * Creates a new #NMSettingWirelessSecurity object with default values.
- *
- * Returns: (transfer full): the new empty #NMSettingWirelessSecurity object
- **/
-NMSetting *
-nm_setting_wireless_security_new (void)
-{
-	return (NMSetting *) g_object_new (NM_TYPE_SETTING_WIRELESS_SECURITY, NULL);
-}
+/*****************************************************************************/
 
 /**
  * nm_setting_wireless_security_get_key_mgmt:
@@ -209,7 +198,7 @@ nm_setting_wireless_security_add_proto (NMSettingWirelessSecurity *setting, cons
 	}
 
 	priv->proto = g_slist_append (priv->proto, g_ascii_strdown (proto, -1));
-	g_object_notify (G_OBJECT (setting), NM_SETTING_WIRELESS_SECURITY_PROTO);
+	_notify (setting, PROP_PROTO);
 	return TRUE;
 }
 
@@ -234,7 +223,7 @@ nm_setting_wireless_security_remove_proto (NMSettingWirelessSecurity *setting, g
 
 	g_free (elt->data);
 	priv->proto = g_slist_delete_link (priv->proto, elt);
-	g_object_notify (G_OBJECT (setting), NM_SETTING_WIRELESS_SECURITY_PROTO);
+	_notify (setting, PROP_PROTO);
 }
 
 /**
@@ -260,7 +249,7 @@ nm_setting_wireless_security_remove_proto_by_value (NMSettingWirelessSecurity *s
 	for (iter = priv->proto; iter; iter = g_slist_next (iter)) {
 		if (strcasecmp (proto, (char *) iter->data) == 0) {
 			priv->proto = g_slist_delete_link (priv->proto, iter);
-			g_object_notify (G_OBJECT (setting), NM_SETTING_WIRELESS_SECURITY_PROTO);
+			_notify (setting, PROP_PROTO);
 			return TRUE;
 		}
 	}
@@ -284,7 +273,7 @@ nm_setting_wireless_security_clear_protos (NMSettingWirelessSecurity *setting)
 	priv = NM_SETTING_WIRELESS_SECURITY_GET_PRIVATE (setting);
 	g_slist_free_full (priv->proto, g_free);
 	priv->proto = NULL;
-	g_object_notify (G_OBJECT (setting), NM_SETTING_WIRELESS_SECURITY_PROTO);
+	_notify (setting, PROP_PROTO);
 }
 
 /**
@@ -353,7 +342,7 @@ nm_setting_wireless_security_add_pairwise (NMSettingWirelessSecurity *setting, c
 	}
 
 	priv->pairwise = g_slist_append (priv->pairwise, g_ascii_strdown (pairwise, -1));
-	g_object_notify (G_OBJECT (setting), NM_SETTING_WIRELESS_SECURITY_PAIRWISE);
+	_notify (setting, PROP_PAIRWISE);
 	return TRUE;
 }
 
@@ -379,7 +368,7 @@ nm_setting_wireless_security_remove_pairwise (NMSettingWirelessSecurity *setting
 
 	g_free (elt->data);
 	priv->pairwise = g_slist_delete_link (priv->pairwise, elt);
-	g_object_notify (G_OBJECT (setting), NM_SETTING_WIRELESS_SECURITY_PAIRWISE);
+	_notify (setting, PROP_PAIRWISE);
 }
 
 /**
@@ -390,7 +379,7 @@ nm_setting_wireless_security_remove_pairwise (NMSettingWirelessSecurity *setting
  * Removes an encryption algorithm from the allowed pairwise encryption
  * algorithm list.
  *
- * Returns: %TRUE if the encryption algorith was found and removed; %FALSE if it was not.
+ * Returns: %TRUE if the encryption algorithm was found and removed; %FALSE if it was not.
  **/
 gboolean
 nm_setting_wireless_security_remove_pairwise_by_value (NMSettingWirelessSecurity *setting,
@@ -406,7 +395,7 @@ nm_setting_wireless_security_remove_pairwise_by_value (NMSettingWirelessSecurity
 	for (iter = priv->pairwise; iter; iter = g_slist_next (iter)) {
 		if (strcasecmp (pairwise, (char *) iter->data) == 0) {
 			priv->pairwise = g_slist_delete_link (priv->pairwise, iter);
-			g_object_notify (G_OBJECT (setting), NM_SETTING_WIRELESS_SECURITY_PAIRWISE);
+			_notify (setting, PROP_PAIRWISE);
 			return TRUE;
 		}
 	}
@@ -430,7 +419,7 @@ nm_setting_wireless_security_clear_pairwise (NMSettingWirelessSecurity *setting)
 	priv = NM_SETTING_WIRELESS_SECURITY_GET_PRIVATE (setting);
 	g_slist_free_full (priv->pairwise, g_free);
 	priv->pairwise = NULL;
-	g_object_notify (G_OBJECT (setting), NM_SETTING_WIRELESS_SECURITY_PAIRWISE);
+	_notify (setting, PROP_PAIRWISE);
 }
 
 /**
@@ -500,7 +489,7 @@ nm_setting_wireless_security_add_group (NMSettingWirelessSecurity *setting, cons
 	}
 
 	priv->group = g_slist_append (priv->group, g_ascii_strdown (group, -1));
-	g_object_notify (G_OBJECT (setting), NM_SETTING_WIRELESS_SECURITY_GROUP);
+	_notify (setting, PROP_GROUP);
 	return TRUE;
 }
 
@@ -526,7 +515,7 @@ nm_setting_wireless_security_remove_group (NMSettingWirelessSecurity *setting, g
 
 	g_free (elt->data);
 	priv->group = g_slist_delete_link (priv->group, elt);
-	g_object_notify (G_OBJECT (setting), NM_SETTING_WIRELESS_SECURITY_GROUP);
+	_notify (setting, PROP_GROUP);
 }
 
 /**
@@ -554,7 +543,7 @@ nm_setting_wireless_security_remove_group_by_value (NMSettingWirelessSecurity *s
 	for (iter = priv->group; iter; iter = g_slist_next (iter)) {
 		if (strcasecmp (group, (char *) iter->data) == 0) {
 			priv->group = g_slist_delete_link (priv->group, iter);
-			g_object_notify (G_OBJECT (setting), NM_SETTING_WIRELESS_SECURITY_GROUP);
+			_notify (setting, PROP_GROUP);
 			return TRUE;
 		}
 	}
@@ -578,7 +567,7 @@ nm_setting_wireless_security_clear_groups (NMSettingWirelessSecurity *setting)
 	priv = NM_SETTING_WIRELESS_SECURITY_GET_PRIVATE (setting);
 	g_slist_free_full (priv->group, g_free);
 	priv->group = NULL;
-	g_object_notify (G_OBJECT (setting), NM_SETTING_WIRELESS_SECURITY_GROUP);
+	_notify (setting, PROP_GROUP);
 }
 
 /*
@@ -721,22 +710,22 @@ nm_setting_wireless_security_set_wep_key (NMSettingWirelessSecurity *setting, gu
 	case 0:
 		g_free (priv->wep_key0);
 		priv->wep_key0 = g_strdup (key);
-		g_object_notify (G_OBJECT (setting), NM_SETTING_WIRELESS_SECURITY_WEP_KEY0);
+		_notify (setting, PROP_WEP_KEY0);
 		break;
 	case 1:
 		g_free (priv->wep_key1);
 		priv->wep_key1 = g_strdup (key);
-		g_object_notify (G_OBJECT (setting), NM_SETTING_WIRELESS_SECURITY_WEP_KEY1);
+		_notify (setting, PROP_WEP_KEY1);
 		break;
 	case 2:
 		g_free (priv->wep_key2);
 		priv->wep_key2 = g_strdup (key);
-		g_object_notify (G_OBJECT (setting), NM_SETTING_WIRELESS_SECURITY_WEP_KEY2);
+		_notify (setting, PROP_WEP_KEY2);
 		break;
 	case 3:
 		g_free (priv->wep_key3);
 		priv->wep_key3 = g_strdup (key);
-		g_object_notify (G_OBJECT (setting), NM_SETTING_WIRELESS_SECURITY_WEP_KEY3);
+		_notify (setting, PROP_WEP_KEY3);
 		break;
 	default:
 		g_assert_not_reached ();
@@ -1177,83 +1166,56 @@ verify_secrets (NMSetting *setting, NMConnection *connection, GError **error)
 static gboolean
 get_secret_flags (NMSetting *setting,
                   const char *secret_name,
-                  gboolean verify_secret,
                   NMSettingSecretFlags *out_flags,
                   GError **error)
 {
-	NMSettingClass *setting_class;
-	gboolean verify_override = verify_secret;
-
-	/* There's only one 'flags' property for WEP keys, so alias all the WEP key
-	 * property names to that flags property.
-	 */
-	if (   !g_strcmp0 (secret_name, NM_SETTING_WIRELESS_SECURITY_WEP_KEY0)
-	    || !g_strcmp0 (secret_name, NM_SETTING_WIRELESS_SECURITY_WEP_KEY1)
-	    || !g_strcmp0 (secret_name, NM_SETTING_WIRELESS_SECURITY_WEP_KEY2)
-	    || !g_strcmp0 (secret_name, NM_SETTING_WIRELESS_SECURITY_WEP_KEY3)) {
-		secret_name = "wep-key";
-		verify_override = FALSE; /* Already know it's a secret */
+	NMSettingSecretFlags flags;
+
+	if (NM_IN_STRSET (secret_name, NM_SETTING_WIRELESS_SECURITY_WEP_KEY0,
+	                               NM_SETTING_WIRELESS_SECURITY_WEP_KEY1,
+	                               NM_SETTING_WIRELESS_SECURITY_WEP_KEY2,
+	                               NM_SETTING_WIRELESS_SECURITY_WEP_KEY3)) {
+		/* There's only one 'flags' property for WEP keys, so alias all the WEP key
+		 * property names to that flags property. */
+		nm_assert (_nm_setting_property_is_regular_secret (setting, secret_name));
+		nm_assert (_nm_setting_property_is_regular_secret_flags (setting, NM_SETTING_WIRELESS_SECURITY_WEP_KEY_FLAGS));
+
+		g_object_get (G_OBJECT (setting),
+		              NM_SETTING_WIRELESS_SECURITY_WEP_KEY_FLAGS,
+		              &flags,
+		              NULL);
+		NM_SET_OUT (out_flags, flags);
+		return TRUE;
 	}
 
-	/* Chain up to superclass with modified key name */
-	setting_class = NM_SETTING_CLASS (nm_setting_wireless_security_parent_class);
-	return setting_class->get_secret_flags (setting, secret_name, verify_override, out_flags, error);
+	return NM_SETTING_CLASS (nm_setting_wireless_security_parent_class)->get_secret_flags (setting, secret_name, out_flags, error);
 }
 
 static gboolean
 set_secret_flags (NMSetting *setting,
                   const char *secret_name,
-                  gboolean verify_secret,
                   NMSettingSecretFlags flags,
                   GError **error)
 {
-	NMSettingClass *setting_class;
-	gboolean verify_override = verify_secret;
-
-	/* There's only one 'flags' property for WEP keys, so alias all the WEP key
-	 * property names to that flags property.
-	 */
-	if (   !g_strcmp0 (secret_name, NM_SETTING_WIRELESS_SECURITY_WEP_KEY0)
-	    || !g_strcmp0 (secret_name, NM_SETTING_WIRELESS_SECURITY_WEP_KEY1)
-	    || !g_strcmp0 (secret_name, NM_SETTING_WIRELESS_SECURITY_WEP_KEY2)
-	    || !g_strcmp0 (secret_name, NM_SETTING_WIRELESS_SECURITY_WEP_KEY3)) {
-		secret_name = "wep-key";
-		verify_override = FALSE; /* Already know it's a secret */
+	if (NM_IN_STRSET (secret_name, NM_SETTING_WIRELESS_SECURITY_WEP_KEY0,
+	                               NM_SETTING_WIRELESS_SECURITY_WEP_KEY1,
+	                               NM_SETTING_WIRELESS_SECURITY_WEP_KEY2,
+	                               NM_SETTING_WIRELESS_SECURITY_WEP_KEY3)) {
+		/* There's only one 'flags' property for WEP keys, so alias all the WEP key
+		 * property names to that flags property. */
+		nm_assert (_nm_setting_property_is_regular_secret (setting, secret_name));
+		nm_assert (_nm_setting_property_is_regular_secret_flags (setting, NM_SETTING_WIRELESS_SECURITY_WEP_KEY_FLAGS));
+
+		if (!nm_g_object_set_property_flags (G_OBJECT (setting),
+		                                     NM_SETTING_WIRELESS_SECURITY_WEP_KEY_FLAGS,
+		                                     NM_TYPE_SETTING_SECRET_FLAGS,
+		                                     flags,
+		                                     error))
+			g_return_val_if_reached (FALSE);
+		return TRUE;
 	}
 
-	/* Chain up to superclass with modified key name */
-	setting_class = NM_SETTING_CLASS (nm_setting_wireless_security_parent_class);
-	return setting_class->set_secret_flags (setting, secret_name, verify_override, flags, error);
-}
-
-static void
-nm_setting_wireless_security_init (NMSettingWirelessSecurity *setting)
-{
-}
-
-static void
-finalize (GObject *object)
-{
-	NMSettingWirelessSecurity *self = NM_SETTING_WIRELESS_SECURITY (object);
-	NMSettingWirelessSecurityPrivate *priv = NM_SETTING_WIRELESS_SECURITY_GET_PRIVATE (self);
-
-	/* Strings first. g_free() already checks for NULLs so we don't have to */
-
-	g_free (priv->key_mgmt);
-	g_free (priv->auth_alg);
-	g_free (priv->leap_username);
-	g_free (priv->wep_key0);
-	g_free (priv->wep_key1);
-	g_free (priv->wep_key2);
-	g_free (priv->wep_key3);
-	g_free (priv->psk);
-	g_free (priv->leap_password);
-
-	g_slist_free_full (priv->proto, g_free);
-	g_slist_free_full (priv->pairwise, g_free);
-	g_slist_free_full (priv->group, g_free);
-
-	G_OBJECT_CLASS (nm_setting_wireless_security_parent_class)->finalize (object);
+	return NM_SETTING_CLASS (nm_setting_wireless_security_parent_class)->set_secret_flags (setting, secret_name, flags, error);
 }
 
 /* NMSettingWirelessSecurity:wep-key-type is an enum, but needs to be marshalled
@@ -1265,88 +1227,75 @@ wep_key_type_to_dbus (const GValue *from)
 	return g_variant_new_uint32 (g_value_get_enum (from));
 }
 
+/*****************************************************************************/
+
 static void
-set_property (GObject *object, guint prop_id,
-              const GValue *value, GParamSpec *pspec)
+get_property (GObject *object, guint prop_id,
+              GValue *value, GParamSpec *pspec)
 {
 	NMSettingWirelessSecurity *setting = NM_SETTING_WIRELESS_SECURITY (object);
 	NMSettingWirelessSecurityPrivate *priv = NM_SETTING_WIRELESS_SECURITY_GET_PRIVATE (setting);
-	const char *str;
 
 	switch (prop_id) {
 	case PROP_KEY_MGMT:
-		g_free (priv->key_mgmt);
-		str = g_value_get_string (value);
-		priv->key_mgmt = str ? g_ascii_strdown (str, -1) : NULL;
+		g_value_set_string (value, priv->key_mgmt);
 		break;
 	case PROP_WEP_TX_KEYIDX:
-		priv->wep_tx_keyidx = g_value_get_uint (value);
+		g_value_set_uint (value, priv->wep_tx_keyidx);
 		break;
 	case PROP_AUTH_ALG:
-		g_free (priv->auth_alg);
-		str = g_value_get_string (value);
-		priv->auth_alg = str ? g_ascii_strdown (str, -1) : NULL;
+		g_value_set_string (value, priv->auth_alg);
 		break;
 	case PROP_PROTO:
-		g_slist_free_full (priv->proto, g_free);
-		priv->proto = _nm_utils_strv_to_slist (g_value_get_boxed (value), TRUE);
+		g_value_take_boxed (value, _nm_utils_slist_to_strv (priv->proto, TRUE));
 		break;
 	case PROP_PAIRWISE:
-		g_slist_free_full (priv->pairwise, g_free);
-		priv->pairwise = _nm_utils_strv_to_slist (g_value_get_boxed (value), TRUE);
+		g_value_take_boxed (value, _nm_utils_slist_to_strv (priv->pairwise, TRUE));
 		break;
 	case PROP_GROUP:
-		g_slist_free_full (priv->group, g_free);
-		priv->group = _nm_utils_strv_to_slist (g_value_get_boxed (value), TRUE);
+		g_value_take_boxed (value, _nm_utils_slist_to_strv (priv->group, TRUE));
 		break;
 	case PROP_PMF:
-		priv->pmf = g_value_get_int (value);
+		g_value_set_int (value, nm_setting_wireless_security_get_pmf (setting));
 		break;
 	case PROP_LEAP_USERNAME:
-		g_free (priv->leap_username);
-		priv->leap_username = g_value_dup_string (value);
+		g_value_set_string (value, priv->leap_username);
 		break;
 	case PROP_WEP_KEY0:
-		g_free (priv->wep_key0);
-		priv->wep_key0 = g_value_dup_string (value);
+		g_value_set_string (value, priv->wep_key0);
 		break;
 	case PROP_WEP_KEY1:
-		g_free (priv->wep_key1);
-		priv->wep_key1 = g_value_dup_string (value);
+		g_value_set_string (value, priv->wep_key1);
 		break;
 	case PROP_WEP_KEY2:
-		g_free (priv->wep_key2);
-		priv->wep_key2 = g_value_dup_string (value);
+		g_value_set_string (value, priv->wep_key2);
 		break;
 	case PROP_WEP_KEY3:
-		g_free (priv->wep_key3);
-		priv->wep_key3 = g_value_dup_string (value);
+		g_value_set_string (value, priv->wep_key3);
 		break;
 	case PROP_WEP_KEY_FLAGS:
-		priv->wep_key_flags = g_value_get_flags (value);
+		g_value_set_flags (value, priv->wep_key_flags);
 		break;
 	case PROP_PSK:
-		g_free (priv->psk);
-		priv->psk = g_value_dup_string (value);
+		g_value_set_string (value, priv->psk);
 		break;
 	case PROP_PSK_FLAGS:
-		priv->psk_flags = g_value_get_flags (value);
+		g_value_set_flags (value, priv->psk_flags);
 		break;
 	case PROP_LEAP_PASSWORD:
-		g_free (priv->leap_password);
-		priv->leap_password = g_value_dup_string (value);
+		g_value_set_string (value, priv->leap_password);
 		break;
 	case PROP_LEAP_PASSWORD_FLAGS:
-		priv->leap_password_flags = g_value_get_flags (value);
+		g_value_set_flags (value, priv->leap_password_flags);
 		break;
 	case PROP_WEP_KEY_TYPE:
-		priv->wep_key_type = g_value_get_enum (value);
+		g_value_set_enum (value, priv->wep_key_type);
 		break;
 	case PROP_WPS_METHOD:
-		priv->wps_method = g_value_get_uint (value);
+		g_value_set_uint (value, priv->wps_method);
 		break;
 	case PROP_FILS:
-		priv->fils = g_value_get_int (value);
+		g_value_set_int (value, nm_setting_wireless_security_get_fils (setting));
 		break;
 	default:
 		G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
@@ -1355,72 +1304,87 @@ set_property (GObject *object, guint prop_id,
 }
 
 static void
-get_property (GObject *object, guint prop_id,
-              GValue *value, GParamSpec *pspec)
+set_property (GObject *object, guint prop_id,
+              const GValue *value, GParamSpec *pspec)
 {
 	NMSettingWirelessSecurity *setting = NM_SETTING_WIRELESS_SECURITY (object);
 	NMSettingWirelessSecurityPrivate *priv = NM_SETTING_WIRELESS_SECURITY_GET_PRIVATE (setting);
+	const char *str;
 
 	switch (prop_id) {
 	case PROP_KEY_MGMT:
-		g_value_set_string (value, priv->key_mgmt);
+		g_free (priv->key_mgmt);
+		str = g_value_get_string (value);
+		priv->key_mgmt = str ? g_ascii_strdown (str, -1) : NULL;
 		break;
 	case PROP_WEP_TX_KEYIDX:
-		g_value_set_uint (value, priv->wep_tx_keyidx);
+		priv->wep_tx_keyidx = g_value_get_uint (value);
 		break;
 	case PROP_AUTH_ALG:
-		g_value_set_string (value, priv->auth_alg);
+		g_free (priv->auth_alg);
+		str = g_value_get_string (value);
+		priv->auth_alg = str ? g_ascii_strdown (str, -1) : NULL;
 		break;
 	case PROP_PROTO:
-		g_value_take_boxed (value, _nm_utils_slist_to_strv (priv->proto, TRUE));
+		g_slist_free_full (priv->proto, g_free);
+		priv->proto = _nm_utils_strv_to_slist (g_value_get_boxed (value), TRUE);
 		break;
 	case PROP_PAIRWISE:
-		g_value_take_boxed (value, _nm_utils_slist_to_strv (priv->pairwise, TRUE));
+		g_slist_free_full (priv->pairwise, g_free);
+		priv->pairwise = _nm_utils_strv_to_slist (g_value_get_boxed (value), TRUE);
 		break;
 	case PROP_GROUP:
-		g_value_take_boxed (value, _nm_utils_slist_to_strv (priv->group, TRUE));
+		g_slist_free_full (priv->group, g_free);
+		priv->group = _nm_utils_strv_to_slist (g_value_get_boxed (value), TRUE);
 		break;
 	case PROP_PMF:
-		g_value_set_int (value, nm_setting_wireless_security_get_pmf (setting));
+		priv->pmf = g_value_get_int (value);
 		break;
 	case PROP_LEAP_USERNAME:
-		g_value_set_string (value, priv->leap_username);
+		g_free (priv->leap_username);
+		priv->leap_username = g_value_dup_string (value);
 		break;
 	case PROP_WEP_KEY0:
-		g_value_set_string (value, priv->wep_key0);
+		g_free (priv->wep_key0);
+		priv->wep_key0 = g_value_dup_string (value);
 		break;
 	case PROP_WEP_KEY1:
-		g_value_set_string (value, priv->wep_key1);
+		g_free (priv->wep_key1);
+		priv->wep_key1 = g_value_dup_string (value);
 		break;
 	case PROP_WEP_KEY2:
-		g_value_set_string (value, priv->wep_key2);
+		g_free (priv->wep_key2);
+		priv->wep_key2 = g_value_dup_string (value);
 		break;
 	case PROP_WEP_KEY3:
-		g_value_set_string (value, priv->wep_key3);
+		g_free (priv->wep_key3);
+		priv->wep_key3 = g_value_dup_string (value);
 		break;
 	case PROP_WEP_KEY_FLAGS:
-		g_value_set_flags (value, priv->wep_key_flags);
+		priv->wep_key_flags = g_value_get_flags (value);
 		break;
 	case PROP_PSK:
-		g_value_set_string (value, priv->psk);
+		g_free (priv->psk);
+		priv->psk = g_value_dup_string (value);
 		break;
 	case PROP_PSK_FLAGS:
-		g_value_set_flags (value, priv->psk_flags);
+		priv->psk_flags = g_value_get_flags (value);
 		break;
 	case PROP_LEAP_PASSWORD:
-		g_value_set_string (value, priv->leap_password);
+		g_free (priv->leap_password);
+		priv->leap_password = g_value_dup_string (value);
 		break;
 	case PROP_LEAP_PASSWORD_FLAGS:
-		g_value_set_flags (value, priv->leap_password_flags);
+		priv->leap_password_flags = g_value_get_flags (value);
 		break;
 	case PROP_WEP_KEY_TYPE:
-		g_value_set_enum (value, priv->wep_key_type);
+		priv->wep_key_type = g_value_get_enum (value);
 		break;
 	case PROP_WPS_METHOD:
-		g_value_set_uint (value, priv->wps_method);
+		priv->wps_method = g_value_get_uint (value);
 		break;
 	case PROP_FILS:
-		g_value_set_int (value, nm_setting_wireless_security_get_fils (setting));
+		priv->fils = g_value_get_int (value);
 		break;
 	default:
 		G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
@@ -1428,6 +1392,49 @@ get_property (GObject *object, guint prop_id,
 	}
 }
 
+/*****************************************************************************/
+
+static void
+nm_setting_wireless_security_init (NMSettingWirelessSecurity *setting)
+{
+}
+
+/**
+ * nm_setting_wireless_security_new:
+ *
+ * Creates a new #NMSettingWirelessSecurity object with default values.
+ *
+ * Returns: (transfer full): the new empty #NMSettingWirelessSecurity object
+ **/
+NMSetting *
+nm_setting_wireless_security_new (void)
+{
+	return (NMSetting *) g_object_new (NM_TYPE_SETTING_WIRELESS_SECURITY, NULL);
+}
+
+static void
+finalize (GObject *object)
+{
+	NMSettingWirelessSecurity *self = NM_SETTING_WIRELESS_SECURITY (object);
+	NMSettingWirelessSecurityPrivate *priv = NM_SETTING_WIRELESS_SECURITY_GET_PRIVATE (self);
+
+	g_free (priv->key_mgmt);
+	g_free (priv->auth_alg);
+	g_free (priv->leap_username);
+	g_free (priv->wep_key0);
+	g_free (priv->wep_key1);
+	g_free (priv->wep_key2);
+	g_free (priv->wep_key3);
+	g_free (priv->psk);
+	g_free (priv->leap_password);
+
+	g_slist_free_full (priv->proto, g_free);
+	g_slist_free_full (priv->pairwise, g_free);
+	g_slist_free_full (priv->group, g_free);
+
+	G_OBJECT_CLASS (nm_setting_wireless_security_parent_class)->finalize (object);
+}
+
 static void
 nm_setting_wireless_security_class_init (NMSettingWirelessSecurityClass *klass)
 {
@@ -1437,8 +1444,8 @@ nm_setting_wireless_security_class_init (NMSettingWirelessSecurityClass *klass)
 
 	g_type_class_add_private (klass, sizeof (NMSettingWirelessSecurityPrivate));
 
-	object_class->set_property = set_property;
 	object_class->get_property = get_property;
+	object_class->set_property = set_property;
 	object_class->finalize     = finalize;
 
 	setting_class->verify           = verify;
@@ -1462,13 +1469,12 @@ nm_setting_wireless_security_class_init (NMSettingWirelessSecurityClass *klass)
 	 * description: Key management menthod.
 	 * ---end---
 	 */
-	g_object_class_install_property
-		(object_class, PROP_KEY_MGMT,
-		 g_param_spec_string (NM_SETTING_WIRELESS_SECURITY_KEY_MGMT, "", "",
-		                      NULL,
-		                      G_PARAM_READWRITE |
-		                      NM_SETTING_PARAM_REQUIRED |
-		                      G_PARAM_STATIC_STRINGS));
+	obj_properties[PROP_KEY_MGMT] =
+	    g_param_spec_string (NM_SETTING_WIRELESS_SECURITY_KEY_MGMT, "", "",
+	                         NULL,
+	                         G_PARAM_READWRITE |
+	                         NM_SETTING_PARAM_REQUIRED |
+	                         G_PARAM_STATIC_STRINGS);
 
 	/**
 	 * NMSettingWirelessSecurity:wep-tx-keyidx:
@@ -1486,13 +1492,12 @@ nm_setting_wireless_security_class_init (NMSettingWirelessSecurityClass *klass)
 	 * description: Index of active WEP key.
 	 * ---end---
 	 */
-	g_object_class_install_property
-		(object_class, PROP_WEP_TX_KEYIDX,
-		 g_param_spec_uint (NM_SETTING_WIRELESS_SECURITY_WEP_TX_KEYIDX, "", "",
-		                    0, 3, 0,
-		                    G_PARAM_READWRITE |
-		                    G_PARAM_CONSTRUCT |
-		                    G_PARAM_STATIC_STRINGS));
+	obj_properties[PROP_WEP_TX_KEYIDX] =
+	    g_param_spec_uint (NM_SETTING_WIRELESS_SECURITY_WEP_TX_KEYIDX, "", "",
+	                       0, 3, 0,
+	                       G_PARAM_READWRITE |
+	                       G_PARAM_CONSTRUCT |
+	                       G_PARAM_STATIC_STRINGS);
 
 	/**
 	 * NMSettingWirelessSecurity:auth-alg:
@@ -1510,12 +1515,11 @@ nm_setting_wireless_security_class_init (NMSettingWirelessSecurityClass *klass)
 	 * description: Authentication algorithm for WEP.
 	 * ---end---
 	 */
-	g_object_class_install_property
-		(object_class, PROP_AUTH_ALG,
-		 g_param_spec_string (NM_SETTING_WIRELESS_SECURITY_AUTH_ALG, "", "",
-		                      NULL,
-		                      G_PARAM_READWRITE |
-		                      G_PARAM_STATIC_STRINGS));
+	obj_properties[PROP_AUTH_ALG] =
+	    g_param_spec_string (NM_SETTING_WIRELESS_SECURITY_AUTH_ALG, "", "",
+	                         NULL,
+	                         G_PARAM_READWRITE |
+	                         G_PARAM_STATIC_STRINGS);
 
 	/**
 	 * NMSettingWirelessSecurity:proto:
@@ -1532,12 +1536,11 @@ nm_setting_wireless_security_class_init (NMSettingWirelessSecurityClass *klass)
 	 * description: Allowed WPA protocols, WPA and WPA2 (RSN).
 	 * ---end---
 	 */
-	g_object_class_install_property
-		(object_class, PROP_PROTO,
-		 g_param_spec_boxed (NM_SETTING_WIRELESS_SECURITY_PROTO, "", "",
-		                     G_TYPE_STRV,
-		                     G_PARAM_READWRITE |
-		                     G_PARAM_STATIC_STRINGS));
+	obj_properties[PROP_PROTO] =
+	    g_param_spec_boxed (NM_SETTING_WIRELESS_SECURITY_PROTO, "", "",
+	                        G_TYPE_STRV,
+	                        G_PARAM_READWRITE |
+	                        G_PARAM_STATIC_STRINGS);
 
 	/**
 	 * NMSettingWirelessSecurity:pairwise:
@@ -1555,12 +1558,11 @@ nm_setting_wireless_security_class_init (NMSettingWirelessSecurityClass *klass)
 	 *   separated list.
 	 * ---end---
 	 */
-	g_object_class_install_property
-		(object_class, PROP_PAIRWISE,
-		 g_param_spec_boxed (NM_SETTING_WIRELESS_SECURITY_PAIRWISE, "", "",
-		                     G_TYPE_STRV,
-		                     G_PARAM_READWRITE |
-		                     G_PARAM_STATIC_STRINGS));
+	obj_properties[PROP_PAIRWISE] =
+	    g_param_spec_boxed (NM_SETTING_WIRELESS_SECURITY_PAIRWISE, "", "",
+	                        G_TYPE_STRV,
+	                        G_PARAM_READWRITE |
+	                        G_PARAM_STATIC_STRINGS);
 
 	/**
 	 * NMSettingWirelessSecurity:group:
@@ -1578,12 +1580,11 @@ nm_setting_wireless_security_class_init (NMSettingWirelessSecurityClass *klass)
 	 *   separated list.
 	 * ---end---
 	 */
-	g_object_class_install_property
-		(object_class, PROP_GROUP,
-		 g_param_spec_boxed (NM_SETTING_WIRELESS_SECURITY_GROUP, "", "",
-		                     G_TYPE_STRV,
-		                     G_PARAM_READWRITE |
-		                     G_PARAM_STATIC_STRINGS));
+	obj_properties[PROP_GROUP] =
+	    g_param_spec_boxed (NM_SETTING_WIRELESS_SECURITY_GROUP, "", "",
+	                        G_TYPE_STRV,
+	                        G_PARAM_READWRITE |
+	                        G_PARAM_STATIC_STRINGS);
 
 	/**
 	 * NMSettingWirelessSecurity:pmf:
@@ -1607,14 +1608,13 @@ nm_setting_wireless_security_class_init (NMSettingWirelessSecurityClass *klass)
 	 * example: PMF=required
 	 * ---end---
 	 */
-	g_object_class_install_property
-		(object_class, PROP_PMF,
-		 g_param_spec_int (NM_SETTING_WIRELESS_SECURITY_PMF, "", "",
-		                   G_MININT32, G_MAXINT32, 0,
-		                   G_PARAM_READWRITE |
-		                   G_PARAM_CONSTRUCT |
-		                   NM_SETTING_PARAM_FUZZY_IGNORE |
-		                   G_PARAM_STATIC_STRINGS));
+	obj_properties[PROP_PMF] =
+	    g_param_spec_int (NM_SETTING_WIRELESS_SECURITY_PMF, "", "",
+	                      G_MININT32, G_MAXINT32, 0,
+	                      G_PARAM_READWRITE |
+	                      G_PARAM_CONSTRUCT |
+	                      NM_SETTING_PARAM_FUZZY_IGNORE |
+	                      G_PARAM_STATIC_STRINGS);
 
 	/**
 	 * NMSettingWirelessSecurity:leap-username:
@@ -1628,12 +1628,11 @@ nm_setting_wireless_security_class_init (NMSettingWirelessSecurityClass *klass)
 	 * description: Login name for LEAP.
 	 * ---end---
 	 */
-	g_object_class_install_property
-		(object_class, PROP_LEAP_USERNAME,
-		 g_param_spec_string (NM_SETTING_WIRELESS_SECURITY_LEAP_USERNAME, "", "",
-		                      NULL,
-		                      G_PARAM_READWRITE |
-		                      G_PARAM_STATIC_STRINGS));
+	obj_properties[PROP_LEAP_USERNAME] =
+	    g_param_spec_string (NM_SETTING_WIRELESS_SECURITY_LEAP_USERNAME, "", "",
+	                         NULL,
+	                         G_PARAM_READWRITE |
+	                         G_PARAM_STATIC_STRINGS);
 
 	/**
 	 * NMSettingWirelessSecurity:wep-key0:
@@ -1647,13 +1646,12 @@ nm_setting_wireless_security_class_init (NMSettingWirelessSecurityClass *klass)
 	 * description: The first WEP key (used in most networks). See also DEFAULTKEY for key index.
 	 * ---end---
 	 */
-	g_object_class_install_property
-		(object_class, PROP_WEP_KEY0,
-		 g_param_spec_string (NM_SETTING_WIRELESS_SECURITY_WEP_KEY0, "", "",
-		                      NULL,
-		                      G_PARAM_READWRITE |
-		                      NM_SETTING_PARAM_SECRET |
-		                      G_PARAM_STATIC_STRINGS));
+	obj_properties[PROP_WEP_KEY0] =
+	    g_param_spec_string (NM_SETTING_WIRELESS_SECURITY_WEP_KEY0, "", "",
+	                         NULL,
+	                         G_PARAM_READWRITE |
+	                         NM_SETTING_PARAM_SECRET |
+	                         G_PARAM_STATIC_STRINGS);
 
 	/**
 	 * NMSettingWirelessSecurity:wep-key1:
@@ -1667,13 +1665,12 @@ nm_setting_wireless_security_class_init (NMSettingWirelessSecurityClass *klass)
 	 * description: WEP key with index 1. See also DEFAULTKEY for key index.
 	 * ---end---
 	 */
-	g_object_class_install_property
-		(object_class, PROP_WEP_KEY1,
-		 g_param_spec_string (NM_SETTING_WIRELESS_SECURITY_WEP_KEY1, "", "",
-		                      NULL,
-		                      G_PARAM_READWRITE |
-		                      NM_SETTING_PARAM_SECRET |
-		                      G_PARAM_STATIC_STRINGS));
+	obj_properties[PROP_WEP_KEY1] =
+	    g_param_spec_string (NM_SETTING_WIRELESS_SECURITY_WEP_KEY1, "", "",
+	                         NULL,
+	                         G_PARAM_READWRITE |
+	                         NM_SETTING_PARAM_SECRET |
+	                         G_PARAM_STATIC_STRINGS);
 
 	/**
 	 * NMSettingWirelessSecurity:wep-key2:
@@ -1687,13 +1684,12 @@ nm_setting_wireless_security_class_init (NMSettingWirelessSecurityClass *klass)
 	 * description: WEP key with index 2. See also DEFAULTKEY for key index.
 	 * ---end---
 	 */
-	g_object_class_install_property
-		(object_class, PROP_WEP_KEY2,
-		 g_param_spec_string (NM_SETTING_WIRELESS_SECURITY_WEP_KEY2, "", "",
-		                      NULL,
-		                      G_PARAM_READWRITE |
-		                      NM_SETTING_PARAM_SECRET |
-		                      G_PARAM_STATIC_STRINGS));
+	obj_properties[PROP_WEP_KEY2] =
+	    g_param_spec_string (NM_SETTING_WIRELESS_SECURITY_WEP_KEY2, "", "",
+	                         NULL,
+	                         G_PARAM_READWRITE |
+	                         NM_SETTING_PARAM_SECRET |
+	                         G_PARAM_STATIC_STRINGS);
 
 	/**
 	 * NMSettingWirelessSecurity:wep-key3:
@@ -1707,13 +1703,12 @@ nm_setting_wireless_security_class_init (NMSettingWirelessSecurityClass *klass)
 	 * description: WEP key with index 3. See also DEFAULTKEY for key index.
 	 * ---end---
 	 */
-	g_object_class_install_property
-		(object_class, PROP_WEP_KEY3,
-		 g_param_spec_string (NM_SETTING_WIRELESS_SECURITY_WEP_KEY3, "", "",
-		                      NULL,
-		                      G_PARAM_READWRITE |
-		                      NM_SETTING_PARAM_SECRET |
-		                      G_PARAM_STATIC_STRINGS));
+	obj_properties[PROP_WEP_KEY3] =
+	    g_param_spec_string (NM_SETTING_WIRELESS_SECURITY_WEP_KEY3, "", "",
+	                         NULL,
+	                         G_PARAM_READWRITE |
+	                         NM_SETTING_PARAM_SECRET |
+	                         G_PARAM_STATIC_STRINGS);
 
 	/**
 	 * NMSettingWirelessSecurity:wep-key-flags:
@@ -1729,13 +1724,12 @@ nm_setting_wireless_security_class_init (NMSettingWirelessSecurityClass *klass)
 	 * description: Password flags for KEY<i>, KEY_PASSPHRASE<i> password.
 	 * ---end---
 	 */
-	g_object_class_install_property
-		(object_class, PROP_WEP_KEY_FLAGS,
-		 g_param_spec_flags (NM_SETTING_WIRELESS_SECURITY_WEP_KEY_FLAGS, "", "",
-		                     NM_TYPE_SETTING_SECRET_FLAGS,
-		                     NM_SETTING_SECRET_FLAG_NONE,
-		                     G_PARAM_READWRITE |
-		                     G_PARAM_STATIC_STRINGS));
+	obj_properties[PROP_WEP_KEY_FLAGS] =
+	    g_param_spec_flags (NM_SETTING_WIRELESS_SECURITY_WEP_KEY_FLAGS, "", "",
+	                        NM_TYPE_SETTING_SECRET_FLAGS,
+	                        NM_SETTING_SECRET_FLAG_NONE,
+	                        G_PARAM_READWRITE |
+	                        G_PARAM_STATIC_STRINGS);
 
 	/**
 	 * NMSettingWirelessSecurity:psk:
@@ -1753,13 +1747,12 @@ nm_setting_wireless_security_class_init (NMSettingWirelessSecurityClass *klass)
 	 * description: Pre-Shared-Key for WPA networks.
 	 * ---end---
 	 */
-	g_object_class_install_property
-		(object_class, PROP_PSK,
-		 g_param_spec_string (NM_SETTING_WIRELESS_SECURITY_PSK, "", "",
-		                      NULL,
-		                      G_PARAM_READWRITE |
-		                      NM_SETTING_PARAM_SECRET |
-		                      G_PARAM_STATIC_STRINGS));
+	obj_properties[PROP_PSK] =
+	    g_param_spec_string (NM_SETTING_WIRELESS_SECURITY_PSK, "", "",
+	                         NULL,
+	                         G_PARAM_READWRITE |
+	                         NM_SETTING_PARAM_SECRET |
+	                         G_PARAM_STATIC_STRINGS);
 
 	/**
 	 * NMSettingWirelessSecurity:psk-flags:
@@ -1775,13 +1768,12 @@ nm_setting_wireless_security_class_init (NMSettingWirelessSecurityClass *klass)
 	 * example: WPA_PSK_FLAGS=user
 	 * ---end---
 	 */
-	g_object_class_install_property
-		(object_class, PROP_PSK_FLAGS,
-		 g_param_spec_flags (NM_SETTING_WIRELESS_SECURITY_PSK_FLAGS, "", "",
-		                     NM_TYPE_SETTING_SECRET_FLAGS,
-		                     NM_SETTING_SECRET_FLAG_NONE,
-		                     G_PARAM_READWRITE |
-		                     G_PARAM_STATIC_STRINGS));
+	obj_properties[PROP_PSK_FLAGS] =
+	    g_param_spec_flags (NM_SETTING_WIRELESS_SECURITY_PSK_FLAGS, "", "",
+	                        NM_TYPE_SETTING_SECRET_FLAGS,
+	                        NM_SETTING_SECRET_FLAG_NONE,
+	                        G_PARAM_READWRITE |
+	                        G_PARAM_STATIC_STRINGS);
 
 	/**
 	 * NMSettingWirelessSecurity:leap-password:
@@ -1796,13 +1788,12 @@ nm_setting_wireless_security_class_init (NMSettingWirelessSecurityClass *klass)
 	 *  lookaside file, or it can be owned by a secret agent.
 	 * ---end---
 	 */
-	g_object_class_install_property
-		(object_class, PROP_LEAP_PASSWORD,
-		 g_param_spec_string (NM_SETTING_WIRELESS_SECURITY_LEAP_PASSWORD, "", "",
-		                      NULL,
-		                      G_PARAM_READWRITE |
-		                      NM_SETTING_PARAM_SECRET |
-		                      G_PARAM_STATIC_STRINGS));
+	obj_properties[PROP_LEAP_PASSWORD] =
+	    g_param_spec_string (NM_SETTING_WIRELESS_SECURITY_LEAP_PASSWORD, "", "",
+	                         NULL,
+	                         G_PARAM_READWRITE |
+	                         NM_SETTING_PARAM_SECRET |
+	                         G_PARAM_STATIC_STRINGS);
 
 	/**
 	 * NMSettingWirelessSecurity:leap-password-flags:
@@ -1817,13 +1808,12 @@ nm_setting_wireless_security_class_init (NMSettingWirelessSecurityClass *klass)
 	 * description: Password flags for IEEE_8021X_PASSWORD_FLAGS.
 	 * ---end---
 	 */
-	g_object_class_install_property
-		(object_class, PROP_LEAP_PASSWORD_FLAGS,
-		 g_param_spec_flags (NM_SETTING_WIRELESS_SECURITY_LEAP_PASSWORD_FLAGS, "", "",
-		                     NM_TYPE_SETTING_SECRET_FLAGS,
-		                     NM_SETTING_SECRET_FLAG_NONE,
-		                     G_PARAM_READWRITE |
-		                     G_PARAM_STATIC_STRINGS));
+	obj_properties[PROP_LEAP_PASSWORD_FLAGS] =
+	    g_param_spec_flags (NM_SETTING_WIRELESS_SECURITY_LEAP_PASSWORD_FLAGS, "", "",
+	                        NM_TYPE_SETTING_SECRET_FLAGS,
+	                        NM_SETTING_SECRET_FLAG_NONE,
+	                        G_PARAM_READWRITE |
+	                        G_PARAM_STATIC_STRINGS);
 
 	/**
 	 * NMSettingWirelessSecurity:wep-key-type:
@@ -1845,18 +1835,16 @@ nm_setting_wireless_security_class_init (NMSettingWirelessSecurityClass *klass)
 	 * example: KEY1=s:ahoj, KEY1=0a1c45bc02, KEY_PASSPHRASE1=mysupersecretkey
 	 * ---end---
 	 */
-	g_object_class_install_property
-		(object_class, PROP_WEP_KEY_TYPE,
-		 g_param_spec_enum (NM_SETTING_WIRELESS_SECURITY_WEP_KEY_TYPE, "", "",
-		                    NM_TYPE_WEP_KEY_TYPE,
-		                    NM_WEP_KEY_TYPE_UNKNOWN,
-		                    G_PARAM_READWRITE |
-		                    G_PARAM_CONSTRUCT |
-		                    G_PARAM_STATIC_STRINGS));
+	obj_properties[PROP_WEP_KEY_TYPE] =
+	    g_param_spec_enum (NM_SETTING_WIRELESS_SECURITY_WEP_KEY_TYPE, "", "",
+	                       NM_TYPE_WEP_KEY_TYPE,
+	                       NM_WEP_KEY_TYPE_UNKNOWN,
+	                       G_PARAM_READWRITE |
+	                       G_PARAM_CONSTRUCT |
+	                       G_PARAM_STATIC_STRINGS);
 
 	_properties_override_add_transform (properties_override,
-	                                    g_object_class_find_property (G_OBJECT_CLASS (setting_class),
-	                                                                  NM_SETTING_WIRELESS_SECURITY_WEP_KEY_TYPE),
+	                                    obj_properties[PROP_WEP_KEY_TYPE],
 	                                    G_VARIANT_TYPE_UINT32,
 	                                    wep_key_type_to_dbus,
 	                                    NULL);
@@ -1882,14 +1870,13 @@ nm_setting_wireless_security_class_init (NMSettingWirelessSecurityClass *klass)
 	 * example: WPS_METHOD=disabled, WPS_METHOD="pin pbc"
 	 * ---end---
 	 */
-	g_object_class_install_property
-		(object_class, PROP_WPS_METHOD,
-		 g_param_spec_uint (NM_SETTING_WIRELESS_SECURITY_WPS_METHOD, "", "",
-		                    0, G_MAXUINT32, NM_SETTING_WIRELESS_SECURITY_WPS_METHOD_DEFAULT,
-		                    G_PARAM_READWRITE |
-		                    G_PARAM_CONSTRUCT |
-		                    NM_SETTING_PARAM_FUZZY_IGNORE |
-		                    G_PARAM_STATIC_STRINGS));
+	obj_properties[PROP_WPS_METHOD] =
+	    g_param_spec_uint (NM_SETTING_WIRELESS_SECURITY_WPS_METHOD, "", "",
+	                       0, G_MAXUINT32, NM_SETTING_WIRELESS_SECURITY_WPS_METHOD_DEFAULT,
+	                       G_PARAM_READWRITE |
+	                       G_PARAM_CONSTRUCT |
+	                       NM_SETTING_PARAM_FUZZY_IGNORE |
+	                       G_PARAM_STATIC_STRINGS);
 
 	/**
 	 * NMSettingWirelessSecurity:fils:
@@ -1913,14 +1900,15 @@ nm_setting_wireless_security_class_init (NMSettingWirelessSecurityClass *klass)
 	 * example: FILS=required
 	 * ---end---
 	 */
-	g_object_class_install_property
-		(object_class, PROP_FILS,
-		 g_param_spec_int (NM_SETTING_WIRELESS_SECURITY_FILS, "", "",
-		                   G_MININT32, G_MAXINT32, 0,
-		                   G_PARAM_READWRITE |
-		                   G_PARAM_CONSTRUCT |
-		                   NM_SETTING_PARAM_FUZZY_IGNORE |
-		                   G_PARAM_STATIC_STRINGS));
+	obj_properties[PROP_FILS] =
+	    g_param_spec_int (NM_SETTING_WIRELESS_SECURITY_FILS, "", "",
+	                      G_MININT32, G_MAXINT32, 0,
+	                      G_PARAM_READWRITE |
+	                      G_PARAM_CONSTRUCT |
+	                      NM_SETTING_PARAM_FUZZY_IGNORE |
+	                      G_PARAM_STATIC_STRINGS);
+
+	g_object_class_install_properties (object_class, _PROPERTY_ENUMS_LAST, obj_properties);
 
 	_nm_setting_class_commit_full (setting_class, NM_META_SETTING_TYPE_WIRELESS_SECURITY,
 	                               NULL, properties_override);
diff --git a/libnm-core/nm-setting-wireless-security.h b/libnm-core/nm-setting-wireless-security.h
index 5a732ac0..2f4b4084 100644
--- a/libnm-core/nm-setting-wireless-security.h
+++ b/libnm-core/nm-setting-wireless-security.h
@@ -54,9 +54,9 @@ G_BEGIN_DECLS
  * @NM_WEP_KEY_TYPE_LAST: placeholder value for bounds-checking
  *
  * The #NMWepKeyType values specify how any WEP keys present in the setting
- * are intepreted.  There are no standards governing how to hash the various WEP
+ * are interpreted.  There are no standards governing how to hash the various WEP
  * key/passphrase formats into the actual WEP key.  Unfortunately some WEP keys
- * can be interpreted in multiple ways, requring the setting to specify how to
+ * can be interpreted in multiple ways, requiring the setting to specify how to
  * interpret the any WEP keys.  For example, the key "732f2d712e4a394a375d366931"
  * is both a valid Hexadecimal WEP key and a WEP passphrase.  Further, many
  * ASCII keys are also valid WEP passphrases, but since passphrases and ASCII
@@ -99,9 +99,12 @@ typedef enum {
  *
  * Configure the use of WPS by a connection while it activates.
  *
+ * Note: prior to 1.16, this was a GEnum type instead of a GFlags type
+ * altough, with the same numeric values.
+ *
  * Since: 1.10
  **/
-typedef enum {
+typedef enum { /*< flags >*/
 	NM_SETTING_WIRELESS_SECURITY_WPS_METHOD_DEFAULT     = 0x00000000,
 	NM_SETTING_WIRELESS_SECURITY_WPS_METHOD_DISABLED    = 0x00000001,
 	NM_SETTING_WIRELESS_SECURITY_WPS_METHOD_AUTO        = 0x00000002,
diff --git a/libnm-core/nm-setting-wireless.c b/libnm-core/nm-setting-wireless.c
index 6f6175b7..5d3f8fe8 100644
--- a/libnm-core/nm-setting-wireless.c
+++ b/libnm-core/nm-setting-wireless.c
@@ -40,9 +40,27 @@
  * necessary for connection to 802.11 Wi-Fi networks.
  **/
 
-G_DEFINE_TYPE (NMSettingWireless, nm_setting_wireless, NM_TYPE_SETTING)
+/*****************************************************************************/
 
-#define NM_SETTING_WIRELESS_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), NM_TYPE_SETTING_WIRELESS, NMSettingWirelessPrivate))
+NM_GOBJECT_PROPERTIES_DEFINE (NMSettingWireless,
+	PROP_SSID,
+	PROP_MODE,
+	PROP_BAND,
+	PROP_CHANNEL,
+	PROP_BSSID,
+	PROP_RATE,
+	PROP_TX_POWER,
+	PROP_MAC_ADDRESS,
+	PROP_CLONED_MAC_ADDRESS,
+	PROP_GENERATE_MAC_ADDRESS_MASK,
+	PROP_MAC_ADDRESS_BLACKLIST,
+	PROP_MTU,
+	PROP_SEEN_BSSIDS,
+	PROP_HIDDEN,
+	PROP_POWERSAVE,
+	PROP_MAC_ADDRESS_RANDOMIZATION,
+	PROP_WAKE_ON_WLAN,
+);
 
 typedef struct {
 	GBytes *ssid;
@@ -64,28 +82,11 @@ typedef struct {
 	guint32 wowl;
 } NMSettingWirelessPrivate;
 
-enum {
-	PROP_0,
-	PROP_SSID,
-	PROP_MODE,
-	PROP_BAND,
-	PROP_CHANNEL,
-	PROP_BSSID,
-	PROP_RATE,
-	PROP_TX_POWER,
-	PROP_MAC_ADDRESS,
-	PROP_CLONED_MAC_ADDRESS,
-	PROP_GENERATE_MAC_ADDRESS_MASK,
-	PROP_MAC_ADDRESS_BLACKLIST,
-	PROP_MTU,
-	PROP_SEEN_BSSIDS,
-	PROP_HIDDEN,
-	PROP_POWERSAVE,
-	PROP_MAC_ADDRESS_RANDOMIZATION,
-	PROP_WAKE_ON_WLAN,
+G_DEFINE_TYPE (NMSettingWireless, nm_setting_wireless, NM_TYPE_SETTING)
 
-	LAST_PROP
-};
+#define NM_SETTING_WIRELESS_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), NM_TYPE_SETTING_WIRELESS, NMSettingWirelessPrivate))
+
+/*****************************************************************************/
 
 static gboolean
 match_cipher (const char *cipher,
@@ -285,19 +286,6 @@ nm_setting_wireless_ap_security_compatible (NMSettingWireless *s_wireless,
 }
 
 /**
- * nm_setting_wireless_new:
- *
- * Creates a new #NMSettingWireless object with default values.
- *
- * Returns: (transfer full): the new empty #NMSettingWireless object
- **/
-NMSetting *
-nm_setting_wireless_new (void)
-{
-	return (NMSetting *) g_object_new (NM_TYPE_SETTING_WIRELESS, NULL);
-}
-
-/**
  * nm_setting_wireless_get_ssid:
  * @setting: the #NMSettingWireless
  *
@@ -523,7 +511,7 @@ nm_setting_wireless_add_mac_blacklist_item (NMSettingWireless *setting, const ch
 
 	mac = nm_utils_hwaddr_canonical (mac, ETH_ALEN);
 	g_array_append_val (priv->mac_address_blacklist, mac);
-	g_object_notify (G_OBJECT (setting), NM_SETTING_WIRELESS_MAC_ADDRESS_BLACKLIST);
+	_notify (setting, PROP_MAC_ADDRESS_BLACKLIST);
 	return TRUE;
 }
 
@@ -545,7 +533,7 @@ nm_setting_wireless_remove_mac_blacklist_item (NMSettingWireless *setting, guint
 	g_return_if_fail (idx < priv->mac_address_blacklist->len);
 
 	g_array_remove_index (priv->mac_address_blacklist, idx);
-	g_object_notify (G_OBJECT (setting), NM_SETTING_WIRELESS_MAC_ADDRESS_BLACKLIST);
+	_notify (setting, PROP_MAC_ADDRESS_BLACKLIST);
 }
 
 /**
@@ -573,7 +561,7 @@ nm_setting_wireless_remove_mac_blacklist_item_by_value (NMSettingWireless *setti
 		candidate = g_array_index (priv->mac_address_blacklist, char *, i);
 		if (!nm_utils_hwaddr_matches (mac, -1, candidate, -1)) {
 			g_array_remove_index (priv->mac_address_blacklist, i);
-			g_object_notify (G_OBJECT (setting), NM_SETTING_WIRELESS_MAC_ADDRESS_BLACKLIST);
+			_notify (setting, PROP_MAC_ADDRESS_BLACKLIST);
 			return TRUE;
 		}
 	}
@@ -592,7 +580,7 @@ nm_setting_wireless_clear_mac_blacklist_items (NMSettingWireless *setting)
 	g_return_if_fail (NM_IS_SETTING_WIRELESS (setting));
 
 	g_array_set_size (NM_SETTING_WIRELESS_GET_PRIVATE (setting)->mac_address_blacklist, 0);
-	g_object_notify (G_OBJECT (setting), NM_SETTING_WIRELESS_MAC_ADDRESS_BLACKLIST);
+	_notify (setting, PROP_MAC_ADDRESS_BLACKLIST);
 }
 
 /**
@@ -695,7 +683,7 @@ nm_setting_wireless_add_seen_bssid (NMSettingWireless *setting,
 
 	if (!found) {
 		priv->seen_bssids = g_slist_prepend (priv->seen_bssids, lower_bssid);
-		g_object_notify (G_OBJECT (setting), NM_SETTING_WIRELESS_SEEN_BSSIDS);
+		_notify (setting, PROP_SEEN_BSSIDS);
 	} else
 		g_free (lower_bssid);
 
@@ -929,34 +917,45 @@ mac_addr_rand_ok:
 	return TRUE;
 }
 
-static gboolean
-compare_property (NMSetting *setting,
+static NMTernary
+compare_property (const NMSettInfoSetting *sett_info,
+                  guint property_idx,
+                  NMSetting *setting,
                   NMSetting *other,
-                  const GParamSpec *prop_spec,
                   NMSettingCompareFlags flags)
 {
-	NMSettingClass *setting_class;
-
-	if (nm_streq (prop_spec->name, NM_SETTING_WIRELESS_CLONED_MAC_ADDRESS)) {
-		return nm_streq0 (NM_SETTING_WIRELESS_GET_PRIVATE (setting)->cloned_mac_address,
-		                  NM_SETTING_WIRELESS_GET_PRIVATE (other)->cloned_mac_address);
+	if (nm_streq (sett_info->property_infos[property_idx].name, NM_SETTING_WIRELESS_CLONED_MAC_ADDRESS)) {
+		return    !other
+		       || nm_streq0 (NM_SETTING_WIRELESS_GET_PRIVATE (setting)->cloned_mac_address,
+		                     NM_SETTING_WIRELESS_GET_PRIVATE (other)->cloned_mac_address);
 	}
 
-	setting_class = NM_SETTING_CLASS (nm_setting_wireless_parent_class);
-	return setting_class->compare_property (setting, other, prop_spec, flags);
+	return NM_SETTING_CLASS (nm_setting_wireless_parent_class)->compare_property (sett_info,
+	                                                                              property_idx,
+	                                                                              setting,
+	                                                                              other,
+	                                                                              flags);
 }
 
 /*****************************************************************************/
 
 static GVariant *
-nm_setting_wireless_get_security (NMSetting    *setting,
+nm_setting_wireless_get_security (const NMSettInfoSetting *sett_info,
+                                  guint property_idx,
                                   NMConnection *connection,
-                                  const char   *property_name)
+                                  NMSetting *setting,
+                                  NMConnectionSerializationFlags flags)
 {
-	if (nm_connection_get_setting_wireless_security (connection))
-		return g_variant_new_string (NM_SETTING_WIRELESS_SECURITY_SETTING_NAME);
-	else
+	if (flags & NM_CONNECTION_SERIALIZE_ONLY_SECRETS)
+		return NULL;
+
+	if (!connection)
 		return NULL;
+
+	if (!nm_connection_get_setting_wireless_security (connection))
+		return NULL;
+
+	return g_variant_new_string (NM_SETTING_WIRELESS_SECURITY_SETTING_NAME);
 }
 
 /**
@@ -983,34 +982,71 @@ clear_blacklist_item (char **item_p)
 	g_free (*item_p);
 }
 
-static void
-nm_setting_wireless_init (NMSettingWireless *setting)
-{
-	NMSettingWirelessPrivate *priv = NM_SETTING_WIRELESS_GET_PRIVATE (setting);
-
-	/* We use GArray rather than GPtrArray so it will automatically be NULL-terminated */
-	priv->mac_address_blacklist = g_array_new (TRUE, FALSE, sizeof (char *));
-	g_array_set_clear_func (priv->mac_address_blacklist, (GDestroyNotify) clear_blacklist_item);
-}
+/*****************************************************************************/
 
 static void
-finalize (GObject *object)
+get_property (GObject *object, guint prop_id,
+              GValue *value, GParamSpec *pspec)
 {
+	NMSettingWireless *setting = NM_SETTING_WIRELESS (object);
 	NMSettingWirelessPrivate *priv = NM_SETTING_WIRELESS_GET_PRIVATE (object);
 
-	g_free (priv->mode);
-	g_free (priv->band);
-
-	if (priv->ssid)
-		g_bytes_unref (priv->ssid);
-	g_free (priv->bssid);
-	g_free (priv->device_mac_address);
-	g_free (priv->cloned_mac_address);
-	g_free (priv->generate_mac_address_mask);
-	g_array_unref (priv->mac_address_blacklist);
-	g_slist_free_full (priv->seen_bssids, g_free);
-
-	G_OBJECT_CLASS (nm_setting_wireless_parent_class)->finalize (object);
+	switch (prop_id) {
+	case PROP_SSID:
+		g_value_set_boxed (value, nm_setting_wireless_get_ssid (setting));
+		break;
+	case PROP_MODE:
+		g_value_set_string (value, nm_setting_wireless_get_mode (setting));
+		break;
+	case PROP_BAND:
+		g_value_set_string (value, nm_setting_wireless_get_band (setting));
+		break;
+	case PROP_CHANNEL:
+		g_value_set_uint (value, nm_setting_wireless_get_channel (setting));
+		break;
+	case PROP_BSSID:
+		g_value_set_string (value, nm_setting_wireless_get_bssid (setting));
+		break;
+	case PROP_RATE:
+		g_value_set_uint (value, nm_setting_wireless_get_rate (setting));
+		break;
+	case PROP_TX_POWER:
+		g_value_set_uint (value, nm_setting_wireless_get_tx_power (setting));
+		break;
+	case PROP_MAC_ADDRESS:
+		g_value_set_string (value, nm_setting_wireless_get_mac_address (setting));
+		break;
+	case PROP_CLONED_MAC_ADDRESS:
+		g_value_set_string (value, nm_setting_wireless_get_cloned_mac_address (setting));
+		break;
+	case PROP_GENERATE_MAC_ADDRESS_MASK:
+		g_value_set_string (value, nm_setting_wireless_get_generate_mac_address_mask (setting));
+		break;
+	case PROP_MAC_ADDRESS_BLACKLIST:
+		g_value_set_boxed (value, (char **) priv->mac_address_blacklist->data);
+		break;
+	case PROP_MTU:
+		g_value_set_uint (value, nm_setting_wireless_get_mtu (setting));
+		break;
+	case PROP_SEEN_BSSIDS:
+		g_value_take_boxed (value, _nm_utils_slist_to_strv (priv->seen_bssids, TRUE));
+		break;
+	case PROP_HIDDEN:
+		g_value_set_boolean (value, nm_setting_wireless_get_hidden (setting));
+		break;
+	case PROP_POWERSAVE:
+		g_value_set_uint (value, nm_setting_wireless_get_powersave (setting));
+		break;
+	case PROP_MAC_ADDRESS_RANDOMIZATION:
+		g_value_set_uint (value, nm_setting_wireless_get_mac_address_randomization (setting));
+		break;
+	case PROP_WAKE_ON_WLAN:
+		g_value_set_uint (value, nm_setting_wireless_get_wake_on_wlan (setting));
+		break;
+	default:
+		G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+		break;
+	}
 }
 
 static void
@@ -1065,7 +1101,7 @@ set_property (GObject *object, guint prop_id,
 			 * In this case, we also clear mac-address-randomization flag */
 			if (priv->mac_address_randomization != NM_SETTING_MAC_RANDOMIZATION_DEFAULT) {
 				priv->mac_address_randomization = NM_SETTING_MAC_RANDOMIZATION_DEFAULT;
-				g_object_notify (object, NM_SETTING_WIRELESS_MAC_ADDRESS);
+				_notify (NM_SETTING_WIRELESS (object), PROP_MAC_ADDRESS_RANDOMIZATION);
 			}
 		}
 		break;
@@ -1108,69 +1144,49 @@ set_property (GObject *object, guint prop_id,
 	}
 }
 
+/*****************************************************************************/
+
 static void
-get_property (GObject *object, guint prop_id,
-              GValue *value, GParamSpec *pspec)
+nm_setting_wireless_init (NMSettingWireless *setting)
+{
+	NMSettingWirelessPrivate *priv = NM_SETTING_WIRELESS_GET_PRIVATE (setting);
+
+	/* We use GArray rather than GPtrArray so it will automatically be NULL-terminated */
+	priv->mac_address_blacklist = g_array_new (TRUE, FALSE, sizeof (char *));
+	g_array_set_clear_func (priv->mac_address_blacklist, (GDestroyNotify) clear_blacklist_item);
+}
+
+/**
+ * nm_setting_wireless_new:
+ *
+ * Creates a new #NMSettingWireless object with default values.
+ *
+ * Returns: (transfer full): the new empty #NMSettingWireless object
+ **/
+NMSetting *
+nm_setting_wireless_new (void)
+{
+	return (NMSetting *) g_object_new (NM_TYPE_SETTING_WIRELESS, NULL);
+}
+
+static void
+finalize (GObject *object)
 {
-	NMSettingWireless *setting = NM_SETTING_WIRELESS (object);
 	NMSettingWirelessPrivate *priv = NM_SETTING_WIRELESS_GET_PRIVATE (object);
 
-	switch (prop_id) {
-	case PROP_SSID:
-		g_value_set_boxed (value, nm_setting_wireless_get_ssid (setting));
-		break;
-	case PROP_MODE:
-		g_value_set_string (value, nm_setting_wireless_get_mode (setting));
-		break;
-	case PROP_BAND:
-		g_value_set_string (value, nm_setting_wireless_get_band (setting));
-		break;
-	case PROP_CHANNEL:
-		g_value_set_uint (value, nm_setting_wireless_get_channel (setting));
-		break;
-	case PROP_BSSID:
-		g_value_set_string (value, nm_setting_wireless_get_bssid (setting));
-		break;
-	case PROP_RATE:
-		g_value_set_uint (value, nm_setting_wireless_get_rate (setting));
-		break;
-	case PROP_TX_POWER:
-		g_value_set_uint (value, nm_setting_wireless_get_tx_power (setting));
-		break;
-	case PROP_MAC_ADDRESS:
-		g_value_set_string (value, nm_setting_wireless_get_mac_address (setting));
-		break;
-	case PROP_CLONED_MAC_ADDRESS:
-		g_value_set_string (value, nm_setting_wireless_get_cloned_mac_address (setting));
-		break;
-	case PROP_GENERATE_MAC_ADDRESS_MASK:
-		g_value_set_string (value, nm_setting_wireless_get_generate_mac_address_mask (setting));
-		break;
-	case PROP_MAC_ADDRESS_BLACKLIST:
-		g_value_set_boxed (value, (char **) priv->mac_address_blacklist->data);
-		break;
-	case PROP_MTU:
-		g_value_set_uint (value, nm_setting_wireless_get_mtu (setting));
-		break;
-	case PROP_SEEN_BSSIDS:
-		g_value_take_boxed (value, _nm_utils_slist_to_strv (priv->seen_bssids, TRUE));
-		break;
-	case PROP_HIDDEN:
-		g_value_set_boolean (value, nm_setting_wireless_get_hidden (setting));
-		break;
-	case PROP_POWERSAVE:
-		g_value_set_uint (value, nm_setting_wireless_get_powersave (setting));
-		break;
-	case PROP_MAC_ADDRESS_RANDOMIZATION:
-		g_value_set_uint (value, nm_setting_wireless_get_mac_address_randomization (setting));
-		break;
-	case PROP_WAKE_ON_WLAN:
-		g_value_set_uint (value, nm_setting_wireless_get_wake_on_wlan (setting));
-		break;
-	default:
-		G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
-		break;
-	}
+	g_free (priv->mode);
+	g_free (priv->band);
+
+	if (priv->ssid)
+		g_bytes_unref (priv->ssid);
+	g_free (priv->bssid);
+	g_free (priv->device_mac_address);
+	g_free (priv->cloned_mac_address);
+	g_free (priv->generate_mac_address_mask);
+	g_array_unref (priv->mac_address_blacklist);
+	g_slist_free_full (priv->seen_bssids, g_free);
+
+	G_OBJECT_CLASS (nm_setting_wireless_parent_class)->finalize (object);
 }
 
 static void
@@ -1207,12 +1223,11 @@ nm_setting_wireless_class_init (NMSettingWirelessClass *klass)
 	 * example: ESSID="Quick Net"
 	 * ---end---
 	 */
-	g_object_class_install_property
-		(object_class, PROP_SSID,
-		 g_param_spec_boxed (NM_SETTING_WIRELESS_SSID, "", "",
-		                     G_TYPE_BYTES,
-		                     G_PARAM_READWRITE |
-		                     G_PARAM_STATIC_STRINGS));
+	obj_properties[PROP_SSID] =
+	    g_param_spec_boxed (NM_SETTING_WIRELESS_SSID, "", "",
+	                        G_TYPE_BYTES,
+	                        G_PARAM_READWRITE |
+	                        G_PARAM_STATIC_STRINGS);
 
 	/**
 	 * NMSettingWireless:mode:
@@ -1227,12 +1242,11 @@ nm_setting_wireless_class_init (NMSettingWirelessClass *klass)
 	 * description: Wi-Fi network mode.
 	 * ---end---
 	 */
-	g_object_class_install_property
-		(object_class, PROP_MODE,
-		 g_param_spec_string (NM_SETTING_WIRELESS_MODE, "", "",
-		                      NULL,
-		                      G_PARAM_READWRITE |
-		                      G_PARAM_STATIC_STRINGS));
+	obj_properties[PROP_MODE] =
+	    g_param_spec_string (NM_SETTING_WIRELESS_MODE, "", "",
+	                         NULL,
+	                         G_PARAM_READWRITE |
+	                         G_PARAM_STATIC_STRINGS);
 
 	/**
 	 * NMSettingWireless:band:
@@ -1253,12 +1267,11 @@ nm_setting_wireless_class_init (NMSettingWirelessClass *klass)
 	 * example: BAND=bg
 	 * ---end---
 	 */
-	g_object_class_install_property
-		(object_class, PROP_BAND,
-		 g_param_spec_string (NM_SETTING_WIRELESS_BAND, "", "",
-		                      NULL,
-		                      G_PARAM_READWRITE |
-		                      G_PARAM_STATIC_STRINGS));
+	obj_properties[PROP_BAND] =
+	    g_param_spec_string (NM_SETTING_WIRELESS_BAND, "", "",
+	                         NULL,
+	                         G_PARAM_READWRITE |
+	                         G_PARAM_STATIC_STRINGS);
 
 	/**
 	 * NMSettingWireless:channel:
@@ -1277,13 +1290,12 @@ nm_setting_wireless_class_init (NMSettingWirelessClass *klass)
 	 * example: CHANNEL=6
 	 * ---end---
 	 */
-	g_object_class_install_property
-		(object_class, PROP_CHANNEL,
-		 g_param_spec_uint (NM_SETTING_WIRELESS_CHANNEL, "", "",
-		                    0, G_MAXUINT32, 0,
-		                    G_PARAM_READWRITE |
-		                    G_PARAM_CONSTRUCT |
-		                    G_PARAM_STATIC_STRINGS));
+	obj_properties[PROP_CHANNEL] =
+	    g_param_spec_uint (NM_SETTING_WIRELESS_CHANNEL, "", "",
+	                       0, G_MAXUINT32, 0,
+	                       G_PARAM_READWRITE |
+	                       G_PARAM_CONSTRUCT |
+	                       G_PARAM_STATIC_STRINGS);
 
 	/**
 	 * NMSettingWireless:bssid:
@@ -1300,16 +1312,14 @@ nm_setting_wireless_class_init (NMSettingWirelessClass *klass)
 	 * example: BSSID=00:1E:BD:64:83:21
 	 * ---end---
 	 */
-	g_object_class_install_property
-		(object_class, PROP_BSSID,
-		 g_param_spec_string (NM_SETTING_WIRELESS_BSSID, "", "",
-		                      NULL,
-		                      G_PARAM_READWRITE |
-		                      G_PARAM_STATIC_STRINGS));
+	obj_properties[PROP_BSSID] =
+	    g_param_spec_string (NM_SETTING_WIRELESS_BSSID, "", "",
+	                         NULL,
+	                         G_PARAM_READWRITE |
+	                         G_PARAM_STATIC_STRINGS);
 
 	_properties_override_add_transform (properties_override,
-	                                    g_object_class_find_property (G_OBJECT_CLASS (setting_class),
-	                                                                  NM_SETTING_WIRELESS_BSSID),
+	                                    obj_properties[PROP_BSSID],
 	                                    G_VARIANT_TYPE_BYTESTRING,
 	                                    _nm_utils_hwaddr_to_dbus,
 	                                    _nm_utils_hwaddr_from_dbus);
@@ -1328,14 +1338,13 @@ nm_setting_wireless_class_init (NMSettingWirelessClass *klass)
 	 * description: This property is not handled by ifcfg-rh plugin.
 	 * ---end---
 	 */
-	g_object_class_install_property
-		(object_class, PROP_RATE,
-		 g_param_spec_uint (NM_SETTING_WIRELESS_RATE, "", "",
-		                    0, G_MAXUINT32, 0,
-		                    G_PARAM_READWRITE |
-		                    G_PARAM_CONSTRUCT |
-		                    NM_SETTING_PARAM_FUZZY_IGNORE |
-		                    G_PARAM_STATIC_STRINGS));
+	obj_properties[PROP_RATE] =
+	    g_param_spec_uint (NM_SETTING_WIRELESS_RATE, "", "",
+	                       0, G_MAXUINT32, 0,
+	                       G_PARAM_READWRITE |
+	                       G_PARAM_CONSTRUCT |
+	                       NM_SETTING_PARAM_FUZZY_IGNORE |
+	                       G_PARAM_STATIC_STRINGS);
 
 	/**
 	 * NMSettingWireless:tx-power:
@@ -1350,14 +1359,13 @@ nm_setting_wireless_class_init (NMSettingWirelessClass *klass)
 	 * description: This property is not handled by ifcfg-rh plugin.
 	 * ---end---
 	 */
-	g_object_class_install_property
-		(object_class, PROP_TX_POWER,
-		 g_param_spec_uint (NM_SETTING_WIRELESS_TX_POWER, "", "",
-		                    0, G_MAXUINT32, 0,
-		                    G_PARAM_READWRITE |
-		                    G_PARAM_CONSTRUCT |
-		                    NM_SETTING_PARAM_FUZZY_IGNORE |
-		                    G_PARAM_STATIC_STRINGS));
+	obj_properties[PROP_TX_POWER] =
+	    g_param_spec_uint (NM_SETTING_WIRELESS_TX_POWER, "", "",
+	                       0, G_MAXUINT32, 0,
+	                       G_PARAM_READWRITE |
+	                       G_PARAM_CONSTRUCT |
+	                       NM_SETTING_PARAM_FUZZY_IGNORE |
+	                       G_PARAM_STATIC_STRINGS);
 
 	/**
 	 * NMSettingWireless:mac-address:
@@ -1383,16 +1391,14 @@ nm_setting_wireless_class_init (NMSettingWirelessClass *klass)
 	 *    permanent MAC address exists, the MAC address initially configured on the device.
 	 * ---end---
 	 */
-	g_object_class_install_property
-		(object_class, PROP_MAC_ADDRESS,
-		 g_param_spec_string (NM_SETTING_WIRELESS_MAC_ADDRESS, "", "",
-		                      NULL,
-		                      G_PARAM_READWRITE |
-		                      G_PARAM_STATIC_STRINGS));
+	obj_properties[PROP_MAC_ADDRESS] =
+	    g_param_spec_string (NM_SETTING_WIRELESS_MAC_ADDRESS, "", "",
+	                         NULL,
+	                         G_PARAM_READWRITE |
+	                         G_PARAM_STATIC_STRINGS);
 
 	_properties_override_add_transform (properties_override,
-	                                    g_object_class_find_property (G_OBJECT_CLASS (setting_class),
-	                                                                  NM_SETTING_WIRELESS_MAC_ADDRESS),
+	                                    obj_properties[PROP_MAC_ADDRESS],
 	                                    G_VARIANT_TYPE_BYTESTRING,
 	                                    _nm_utils_hwaddr_to_dbus,
 	                                    _nm_utils_hwaddr_from_dbus);
@@ -1439,16 +1445,15 @@ nm_setting_wireless_class_init (NMSettingWirelessClass *klass)
 	 *    For libnm and nmcli, this field is called "cloned-mac-address".
 	 * ---end---
 	 */
-	g_object_class_install_property
-		(object_class, PROP_CLONED_MAC_ADDRESS,
-		 g_param_spec_string (NM_SETTING_WIRELESS_CLONED_MAC_ADDRESS, "", "",
-		                      NULL,
-		                      G_PARAM_READWRITE |
-		                      G_PARAM_STATIC_STRINGS));
+	obj_properties[PROP_CLONED_MAC_ADDRESS] =
+	    g_param_spec_string (NM_SETTING_WIRELESS_CLONED_MAC_ADDRESS, "", "",
+	                         NULL,
+	                         G_PARAM_READWRITE |
+	                         NM_SETTING_PARAM_INFERRABLE |
+	                         G_PARAM_STATIC_STRINGS);
 
 	_properties_override_add_override (properties_override,
-	                                   g_object_class_find_property (G_OBJECT_CLASS (setting_class),
-	                                                                 NM_SETTING_WIRELESS_CLONED_MAC_ADDRESS),
+	                                   obj_properties[PROP_CLONED_MAC_ADDRESS],
 	                                   G_VARIANT_TYPE_BYTESTRING,
 	                                   _nm_utils_hwaddr_cloned_get,
 	                                   _nm_utils_hwaddr_cloned_set,
@@ -1461,7 +1466,7 @@ nm_setting_wireless_class_init (NMSettingWirelessClass *klass)
 	 *   a hardware address in ASCII representation, or one of the special values
 	 *   "preserve", "permanent", "random" or "stable".
 	 *   This field replaces the deprecated "cloned-mac-address" on D-Bus, which
-	 *   can only contain explict hardware addresses. Note that this property
+	 *   can only contain explicit hardware addresses. Note that this property
 	 *   only exists in D-Bus API. libnm and nmcli continue to call this property
 	 *   "cloned-mac-address".
 	 * ---end---
@@ -1511,13 +1516,12 @@ nm_setting_wireless_class_init (NMSettingWirelessClass *klass)
 	 *   cloned-mac-address.
 	 * ---end---
 	 */
-	g_object_class_install_property
-	    (object_class, PROP_GENERATE_MAC_ADDRESS_MASK,
+	obj_properties[PROP_GENERATE_MAC_ADDRESS_MASK] =
 	     g_param_spec_string (NM_SETTING_WIRELESS_GENERATE_MAC_ADDRESS_MASK, "", "",
 	                          NULL,
 	                          G_PARAM_READWRITE |
 	                          NM_SETTING_PARAM_FUZZY_IGNORE |
-	                          G_PARAM_STATIC_STRINGS));
+	                          G_PARAM_STATIC_STRINGS);
 
 	/**
 	 * NMSettingWireless:mac-address-blacklist:
@@ -1539,13 +1543,12 @@ nm_setting_wireless_class_init (NMSettingWirelessClass *klass)
 	 *   is listed.
 	 * ---end---
 	 */
-	g_object_class_install_property
-		(object_class, PROP_MAC_ADDRESS_BLACKLIST,
-		 g_param_spec_boxed (NM_SETTING_WIRELESS_MAC_ADDRESS_BLACKLIST, "", "",
-		                     G_TYPE_STRV,
-		                     G_PARAM_READWRITE |
-		                     NM_SETTING_PARAM_FUZZY_IGNORE |
-		                     G_PARAM_STATIC_STRINGS));
+	obj_properties[PROP_MAC_ADDRESS_BLACKLIST] =
+	    g_param_spec_boxed (NM_SETTING_WIRELESS_MAC_ADDRESS_BLACKLIST, "", "",
+	                        G_TYPE_STRV,
+	                        G_PARAM_READWRITE |
+	                        NM_SETTING_PARAM_FUZZY_IGNORE |
+	                        G_PARAM_STATIC_STRINGS);
 
 	/**
 	 * NMSettingWireless:seen-bssids:
@@ -1563,13 +1566,12 @@ nm_setting_wireless_class_init (NMSettingWirelessClass *klass)
 	 * description: This property is not handled by ifcfg-rh plugin.
 	 * ---end---
 	 */
-	g_object_class_install_property
-		(object_class, PROP_SEEN_BSSIDS,
-		 g_param_spec_boxed (NM_SETTING_WIRELESS_SEEN_BSSIDS, "", "",
-		                     G_TYPE_STRV,
-		                     G_PARAM_READWRITE |
-		                     NM_SETTING_PARAM_FUZZY_IGNORE |
-		                     G_PARAM_STATIC_STRINGS));
+	obj_properties[PROP_SEEN_BSSIDS] =
+	    g_param_spec_boxed (NM_SETTING_WIRELESS_SEEN_BSSIDS, "", "",
+	                        G_TYPE_STRV,
+	                        G_PARAM_READWRITE |
+	                        NM_SETTING_PARAM_FUZZY_IGNORE |
+	                        G_PARAM_STATIC_STRINGS);
 
 	/**
 	 * NMSettingWireless:mtu:
@@ -1583,14 +1585,13 @@ nm_setting_wireless_class_init (NMSettingWirelessClass *klass)
 	 * description: MTU of the wireless interface.
 	 * ---end---
 	 */
-	g_object_class_install_property
-		(object_class, PROP_MTU,
-		 g_param_spec_uint (NM_SETTING_WIRELESS_MTU, "", "",
-		                    0, G_MAXUINT32, 0,
-		                    G_PARAM_READWRITE |
-		                    G_PARAM_CONSTRUCT |
-		                    NM_SETTING_PARAM_FUZZY_IGNORE |
-		                    G_PARAM_STATIC_STRINGS));
+	obj_properties[PROP_MTU] =
+	    g_param_spec_uint (NM_SETTING_WIRELESS_MTU, "", "",
+	                       0, G_MAXUINT32, 0,
+	                       G_PARAM_READWRITE |
+	                       G_PARAM_CONSTRUCT |
+	                       NM_SETTING_PARAM_FUZZY_IGNORE |
+	                       G_PARAM_STATIC_STRINGS);
 
 	/**
 	 * NMSettingWireless:hidden:
@@ -1616,12 +1617,11 @@ nm_setting_wireless_class_init (NMSettingWirelessClass *klass)
 	 * description: Whether the network hides the SSID.
 	 * ---end---
 	 */
-	g_object_class_install_property
-		(object_class, PROP_HIDDEN,
-		 g_param_spec_boolean (NM_SETTING_WIRELESS_HIDDEN, "", "",
-		                       FALSE,
-		                       G_PARAM_READWRITE |
-		                       G_PARAM_STATIC_STRINGS));
+	obj_properties[PROP_HIDDEN] =
+	    g_param_spec_boolean (NM_SETTING_WIRELESS_HIDDEN, "", "",
+	                          FALSE,
+	                          G_PARAM_READWRITE |
+	                          G_PARAM_STATIC_STRINGS);
 
 	/**
 	 * NMSettingWireless:powersave:
@@ -1642,12 +1642,11 @@ nm_setting_wireless_class_init (NMSettingWirelessClass *klass)
 	 * example: POWERSAVE=enable
 	 * ---end---
 	 */
-	g_object_class_install_property
-		(object_class, PROP_POWERSAVE,
-		 g_param_spec_uint (NM_SETTING_WIRELESS_POWERSAVE, "", "",
-		                    0, G_MAXUINT32, NM_SETTING_WIRELESS_POWERSAVE_DEFAULT,
-		                    G_PARAM_READWRITE |
-		                    G_PARAM_STATIC_STRINGS));
+	obj_properties[PROP_POWERSAVE] =
+	    g_param_spec_uint (NM_SETTING_WIRELESS_POWERSAVE, "", "",
+	                       0, G_MAXUINT32, NM_SETTING_WIRELESS_POWERSAVE_DEFAULT,
+	                       G_PARAM_READWRITE |
+	                       G_PARAM_STATIC_STRINGS);
 
 	/**
 	 * NMSettingWireless:mac-address-randomization:
@@ -1670,12 +1669,11 @@ nm_setting_wireless_class_init (NMSettingWirelessClass *klass)
 	 * example: MAC_ADDRESS_RANDOMIZATION=always
 	 * ---end---
 	 */
-	g_object_class_install_property
-		(object_class, PROP_MAC_ADDRESS_RANDOMIZATION,
-		 g_param_spec_uint (NM_SETTING_WIRELESS_MAC_ADDRESS_RANDOMIZATION, "", "",
-		                    0, G_MAXUINT32, NM_SETTING_MAC_RANDOMIZATION_DEFAULT,
-		                    G_PARAM_READWRITE |
-		                    G_PARAM_STATIC_STRINGS));
+	obj_properties[PROP_MAC_ADDRESS_RANDOMIZATION] =
+	    g_param_spec_uint (NM_SETTING_WIRELESS_MAC_ADDRESS_RANDOMIZATION, "", "",
+	                       0, G_MAXUINT32, NM_SETTING_MAC_RANDOMIZATION_DEFAULT,
+	                       G_PARAM_READWRITE |
+	                       G_PARAM_STATIC_STRINGS);
 
 	/* Compatibility for deprecated property */
 	/* ---ifcfg-rh---
@@ -1715,13 +1713,14 @@ nm_setting_wireless_class_init (NMSettingWirelessClass *klass)
 	 *
 	 * Since: 1.12
 	 **/
-	g_object_class_install_property
-		(object_class, PROP_WAKE_ON_WLAN,
-		 g_param_spec_uint (NM_SETTING_WIRELESS_WAKE_ON_WLAN, "", "",
-		                    0, G_MAXUINT32, NM_SETTING_WIRELESS_WAKE_ON_WLAN_DEFAULT,
-		                    G_PARAM_CONSTRUCT |
-		                    G_PARAM_READWRITE |
-		                    G_PARAM_STATIC_STRINGS));
+	obj_properties[PROP_WAKE_ON_WLAN] =
+	    g_param_spec_uint (NM_SETTING_WIRELESS_WAKE_ON_WLAN, "", "",
+	                       0, G_MAXUINT32, NM_SETTING_WIRELESS_WAKE_ON_WLAN_DEFAULT,
+	                       G_PARAM_CONSTRUCT |
+	                       G_PARAM_READWRITE |
+	                       G_PARAM_STATIC_STRINGS);
+
+	g_object_class_install_properties (object_class, _PROPERTY_ENUMS_LAST, obj_properties);
 
 	_nm_setting_class_commit_full (setting_class, NM_META_SETTING_TYPE_WIRELESS,
 	                               NULL, properties_override);
diff --git a/libnm-core/nm-setting-wireless.h b/libnm-core/nm-setting-wireless.h
index e9afe2c6..4611f94b 100644
--- a/libnm-core/nm-setting-wireless.h
+++ b/libnm-core/nm-setting-wireless.h
@@ -49,7 +49,7 @@ G_BEGIN_DECLS
  * @NM_SETTING_WIRELESS_WAKE_ON_WLAN_MAGIC: Wake on magic packet
  * @NM_SETTING_WIRELESS_WAKE_ON_WLAN_GTK_REKEY_FAILURE: Wake on GTK rekey failure
  * @NM_SETTING_WIRELESS_WAKE_ON_WLAN_EAP_IDENTITY_REQUEST: Wake on EAP identity request
- * @NM_SETTING_WIRELESS_WAKE_ON_WLAN_4WAY_HANDSHAKE: Wake on 4way hanshake
+ * @NM_SETTING_WIRELESS_WAKE_ON_WLAN_4WAY_HANDSHAKE: Wake on 4way handshake
  * @NM_SETTING_WIRELESS_WAKE_ON_WLAN_RFKILL_RELEASE: Wake on rfkill release
  * @NM_SETTING_WIRELESS_WAKE_ON_WLAN_ALL: Wake on all events. This does not
  *   include the exclusive flags @NM_SETTING_WIRELESS_WAKE_ON_WLAN_DEFAULT or
diff --git a/libnm-core/nm-setting-wpan.c b/libnm-core/nm-setting-wpan.c
index 6e1aaadc..f4270032 100644
--- a/libnm-core/nm-setting-wpan.c
+++ b/libnm-core/nm-setting-wpan.c
@@ -26,22 +26,43 @@
 #include "nm-setting-private.h"
 #include "nm-utils-private.h"
 
-/* Ideally we'll be able to get this from a public header. */
+/**
+ * SECTION:nm-setting-wpan
+ * @short_description: Describes connection properties for IEEE 802.15.4 (WPAN) MAC
+ *
+ * The #NMSettingWpan object is a #NMSetting subclass that describes properties
+ * necessary for configuring IEEE 802.15.4 (WPAN) MAC layer devices.
+ **/
+
+/* Ideally we'll be able to get these from a public header. */
 #ifndef IEEE802154_ADDR_LEN
 #define IEEE802154_ADDR_LEN 8
 #endif
 
-enum {
-	PROP_0,
+#ifndef IEEE802154_MAX_PAGE
+#define IEEE802154_MAX_PAGE 31
+#endif
+
+#ifndef IEEE802154_MAX_CHANNEL
+#define IEEE802154_MAX_CHANNEL 26
+#endif
+
+/*****************************************************************************/
+
+NM_GOBJECT_PROPERTIES_DEFINE_BASE (
 	PROP_MAC_ADDRESS,
 	PROP_PAN_ID,
 	PROP_SHORT_ADDRESS,
-};
+	PROP_PAGE,
+	PROP_CHANNEL,
+);
 
 typedef struct {
 	char *mac_address;
 	guint16 pan_id;
 	guint16 short_address;
+	gint16 page;
+	gint16 channel;
 } NMSettingWpanPrivate;
 
 /**
@@ -57,18 +78,12 @@ struct _NMSettingWpanClass {
         NMSettingClass parent;
 };
 
-/**
- * SECTION:nm-setting-wpan
- * @short_description: Describes connection properties for IEEE 802.15.4 (WPAN) MAC
- *
- * The #NMSettingWpan object is a #NMSetting subclass that describes properties
- * necessary for configuring IEEE 802.15.4 (WPAN) MAC layer devices.
- **/
-
 G_DEFINE_TYPE (NMSettingWpan, nm_setting_wpan, NM_TYPE_SETTING)
 
 #define NM_SETTING_WPAN_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), NM_TYPE_SETTING_WPAN, NMSettingWpanPrivate))
 
+/*****************************************************************************/
+
 /**
  * nm_setting_wpan_get_mac_address:
  * @setting: the #NMSettingWpan
@@ -117,6 +132,38 @@ nm_setting_wpan_get_short_address (NMSettingWpan *setting)
 	return NM_SETTING_WPAN_GET_PRIVATE (setting)->short_address;
 }
 
+/**
+ * nm_setting_wpan_get_page:
+ * @setting: the #NMSettingWpan
+ *
+ * Returns: the #NMSettingWpan:page property of the setting
+ *
+ * Since: 1.16
+ **/
+gint16
+nm_setting_wpan_get_page (NMSettingWpan *setting)
+{
+	g_return_val_if_fail (NM_IS_SETTING_WPAN (setting), NM_SETTING_WPAN_PAGE_DEFAULT);
+
+	return NM_SETTING_WPAN_GET_PRIVATE (setting)->page;
+}
+
+/**
+ * nm_setting_wpan_get_channel:
+ * @setting: the #NMSettingWpan
+ *
+ * Returns: the #NMSettingWpan:channel property of the setting
+ *
+ * Since: 1.16
+ **/
+gint16
+nm_setting_wpan_get_channel (NMSettingWpan *setting)
+{
+	g_return_val_if_fail (NM_IS_SETTING_WPAN (setting), NM_SETTING_WPAN_CHANNEL_DEFAULT);
+
+	return NM_SETTING_WPAN_GET_PRIVATE (setting)->channel;
+}
+
 static gboolean
 verify (NMSetting *setting, NMConnection *connection, GError **error)
 {
@@ -131,9 +178,42 @@ verify (NMSetting *setting, NMConnection *connection, GError **error)
 		return FALSE;
 	}
 
+	if ((priv->page == NM_SETTING_WPAN_PAGE_DEFAULT) != (priv->channel == NM_SETTING_WPAN_CHANNEL_DEFAULT)) {
+		g_set_error_literal (error,
+		                     NM_CONNECTION_ERROR,
+		                     NM_CONNECTION_ERROR_INVALID_PROPERTY,
+		                     _("page must be defined along with a channel"));
+		g_prefix_error (error, "%s.%s: ", NM_SETTING_WPAN_SETTING_NAME, NM_SETTING_WPAN_PAGE);
+		return FALSE;
+	}
+
+	if (priv->page < NM_SETTING_WPAN_PAGE_DEFAULT || priv->page > IEEE802154_MAX_PAGE) {
+		g_set_error (error,
+		             NM_CONNECTION_ERROR,
+		             NM_CONNECTION_ERROR_INVALID_PROPERTY,
+		             _("page must be between %d and %d"),
+		             NM_SETTING_WPAN_PAGE_DEFAULT,
+		             IEEE802154_MAX_PAGE);
+		g_prefix_error (error, "%s.%s: ", NM_SETTING_WPAN_SETTING_NAME, NM_SETTING_WPAN_PAGE);
+		return FALSE;
+	}
+
+	if (priv->channel < NM_SETTING_WPAN_CHANNEL_DEFAULT || priv->channel > IEEE802154_MAX_CHANNEL) {
+		g_set_error (error,
+		             NM_CONNECTION_ERROR,
+		             NM_CONNECTION_ERROR_INVALID_PROPERTY,
+		             _("channel must not be between %d and %d"),
+		             NM_SETTING_WPAN_CHANNEL_DEFAULT,
+		             IEEE802154_MAX_CHANNEL);
+		g_prefix_error (error, "%s.%s: ", NM_SETTING_WPAN_SETTING_NAME, NM_SETTING_WPAN_CHANNEL);
+		return FALSE;
+	}
+
 	return TRUE;
 }
 
+/*****************************************************************************/
+
 static void
 get_property (GObject *object, guint prop_id, GValue *value, GParamSpec *pspec)
 {
@@ -149,6 +229,12 @@ get_property (GObject *object, guint prop_id, GValue *value, GParamSpec *pspec)
 	case PROP_SHORT_ADDRESS:
 		g_value_set_uint (value, nm_setting_wpan_get_short_address (setting));
 		break;
+	case PROP_PAGE:
+		g_value_set_int (value, nm_setting_wpan_get_page (setting));
+		break;
+	case PROP_CHANNEL:
+		g_value_set_int (value, nm_setting_wpan_get_channel (setting));
+		break;
 	default:
 		G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
 		break;
@@ -172,19 +258,29 @@ set_property (GObject *object, guint prop_id, const GValue *value, GParamSpec *p
 	case PROP_SHORT_ADDRESS:
 		priv->short_address = g_value_get_uint (value);
 		break;
+	case PROP_PAGE:
+		priv->page = g_value_get_int (value);
+		break;
+	case PROP_CHANNEL:
+		priv->channel = g_value_get_int (value);
+		break;
 	default:
 		G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
 		break;
 	}
 }
 
+/*****************************************************************************/
+
 static void
 nm_setting_wpan_init (NMSettingWpan *setting)
 {
 	NMSettingWpanPrivate *priv = NM_SETTING_WPAN_GET_PRIVATE (setting);
 
-	priv->short_address = G_MAXUINT16;
 	priv->pan_id = G_MAXUINT16;
+	priv->short_address = G_MAXUINT16;
+	priv->page = NM_SETTING_WPAN_PAGE_DEFAULT;
+	priv->channel = NM_SETTING_WPAN_CHANNEL_DEFAULT;
 }
 
 /**
@@ -220,8 +316,8 @@ nm_setting_wpan_class_init (NMSettingWpanClass *klass)
 
 	g_type_class_add_private (setting_class, sizeof (NMSettingWpanPrivate));
 
-	object_class->set_property = set_property;
 	object_class->get_property = get_property;
+	object_class->set_property = set_property;
 	object_class->finalize     = finalize;
 
 	setting_class->verify = verify;
@@ -239,36 +335,67 @@ nm_setting_wpan_class_init (NMSettingWpanClass *klass)
 	 *   (e.g. 76:d8:9b:87:66:60:84:ee).
 	 * ---end---
 	 */
-	g_object_class_install_property
-	        (object_class, PROP_MAC_ADDRESS,
-	         g_param_spec_string (NM_SETTING_WPAN_MAC_ADDRESS, "", "",
-	                              NULL,
-	                              G_PARAM_READWRITE |
-	                              G_PARAM_STATIC_STRINGS));
+	obj_properties[PROP_MAC_ADDRESS] =
+	    g_param_spec_string (NM_SETTING_WPAN_MAC_ADDRESS, "", "",
+	                         NULL,
+	                         G_PARAM_READWRITE |
+	                         G_PARAM_STATIC_STRINGS);
 
 	/**
 	 * NMSettingWpan:pan-id:
 	 *
 	 * IEEE 802.15.4 Personal Area Network (PAN) identifier.
 	 **/
-	g_object_class_install_property
-	        (object_class, PROP_PAN_ID,
-	         g_param_spec_uint (NM_SETTING_WPAN_PAN_ID, "", "",
-	                            0, G_MAXUINT16, G_MAXUINT16,
-	                            G_PARAM_READWRITE |
-	                            G_PARAM_STATIC_STRINGS));
+	obj_properties[PROP_PAN_ID] =
+	    g_param_spec_uint (NM_SETTING_WPAN_PAN_ID, "", "",
+	                       0, G_MAXUINT16, G_MAXUINT16,
+	                       G_PARAM_READWRITE |
+	                       G_PARAM_STATIC_STRINGS);
 
 	/**
 	 * NMSettingWpan:short-address:
 	 *
 	 * Short IEEE 802.15.4 address to be used within a restricted environment.
 	 **/
-	g_object_class_install_property
-	        (object_class, PROP_SHORT_ADDRESS,
-	         g_param_spec_uint (NM_SETTING_WPAN_SHORT_ADDRESS, "", "",
-	                            0, G_MAXUINT16, G_MAXUINT16,
-	                            G_PARAM_READWRITE |
-	                            G_PARAM_STATIC_STRINGS));
+	obj_properties[PROP_SHORT_ADDRESS] =
+	    g_param_spec_uint (NM_SETTING_WPAN_SHORT_ADDRESS, "", "",
+	                       0, G_MAXUINT16, G_MAXUINT16,
+	                       G_PARAM_READWRITE |
+	                       G_PARAM_STATIC_STRINGS);
+
+	/**
+	 * NMSettingWpan:page:
+	 *
+	 * IEEE 802.15.4 channel page. A positive integer or -1, meaning "do not
+	 * set, use whatever the device is already set to".
+	 *
+	 * Since: 1.16
+	 **/
+	obj_properties[PROP_PAGE] =
+	    g_param_spec_int (NM_SETTING_WPAN_PAGE, "", "",
+	                       G_MININT16,
+	                       G_MAXINT16,
+	                       NM_SETTING_WPAN_PAGE_DEFAULT,
+	                       G_PARAM_READWRITE |
+	                       G_PARAM_STATIC_STRINGS);
+
+	/**
+	 * NMSettingWpan:channel:
+	 *
+	 * IEEE 802.15.4 channel. A positive integer or -1, meaning "do not
+	 * set, use whatever the device is already set to".
+	 *
+	 * Since: 1.16
+	 **/
+	obj_properties[PROP_CHANNEL] =
+	    g_param_spec_int (NM_SETTING_WPAN_CHANNEL, "", "",
+	                       G_MININT16,
+	                       G_MAXINT16,
+	                       NM_SETTING_WPAN_CHANNEL_DEFAULT,
+	                       G_PARAM_READWRITE |
+	                       G_PARAM_STATIC_STRINGS);
+
+	g_object_class_install_properties (object_class, _PROPERTY_ENUMS_LAST, obj_properties);
 
 	_nm_setting_class_commit (setting_class, NM_META_SETTING_TYPE_WPAN);
 }
diff --git a/libnm-core/nm-setting-wpan.h b/libnm-core/nm-setting-wpan.h
index a39e377e..aaea1086 100644
--- a/libnm-core/nm-setting-wpan.h
+++ b/libnm-core/nm-setting-wpan.h
@@ -39,6 +39,11 @@ G_BEGIN_DECLS
 #define NM_SETTING_WPAN_MAC_ADDRESS        "mac-address"
 #define NM_SETTING_WPAN_PAN_ID             "pan-id"
 #define NM_SETTING_WPAN_SHORT_ADDRESS      "short-address"
+#define NM_SETTING_WPAN_PAGE               "page"
+#define NM_SETTING_WPAN_CHANNEL            "channel"
+
+#define NM_SETTING_WPAN_PAGE_DEFAULT    -1
+#define NM_SETTING_WPAN_CHANNEL_DEFAULT -1
 
 typedef struct _NMSettingWpanClass NMSettingWpanClass;
 
@@ -53,6 +58,10 @@ NM_AVAILABLE_IN_1_14
 guint16     nm_setting_wpan_get_pan_id             (NMSettingWpan *setting);
 NM_AVAILABLE_IN_1_14
 guint16     nm_setting_wpan_get_short_address      (NMSettingWpan *setting);
+NM_AVAILABLE_IN_1_16
+gint16      nm_setting_wpan_get_page               (NMSettingWpan *setting);
+NM_AVAILABLE_IN_1_16
+gint16      nm_setting_wpan_get_channel            (NMSettingWpan *setting);
 
 G_END_DECLS
 
diff --git a/libnm-core/nm-setting.c b/libnm-core/nm-setting.c
index 6b9681b5..976f7f00 100644
--- a/libnm-core/nm-setting.c
+++ b/libnm-core/nm-setting.c
@@ -67,12 +67,9 @@ typedef struct {
 	NMSettingPriority priority;
 } SettingInfo;
 
-enum {
-	PROP_0,
+NM_GOBJECT_PROPERTIES_DEFINE_BASE (
 	PROP_NAME,
-
-	PROP_LAST
-};
+);
 
 typedef struct {
 	GenData *gendata;
@@ -354,6 +351,77 @@ _properties_override_add_transform (GArray *properties_override,
 
 static NMSettInfoSetting _sett_info_settings[_NM_META_SETTING_TYPE_NUM];
 
+static int
+_property_infos_sort_cmp_setting_connection (gconstpointer p_a,
+                                             gconstpointer p_b,
+                                             gpointer user_data)
+{
+	const NMSettInfoProperty *a = *((const NMSettInfoProperty *const*) p_a);
+	const NMSettInfoProperty *b = *((const NMSettInfoProperty *const*) p_b);
+	int c_name;
+
+	c_name = strcmp (a->name, b->name);
+	nm_assert (c_name != 0);
+
+#define CMP_AND_RETURN(n_a, n_b, name) \
+	G_STMT_START { \
+		gboolean _is = nm_streq (n_a, ""name); \
+		\
+		if (   _is \
+		    || nm_streq (n_b, ""name)) \
+			return _is ? -1 : 1; \
+	} G_STMT_END
+
+	/* for [connection], report first id, uuid, type in that order. */
+	if (c_name != 0) {
+		CMP_AND_RETURN (a->name, b->name, NM_SETTING_CONNECTION_ID);
+		CMP_AND_RETURN (a->name, b->name, NM_SETTING_CONNECTION_UUID);
+		CMP_AND_RETURN (a->name, b->name, NM_SETTING_CONNECTION_TYPE);
+	}
+
+#undef CMP_AND_RETURN
+
+	return c_name;
+}
+
+static const NMSettInfoProperty *const*
+_property_infos_sort (const NMSettInfoProperty *property_infos,
+                      guint property_infos_len,
+                      NMSettingClass *setting_class)
+{
+	const NMSettInfoProperty **arr;
+	guint i;
+
+#if NM_MORE_ASSERTS > 5
+	/* assert that the property names are all unique and sorted. */
+	for (i = 0; i < property_infos_len; i++) {
+		if (property_infos[i].param_spec)
+			nm_assert (nm_streq (property_infos[i].name, property_infos[i].param_spec->name));
+		if (i > 0)
+			nm_assert (strcmp (property_infos[i - 1].name, property_infos[i].name) < 0);
+	}
+#endif
+
+	if (property_infos_len <= 1)
+		return NULL;
+	if (G_TYPE_FROM_CLASS (setting_class) != NM_TYPE_SETTING_CONNECTION) {
+		/* we only do something special for certain setting types. This one,
+		 * has just alphabetical sorting. */
+		return NULL;
+	}
+
+	arr = g_new (const NMSettInfoProperty *, property_infos_len);
+	for (i = 0; i < property_infos_len; i++)
+		arr[i] = &property_infos[i];
+
+	g_qsort_with_data (arr,
+	                   property_infos_len,
+	                   sizeof (const NMSettInfoProperty *),
+	                   _property_infos_sort_cmp_setting_connection,
+	                   NULL);
+	return arr;
+}
+
 void
 _nm_setting_class_commit_full (NMSettingClass *setting_class,
                                NMMetaSettingType meta_type,
@@ -387,19 +455,21 @@ _nm_setting_class_commit_full (NMSettingClass *setting_class,
 #if NM_MORE_ASSERTS > 10
 	/* assert that properties_override is constructed consistently. */
 	for (i = 0; i < override_len; i++) {
-		guint j;
 		const NMSettInfoProperty *p = &g_array_index (properties_override, NMSettInfoProperty, i);
+		gboolean found = FALSE;
+		guint j;
 
 		nm_assert (!_nm_sett_info_property_find_in_array ((NMSettInfoProperty *) properties_override->data,
 		                                                  i,
 		                                                  p->name));
 		for (j = 0; j < n_property_specs; j++) {
-			if (nm_streq (property_specs[j]->name, p->name)) {
-				nm_assert (p->param_spec == property_specs[j]);
-				break;
-			}
+			if (!nm_streq (property_specs[j]->name, p->name))
+				continue;
+			nm_assert (!found);
+			found = TRUE;
+			nm_assert (p->param_spec == property_specs[j]);
 		}
-		nm_assert ((j == n_property_specs) == (p->param_spec == NULL));
+		nm_assert (found == (p->param_spec != NULL));
 	}
 #endif
 
@@ -429,27 +499,21 @@ _nm_setting_class_commit_full (NMSettingClass *setting_class,
 	sett_info->property_infos_len = properties_override->len;
 	sett_info->property_infos = (const NMSettInfoProperty *) g_array_free (properties_override,
 	                                                                       properties_override->len == 0);
-}
 
-const NMSettInfoSetting *
-_nm_sett_info_setting_get (NMSettingClass *setting_class)
-{
-	if (   NM_IS_SETTING_CLASS (setting_class)
-	    && setting_class->setting_info) {
-		nm_assert (setting_class->setting_info->meta_type < G_N_ELEMENTS (_sett_info_settings));
-		return &_sett_info_settings[setting_class->setting_info->meta_type];
-	}
-	return NULL;
+	sett_info->property_infos_sorted = _property_infos_sort (sett_info->property_infos,
+	                                                         sett_info->property_infos_len,
+	                                                         setting_class);
 }
 
 const NMSettInfoProperty *
-_nm_sett_info_property_get (NMSettingClass *setting_class,
-                            const char *property_name)
+_nm_sett_info_setting_get_property_info (const NMSettInfoSetting *sett_info,
+                                         const char *property_name)
 {
-	const NMSettInfoSetting *sett_info = _nm_sett_info_setting_get (setting_class);
 	const NMSettInfoProperty *property;
 	gssize idx;
 
+	nm_assert (property_name);
+
 	if (!sett_info)
 		return NULL;
 
@@ -472,6 +536,21 @@ _nm_sett_info_property_get (NMSettingClass *setting_class,
 	return property;
 }
 
+const NMSettInfoSetting *
+_nm_setting_class_get_sett_info (NMSettingClass *setting_class)
+{
+	const NMSettInfoSetting *sett_info;
+
+	if (   !NM_IS_SETTING_CLASS (setting_class)
+	    || !setting_class->setting_info)
+		return NULL;
+
+	nm_assert (setting_class->setting_info->meta_type < G_N_ELEMENTS (_sett_info_settings));
+	sett_info = &_sett_info_settings[setting_class->setting_info->meta_type];
+	nm_assert (sett_info->setting_class == setting_class);
+	return sett_info;
+}
+
 /*****************************************************************************/
 
 gboolean
@@ -654,7 +733,7 @@ _nm_setting_to_dbus (NMSetting *setting, NMConnection *connection, NMConnectionS
 		                       g_hash_table_lookup (priv->gendata->hash, gendata_keys[i]));
 	}
 
-	sett_info = _nm_sett_info_setting_get (NM_SETTING_GET_CLASS (setting));
+	sett_info = _nm_setting_class_get_sett_info (NM_SETTING_GET_CLASS (setting));
 	for (i = 0; i < sett_info->property_infos_len; i++) {
 		const NMSettInfoProperty *property = &sett_info->property_infos[i];
 		GParamSpec *prop_spec = property->param_spec;
@@ -662,10 +741,13 @@ _nm_setting_to_dbus (NMSetting *setting, NMConnection *connection, NMConnectionS
 		if (!prop_spec) {
 			if (!property->synth_func)
 				continue;
-
-			if (flags & NM_CONNECTION_SERIALIZE_ONLY_SECRETS)
-				continue;
 		} else {
+
+			/* For the moment, properties backed by a GObject property don't
+			 * define a synth function. There is no problem supporting that,
+			 * however, for now just disallow it. */
+			nm_assert (!property->synth_func);
+
 			if (!(prop_spec->flags & G_PARAM_WRITABLE))
 				continue;
 
@@ -686,9 +768,10 @@ _nm_setting_to_dbus (NMSetting *setting, NMConnection *connection, NMConnectionS
 		}
 
 		if (property->synth_func)
-			dbus_value = property->synth_func (setting, connection, property->name);
+			dbus_value = property->synth_func (sett_info, i, connection, setting, flags);
 		else
 			dbus_value = get_property_for_dbus (setting, property, TRUE);
+
 		if (dbus_value) {
 			/* Allow dbus_value to be either floating or not. */
 			g_variant_take_ref (dbus_value);
@@ -775,7 +858,7 @@ _nm_setting_new_from_dbus (GType setting_type,
 		}
 	}
 
-	sett_info = _nm_sett_info_setting_get (NM_SETTING_GET_CLASS (setting));
+	sett_info = _nm_setting_class_get_sett_info (NM_SETTING_GET_CLASS (setting));
 
 	if (sett_info->detail.gendata_info) {
 		GHashTable *hash;
@@ -797,89 +880,94 @@ _nm_setting_new_from_dbus (GType setting_type,
 	}
 
 	for (i = 0; i < sett_info->property_infos_len; i++) {
-		const NMSettInfoProperty *property = &sett_info->property_infos[i];
+		const NMSettInfoProperty *property_info = &sett_info->property_infos[i];
 		gs_unref_variant GVariant *value = NULL;
 		gs_free_error GError *local = NULL;
 
-		if (property->param_spec && !(property->param_spec->flags & G_PARAM_WRITABLE))
+		if (   property_info->param_spec
+		    && !(property_info->param_spec->flags & G_PARAM_WRITABLE))
 			continue;
 
-		value = g_variant_lookup_value (setting_dict, property->name, NULL);
+		value = g_variant_lookup_value (setting_dict, property_info->name, NULL);
 
 		if (value && keys)
-			g_hash_table_remove (keys, property->name);
+			g_hash_table_remove (keys, property_info->name);
 
-		if (value && property->set_func) {
+		if (   value
+		    && property_info->set_func) {
 
-			if (!g_variant_type_equal (g_variant_get_type (value), property->dbus_type)) {
+			if (!g_variant_type_equal (g_variant_get_type (value), property_info->dbus_type)) {
 				/* 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)",
+				             property_info->dbus_type ?
+				                 g_variant_type_peek_string (property_info->dbus_type) :
+				                 property_info->param_spec ?
+				                     g_type_name (property_info->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_prefix_error (error, "%s.%s: ", nm_setting_get_name (setting), property_info->name);
 				return NULL;
 			}
 
-			if (!property->set_func (setting,
-			                         connection_dict,
-			                         property->name,
-			                         value,
-			                         parse_flags,
-			                         &local)) {
+			if (!property_info->set_func (setting,
+			                             connection_dict,
+			                             property_info->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);
+				g_prefix_error (error, "%s.%s: ", nm_setting_get_name (setting), property_info->name);
 				return NULL;
 			}
-		} else if (!value && property->not_set_func) {
-			if (!property->not_set_func (setting,
-			                             connection_dict,
-			                             property->name,
-			                             parse_flags,
-			                             &local)) {
+		} else if (   !value
+		           && property_info->not_set_func) {
+			if (!property_info->not_set_func (setting,
+			                                  connection_dict,
+			                                  property_info->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);
+				g_prefix_error (error, "%s.%s: ", nm_setting_get_name (setting), property_info->name);
 				return NULL;
 			}
-		} else if (value && property->param_spec) {
+		} else if (   value
+		           && property_info->param_spec) {
 			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)) {
+			g_value_init (&object_value, property_info->param_spec->value_type);
+			if (!set_property_from_dbus (property_info, 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)",
+				               property_info->dbus_type
+				             ? g_variant_type_peek_string (property_info->dbus_type)
+				             : (  property_info->param_spec
+				                ? g_type_name (property_info->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_prefix_error (error, "%s.%s: ", nm_setting_get_name (setting), property_info->name);
 				return NULL;
 			}
 
-			if (!nm_g_object_set_property (G_OBJECT (setting), property->param_spec->name, &object_value, &local)) {
+			if (!nm_g_object_set_property (G_OBJECT (setting), property_info->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);
+				g_prefix_error (error, "%s.%s: ", nm_setting_get_name (setting), property_info->name);
 				return NULL;
 			}
 		}
@@ -921,7 +1009,7 @@ nm_setting_get_dbus_property_type (NMSetting *setting,
 	g_return_val_if_fail (NM_IS_SETTING (setting), NULL);
 	g_return_val_if_fail (property_name != NULL, NULL);
 
-	property = _nm_sett_info_property_get (NM_SETTING_GET_CLASS (setting), property_name);
+	property = _nm_setting_class_get_property_info (NM_SETTING_GET_CLASS (setting), property_name);
 	g_return_val_if_fail (property != NULL, NULL);
 
 	if (property->dbus_type)
@@ -934,13 +1022,13 @@ gboolean
 _nm_setting_get_property (NMSetting *setting, const char *property_name, GValue *value)
 {
 	const NMSettInfoSetting *sett_info;
-	GParamSpec *prop_spec;
+	const NMSettInfoProperty *property_info;
 
 	g_return_val_if_fail (NM_IS_SETTING (setting), FALSE);
 	g_return_val_if_fail (property_name, FALSE);
 	g_return_val_if_fail (value, FALSE);
 
-	sett_info = _nm_sett_info_setting_get (NM_SETTING_GET_CLASS (setting));
+	sett_info = _nm_setting_class_get_sett_info (NM_SETTING_GET_CLASS (setting));
 
 	if (sett_info->detail.gendata_info) {
 		GVariant *variant;
@@ -958,26 +1046,84 @@ _nm_setting_get_property (NMSetting *setting, const char *property_name, GValue
 		return TRUE;
 	}
 
-	prop_spec = g_object_class_find_property (G_OBJECT_GET_CLASS (setting), property_name);
-	if (!prop_spec) {
+	property_info = _nm_sett_info_setting_get_property_info (sett_info, property_name);
+	if (   !property_info
+	    || !property_info->param_spec) {
 		g_value_unset (value);
 		return FALSE;
 	}
 
-	g_value_init (value, prop_spec->value_type);
+	g_value_init (value, property_info->param_spec->value_type);
 	g_object_get_property (G_OBJECT (setting), property_name, value);
 	return TRUE;
 }
 
 static void
-duplicate_setting (NMSetting *setting,
-                   const char *name,
-                   const GValue *value,
-                   GParamFlags flags,
-                   gpointer user_data)
+_gobject_copy_property (GObject *src,
+                        GObject *dst,
+                        const char *property_name,
+                        GType gtype)
+{
+	nm_auto_unset_gvalue GValue value = G_VALUE_INIT;
+
+	nm_assert (G_IS_OBJECT (src));
+	nm_assert (G_IS_OBJECT (dst));
+
+	g_value_init (&value, gtype);
+	g_object_get_property (src, property_name, &value);
+	g_object_set_property (dst, property_name, &value);
+}
+
+static void
+duplicate_copy_properties (const NMSettInfoSetting *sett_info,
+                           NMSetting *src,
+                           NMSetting *dst)
 {
-	if ((flags & (G_PARAM_WRITABLE | G_PARAM_CONSTRUCT_ONLY)) == G_PARAM_WRITABLE)
-		g_object_set_property (G_OBJECT (user_data), name, value);
+	if (sett_info->detail.gendata_info) {
+		GenData *gendata = _gendata_hash (src, FALSE);
+
+		if (   gendata
+		    && g_hash_table_size (gendata->hash) > 0) {
+			GHashTableIter iter;
+			GHashTable *h = _gendata_hash (dst, TRUE)->hash;
+			const char *key;
+			GVariant *val;
+
+			g_hash_table_iter_init (&iter, gendata->hash);
+			while (g_hash_table_iter_next (&iter, (gpointer *) &key, (gpointer *) &val)) {
+				g_hash_table_insert (h,
+				                     g_strdup (key),
+				                     g_variant_ref (val));
+			}
+		}
+	}
+
+	if (sett_info->property_infos_len > 0) {
+		gboolean frozen = FALSE;
+		guint i;
+
+		for (i = 0; i < sett_info->property_infos_len; i++) {
+			const NMSettInfoProperty *property_info = &sett_info->property_infos[i];
+
+			if (property_info->param_spec) {
+				if ((property_info->param_spec->flags & (G_PARAM_WRITABLE | G_PARAM_CONSTRUCT_ONLY)) != G_PARAM_WRITABLE)
+					continue;
+
+				if (!frozen) {
+					g_object_freeze_notify (G_OBJECT (dst));
+					frozen = TRUE;
+				}
+				_gobject_copy_property (G_OBJECT (src),
+				                        G_OBJECT (dst),
+				                        property_info->param_spec->name,
+				                        G_PARAM_SPEC_VALUE_TYPE (property_info->param_spec));
+				continue;
+			}
+		}
+
+		if (frozen)
+			g_object_thaw_notify (G_OBJECT (dst));
+	}
 }
 
 /**
@@ -993,37 +1139,22 @@ NMSetting *
 nm_setting_duplicate (NMSetting *setting)
 {
 	const NMSettInfoSetting *sett_info;
-	GObject *dup;
+	NMSettingClass *klass;
+	NMSetting *dst;
 
 	g_return_val_if_fail (NM_IS_SETTING (setting), NULL);
 
-	dup = g_object_new (G_OBJECT_TYPE (setting), NULL);
-
-	sett_info = _nm_sett_info_setting_get (NM_SETTING_GET_CLASS (setting));
+	klass = NM_SETTING_GET_CLASS (setting);
+	nm_assert (NM_IS_SETTING_CLASS (klass));
+	nm_assert (klass->duplicate_copy_properties);
 
-	if (sett_info->detail.gendata_info) {
-		GenData *gendata = _gendata_hash (setting, FALSE);
+	dst = g_object_new (G_TYPE_FROM_CLASS (klass), NULL);
 
-		if (   gendata
-		    && g_hash_table_size (gendata->hash) > 0) {
-			GHashTableIter iter;
-			GHashTable *h = _gendata_hash (NM_SETTING (dup), TRUE)->hash;
-			const char *key;
-			GVariant *val;
+	sett_info = _nm_setting_class_get_sett_info (klass);
+	nm_assert (sett_info);
 
-			g_hash_table_iter_init (&iter, gendata->hash);
-			while (g_hash_table_iter_next (&iter, (gpointer *) &key, (gpointer *) &val)) {
-				g_hash_table_insert (h,
-				                     g_strdup (key),
-				                     g_variant_ref (val));
-			}
-		}
-	} else {
-		g_object_freeze_notify (dup);
-		nm_setting_enumerate_values (setting, duplicate_setting, dup);
-		g_object_thaw_notify (dup);
-	}
-	return NM_SETTING (dup);
+	klass->duplicate_copy_properties (sett_info, setting, dst);
+	return dst;
 }
 
 /**
@@ -1131,58 +1262,148 @@ _nm_setting_verify_secret_string (const char *str,
 	return TRUE;
 }
 
-static gboolean
-compare_property (NMSetting *setting,
+gboolean
+_nm_setting_should_compare_secret_property (NMSetting *setting,
+                                            NMSetting *other,
+                                            const char *secret_name,
+                                            NMSettingCompareFlags flags)
+{
+	NMSettingSecretFlags a_secret_flags = NM_SETTING_SECRET_FLAG_NONE;
+	NMSettingSecretFlags b_secret_flags = NM_SETTING_SECRET_FLAG_NONE;
+
+	nm_assert (NM_IS_SETTING (setting));
+	nm_assert (!other || G_OBJECT_TYPE (setting) == G_OBJECT_TYPE (other));
+
+	/* secret_name must be a valid secret for @setting. */
+	nm_assert (nm_setting_get_secret_flags (setting, secret_name, NULL, NULL));
+
+	if (!NM_FLAGS_ANY (flags,   NM_SETTING_COMPARE_FLAG_IGNORE_AGENT_OWNED_SECRETS
+	                          | NM_SETTING_COMPARE_FLAG_IGNORE_NOT_SAVED_SECRETS))
+		return TRUE;
+
+	nm_setting_get_secret_flags (setting, secret_name, &a_secret_flags, NULL);
+	if (other) {
+		if (!nm_setting_get_secret_flags (other, secret_name, &b_secret_flags, NULL)) {
+			/* secret-name may not be a valid secret for @other. That is fine, we ignore that
+			 * and treat @b_secret_flags as NM_SETTING_SECRET_FLAG_NONE.
+			 *
+			 * This can happen with VPN secrets, where the caller knows that @secret_name
+			 * is a secret for setting, but it may not be a secret for @other. Accept that.
+			 *
+			 * Mark @other as missing. */
+			other = NULL;
+		}
+	}
+
+	/* when @setting has the secret-flags that should be ignored,
+	 * we skip the comparisong if:
+	 *
+	 *   - @other is not present,
+	 *   - @other does not have a secret named @secret_name
+	 *   - @other also has the secret flat to be ignored.
+	 *
+	 * This makes the check symmetric (aside the fact that @setting must
+	 * have the secret while @other may not -- which is asymetric). */
+	if (   NM_FLAGS_HAS (flags, NM_SETTING_COMPARE_FLAG_IGNORE_AGENT_OWNED_SECRETS)
+	    && NM_FLAGS_HAS (a_secret_flags, NM_SETTING_SECRET_FLAG_AGENT_OWNED)
+	    && (   !other
+	        || NM_FLAGS_HAS (b_secret_flags, NM_SETTING_SECRET_FLAG_AGENT_OWNED)))
+		return FALSE;
+
+	if (   NM_FLAGS_HAS (flags, NM_SETTING_COMPARE_FLAG_IGNORE_NOT_SAVED_SECRETS)
+	    && NM_FLAGS_HAS (a_secret_flags, NM_SETTING_SECRET_FLAG_NOT_SAVED)
+	    && (   !other
+	        || NM_FLAGS_HAS (b_secret_flags, NM_SETTING_SECRET_FLAG_NOT_SAVED)))
+		return FALSE;
+
+	return TRUE;
+}
+
+static NMTernary
+compare_property (const NMSettInfoSetting *sett_info,
+                  guint property_idx,
+                  NMSetting *setting,
                   NMSetting *other,
-                  const GParamSpec *prop_spec,
                   NMSettingCompareFlags flags)
 {
-	const NMSettInfoProperty *property;
-	GVariant *value1, *value2;
-	int cmp;
+	const NMSettInfoProperty *property_info = &sett_info->property_infos[property_idx];
+	const GParamSpec *param_spec = property_info->param_spec;
 
-	/* Handle compare flags */
-	if (prop_spec->flags & NM_SETTING_PARAM_SECRET) {
-		NMSettingSecretFlags a_secret_flags = NM_SETTING_SECRET_FLAG_NONE;
-		NMSettingSecretFlags b_secret_flags = NM_SETTING_SECRET_FLAG_NONE;
+	if (!param_spec)
+		return NM_TERNARY_DEFAULT;
 
-		g_return_val_if_fail (!NM_IS_SETTING_VPN (setting), FALSE);
+	if (   NM_FLAGS_HAS (flags, NM_SETTING_COMPARE_FLAG_FUZZY)
+	    && NM_FLAGS_ANY (param_spec->flags, NM_SETTING_PARAM_FUZZY_IGNORE | NM_SETTING_PARAM_SECRET))
+		return NM_TERNARY_DEFAULT;
 
-		if (!nm_setting_get_secret_flags (setting, prop_spec->name, &a_secret_flags, NULL))
-			g_return_val_if_reached (FALSE);
-		if (!nm_setting_get_secret_flags (other, prop_spec->name, &b_secret_flags, NULL))
-			g_return_val_if_reached (FALSE);
+	if (   NM_FLAGS_HAS (flags, NM_SETTING_COMPARE_FLAG_INFERRABLE)
+	    && !NM_FLAGS_HAS (param_spec->flags, NM_SETTING_PARAM_INFERRABLE))
+		return NM_TERNARY_DEFAULT;
 
-		/* If the secret flags aren't the same the settings aren't the same */
-		if (a_secret_flags != b_secret_flags)
-			return FALSE;
+	if (   NM_FLAGS_HAS (flags, NM_SETTING_COMPARE_FLAG_IGNORE_REAPPLY_IMMEDIATELY)
+	    && NM_FLAGS_HAS (param_spec->flags, NM_SETTING_PARAM_REAPPLY_IMMEDIATELY))
+		return NM_TERNARY_DEFAULT;
 
-		/* Check for various secret flags that might cause us to ignore comparing
-		 * this property.
-		 */
-		if (   (flags & NM_SETTING_COMPARE_FLAG_IGNORE_AGENT_OWNED_SECRETS)
-		    && (a_secret_flags & NM_SETTING_SECRET_FLAG_AGENT_OWNED))
-			return TRUE;
+	if (   NM_FLAGS_HAS (flags, NM_SETTING_COMPARE_FLAG_IGNORE_SECRETS)
+	    && NM_FLAGS_HAS (param_spec->flags, NM_SETTING_PARAM_SECRET))
+		return NM_TERNARY_DEFAULT;
 
-		if (   (flags & NM_SETTING_COMPARE_FLAG_IGNORE_NOT_SAVED_SECRETS)
-		    && (a_secret_flags & NM_SETTING_SECRET_FLAG_NOT_SAVED))
-			return TRUE;
-	}
+	if (nm_streq (param_spec->name, NM_SETTING_NAME))
+		return NM_TERNARY_DEFAULT;
 
-	property = _nm_sett_info_property_get (NM_SETTING_GET_CLASS (setting), prop_spec->name);
-	g_return_val_if_fail (property != NULL, FALSE);
+	if (   NM_FLAGS_HAS (param_spec->flags, NM_SETTING_PARAM_SECRET)
+	    && !_nm_setting_should_compare_secret_property (setting,
+	                                                    other,
+	                                                    param_spec->name,
+	                                                    flags))
+		return NM_TERNARY_DEFAULT;
 
-	value1 = get_property_for_dbus (setting, property, TRUE);
-	value2 = get_property_for_dbus (other, property, TRUE);
+	if (other) {
+		gs_unref_variant GVariant *value1  = NULL;
+		gs_unref_variant GVariant *value2  = NULL;
 
-	cmp = nm_property_compare (value1, value2);
+		value1 = get_property_for_dbus (setting, property_info, TRUE);
+		value2 = get_property_for_dbus (other, property_info, TRUE);
+
+		if (nm_property_compare (value1, value2) != 0)
+			return NM_TERNARY_FALSE;
+	}
 
-	if (value1)
-		g_variant_unref (value1);
-	if (value2)
-		g_variant_unref (value2);
+	return NM_TERNARY_TRUE;
+}
 
-	return cmp == 0;
+static NMTernary
+_compare_property (const NMSettInfoSetting *sett_info,
+                   guint property_idx,
+                   NMSetting *setting,
+                   NMSetting *other,
+                   NMSettingCompareFlags flags)
+{
+	NMTernary compare_result;
+
+	nm_assert (sett_info);
+	nm_assert (NM_IS_SETTING_CLASS (sett_info->setting_class));
+	nm_assert (property_idx < sett_info->property_infos_len);
+	nm_assert (NM_SETTING_GET_CLASS (setting) == sett_info->setting_class);
+	nm_assert (!other || NM_SETTING_GET_CLASS (other) == sett_info->setting_class);
+
+	compare_result = NM_SETTING_GET_CLASS (setting)->compare_property (sett_info,
+	                                                                   property_idx,
+	                                                                   setting,
+	                                                                   other,
+	                                                                   flags);
+
+	nm_assert (NM_IN_SET (compare_result, NM_TERNARY_DEFAULT,
+	                                      NM_TERNARY_FALSE,
+	                                      NM_TERNARY_TRUE));
+
+	/* check that the inferable flag and the GObject property flag corresponds. */
+	nm_assert (   !NM_FLAGS_HAS (flags, NM_SETTING_COMPARE_FLAG_INFERRABLE)
+	           || !sett_info->property_infos[property_idx].param_spec
+	           || NM_FLAGS_HAS (sett_info->property_infos[property_idx].param_spec->flags, NM_SETTING_PARAM_INFERRABLE)
+	           || compare_result == NM_TERNARY_DEFAULT);
+
+	return compare_result;
 }
 
 /**
@@ -1203,9 +1424,6 @@ nm_setting_compare (NMSetting *a,
                     NMSettingCompareFlags flags)
 {
 	const NMSettInfoSetting *sett_info;
-	GParamSpec **property_specs;
-	guint n_property_specs;
-	int same = TRUE;
 	guint i;
 
 	g_return_val_if_fail (NM_IS_SETTING (a), FALSE);
@@ -1215,7 +1433,7 @@ nm_setting_compare (NMSetting *a,
 	if (G_OBJECT_TYPE (a) != G_OBJECT_TYPE (b))
 		return FALSE;
 
-	sett_info = _nm_sett_info_setting_get (NM_SETTING_GET_CLASS (a));
+	sett_info = _nm_setting_class_get_sett_info (NM_SETTING_GET_CLASS (a));
 
 	if (sett_info->detail.gendata_info) {
 		GenData *a_gendata = _gendata_hash (a, FALSE);
@@ -1227,88 +1445,11 @@ nm_setting_compare (NMSetting *a,
 		                                  g_variant_equal);
 	}
 
-	/* And now all properties */
-	property_specs = g_object_class_list_properties (G_OBJECT_GET_CLASS (a), &n_property_specs);
-	for (i = 0; i < n_property_specs && same; i++) {
-		GParamSpec *prop_spec = property_specs[i];
-
-		/* Fuzzy compare ignores secrets and properties defined with the FUZZY_IGNORE flag */
-		if (   NM_FLAGS_HAS (flags, NM_SETTING_COMPARE_FLAG_FUZZY)
-		    && !NM_FLAGS_ANY (prop_spec->flags, NM_SETTING_PARAM_FUZZY_IGNORE | NM_SETTING_PARAM_SECRET))
-			continue;
-
-		if (   NM_FLAGS_HAS (flags, NM_SETTING_COMPARE_FLAG_INFERRABLE)
-		    && !NM_FLAGS_HAS (prop_spec->flags, NM_SETTING_PARAM_INFERRABLE))
-			continue;
-
-		if (   NM_FLAGS_HAS (flags, NM_SETTING_COMPARE_FLAG_IGNORE_REAPPLY_IMMEDIATELY)
-		    && NM_FLAGS_HAS (prop_spec->flags, NM_SETTING_PARAM_REAPPLY_IMMEDIATELY))
-			continue;
-
-		if (   NM_FLAGS_HAS (flags, NM_SETTING_COMPARE_FLAG_IGNORE_SECRETS)
-		    && NM_FLAGS_HAS (prop_spec->flags, NM_SETTING_PARAM_SECRET))
-			continue;
-
-		same = NM_SETTING_GET_CLASS (a)->compare_property (a, b, prop_spec, flags);
-	}
-	g_free (property_specs);
-
-	return same;
-}
-
-static inline gboolean
-should_compare_prop (NMSetting *setting,
-                     const char *prop_name,
-                     NMSettingCompareFlags comp_flags,
-                     GParamFlags prop_flags)
-{
-	/* Fuzzy compare ignores secrets and properties defined with the FUZZY_IGNORE flag */
-	if (   (comp_flags & NM_SETTING_COMPARE_FLAG_FUZZY)
-	    && (prop_flags & (NM_SETTING_PARAM_FUZZY_IGNORE | NM_SETTING_PARAM_SECRET)))
-		return FALSE;
-
-	if ((comp_flags & NM_SETTING_COMPARE_FLAG_INFERRABLE) && !(prop_flags & NM_SETTING_PARAM_INFERRABLE))
-		return FALSE;
-
-	if ((comp_flags & NM_SETTING_COMPARE_FLAG_IGNORE_REAPPLY_IMMEDIATELY) && !(prop_flags & NM_SETTING_PARAM_REAPPLY_IMMEDIATELY))
-		return FALSE;
-
-	if (prop_flags & NM_SETTING_PARAM_SECRET) {
-		NMSettingSecretFlags secret_flags = NM_SETTING_SECRET_FLAG_NONE;
-
-		if (comp_flags & NM_SETTING_COMPARE_FLAG_IGNORE_SECRETS)
-			return FALSE;
-
-		if (   NM_IS_SETTING_VPN (setting)
-		    && g_strcmp0 (prop_name, NM_SETTING_VPN_SECRETS) == 0) {
-			/* FIXME: NMSettingVPN:NM_SETTING_VPN_SECRETS has NM_SETTING_PARAM_SECRET.
-			 * nm_setting_get_secret_flags() quite possibly fails, but it might succeed if the
-			 * setting accidently uses a key "secrets". */
-			return TRUE;
-		}
-
-		if (!nm_setting_get_secret_flags (setting, prop_name, &secret_flags, NULL))
-			g_return_val_if_reached (FALSE);
-
-		if (   (comp_flags & NM_SETTING_COMPARE_FLAG_IGNORE_AGENT_OWNED_SECRETS)
-		    && (secret_flags & NM_SETTING_SECRET_FLAG_AGENT_OWNED))
-			return FALSE;
-
-		if (   (comp_flags & NM_SETTING_COMPARE_FLAG_IGNORE_NOT_SAVED_SECRETS)
-		    && (secret_flags & NM_SETTING_SECRET_FLAG_NOT_SAVED))
+	for (i = 0; i < sett_info->property_infos_len; i++) {
+		if (_compare_property (sett_info, i, a, b, flags) == NM_TERNARY_FALSE)
 			return FALSE;
 	}
 
-	if (   (comp_flags & NM_SETTING_COMPARE_FLAG_IGNORE_ID)
-	    && NM_IS_SETTING_CONNECTION (setting)
-	    && !strcmp (prop_name, NM_SETTING_CONNECTION_ID))
-		return FALSE;
-
-	if (   (comp_flags & NM_SETTING_COMPARE_FLAG_IGNORE_TIMESTAMP)
-	    && NM_IS_SETTING_CONNECTION (setting)
-	    && !strcmp (prop_name, NM_SETTING_CONNECTION_TIMESTAMP))
-		return FALSE;
-
 	return TRUE;
 }
 
@@ -1399,7 +1540,7 @@ nm_setting_diff (NMSetting *a,
 		results_created = TRUE;
 	}
 
-	sett_info = _nm_sett_info_setting_get (NM_SETTING_GET_CLASS (a));
+	sett_info = _nm_setting_class_get_sett_info (NM_SETTING_GET_CLASS (a));
 
 	if (sett_info->detail.gendata_info) {
 		const char *key;
@@ -1442,71 +1583,93 @@ nm_setting_diff (NMSetting *a,
 			}
 		}
 	} else {
-		gs_free GParamSpec **property_specs = NULL;
-		guint n_property_specs;
-
-		property_specs = g_object_class_list_properties (G_OBJECT_GET_CLASS (a), &n_property_specs);
-
-		for (i = 0; i < n_property_specs; i++) {
-			GParamSpec *prop_spec = property_specs[i];
+		for (i = 0; i < sett_info->property_infos_len; i++) {
 			NMSettingDiffResult r = NM_SETTING_DIFF_RESULT_UNKNOWN;
+			const NMSettInfoProperty *property_info;
+			NMTernary compare_result;
+			GParamSpec *prop_spec;
 
-			/* Handle compare flags */
-			if (!should_compare_prop (a, prop_spec->name, flags, prop_spec->flags))
-				continue;
-			if (strcmp (prop_spec->name, NM_SETTING_NAME) == 0)
+			compare_result = _compare_property (sett_info, i, a, b, flags);
+			if (compare_result == NM_TERNARY_DEFAULT)
 				continue;
 
-			compared_any = TRUE;
-
-			if (b) {
-				gboolean different;
-
-				different = !NM_SETTING_GET_CLASS (a)->compare_property (a, b, prop_spec, flags);
-				if (different) {
-					gboolean a_is_default, b_is_default;
-					GValue value = G_VALUE_INIT;
+			if (   NM_FLAGS_ANY (flags,   NM_SETTING_COMPARE_FLAG_IGNORE_AGENT_OWNED_SECRETS
+			                            | NM_SETTING_COMPARE_FLAG_IGNORE_NOT_SAVED_SECRETS)
+			    && b
+			    && compare_result == NM_TERNARY_FALSE) {
+				/* we have setting @b and the property is not the same. But we also are instructed
+				 * to ignore secrets based on the flags.
+				 *
+				 * Note that compare_property() called with two settings will ignore secrets
+				 * based on the flags, but it will do so if *both* settings have the flag we
+				 * look for. So that is symetric behavior and good.
+				 *
+				 * But for the purpose of diff(), we do a asymmetric comparison because and
+				 * we want to skip testing the property if setting @a alone indicates to do
+				 * so.
+				 *
+				 * We need to double-check whether the property should be ignored by
+				 * looking at @a alone. */
+				if (_compare_property (sett_info, i, a, NULL, flags) == NM_TERNARY_DEFAULT)
+					continue;
+			}
 
-					g_value_init (&value, prop_spec->value_type);
-					g_object_get_property (G_OBJECT (a), prop_spec->name, &value);
-					a_is_default = g_param_value_defaults (prop_spec, &value);
+			compared_any = TRUE;
 
-					g_value_reset (&value);
-					g_object_get_property (G_OBJECT (b), prop_spec->name, &value);
-					b_is_default = g_param_value_defaults (prop_spec, &value);
+			property_info = &sett_info->property_infos[i];
+			prop_spec = property_info->param_spec;
 
-					g_value_unset (&value);
-					if ((flags & NM_SETTING_COMPARE_FLAG_DIFF_RESULT_WITH_DEFAULT) == 0) {
-						if (!a_is_default)
-							r |= a_result;
-						if (!b_is_default)
-							r |= b_result;
-					} else {
+			if (b) {
+				if (compare_result == NM_TERNARY_FALSE) {
+					if (prop_spec) {
+						gboolean a_is_default, b_is_default;
+						GValue value = G_VALUE_INIT;
+
+						g_value_init (&value, prop_spec->value_type);
+						g_object_get_property (G_OBJECT (a), prop_spec->name, &value);
+						a_is_default = g_param_value_defaults (prop_spec, &value);
+
+						g_value_reset (&value);
+						g_object_get_property (G_OBJECT (b), prop_spec->name, &value);
+						b_is_default = g_param_value_defaults (prop_spec, &value);
+
+						g_value_unset (&value);
+						if (!NM_FLAGS_HAS (flags, NM_SETTING_COMPARE_FLAG_DIFF_RESULT_WITH_DEFAULT)) {
+							if (!a_is_default)
+								r |= a_result;
+							if (!b_is_default)
+								r |= b_result;
+						} else {
+							r |= a_result | b_result;
+							if (a_is_default)
+								r |= a_result_default;
+							if (b_is_default)
+								r |= b_result_default;
+						}
+					} else
 						r |= a_result | b_result;
-						if (a_is_default)
-							r |= a_result_default;
-						if (b_is_default)
-							r |= b_result_default;
-					}
 				}
 			} else if ((flags & (NM_SETTING_COMPARE_FLAG_DIFF_RESULT_WITH_DEFAULT | NM_SETTING_COMPARE_FLAG_DIFF_RESULT_NO_DEFAULT)) == 0)
 				r = a_result;  /* only in A */
 			else {
-				GValue value = G_VALUE_INIT;
+				if (prop_spec) {
+					GValue value = G_VALUE_INIT;
 
-				g_value_init (&value, prop_spec->value_type);
-				g_object_get_property (G_OBJECT (a), prop_spec->name, &value);
-				if (!g_param_value_defaults (prop_spec, &value))
-					r |= a_result;
-				else if (flags & NM_SETTING_COMPARE_FLAG_DIFF_RESULT_WITH_DEFAULT)
-					r |= a_result | a_result_default;
+					g_value_init (&value, prop_spec->value_type);
+					g_object_get_property (G_OBJECT (a), prop_spec->name, &value);
+					if (!g_param_value_defaults (prop_spec, &value))
+						r |= a_result;
+					else if (flags & NM_SETTING_COMPARE_FLAG_DIFF_RESULT_WITH_DEFAULT)
+						r |= a_result | a_result_default;
 
-				g_value_unset (&value);
+					g_value_unset (&value);
+				} else
+					r |= a_result;
 			}
 
 			if (r != NM_SETTING_DIFF_RESULT_UNKNOWN) {
 				diff_found = TRUE;
-				_setting_diff_add_result (*results, prop_spec->name, r);
+				_setting_diff_add_result (*results, property_info->name, r);
 			}
 		}
 	}
@@ -1535,33 +1698,6 @@ nm_setting_diff (NMSetting *a,
 	}
 }
 
-#define CMP_AND_RETURN(n_a, n_b, name) \
-	G_STMT_START { \
-		gboolean _is = (strcmp (n_a, ""name) == 0); \
-		\
-		if (_is || (strcmp (n_b, ""name) == 0)) \
-			return _is ? -1 : 1; \
-	} G_STMT_END
-
-static int
-_enumerate_values_sort (GParamSpec **p_a, GParamSpec **p_b, GType *p_type)
-{
-	const char *n_a = (*p_a)->name;
-	const char *n_b = (*p_b)->name;
-	int c = strcmp (n_a, n_b);
-
-	if (c) {
-		if (*p_type == NM_TYPE_SETTING_CONNECTION) {
-			/* for [connection], report first id, uuid, type in that order. */
-			CMP_AND_RETURN (n_a, n_b, NM_SETTING_CONNECTION_ID);
-			CMP_AND_RETURN (n_a, n_b, NM_SETTING_CONNECTION_UUID);
-			CMP_AND_RETURN (n_a, n_b, NM_SETTING_CONNECTION_TYPE);
-		}
-	}
-	return c;
-}
-#undef CMP_AND_RETURN
-
 /**
  * nm_setting_enumerate_values:
  * @setting: the #NMSetting
@@ -1577,18 +1713,16 @@ nm_setting_enumerate_values (NMSetting *setting,
                              gpointer user_data)
 {
 	const NMSettInfoSetting *sett_info;
-	GParamSpec **property_specs;
-	guint n_properties;
 	guint i;
-	GType type;
 
 	g_return_if_fail (NM_IS_SETTING (setting));
 	g_return_if_fail (func != NULL);
 
-	sett_info = _nm_sett_info_setting_get (NM_SETTING_GET_CLASS (setting));
+	sett_info = _nm_setting_class_get_sett_info (NM_SETTING_GET_CLASS (setting));
 
 	if (sett_info->detail.gendata_info) {
 		const char *const*names;
+		guint n_properties;
 
 		/* the properties of this setting are not real GObject properties.
 		 * Hence, this API makes little sense (or does it?). Still, call
@@ -1618,100 +1752,135 @@ nm_setting_enumerate_values (NMSetting *setting,
 		return;
 	}
 
-	property_specs = g_object_class_list_properties (G_OBJECT_GET_CLASS (setting), &n_properties);
-
-	/* sort the properties. This has an effect on the order in which keyfile
-	 * prints them. */
-	type = G_OBJECT_TYPE (setting);
-	g_qsort_with_data (property_specs, n_properties, sizeof (gpointer),
-	                   (GCompareDataFunc) _enumerate_values_sort, &type);
-
-	for (i = 0; i < n_properties; i++) {
-		GParamSpec *prop_spec = property_specs[i];
+	for (i = 0; i < sett_info->property_infos_len; i++) {
+		GParamSpec *prop_spec = _nm_sett_info_property_info_get_sorted (sett_info, i)->param_spec;
 		GValue value = G_VALUE_INIT;
 
+		if (!prop_spec)
+			continue;
+
 		g_value_init (&value, G_PARAM_SPEC_VALUE_TYPE (prop_spec));
 		g_object_get_property (G_OBJECT (setting), prop_spec->name, &value);
 		func (setting, prop_spec->name, &value, prop_spec->flags, user_data);
 		g_value_unset (&value);
 	}
-
-	g_free (property_specs);
 }
 
 /**
- * _nm_setting_clear_secrets:
- * @setting: the #NMSetting
+ * _nm_setting_aggregate:
+ * @setting: the #NMSetting to aggregate.
+ * @type: the #NMConnectionAggregateType aggregate type.
+ * @arg: the in/out arguments for aggregation. They depend on @type.
  *
- * Resets and clears any secrets in the setting.  Secrets should be added to the
- * setting only when needed, and cleared immediately after use to prevent
- * leakage of information.
+ * This is the implementation detail of _nm_connection_aggregate(). It
+ * makes no sense to call this function directly outside of _nm_connection_aggregate().
  *
- * Returns: %TRUE if the setting changed at all
- **/
+ * Returns: %TRUE if afterwards the aggregation is complete. That means,
+ *   the only caller _nm_connection_aggregate() will not visit other settings
+ *   after a setting returns %TRUE (indicating that there is nothing further
+ *   to aggregate). Note that is very different from the boolean return
+ *   argument of _nm_connection_aggregate(), which serves a different purpose.
+ */
 gboolean
-_nm_setting_clear_secrets (NMSetting *setting)
+_nm_setting_aggregate (NMSetting *setting,
+                       NMConnectionAggregateType type,
+                       gpointer arg)
 {
-	gs_free GParamSpec **property_specs = NULL;
-	guint n_property_specs;
+	const NMSettInfoSetting *sett_info;
 	guint i;
-	gboolean changed = FALSE;
 
 	g_return_val_if_fail (NM_IS_SETTING (setting), FALSE);
+	g_return_val_if_fail (arg, FALSE);
+	g_return_val_if_fail (NM_IN_SET (type, NM_CONNECTION_AGGREGATE_ANY_SECRETS,
+	                                       NM_CONNECTION_AGGREGATE_ANY_SYSTEM_SECRET_FLAGS),
+	                      FALSE);
 
-	property_specs = g_object_class_list_properties (G_OBJECT_GET_CLASS (setting), &n_property_specs);
-	for (i = 0; i < n_property_specs; i++) {
-		GParamSpec *prop_spec = property_specs[i];
+	if (NM_IS_SETTING_VPN (setting))
+		return _nm_setting_vpn_aggregate (NM_SETTING_VPN (setting), type, arg);
+
+	sett_info = _nm_setting_class_get_sett_info (NM_SETTING_GET_CLASS (setting));
+	for (i = 0; i < sett_info->property_infos_len; i++) {
+		const NMSettInfoProperty *property_info = &sett_info->property_infos[i];
+		GParamSpec *prop_spec = property_info->param_spec;
+		nm_auto_unset_gvalue GValue value = G_VALUE_INIT;
+		NMSettingSecretFlags secret_flags;
+
+		if (   !prop_spec
+		    || !NM_FLAGS_HAS (prop_spec->flags, NM_SETTING_PARAM_SECRET)) {
+			nm_assert (!nm_setting_get_secret_flags (setting, property_info->name, NULL, NULL));
+			continue;
+		}
+
+		/* for the moment, all aggregate types only care about secrets. */
+		nm_assert (nm_setting_get_secret_flags (setting, property_info->name, NULL, NULL));
 
-		if (prop_spec->flags & NM_SETTING_PARAM_SECRET) {
-			GValue value = G_VALUE_INIT;
+		switch (type) {
 
-			g_value_init (&value, prop_spec->value_type);
+		case NM_CONNECTION_AGGREGATE_ANY_SECRETS:
+			g_value_init (&value, G_PARAM_SPEC_VALUE_TYPE (prop_spec));
 			g_object_get_property (G_OBJECT (setting), prop_spec->name, &value);
 			if (!g_param_value_defaults (prop_spec, &value)) {
-				g_param_value_set_default (prop_spec, &value);
-				g_object_set_property (G_OBJECT (setting), prop_spec->name, &value);
-				changed = TRUE;
+				*((gboolean *) arg) = TRUE;
+				return TRUE;
+			}
+			break;
+
+		case NM_CONNECTION_AGGREGATE_ANY_SYSTEM_SECRET_FLAGS:
+			if (!nm_setting_get_secret_flags (setting, prop_spec->name, &secret_flags, NULL))
+				nm_assert_not_reached ();
+			if (secret_flags == NM_SETTING_SECRET_FLAG_NONE) {
+				*((gboolean *) arg) = TRUE;
+				return TRUE;
 			}
-			g_value_unset (&value);
+			break;
+
 		}
 	}
-	return changed;
+
+	return FALSE;
 }
 
 static gboolean
-clear_secrets_with_flags (NMSetting *setting,
-                          GParamSpec *pspec,
-                          NMSettingClearSecretsWithFlagsFn func,
-                          gpointer user_data)
+clear_secrets (const NMSettInfoSetting *sett_info,
+               guint property_idx,
+               NMSetting *setting,
+               NMSettingClearSecretsWithFlagsFn func,
+               gpointer user_data)
 {
 	NMSettingSecretFlags flags = NM_SETTING_SECRET_FLAG_NONE;
-	gboolean changed = FALSE;
+	GParamSpec *param_spec = sett_info->property_infos[property_idx].param_spec;
 
-	g_return_val_if_fail (!NM_IS_SETTING_VPN (setting), FALSE);
+	if (!param_spec)
+		return FALSE;
 
-	/* Clear the secret if the user function says to do so */
-	if (!nm_setting_get_secret_flags (setting, pspec->name, &flags, NULL))
-		g_return_val_if_reached (FALSE);
+	if (!NM_FLAGS_HAS (param_spec->flags, NM_SETTING_PARAM_SECRET))
+		return FALSE;
 
-	if (func (setting, pspec->name, flags, user_data) == TRUE) {
-		GValue value = G_VALUE_INIT;
+	if (func) {
+		if (!nm_setting_get_secret_flags (setting, param_spec->name, &flags, NULL))
+			nm_assert_not_reached ();
+		if (!func (setting, param_spec->name, flags, user_data))
+			return FALSE;
+	} else
+		nm_assert (nm_setting_get_secret_flags (setting, param_spec->name, NULL, NULL));
 
-		g_value_init (&value, pspec->value_type);
-		g_object_get_property (G_OBJECT (setting), pspec->name, &value);
-		if (!g_param_value_defaults (pspec, &value)) {
-			g_param_value_set_default (pspec, &value);
-			g_object_set_property (G_OBJECT (setting), pspec->name, &value);
-			changed = TRUE;
-		}
-		g_value_unset (&value);
+	{
+		nm_auto_unset_gvalue GValue value = G_VALUE_INIT;
+
+		g_value_init (&value, param_spec->value_type);
+		g_object_get_property (G_OBJECT (setting), param_spec->name, &value);
+		if (g_param_value_defaults (param_spec, &value))
+			return FALSE;
+
+		g_param_value_set_default (param_spec, &value);
+		g_object_set_property (G_OBJECT (setting), param_spec->name, &value);
 	}
 
-	return changed;
+	return TRUE;
 }
 
 /**
- * _nm_setting_clear_secrets_with_flags:
+ * _nm_setting_clear_secrets:
  * @setting: the #NMSetting
  * @func: (scope call): function to be called to determine whether a
  *     specific secret should be cleared or not
@@ -1722,27 +1891,30 @@ clear_secrets_with_flags (NMSetting *setting,
  * Returns: %TRUE if the setting changed at all
  **/
 gboolean
-_nm_setting_clear_secrets_with_flags (NMSetting *setting,
-                                      NMSettingClearSecretsWithFlagsFn func,
-                                      gpointer user_data)
+_nm_setting_clear_secrets (NMSetting *setting,
+                           NMSettingClearSecretsWithFlagsFn func,
+                           gpointer user_data)
 {
-	gs_free GParamSpec **property_specs = NULL;
-	guint n_property_specs;
-	guint i;
+	const NMSettInfoSetting *sett_info;
 	gboolean changed = FALSE;
+	guint i;
+	gboolean (*my_clear_secrets) (const struct _NMSettInfoSetting *sett_info,
+	                              guint property_idx,
+	                              NMSetting *setting,
+	                              NMSettingClearSecretsWithFlagsFn func,
+	                              gpointer user_data);
 
-	g_return_val_if_fail (setting, FALSE);
 	g_return_val_if_fail (NM_IS_SETTING (setting), FALSE);
-	g_return_val_if_fail (func != NULL, FALSE);
 
-	property_specs = g_object_class_list_properties (G_OBJECT_GET_CLASS (setting), &n_property_specs);
-	for (i = 0; i < n_property_specs; i++) {
-		if (property_specs[i]->flags & NM_SETTING_PARAM_SECRET) {
-			changed |= NM_SETTING_GET_CLASS (setting)->clear_secrets_with_flags (setting,
-			                                                                     property_specs[i],
-			                                                                     func,
-			                                                                     user_data);
-		}
+	my_clear_secrets = NM_SETTING_GET_CLASS (setting)->clear_secrets;
+
+	sett_info = _nm_setting_class_get_sett_info (NM_SETTING_GET_CLASS (setting));
+	for (i = 0; i < sett_info->property_infos_len; i++) {
+		changed |= my_clear_secrets (sett_info,
+		                             i,
+		                             setting,
+		                             func,
+		                             user_data);
 	}
 	return changed;
 }
@@ -1781,7 +1953,7 @@ update_one_secret (NMSetting *setting, const char *key, GVariant *value, GError
 	GParamSpec *prop_spec;
 	GValue prop_value = { 0, };
 
-	property = _nm_sett_info_property_get (NM_SETTING_GET_CLASS (setting), key);
+	property = _nm_setting_class_get_property_info (NM_SETTING_GET_CLASS (setting), key);
 	if (!property) {
 		g_set_error_literal (error,
 		                     NM_CONNECTION_ERROR,
@@ -1867,52 +2039,72 @@ _nm_setting_update_secrets (NMSetting *setting, GVariant *secrets, GError **erro
 	return result;
 }
 
-static gboolean
-is_secret_prop (NMSetting *setting, const char *secret_name, GError **error)
+static void
+_set_error_secret_property_not_found (GError **error,
+                                      NMSetting *setting,
+                                      const char *secret_name)
+{
+	g_set_error_literal (error,
+	                     NM_CONNECTION_ERROR,
+	                     NM_CONNECTION_ERROR_PROPERTY_NOT_FOUND,
+	                     _("not a secret property"));
+	g_prefix_error (error, "%s.%s: ", nm_setting_get_name (setting), secret_name);
+}
+
+gboolean
+_nm_setting_property_is_regular_secret (NMSetting *setting,
+                                        const char *secret_name)
 {
 	const NMSettInfoProperty *property;
-	GParamSpec *pspec;
 
-	property = _nm_sett_info_property_get (NM_SETTING_GET_CLASS (setting), secret_name);
-	if (!property) {
-		g_set_error_literal (error,
-		                     NM_CONNECTION_ERROR,
-		                     NM_CONNECTION_ERROR_PROPERTY_NOT_FOUND,
-		                     _("secret is not set"));
-		g_prefix_error (error, "%s.%s: ", nm_setting_get_name (setting), secret_name);
-		return FALSE;
-	}
+	nm_assert (NM_IS_SETTING (setting));
+	nm_assert (secret_name);
 
-	pspec = property->param_spec;
-	if (!pspec || !(pspec->flags & NM_SETTING_PARAM_SECRET)) {
-		g_set_error_literal (error,
-		                     NM_CONNECTION_ERROR,
-		                     NM_CONNECTION_ERROR_PROPERTY_NOT_SECRET,
-		                     _("not a secret property"));
-		g_prefix_error (error, "%s.%s: ", nm_setting_get_name (setting), secret_name);
-		return FALSE;
-	}
+	property = _nm_setting_class_get_property_info (NM_SETTING_GET_CLASS (setting), secret_name);
+	return    property
+	       && property->param_spec
+	       && NM_FLAGS_HAS (property->param_spec->flags, NM_SETTING_PARAM_SECRET);
+}
 
-	return TRUE;
+gboolean
+_nm_setting_property_is_regular_secret_flags (NMSetting *setting,
+                                              const char *secret_flags_name)
+{
+	const NMSettInfoProperty *property;
+
+	nm_assert (NM_IS_SETTING (setting));
+	nm_assert (secret_flags_name);
+
+	property = _nm_setting_class_get_property_info (NM_SETTING_GET_CLASS (setting), secret_flags_name);
+	return    property
+	       && property->param_spec
+	       && !NM_FLAGS_HAS (property->param_spec->flags, NM_SETTING_PARAM_SECRET)
+	       && G_PARAM_SPEC_VALUE_TYPE (property->param_spec) == NM_TYPE_SETTING_SECRET_FLAGS;
 }
 
 static gboolean
 get_secret_flags (NMSetting *setting,
                   const char *secret_name,
-                  gboolean verify_secret,
                   NMSettingSecretFlags *out_flags,
                   GError **error)
 {
-	gs_free char *name_to_free = NULL;
-	NMSettingSecretFlags flags = NM_SETTING_SECRET_FLAG_NONE;
+	gs_free char *secret_flags_name_free = NULL;
+	const char *secret_flags_name;
+	NMSettingSecretFlags flags;
 
-	if (verify_secret && !is_secret_prop (setting, secret_name, error)) {
+	if (!_nm_setting_property_is_regular_secret (setting,
+	                                             secret_name)) {
+		_set_error_secret_property_not_found (error, setting, secret_name);
 		NM_SET_OUT (out_flags, NM_SETTING_SECRET_FLAG_NONE);
 		return FALSE;
 	}
 
+	secret_flags_name = nm_construct_name_a ("%s-flags", secret_name, &secret_flags_name_free);
+
+	nm_assert (_nm_setting_property_is_regular_secret_flags (setting, secret_flags_name));
+
 	g_object_get (G_OBJECT (setting),
-	              nm_construct_name_a ("%s-flags", secret_name, &name_to_free),
+	              secret_flags_name,
 	              &flags,
 	              NULL);
 	NM_SET_OUT (out_flags, flags);
@@ -1941,25 +2133,34 @@ nm_setting_get_secret_flags (NMSetting *setting,
 	g_return_val_if_fail (NM_IS_SETTING (setting), FALSE);
 	g_return_val_if_fail (secret_name != NULL, FALSE);
 
-	return NM_SETTING_GET_CLASS (setting)->get_secret_flags (setting, secret_name, TRUE, out_flags, error);
+	return NM_SETTING_GET_CLASS (setting)->get_secret_flags (setting, secret_name, out_flags, error);
 }
 
 static gboolean
 set_secret_flags (NMSetting *setting,
                   const char *secret_name,
-                  gboolean verify_secret,
                   NMSettingSecretFlags flags,
                   GError **error)
 {
-	gs_free char *name_to_free = NULL;
+	gs_free char *secret_flags_name_free = NULL;
+	const char *secret_flags_name;
 
-	if (verify_secret)
-		g_return_val_if_fail (is_secret_prop (setting, secret_name, error), FALSE);
+	if (!_nm_setting_property_is_regular_secret (setting,
+	                                             secret_name)) {
+		_set_error_secret_property_not_found (error, setting, secret_name);
+		return FALSE;
+	}
 
-	g_object_set (G_OBJECT (setting),
-	              nm_construct_name_a ("%s-flags", secret_name, &name_to_free),
-	              flags,
-	              NULL);
+	secret_flags_name = nm_construct_name_a ("%s-flags", secret_name, &secret_flags_name_free);
+
+	nm_assert (_nm_setting_property_is_regular_secret_flags (setting, secret_flags_name));
+
+	if (!nm_g_object_set_property_flags (G_OBJECT (setting),
+	                                     secret_flags_name,
+	                                     NM_TYPE_SETTING_SECRET_FLAGS,
+	                                     flags,
+	                                     error))
+		g_return_val_if_reached (FALSE);
 	return TRUE;
 }
 
@@ -1984,9 +2185,9 @@ nm_setting_set_secret_flags (NMSetting *setting,
 {
 	g_return_val_if_fail (NM_IS_SETTING (setting), FALSE);
 	g_return_val_if_fail (secret_name != NULL, FALSE);
-	g_return_val_if_fail (flags <= NM_SETTING_SECRET_FLAGS_ALL, FALSE);
+	g_return_val_if_fail (_nm_setting_secret_flags_valid (flags), FALSE);
 
-	return NM_SETTING_GET_CLASS (setting)->set_secret_flags (setting, secret_name, TRUE, flags, error);
+	return NM_SETTING_GET_CLASS (setting)->set_secret_flags (setting, secret_name, flags, error);
 }
 
 /**
@@ -2031,9 +2232,11 @@ nm_setting_to_string (NMSetting *setting)
 }
 
 GVariant *
-_nm_setting_get_deprecated_virtual_interface_name (NMSetting *setting,
+_nm_setting_get_deprecated_virtual_interface_name (const NMSettInfoSetting *sett_info,
+                                                   guint property_idx,
                                                    NMConnection *connection,
-                                                   const char *property)
+                                                   NMSetting *setting,
+                                                   NMConnectionSerializationFlags flags)
 {
 	NMSettingConnection *s_con;
 
@@ -2301,11 +2504,6 @@ _nm_setting_gendata_reset_from_hash (NMSetting *setting,
 /*****************************************************************************/
 
 static void
-nm_setting_init (NMSetting *setting)
-{
-}
-
-static void
 get_property (GObject *object, guint prop_id,
               GValue *value, GParamSpec *pspec)
 {
@@ -2321,6 +2519,13 @@ get_property (GObject *object, guint prop_id,
 	}
 }
 
+/*****************************************************************************/
+
+static void
+nm_setting_init (NMSetting *setting)
+{
+}
+
 static void
 finalize (GObject *object)
 {
@@ -2361,11 +2566,12 @@ nm_setting_class_init (NMSettingClass *setting_class)
 	object_class->get_property = get_property;
 	object_class->finalize     = finalize;
 
-	setting_class->update_one_secret = update_one_secret;
-	setting_class->get_secret_flags = get_secret_flags;
-	setting_class->set_secret_flags = set_secret_flags;
-	setting_class->compare_property = compare_property;
-	setting_class->clear_secrets_with_flags = clear_secrets_with_flags;
+	setting_class->update_one_secret         = update_one_secret;
+	setting_class->get_secret_flags          = get_secret_flags;
+	setting_class->set_secret_flags          = set_secret_flags;
+	setting_class->compare_property          = compare_property;
+	setting_class->clear_secrets             = clear_secrets;
+	setting_class->duplicate_copy_properties = duplicate_copy_properties;
 
 	/**
 	 * NMSetting:name:
@@ -2374,10 +2580,11 @@ nm_setting_class_init (NMSettingClass *setting_class)
 	 * connection.  Each setting type has a name unique to that type, for
 	 * example "ppp" or "802-11-wireless" or "802-3-ethernet".
 	 **/
-	g_object_class_install_property
-		(object_class, PROP_NAME,
-		 g_param_spec_string (NM_SETTING_NAME, "", "",
-		                      NULL,
-		                      G_PARAM_READABLE |
-		                      G_PARAM_STATIC_STRINGS));
+	obj_properties[PROP_NAME] =
+	    g_param_spec_string (NM_SETTING_NAME, "", "",
+	                         NULL,
+	                         G_PARAM_READABLE |
+	                         G_PARAM_STATIC_STRINGS);
+
+	g_object_class_install_properties (object_class, _PROPERTY_ENUMS_LAST, obj_properties);
 }
diff --git a/libnm-core/nm-setting.h b/libnm-core/nm-setting.h
index a7a0f81f..0f0ac8f3 100644
--- a/libnm-core/nm-setting.h
+++ b/libnm-core/nm-setting.h
@@ -64,7 +64,7 @@ G_BEGIN_DECLS
  * should be requested from the user each time it is needed
  * @NM_SETTING_SECRET_FLAG_NOT_REQUIRED: in situations where it cannot be
  * automatically determined that the secret is required (some VPNs and PPP
- * providers dont require all secrets) this flag indicates that the specific
+ * providers don't require all secrets) this flag indicates that the specific
  * secret is not required
  *
  * These flags indicate specific behavior related to handling of a secret.  Each
@@ -169,6 +169,7 @@ typedef gboolean (*NMSettingClearSecretsWithFlagsFn) (NMSetting *setting,
                                                       gpointer user_data);
 
 struct _NMMetaSettingInfo;
+struct _NMSettInfoSetting;
 
 typedef struct {
 	GObjectClass parent;
@@ -191,32 +192,44 @@ typedef struct {
 
 	gboolean    (*get_secret_flags)  (NMSetting  *setting,
 	                                  const char *secret_name,
-	                                  gboolean verify_secret,
 	                                  NMSettingSecretFlags *out_flags,
 	                                  GError **error);
 
 	gboolean    (*set_secret_flags)  (NMSetting  *setting,
 	                                  const char *secret_name,
-	                                  gboolean verify_secret,
 	                                  NMSettingSecretFlags flags,
 	                                  GError **error);
 
-	gboolean    (*clear_secrets_with_flags) (NMSetting *setting,
-	                                         GParamSpec *pspec,
-	                                         NMSettingClearSecretsWithFlagsFn func,
-	                                         gpointer user_data);
+	/*< private >*/
+	gboolean    (*clear_secrets) (const struct _NMSettInfoSetting *sett_info,
+	                              guint property_idx,
+	                              NMSetting *setting,
+	                              NMSettingClearSecretsWithFlagsFn func,
+	                              gpointer user_data);
+
+	/* compare_property() returns a ternary, where DEFAULT means that the property should not
+	 * be compared due to the compare @flags. A TRUE/FALSE result means that the property is
+	 * equal/not-equal.
+	 *
+	 * @other may be %NULL, in which case the function only determines whether
+	 * the setting should be compared (TRUE) or not (DEFAULT). */
+	/*< private >*/
+	NMTernary  (*compare_property)  (const struct _NMSettInfoSetting *sett_info,
+	                                 guint property_idx,
+	                                 NMSetting *setting,
+	                                 NMSetting *other,
+	                                 NMSettingCompareFlags flags);
 
-	/* Returns TRUE if the given property contains the same value in both settings */
-	gboolean    (*compare_property)  (NMSetting *setting,
-	                                  NMSetting *other,
-	                                  const GParamSpec *prop_spec,
-	                                  NMSettingCompareFlags flags);
+	/*< private >*/
+	void (*duplicate_copy_properties) (const struct _NMSettInfoSetting *sett_info,
+	                                   NMSetting *src,
+	                                   NMSetting *dst);
 
 	/*< private >*/
 	const struct _NMMetaSettingInfo *setting_info;
 
 	/*< private >*/
-	gpointer padding[6];
+	gpointer padding[5];
 } NMSettingClass;
 
 /**
@@ -272,7 +285,7 @@ typedef enum {
 	NM_SETTING_DIFF_RESULT_IN_A =    0x00000001,
 	NM_SETTING_DIFF_RESULT_IN_B =    0x00000002,
 	NM_SETTING_DIFF_RESULT_IN_A_DEFAULT = 0x00000004,
-	NM_SETTING_DIFF_RESULT_IN_B_DEFAULT = 0x00000004,
+	NM_SETTING_DIFF_RESULT_IN_B_DEFAULT = 0x00000008,
 } NMSettingDiffResult;
 
 gboolean    nm_setting_diff          (NMSetting *a,
diff --git a/libnm-core/nm-simple-connection.c b/libnm-core/nm-simple-connection.c
index 9ccdbb21..55e8229f 100644
--- a/libnm-core/nm-simple-connection.c
+++ b/libnm-core/nm-simple-connection.c
@@ -22,6 +22,7 @@
 #include "nm-default.h"
 
 #include "nm-simple-connection.h"
+
 #include "nm-setting-private.h"
 
 /**
@@ -32,12 +33,16 @@
  * but might be used in the process of creating a new one.
  **/
 
+/*****************************************************************************/
+
 static void nm_simple_connection_interface_init (NMConnectionInterface *iface);
 
 G_DEFINE_TYPE_WITH_CODE (NMSimpleConnection, nm_simple_connection, G_TYPE_OBJECT,
                          G_IMPLEMENT_INTERFACE (NM_TYPE_CONNECTION, nm_simple_connection_interface_init);
                          )
 
+/*****************************************************************************/
+
 static void
 nm_simple_connection_init (NMSimpleConnection *self)
 {
diff --git a/libnm-core/nm-utils-private.h b/libnm-core/nm-utils-private.h
index b886730a..58822cde 100644
--- a/libnm-core/nm-utils-private.h
+++ b/libnm-core/nm-utils-private.h
@@ -56,9 +56,11 @@ gboolean    _nm_utils_hwaddr_cloned_not_set (NMSetting *setting,
                                              const char    *property,
                                              NMSettingParseFlags parse_flags,
                                              GError       **error);
-GVariant *  _nm_utils_hwaddr_cloned_data_synth (NMSetting *setting,
+GVariant *  _nm_utils_hwaddr_cloned_data_synth (const NMSettInfoSetting *sett_info,
+                                                guint property_idx,
                                                 NMConnection *connection,
-                                                const char *property);
+                                                NMSetting *setting,
+                                                NMConnectionSerializationFlags flags);
 gboolean    _nm_utils_hwaddr_cloned_data_set (NMSetting *setting,
                                               GVariant *connection_dict,
                                               const char *property,
diff --git a/libnm-core/nm-utils.c b/libnm-core/nm-utils.c
index 0f524e11..47099712 100644
--- a/libnm-core/nm-utils.c
+++ b/libnm-core/nm-utils.c
@@ -67,7 +67,7 @@ struct IsoLangToEncodings
 	const char *const *encodings;
 };
 
-#define LANG_ENCODINGS(l, ...) { .lang = l, .encodings = (const char *[]) { __VA_ARGS__, NULL }}
+#define LANG_ENCODINGS(l, ...) { .lang = l, .encodings = NM_MAKE_STRV (__VA_ARGS__), }
 
 /* 5-letter language codes */
 static const struct IsoLangToEncodings isoLangEntries5[] =
@@ -112,7 +112,7 @@ static const struct IsoLangToEncodings isoLangEntries2[] =
 	LANG_ENCODINGS ("bg",      "windows-1251","koi8-r", "iso-8859-5"), /* Bulgarian */
 	LANG_ENCODINGS ("mk",      "koi8-r", "windows-1251", "iso-8859-5"),/* Macedonian */
 	LANG_ENCODINGS ("sr",      "koi8-r", "windows-1251", "iso-8859-5"),/* Serbian */
-	LANG_ENCODINGS ("uk",      "koi8-u", "koi8-r", "windows-1251"),    /* Ukranian */
+	LANG_ENCODINGS ("uk",      "koi8-u", "koi8-r", "windows-1251"),    /* Ukrainian */
 
 	/* Arabic */
 	LANG_ENCODINGS ("ar",      "iso-8859-6","windows-1256"),
@@ -836,7 +836,7 @@ device_supports_ap_ciphers (guint32 dev_caps,
 
 /**
  * nm_utils_ap_mode_security_valid:
- * @type: the security type to check device capabilties against,
+ * @type: the security type to check device capabilities against,
  * e.g. #NMU_SEC_STATIC_WEP
  * @wifi_caps: bitfield of the capabilities of the specific Wi-Fi device, e.g.
  * #NM_WIFI_DEVICE_CAP_CIPHER_WEP40
@@ -872,16 +872,16 @@ nm_utils_ap_mode_security_valid (NMUtilsSecurityType type,
 
 /**
  * nm_utils_security_valid:
- * @type: the security type to check AP flags and device capabilties against,
+ * @type: the security type to check AP flags and device capabilities against,
  * e.g. #NMU_SEC_STATIC_WEP
  * @wifi_caps: bitfield of the capabilities of the specific Wi-Fi device, e.g.
  * #NM_WIFI_DEVICE_CAP_CIPHER_WEP40
  * @have_ap: whether the @ap_flags, @ap_wpa, and @ap_rsn arguments are valid
  * @adhoc: whether the capabilities being tested are from an Ad-Hoc AP (IBSS)
  * @ap_flags: bitfield of AP capabilities, e.g. #NM_802_11_AP_FLAGS_PRIVACY
- * @ap_wpa: bitfield of AP capabilties derived from the AP's WPA beacon,
+ * @ap_wpa: bitfield of AP capabilities derived from the AP's WPA beacon,
  * e.g. (#NM_802_11_AP_SEC_PAIR_TKIP | #NM_802_11_AP_SEC_KEY_MGMT_PSK)
- * @ap_rsn: bitfield of AP capabilties derived from the AP's RSN/WPA2 beacon,
+ * @ap_rsn: bitfield of AP capabilities derived from the AP's RSN/WPA2 beacon,
  * e.g. (#NM_802_11_AP_SEC_PAIR_CCMP | #NM_802_11_AP_SEC_PAIR_TKIP)
  *
  * Given a set of device capabilities, and a desired security type to check
@@ -891,7 +891,7 @@ nm_utils_ap_mode_security_valid (NMUtilsSecurityType type,
  * NOTE: this function cannot handle checking security for AP/Hotspot mode;
  * use nm_utils_ap_mode_security_valid() instead.
  *
- * Returns: %TRUE if the device capabilities and AP capabilties intersect and are
+ * Returns: %TRUE if the device capabilities and AP capabilities intersect and are
  * compatible with the desired @type, %FALSE if they are not
  **/
 gboolean
@@ -1173,7 +1173,7 @@ nm_utils_ip4_dns_from_variant (GVariant *value)
 	dns = g_new (char *, length + 1);
 
 	for (i = 0; i < length; i++)
-		dns[i] = g_strdup (nm_utils_inet4_ntop (array[i], NULL));
+		dns[i] = nm_utils_inet4_ntop_dup (array[i]);
 	dns[i] = NULL;
 
 	return dns;
@@ -1271,7 +1271,7 @@ nm_utils_ip4_addresses_from_variant (GVariant *value, char **out_gateway)
 			g_ptr_array_add (addresses, addr);
 
 			if (addr_array[2] && out_gateway && !*out_gateway)
-				*out_gateway = g_strdup (nm_utils_inet4_ntop (addr_array[2], NULL));
+				*out_gateway = nm_utils_inet4_ntop_dup (addr_array[2]);
 		} else {
 			g_warning ("Ignoring invalid IP4 address: %s", error->message);
 			g_clear_error (&error);
@@ -1389,30 +1389,13 @@ nm_utils_ip4_routes_from_variant (GVariant *value)
 guint32
 nm_utils_ip4_netmask_to_prefix (guint32 netmask)
 {
-	guint32 prefix;
-	guint8 v;
-	const guint8 *p = (guint8 *) &netmask;
-
-	if (p[3]) {
-		prefix = 24;
-		v = p[3];
-	} else if (p[2]) {
-		prefix = 16;
-		v = p[2];
-	} else if (p[1]) {
-		prefix = 8;
-		v = p[1];
-	} else {
-		prefix = 0;
-		v = p[0];
-	}
-
-	while (v) {
-		prefix++;
-		v <<= 1;
-	}
+	G_STATIC_ASSERT_EXPR (__SIZEOF_INT__   == 4);
+	G_STATIC_ASSERT_EXPR (sizeof (int)     == 4);
+	G_STATIC_ASSERT_EXPR (sizeof (netmask) == 4);
 
-	return prefix;
+	return  (  (netmask != 0)
+	         ? (32 - __builtin_ctz (ntohl (netmask)))
+	         : 0);
 }
 
 /**
@@ -1510,7 +1493,7 @@ nm_utils_ip6_dns_from_variant (GVariant *value)
 			continue;
 		}
 
-		dns[i++] = g_strdup (nm_utils_inet6_ntop (ip, NULL));
+		dns[i++] = nm_utils_inet6_ntop_dup (ip);
 		g_variant_unref (ip_var);
 	}
 	dns[i] = NULL;
@@ -1629,7 +1612,7 @@ nm_utils_ip6_addresses_from_variant (GVariant *value, char **out_gateway)
 					goto next;
 				}
 				if (!IN6_IS_ADDR_UNSPECIFIED (gateway_bytes))
-					*out_gateway = g_strdup (nm_utils_inet6_ntop (gateway_bytes, NULL));
+					*out_gateway = nm_utils_inet6_ntop_dup (gateway_bytes);
 			}
 		} else {
 			g_warning ("Ignoring invalid IP6 address: %s", error->message);
@@ -2017,7 +2000,7 @@ _string_append_tc_handle (GString *string, guint32 handle)
  * or to pretty-format (use symbolic name for root) the key in keyfile.
  * The presence of prefix determnines which one is the case.
  *
- * Private API due to general uglyness and overall uselessness for anything
+ * Private API due to general ugliness and overall uselessness for anything
  * sensible.
  */
 void
@@ -2737,11 +2720,14 @@ nm_utils_sriov_vf_from_str (const char *str, GError **error)
 		detail++;
 	}
 
-	return _nm_utils_sriov_vf_from_strparts (str, detail, error);
+	return _nm_utils_sriov_vf_from_strparts (str, detail, FALSE, error);
 }
 
 NMSriovVF *
-_nm_utils_sriov_vf_from_strparts (const char *index, const char *detail, GError **error)
+_nm_utils_sriov_vf_from_strparts (const char *index,
+                                  const char *detail,
+                                  gboolean ignore_unknown,
+                                  GError **error)
 {
 	NMSriovVF *vf;
 	guint32 n_index;
@@ -2761,7 +2747,12 @@ _nm_utils_sriov_vf_from_strparts (const char *index, const char *detail, GError
 
 	vf = nm_sriov_vf_new (n_index);
 	if (detail) {
-		ht = nm_utils_parse_variant_attributes (detail, ' ', '=', TRUE, _nm_sriov_vf_attribute_spec, error);
+		ht = nm_utils_parse_variant_attributes (detail,
+		                                        ' ',
+		                                        '=',
+		                                        ignore_unknown,
+		                                        _nm_sriov_vf_attribute_spec,
+		                                        error);
 		if (!ht) {
 			nm_sriov_vf_unref (vf);
 			return NULL;
@@ -2785,6 +2776,57 @@ _nm_utils_sriov_vf_from_strparts (const char *index, const char *detail, GError
 
 /*****************************************************************************/
 
+NMUuid *
+_nm_utils_uuid_parse (const char *str,
+                      NMUuid *out_uuid)
+{
+	nm_assert (str);
+	nm_assert (out_uuid);
+
+	if (uuid_parse (str, out_uuid->uuid) != 0)
+		return NULL;
+	return out_uuid;
+}
+
+char *
+_nm_utils_uuid_unparse (const NMUuid *uuid,
+                        char *out_str /*[37]*/)
+{
+	nm_assert (uuid);
+
+	if (!out_str) {
+		/* for convenience, allow %NULL to indicate that a new
+		 * string should be allocated. */
+		out_str = g_malloc (37);
+	}
+	uuid_unparse_lower (uuid->uuid, out_str);
+	return out_str;
+}
+
+NMUuid *
+_nm_utils_uuid_generate_random (NMUuid *out_uuid)
+{
+	nm_assert (out_uuid);
+
+	uuid_generate_random (out_uuid->uuid);
+	return out_uuid;
+}
+
+gboolean
+nm_utils_uuid_is_null (const NMUuid *uuid)
+{
+	int i;
+
+	if (!uuid)
+		return TRUE;
+
+	for (i = 0; i < G_N_ELEMENTS (uuid->uuid); i++) {
+		if (uuid->uuid[i])
+			return FALSE;
+	}
+	return TRUE;
+}
+
 /**
  * nm_utils_uuid_generate_buf_:
  * @buf: input buffer, must contain at least 37 bytes
@@ -2794,11 +2836,12 @@ _nm_utils_sriov_vf_from_strparts (const char *index, const char *detail, GError
 char *
 nm_utils_uuid_generate_buf_ (char *buf)
 {
-	uuid_t uuid;
+	NMUuid uuid;
+
+	nm_assert (buf);
 
-	uuid_generate_random (uuid);
-	uuid_unparse_lower (uuid, buf);
-	return buf;
+	_nm_utils_uuid_generate_random (&uuid);
+	return _nm_utils_uuid_unparse (&uuid, buf);
 }
 
 /**
@@ -2814,7 +2857,9 @@ nm_utils_uuid_generate (void)
 }
 
 /**
- * nm_utils_uuid_generate_from_string:
+ * nm_utils_uuid_generate_from_string_bin:
+ * @uuid: the UUID to update inplace. This function cannot
+ *   fail to succeed.
  * @s: a string to use as the seed for the UUID
  * @slen: if negative, treat @s as zero terminated C string.
  *   Otherwise, assume the length as given (and allow @s to be
@@ -2824,60 +2869,92 @@ nm_utils_uuid_generate (void)
  *
  * For a given @s, this function will always return the same UUID.
  *
- * Returns: a newly allocated UUID suitable for use as the #NMSettingConnection
- * object's #NMSettingConnection:id: property
+ * Returns: the input @uuid. This function cannot fail.
  **/
-char *
-nm_utils_uuid_generate_from_string (const char *s, gssize slen, int uuid_type, gpointer type_args)
+NMUuid *
+nm_utils_uuid_generate_from_string_bin (NMUuid *uuid, const char *s, gssize slen, int uuid_type, gpointer type_args)
 {
-	uuid_t uuid;
-	char *buf;
-
+	g_return_val_if_fail (uuid, FALSE);
 	g_return_val_if_fail (slen == 0 || s, FALSE);
 
-	g_return_val_if_fail (uuid_type == NM_UTILS_UUID_TYPE_LEGACY || uuid_type == NM_UTILS_UUID_TYPE_VARIANT3, NULL);
-	g_return_val_if_fail (!type_args || uuid_type == NM_UTILS_UUID_TYPE_VARIANT3, NULL);
-
 	if (slen < 0)
 		slen = s ? strlen (s) : 0;
 
 	switch (uuid_type) {
 	case NM_UTILS_UUID_TYPE_LEGACY:
+		g_return_val_if_fail (!type_args, NULL);
 		nm_crypto_md5_hash (NULL,
 		                    0,
 		                    (guint8 *) s,
 		                    slen,
 		                    (guint8 *) uuid,
-		                    sizeof (uuid));
+		                    sizeof (*uuid));
 		break;
-	case NM_UTILS_UUID_TYPE_VARIANT3: {
-		uuid_t ns_uuid = { 0 };
+	case NM_UTILS_UUID_TYPE_VERSION3:
+	case NM_UTILS_UUID_TYPE_VERSION5: {
+		NMUuid ns_uuid = { 0 };
 
 		if (type_args) {
 			/* type_args can be a name space UUID. Interpret it as (char *) */
-			if (uuid_parse ((char *) type_args, ns_uuid) != 0)
+			if (!_nm_utils_uuid_parse (type_args, &ns_uuid))
 				g_return_val_if_reached (NULL);
 		}
 
-		nm_crypto_md5_hash ((guint8 *) s,
-		                    slen,
-		                    (guint8 *) ns_uuid,
-		                    sizeof (ns_uuid),
-		                    (guint8 *) uuid,
-		                    sizeof (uuid));
+		if (uuid_type == NM_UTILS_UUID_TYPE_VERSION3) {
+			nm_crypto_md5_hash ((guint8 *) s,
+			                    slen,
+			                    (guint8 *) &ns_uuid,
+			                    sizeof (ns_uuid),
+			                    (guint8 *) uuid,
+			                    sizeof (*uuid));
+		} else {
+			nm_auto_free_checksum GChecksum *sum = NULL;
+			union {
+				guint8 sha1[NM_UTILS_CHECKSUM_LENGTH_SHA1];
+				NMUuid uuid;
+			} digest;
+
+			sum = g_checksum_new (G_CHECKSUM_SHA1);
+			g_checksum_update (sum, (guchar *) &ns_uuid, sizeof (ns_uuid));
+			g_checksum_update (sum, (guchar *) s, slen);
+			nm_utils_checksum_get_digest (sum, digest.sha1);
+
+			G_STATIC_ASSERT_EXPR (sizeof (digest.sha1) > sizeof (digest.uuid));
+			*uuid = digest.uuid;
+		}
 
-		uuid[6] = (uuid[6] & 0x0F) | 0x30;
-		uuid[8] = (uuid[8] & 0x3F) | 0x80;
+		uuid->uuid[6] = (uuid->uuid[6] & 0x0F) | (uuid_type << 4);
+		uuid->uuid[8] = (uuid->uuid[8] & 0x3F) | 0x80;
 		break;
 	}
 	default:
 		g_return_val_if_reached (NULL);
 	}
 
-	buf = g_malloc (37);
-	uuid_unparse_lower (uuid, &buf[0]);
+	return uuid;
+}
 
-	return buf;
+/**
+ * nm_utils_uuid_generate_from_string:
+ * @s: a string to use as the seed for the UUID
+ * @slen: if negative, treat @s as zero terminated C string.
+ *   Otherwise, assume the length as given (and allow @s to be
+ *   non-null terminated or contain '\0').
+ * @uuid_type: a type identifier which UUID format to generate.
+ * @type_args: additional arguments, depending on the uuid_type
+ *
+ * For a given @s, this function will always return the same UUID.
+ *
+ * Returns: a newly allocated UUID suitable for use as the #NMSettingConnection
+ * object's #NMSettingConnection:id: property
+ **/
+char *
+nm_utils_uuid_generate_from_string (const char *s, gssize slen, int uuid_type, gpointer type_args)
+{
+	NMUuid uuid;
+
+	nm_utils_uuid_generate_from_string_bin (&uuid, s, slen, uuid_type, type_args);
+	return _nm_utils_uuid_unparse (&uuid, NULL);
 }
 
 /**
@@ -2902,7 +2979,7 @@ _nm_utils_uuid_generate_from_strings (const char *string1, ...)
 	char *uuid;
 
 	if (!string1)
-		return nm_utils_uuid_generate_from_string (NULL, 0, NM_UTILS_UUID_TYPE_VARIANT3, NM_UTILS_UUID_NS);
+		return nm_utils_uuid_generate_from_string (NULL, 0, NM_UTILS_UUID_TYPE_VERSION3, NM_UTILS_UUID_NS);
 
 	str = g_string_sized_new (120); /* effectively allocates power of 2 (128)*/
 
@@ -2916,7 +2993,7 @@ _nm_utils_uuid_generate_from_strings (const char *string1, ...)
 	}
 	va_end (args);
 
-	uuid = nm_utils_uuid_generate_from_string (str->str, str->len, NM_UTILS_UUID_TYPE_VARIANT3, NM_UTILS_UUID_NS);
+	uuid = nm_utils_uuid_generate_from_string (str->str, str->len, NM_UTILS_UUID_TYPE_VERSION3, NM_UTILS_UUID_NS);
 
 	g_string_free (str, TRUE);
 	return uuid;
@@ -3527,60 +3604,68 @@ nm_utils_hwaddr_len (int type)
 }
 
 guint8 *
-_nm_utils_str2bin_full (const char *asc,
-                        gboolean delimiter_required,
-                        const char *delimiter_candidates,
-                        guint8 *buffer,
-                        gsize buffer_length,
-                        gsize *out_len)
-{
-	const char *in = asc;
+_nm_utils_hexstr2bin_full (const char *hexstr,
+                           gboolean allow_0x_prefix,
+                           gboolean delimiter_required,
+                           const char *delimiter_candidates,
+                           gsize required_len,
+                           guint8 *buffer,
+                           gsize buffer_len,
+                           gsize *out_len)
+{
+	const char *in = hexstr;
 	guint8 *out = buffer;
 	gboolean delimiter_has = TRUE;
 	guint8 delimiter = '\0';
+	gsize len;
 
-	nm_assert (asc);
+	nm_assert (hexstr);
 	nm_assert (buffer);
-	nm_assert (buffer_length);
-	nm_assert (out_len);
+	nm_assert (required_len > 0 || out_len);
+
+	if (   allow_0x_prefix
+	    && in[0] == '0'
+	    && in[1] == 'x')
+		in += 2;
 
 	while (TRUE) {
 		const guint8 d1 = in[0];
 		guint8 d2;
+		int i1, i2;
 
-		if (!g_ascii_isxdigit (d1))
-			return NULL;
-
-#define HEXVAL(c) ((c) <= '9' ? (c) - '0' : ((c) & 0x4F) - ('A' - 10))
+		i1 = nm_utils_hexchar_to_int (d1);
+		if (i1 < 0)
+			goto fail;
 
 		/* If there's no leading zero (ie "aa:b:cc") then fake it */
 		d2 = in[1];
-		if (d2 && g_ascii_isxdigit (d2)) {
-			*out++ = (HEXVAL (d1) << 4) + HEXVAL (d2);
+		if (   d2
+		    && (i2 = nm_utils_hexchar_to_int (d2)) >= 0) {
+			*out++ = (i1 << 4) + i2;
 			d2 = in[2];
 			if (!d2)
 				break;
 			in += 2;
 		} else {
 			/* Fake leading zero */
-			*out++ = HEXVAL (d1);
+			*out++ = i1;
 			if (!d2) {
 				if (!delimiter_has) {
 					/* when using no delimiter, there must be pairs of hex chars */
-					return NULL;
+					goto fail;
 				}
 				break;
 			}
 			in += 1;
 		}
 
-		if (--buffer_length == 0)
-			return NULL;
+		if (--buffer_len == 0)
+			goto fail;
 
 		if (delimiter_has) {
 			if (d2 != delimiter) {
 				if (delimiter)
-					return NULL;
+					goto fail;
 				if (delimiter_candidates) {
 					while (delimiter_candidates[0]) {
 						if (delimiter_candidates++[0] == d2)
@@ -3589,7 +3674,7 @@ _nm_utils_str2bin_full (const char *asc,
 				}
 				if (!delimiter) {
 					if (delimiter_required)
-						return NULL;
+						goto fail;
 					delimiter_has = FALSE;
 					continue;
 				}
@@ -3598,11 +3683,66 @@ _nm_utils_str2bin_full (const char *asc,
 		}
 	}
 
-	*out_len = out - buffer;
-	return buffer;
+	len = out - buffer;
+	if (   required_len == 0
+	    || len == required_len) {
+		NM_SET_OUT (out_len, len);
+		return buffer;
+	}
+
+fail:
+	NM_SET_OUT (out_len, 0);
+	return NULL;
 }
 
-#define hwaddr_aton(asc, buffer, buffer_length, out_len) _nm_utils_str2bin_full ((asc), TRUE, ":-", (buffer), (buffer_length), (out_len))
+guint8 *
+_nm_utils_hexstr2bin_alloc (const char *hexstr,
+                            gboolean allow_0x_prefix,
+                            gboolean delimiter_required,
+                            const char *delimiter_candidates,
+                            gsize required_len,
+                            gsize *out_len)
+{
+	guint8 *buffer;
+	gsize buffer_len, len;
+
+	g_return_val_if_fail (hexstr, NULL);
+
+	nm_assert (required_len > 0 || out_len);
+
+	if (   allow_0x_prefix
+	    && hexstr[0] == '0'
+	    && hexstr[1] == 'x')
+		hexstr += 2;
+
+	if (!hexstr[0])
+		goto fail;
+
+	if (required_len > 0)
+		buffer_len = required_len;
+	else
+		buffer_len = strlen (hexstr) / 2 + 3;
+
+	buffer = g_malloc (buffer_len);
+
+	if (_nm_utils_hexstr2bin_full (hexstr,
+	                               FALSE,
+	                               delimiter_required,
+	                               delimiter_candidates,
+	                               required_len,
+	                               buffer,
+	                               buffer_len,
+	                               &len)) {
+		NM_SET_OUT (out_len, len);
+		return buffer;
+	}
+
+	g_free (buffer);
+
+fail:
+	NM_SET_OUT (out_len, 0);
+	return NULL;
+}
 
 /**
  * nm_utils_hexstr2bin:
@@ -3619,23 +3759,17 @@ GBytes *
 nm_utils_hexstr2bin (const char *hex)
 {
 	guint8 *buffer;
-	gsize buffer_length, len;
-
-	g_return_val_if_fail (hex != NULL, NULL);
-
-	if (hex[0] == '0' && hex[1] == 'x')
-		hex += 2;
+	gsize len;
 
-	buffer_length = strlen (hex) / 2 + 3;
-	buffer = g_malloc (buffer_length);
-	if (!_nm_utils_str2bin_full (hex, FALSE, ":", buffer, buffer_length, &len)) {
-		g_free (buffer);
+	buffer = _nm_utils_hexstr2bin_alloc (hex, TRUE, FALSE, ":", 0, &len);
+	if (!buffer)
 		return NULL;
-	}
 	buffer = g_realloc (buffer, len);
 	return g_bytes_new_take (buffer, len);
 }
 
+#define hwaddr_aton(asc, buffer, buffer_len, out_len) _nm_utils_hexstr2bin_full ((asc), FALSE, TRUE, ":-", 0, (buffer), (buffer_len), (out_len))
+
 /**
  * nm_utils_hwaddr_atoba:
  * @asc: the ASCII representation of a hardware address
@@ -3728,16 +3862,46 @@ nm_utils_hwaddr_aton (const char *asc, gpointer buffer, gsize length)
 	return buffer;
 }
 
-void
-_nm_utils_bin2str_full (gconstpointer addr, gsize length, const char delimiter, gboolean upper_case, char *out)
+/**
+ * _nm_utils_bin2hexstr_full:
+ * @addr: pointer of @length bytes.
+ * @length: number of bytes in @addr
+ * @delimiter: either '\0', otherwise the output string will have the
+ *   given delimiter character between each two hex numbers.
+ * @upper_case: if TRUE, use upper case ASCII characters for hex.
+ * @out: if %NULL, the function will allocate a new buffer of
+ *   either (@length*2+1) or (@length*3) bytes, depending on whether
+ *   a @delimiter is specified. In that case, the allocated buffer will
+ *   be returned and must be freed by the caller.
+ *   If not %NULL, the buffer must already be preallocated and contain
+ *   at least (@length*2+1) or (@length*3) bytes, depending on the delimiter.
+ *
+ * Returns: the binary value converted to a hex string. If @out is given,
+ *   this always returns @out. If @out is %NULL, a newly allocated string
+ *   is returned.
+ */
+char *
+_nm_utils_bin2hexstr_full (gconstpointer addr,
+                           gsize length,
+                           char delimiter,
+                           gboolean upper_case,
+                           char *out)
 {
 	const guint8 *in = addr;
 	const char *LOOKUP = upper_case ? "0123456789ABCDEF" : "0123456789abcdef";
+	char *out0;
 
 	nm_assert (addr);
-	nm_assert (out);
 	nm_assert (length > 0);
 
+	if (out)
+		out0 = out;
+	else {
+		out0 = out = g_new (char, delimiter == '\0'
+		                          ? length * 2 + 1
+		                          : length * 3);
+	}
+
 	/* @out must contain at least @length*3 bytes if @delimiter is set,
 	 * otherwise, @length*2+1. */
 
@@ -3754,6 +3918,7 @@ _nm_utils_bin2str_full (gconstpointer addr, gsize length, const char delimiter,
 	}
 
 	*out = 0;
+	return out0;
 }
 
 /**
@@ -3779,7 +3944,8 @@ nm_utils_bin2hexstr (gconstpointer src, gsize len, int final_len)
 	g_return_val_if_fail (final_len < 0 || (gsize) final_len < buflen, NULL);
 
 	result = g_malloc (buflen);
-	_nm_utils_bin2str_full (src, len, '\0', FALSE, result);
+
+	_nm_utils_bin2hexstr_full (src, len, '\0', FALSE, result);
 
 	/* Cut converted key off at the correct length for this cipher type */
 	if (final_len >= 0 && (gsize) final_len < buflen)
@@ -3800,14 +3966,10 @@ nm_utils_bin2hexstr (gconstpointer src, gsize len, int final_len)
 char *
 nm_utils_hwaddr_ntoa (gconstpointer addr, gsize length)
 {
-	char *result;
-
 	g_return_val_if_fail (addr, g_strdup (""));
 	g_return_val_if_fail (length > 0, g_strdup (""));
 
-	result = g_malloc (length * 3);
-	_nm_utils_bin2str_full (addr, length, ':', TRUE, result);
-	return result;
+	return _nm_utils_bin2hexstr_full (addr, length, ':', TRUE, NULL);
 }
 
 const char *
@@ -3819,31 +3981,7 @@ nm_utils_hwaddr_ntoa_buf (gconstpointer addr, gsize addr_len, gboolean upper_cas
 	if (buf_len < addr_len * 3)
 		g_return_val_if_reached (NULL);
 
-	_nm_utils_bin2str_full (addr, addr_len, ':', upper_case, buf);
-	return buf;
-}
-
-/**
- * _nm_utils_bin2str:
- * @addr: (type guint8) (array length=length): a binary hardware address
- * @length: the length of @addr
- * @upper_case: the case for the hexadecimal digits.
- *
- * Converts @addr to textual form.
- *
- * Return value: (transfer full): the textual form of @addr
- */
-char *
-_nm_utils_bin2str (gconstpointer addr, gsize length, gboolean upper_case)
-{
-	char *result;
-
-	g_return_val_if_fail (addr, g_strdup (""));
-	g_return_val_if_fail (length > 0, g_strdup (""));
-
-	result = g_malloc (length * 3);
-	_nm_utils_bin2str_full (addr, length, ':', upper_case, result);
-	return result;
+	return _nm_utils_bin2hexstr_full (addr, addr_len, ':', upper_case, buf);
 }
 
 /**
@@ -4096,13 +4234,18 @@ _nm_utils_hwaddr_cloned_not_set (NMSetting *setting,
 }
 
 GVariant *
-_nm_utils_hwaddr_cloned_data_synth (NMSetting *setting,
+_nm_utils_hwaddr_cloned_data_synth (const NMSettInfoSetting *sett_info,
+                                    guint property_idx,
                                     NMConnection *connection,
-                                    const char *property)
+                                    NMSetting *setting,
+                                    NMConnectionSerializationFlags flags)
 {
 	gs_free char *addr = NULL;
 
-	nm_assert (nm_streq0 (property, "assigned-mac-address"));
+	if (flags & NM_CONNECTION_SERIALIZE_ONLY_SECRETS)
+		return NULL;
+
+	nm_assert (nm_streq0 (sett_info->property_infos[property_idx].name, "assigned-mac-address"));
 
 	g_object_get (setting,
 	              "cloned-mac-address",
@@ -4123,7 +4266,9 @@ _nm_utils_hwaddr_cloned_data_synth (NMSetting *setting,
 	 * To preserve that behavior, serialize "" as NULL.
 	 */
 
-	return addr && addr[0] ? g_variant_new_string (addr) : NULL;
+	return addr && addr[0]
+	       ? g_variant_new_take_string (g_steal_pointer (&addr))
+	       : NULL;
 }
 
 gboolean
@@ -4362,10 +4507,11 @@ nm_utils_inet_ntop (int addr_family, gconstpointer addr, char *dst)
 
 	nm_assert_addr_family (addr_family);
 	nm_assert (addr);
+	nm_assert (dst);
 
 	s = inet_ntop (addr_family,
 	               addr,
-	               dst ?: _nm_utils_inet_ntop_buffer,
+	               dst,
 	               addr_family == AF_INET6 ? INET6_ADDRSTRLEN : INET_ADDRSTRLEN);
 	nm_assert (s);
 	return s;
@@ -4391,6 +4537,11 @@ nm_utils_inet_ntop (int addr_family, gconstpointer addr, char *dst)
 const char *
 nm_utils_inet4_ntop (in_addr_t inaddr, char *dst)
 {
+	/* relying on the static buffer (by leaving @dst as %NULL) is discouraged.
+	 * Don't do that!
+	 *
+	 * However, still support it to be lenient against mistakes and because
+	 * this is public API of libnm. */
 	return inet_ntop (AF_INET, &inaddr, dst ?: _nm_utils_inet_ntop_buffer,
 	                  INET_ADDRSTRLEN);
 }
@@ -4416,6 +4567,11 @@ nm_utils_inet4_ntop (in_addr_t inaddr, char *dst)
 const char *
 nm_utils_inet6_ntop (const struct in6_addr *in6addr, char *dst)
 {
+	/* relying on the static buffer (by leaving @dst as %NULL) is discouraged.
+	 * Don't do that!
+	 *
+	 * However, still support it to be lenient against mistakes and because
+	 * this is public API of libnm. */
 	g_return_val_if_fail (in6addr, NULL);
 	return inet_ntop (AF_INET6, in6addr, dst ?: _nm_utils_inet_ntop_buffer,
 	                  INET6_ADDRSTRLEN);
@@ -4510,7 +4666,7 @@ _nm_utils_dhcp_duid_valid (const char *duid, GBytes **out_duid_bin)
 		return TRUE;
 	}
 
-	if (_nm_utils_str2bin_full (duid, FALSE, ":", duid_arr, sizeof (duid_arr), &duid_len)) {
+	if (_nm_utils_hexstr2bin_full (duid, FALSE, FALSE, ":", 0, duid_arr, sizeof (duid_arr), &duid_len)) {
 		/* MAX DUID length is 128 octects + the type code (2 octects). */
 		if (   duid_len > 2
 		    && duid_len <= (128 + 2)) {
@@ -5280,7 +5436,7 @@ _nm_utils_team_link_watcher_from_json (json_t *json_element)
 	const char *j_key;
 	json_t *j_val;
 	gs_free char *name = NULL, *target_host = NULL, *source_host = NULL;
-	int val1 = 0, val2 = 0, val3 = 3;
+	int val1 = 0, val2 = 0, val3 = 3, val4 = -1;
 	NMTeamLinkWatcherArpPingFlags flags = 0;
 
 	g_return_val_if_fail (json_element, NULL);
@@ -5301,6 +5457,8 @@ _nm_utils_team_link_watcher_from_json (json_t *json_element)
 			val2 = json_integer_value (j_val);
 		else if (nm_streq (j_key, "missed_max"))
 			val3 = json_integer_value (j_val);
+		else if (nm_streq (j_key, "vlanid"))
+			val4 = json_integer_value (j_val);
 		else if (nm_streq (j_key, "validate_active")) {
 			if (json_is_true (j_val))
 				flags |= NM_TEAM_LINK_WATCHER_ARP_PING_FLAG_VALIDATE_ACTIVE;
@@ -5318,8 +5476,8 @@ _nm_utils_team_link_watcher_from_json (json_t *json_element)
 	else if (nm_streq0 (name, NM_TEAM_LINK_WATCHER_NSNA_PING))
 		return nm_team_link_watcher_new_nsna_ping (val1, val2, val3, target_host, NULL);
 	else if (nm_streq0 (name, NM_TEAM_LINK_WATCHER_ARP_PING)) {
-		return nm_team_link_watcher_new_arp_ping (val1, val2, val3, target_host,
-		                                          source_host, flags, NULL);
+		return nm_team_link_watcher_new_arp_ping2 (val1, val2, val3, val4, target_host,
+		                                           source_host, flags, NULL);
 	} else
 		return NULL;
 }
@@ -5369,6 +5527,9 @@ _nm_utils_team_link_watcher_to_json (NMTeamLinkWatcher *watcher)
 	if (nm_streq (name, NM_TEAM_LINK_WATCHER_NSNA_PING))
 		return json_element;
 
+	int_val = nm_team_link_watcher_get_vlanid (watcher);
+	if (int_val != -1)
+		json_object_set_new (json_element, "vlanid", json_integer (int_val));
 	str_val = nm_team_link_watcher_get_source_host (watcher);
 	if (!str_val)
 		goto fail;
@@ -5870,6 +6031,12 @@ _nm_utils_team_link_watchers_to_variant (GPtrArray *link_watchers)
 		}
 
 		/* arp_ping watcher only */
+		int_val = nm_team_link_watcher_get_vlanid (watcher);
+		if (int_val != -1) {
+			g_variant_builder_add (&watcher_builder, "{sv}",
+			                       "vlanid",
+			                       g_variant_new_int32 (int_val));
+		}
 		g_variant_builder_add (&watcher_builder, "{sv}",
 		                       "source-host",
 		                       g_variant_new_string (nm_team_link_watcher_get_source_host (watcher)));
@@ -5920,7 +6087,7 @@ _nm_utils_team_link_watchers_from_variant (GVariant *value)
 	while (g_variant_iter_next (&iter, "@a{sv}", &watcher_var)) {
 		NMTeamLinkWatcher *watcher;
 		const char *name;
-		int val1, val2, val3 = 0;
+		int val1, val2, val3 = 0, val4 = -1;
 		const char *target_host = NULL, *source_host = NULL;
 		gboolean bval;
 		NMTeamLinkWatcherArpPingFlags flags = NM_TEAM_LINK_WATCHER_ARP_PING_FLAG_NONE;
@@ -5951,6 +6118,8 @@ _nm_utils_team_link_watchers_from_variant (GVariant *value)
 			if (!g_variant_lookup (watcher_var, "missed-max", "i", &val3))
 				val3 = 3;
 			if nm_streq (name, NM_TEAM_LINK_WATCHER_ARP_PING) {
+				if (!g_variant_lookup (watcher_var, "vlanid", "i", &val4))
+					val4 = -1;
 				if (!g_variant_lookup (watcher_var, "source-host", "&s", &source_host))
 					goto next;
 				if (!g_variant_lookup (watcher_var, "validate-active", "b", &bval))
@@ -5965,9 +6134,9 @@ _nm_utils_team_link_watchers_from_variant (GVariant *value)
 					bval = FALSE;
 				if (bval)
 					flags |= NM_TEAM_LINK_WATCHER_ARP_PING_FLAG_SEND_ALWAYS;
-				watcher = nm_team_link_watcher_new_arp_ping (val1, val2, val3,
-				                                             target_host, source_host,
-				                                             flags, &error);
+				watcher = nm_team_link_watcher_new_arp_ping2 (val1, val2, val3, val4,
+				                                              target_host, source_host,
+				                                              flags, &error);
 			} else
 				watcher = nm_team_link_watcher_new_nsna_ping (val1, val2, val3,
 				                                              target_host, &error);
diff --git a/libnm-core/nm-version.h b/libnm-core/nm-version.h
index 59482d4e..7fe2e45b 100644
--- a/libnm-core/nm-version.h
+++ b/libnm-core/nm-version.h
@@ -174,4 +174,18 @@
 # define NM_AVAILABLE_IN_1_14
 #endif
 
+#if NM_VERSION_MIN_REQUIRED >= NM_VERSION_1_16
+# define NM_DEPRECATED_IN_1_16           G_DEPRECATED
+# define NM_DEPRECATED_IN_1_16_FOR(f)    G_DEPRECATED_FOR(f)
+#else
+# define NM_DEPRECATED_IN_1_16
+# define NM_DEPRECATED_IN_1_16_FOR(f)
+#endif
+
+#if NM_VERSION_MAX_ALLOWED < NM_VERSION_1_16
+# define NM_AVAILABLE_IN_1_16            G_UNAVAILABLE(1,16)
+#else
+# define NM_AVAILABLE_IN_1_16
+#endif
+
 #endif  /* NM_VERSION_H */
diff --git a/libnm-core/nm-vpn-editor-plugin.c b/libnm-core/nm-vpn-editor-plugin.c
index d690d9b0..30213ea0 100644
--- a/libnm-core/nm-vpn-editor-plugin.c
+++ b/libnm-core/nm-vpn-editor-plugin.c
@@ -29,6 +29,8 @@
 
 #include "nm-core-internal.h"
 
+/*****************************************************************************/
+
 static void nm_vpn_editor_plugin_default_init (NMVpnEditorPluginInterface *iface);
 
 G_DEFINE_INTERFACE (NMVpnEditorPlugin, nm_vpn_editor_plugin, G_TYPE_OBJECT)
@@ -36,18 +38,16 @@ G_DEFINE_INTERFACE (NMVpnEditorPlugin, nm_vpn_editor_plugin, G_TYPE_OBJECT)
 static void
 nm_vpn_editor_plugin_default_init (NMVpnEditorPluginInterface *iface)
 {
-	/* Properties */
-
 	/**
 	 * NMVpnEditorPlugin:name:
 	 *
 	 * Short display name of the VPN plugin.
 	 */
 	g_object_interface_install_property (iface,
-		 g_param_spec_string (NM_VPN_EDITOR_PLUGIN_NAME, "", "",
-		                      NULL,
-		                      G_PARAM_READABLE |
-		                      G_PARAM_STATIC_STRINGS));
+	    g_param_spec_string (NM_VPN_EDITOR_PLUGIN_NAME, "", "",
+	                         NULL,
+	                         G_PARAM_READABLE |
+	                         G_PARAM_STATIC_STRINGS));
 
 	/**
 	 * NMVpnEditorPlugin:description:
@@ -55,10 +55,10 @@ nm_vpn_editor_plugin_default_init (NMVpnEditorPluginInterface *iface)
 	 * Longer description of the VPN plugin.
 	 */
 	g_object_interface_install_property (iface,
-		 g_param_spec_string (NM_VPN_EDITOR_PLUGIN_DESCRIPTION, "", "",
-		                      NULL,
-		                      G_PARAM_READABLE |
-		                      G_PARAM_STATIC_STRINGS));
+	    g_param_spec_string (NM_VPN_EDITOR_PLUGIN_DESCRIPTION, "", "",
+	                         NULL,
+	                         G_PARAM_READABLE |
+	                         G_PARAM_STATIC_STRINGS));
 
 	/**
 	 * NMVpnEditorPlugin:service:
@@ -66,10 +66,10 @@ nm_vpn_editor_plugin_default_init (NMVpnEditorPluginInterface *iface)
 	 * D-Bus service name of the plugin's VPN service.
 	 */
 	g_object_interface_install_property (iface,
-		 g_param_spec_string (NM_VPN_EDITOR_PLUGIN_SERVICE, "", "",
-		                      NULL,
-		                      G_PARAM_READABLE |
-		                      G_PARAM_STATIC_STRINGS));
+	    g_param_spec_string (NM_VPN_EDITOR_PLUGIN_SERVICE, "", "",
+	                         NULL,
+	                         G_PARAM_READABLE |
+	                         G_PARAM_STATIC_STRINGS));
 }
 
 /*****************************************************************************/
@@ -379,8 +379,8 @@ _nm_vpn_editor_plugin_load (const char *plugin_name,
  * @user_data: user data for @check_file
  * @error: on failure the error reason.
  *
- * Load the shared libary @plugin_name and create a new
- * #NMVpnEditorPlugin instace via the #NMVpnEditorPluginFactory
+ * Load the shared library @plugin_name and create a new
+ * #NMVpnEditorPlugin instance via the #NMVpnEditorPluginFactory
  * function.
  *
  * If @plugin_name is not an absolute path name, it assumes the file
@@ -419,8 +419,8 @@ nm_vpn_editor_plugin_load_from_file  (const char *plugin_name,
  *  the given service.
  * @error: on failure the error reason.
  *
- * Load the shared libary @plugin_name and create a new
- * #NMVpnEditorPlugin instace via the #NMVpnEditorPluginFactory
+ * Load the shared library @plugin_name and create a new
+ * #NMVpnEditorPlugin instance via the #NMVpnEditorPluginFactory
  * function.
  *
  * This is similar to nm_vpn_editor_plugin_load_from_file(), but
diff --git a/libnm-core/nm-vpn-plugin-info.c b/libnm-core/nm-vpn-plugin-info.c
index 79542279..275a9dd5 100644
--- a/libnm-core/nm-vpn-plugin-info.c
+++ b/libnm-core/nm-vpn-plugin-info.c
@@ -1095,60 +1095,42 @@ nm_vpn_plugin_info_load_editor_plugin (NMVpnPluginInfo *self, GError **error)
 
 /*****************************************************************************/
 
-/**
- * nm_vpn_plugin_info_new_from_file:
- * @filename: filename to read.
- * @error: on failure, the error reason.
- *
- * Read the plugin info from file @filename. Does not do
- * any further verification on the file. You might want to check
- * file permissions and ownership of the file.
- *
- * Returns: %NULL if there is any error or a newly created
- * #NMVpnPluginInfo instance.
- *
- * Since: 1.2
- */
-NMVpnPluginInfo *
-nm_vpn_plugin_info_new_from_file (const char *filename,
-                                  GError **error)
+static void
+get_property (GObject *object, guint prop_id,
+              GValue *value, GParamSpec *pspec)
 {
-	g_return_val_if_fail (filename, NULL);
+	NMVpnPluginInfoPrivate *priv = NM_VPN_PLUGIN_INFO_GET_PRIVATE (object);
 
-	return NM_VPN_PLUGIN_INFO (g_initable_new (NM_TYPE_VPN_PLUGIN_INFO,
-	                                           NULL,
-	                                           error,
-	                                           NM_VPN_PLUGIN_INFO_FILENAME, filename,
-	                                           NULL));
+	switch (prop_id) {
+	case PROP_NAME:
+		g_value_set_string (value, priv->name);
+		break;
+	case PROP_FILENAME:
+		g_value_set_string (value, priv->filename);
+		break;
+	default:
+		G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+		break;
+	}
 }
 
-/**
- * nm_vpn_plugin_info_new_with_data:
- * @filename: optional filename.
- * @keyfile: inject data for the plugin info instance.
- * @error: construction may fail if the keyfile lacks mandatory fields.
- *   In this case, return the error reason.
- *
- * This constructor does not read any data from file but
- * takes instead a @keyfile argument.
- *
- * Returns: new plugin info instance.
- *
- * Since: 1.2
- */
-NMVpnPluginInfo *
-nm_vpn_plugin_info_new_with_data (const char *filename,
-                                  GKeyFile *keyfile,
-                                  GError **error)
+static void
+set_property (GObject *object, guint prop_id,
+              const GValue *value, GParamSpec *pspec)
 {
-	g_return_val_if_fail (keyfile, NULL);
+	NMVpnPluginInfoPrivate *priv = NM_VPN_PLUGIN_INFO_GET_PRIVATE (object);
 
-	return NM_VPN_PLUGIN_INFO (g_initable_new (NM_TYPE_VPN_PLUGIN_INFO,
-	                                           NULL,
-	                                           error,
-	                                           NM_VPN_PLUGIN_INFO_FILENAME, filename,
-	                                           NM_VPN_PLUGIN_INFO_KEYFILE, keyfile,
-	                                           NULL));
+	switch (prop_id) {
+	case PROP_FILENAME:
+		priv->filename = g_value_dup_string (value);
+		break;
+	case PROP_KEYFILE:
+		priv->keyfile = g_value_dup_boxed (value);
+		break;
+	default:
+		G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+		break;
+	}
 }
 
 /*****************************************************************************/
@@ -1224,42 +1206,60 @@ init_sync (GInitable *initable, GCancellable *cancellable, GError **error)
 	return TRUE;
 }
 
-static void
-set_property (GObject *object, guint prop_id,
-              const GValue *value, GParamSpec *pspec)
+/**
+ * nm_vpn_plugin_info_new_from_file:
+ * @filename: filename to read.
+ * @error: on failure, the error reason.
+ *
+ * Read the plugin info from file @filename. Does not do
+ * any further verification on the file. You might want to check
+ * file permissions and ownership of the file.
+ *
+ * Returns: %NULL if there is any error or a newly created
+ * #NMVpnPluginInfo instance.
+ *
+ * Since: 1.2
+ */
+NMVpnPluginInfo *
+nm_vpn_plugin_info_new_from_file (const char *filename,
+                                  GError **error)
 {
-	NMVpnPluginInfoPrivate *priv = NM_VPN_PLUGIN_INFO_GET_PRIVATE (object);
+	g_return_val_if_fail (filename, NULL);
 
-	switch (prop_id) {
-	case PROP_FILENAME:
-		priv->filename = g_value_dup_string (value);
-		break;
-	case PROP_KEYFILE:
-		priv->keyfile = g_value_dup_boxed (value);
-		break;
-	default:
-		G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
-		break;
-	}
+	return NM_VPN_PLUGIN_INFO (g_initable_new (NM_TYPE_VPN_PLUGIN_INFO,
+	                                           NULL,
+	                                           error,
+	                                           NM_VPN_PLUGIN_INFO_FILENAME, filename,
+	                                           NULL));
 }
 
-static void
-get_property (GObject *object, guint prop_id,
-              GValue *value, GParamSpec *pspec)
+/**
+ * nm_vpn_plugin_info_new_with_data:
+ * @filename: optional filename.
+ * @keyfile: inject data for the plugin info instance.
+ * @error: construction may fail if the keyfile lacks mandatory fields.
+ *   In this case, return the error reason.
+ *
+ * This constructor does not read any data from file but
+ * takes instead a @keyfile argument.
+ *
+ * Returns: new plugin info instance.
+ *
+ * Since: 1.2
+ */
+NMVpnPluginInfo *
+nm_vpn_plugin_info_new_with_data (const char *filename,
+                                  GKeyFile *keyfile,
+                                  GError **error)
 {
-	NMVpnPluginInfoPrivate *priv = NM_VPN_PLUGIN_INFO_GET_PRIVATE (object);
+	g_return_val_if_fail (keyfile, NULL);
 
-	switch (prop_id) {
-	case PROP_NAME:
-		g_value_set_string (value, priv->name);
-		break;
-	case PROP_FILENAME:
-		g_value_set_string (value, priv->filename);
-		break;
-	default:
-		G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
-		break;
-	}
+	return NM_VPN_PLUGIN_INFO (g_initable_new (NM_TYPE_VPN_PLUGIN_INFO,
+	                                           NULL,
+	                                           error,
+	                                           NM_VPN_PLUGIN_INFO_FILENAME, filename,
+	                                           NM_VPN_PLUGIN_INFO_KEYFILE, keyfile,
+	                                           NULL));
 }
 
 static void
@@ -1298,14 +1298,11 @@ nm_vpn_plugin_info_class_init (NMVpnPluginInfoClass *plugin_class)
 
 	g_type_class_add_private (object_class, sizeof (NMVpnPluginInfoPrivate));
 
-	/* virtual methods */
 	object_class->set_property = set_property;
 	object_class->get_property = get_property;
 	object_class->dispose      = dispose;
 	object_class->finalize     = finalize;
 
-	/* properties */
-
 	/**
 	 * NMVpnPluginInfo:name:
 	 *
@@ -1341,7 +1338,7 @@ nm_vpn_plugin_info_class_init (NMVpnPluginInfoClass *plugin_class)
 	/**
 	 * NMVpnPluginInfo:keyfile:
 	 *
-	 * Initalize the instance with a different keyfile instance.
+	 * Initialize the instance with a different keyfile instance.
 	 * When passing a keyfile instance, the constructor will not
 	 * try to read from filename.
 	 *
@@ -1361,4 +1358,3 @@ nm_vpn_plugin_info_initable_iface_init (GInitableIface *iface)
 {
 	iface->init = init_sync;
 }
-
diff --git a/libnm-core/tests/meson.build b/libnm-core/tests/meson.build
index 627e6b53..b9411074 100644
--- a/libnm-core/tests/meson.build
+++ b/libnm-core/tests/meson.build
@@ -14,7 +14,7 @@ enum = gnome.mkenums(
   sources: 'test-general-enums.h',
   identifier_prefix: nm_id_prefix,
   c_template: enum_types + '.c.template',
-  h_template: enum_types + '.h.template'
+  h_template: enum_types + '.h.template',
 )
 
 test_units = [
@@ -24,7 +24,7 @@ test_units = [
   'test-keyfile',
   'test-secrets',
   'test-setting',
-  'test-settings-defaults'
+  'test-settings-defaults',
 ]
 
 test_cert_dir = join_paths(meson.current_source_dir(), 'certs')
@@ -33,16 +33,19 @@ foreach test_unit: test_units
   exe = executable(
     'libnm-core-' + test_unit,
     [test_unit + '.c'] + enum,
-    dependencies: nm_core_dep,
+    dependencies: [
+      nm_core_dep,
+      libnm_systemd_shared_no_logging_dep,
+    ],
     c_args: [
         '-DNETWORKMANAGER_COMPILATION_TEST',
         '-DNETWORKMANAGER_COMPILATION=NM_NETWORKMANAGER_COMPILATION_LIBNM_CORE',
       ],
-    link_with: libnm_core
+    link_with: libnm_core,
   )
   test(
     'libnm-core/' + test_unit,
     test_script,
-    args: test_args + [exe.full_path()]
+    args: test_args + [exe.full_path()],
   )
 endforeach
diff --git a/libnm-core/tests/test-general.c b/libnm-core/tests/test-general.c
index 5a954270..0806e7b9 100644
--- a/libnm-core/tests/test-general.c
+++ b/libnm-core/tests/test-general.c
@@ -755,10 +755,12 @@ vpn_check_empty_func (const char *key, const char *value, gpointer user_data)
 static void
 test_setting_vpn_items (void)
 {
-	gs_unref_object NMSettingVpn *s_vpn = NULL;
+	gs_unref_object NMConnection *connection = NULL;
+	NMSettingVpn *s_vpn;
 
-	s_vpn = (NMSettingVpn *) nm_setting_vpn_new ();
-	g_assert (s_vpn);
+	connection = nmtst_create_minimal_connection ("vpn-items", NULL, NM_SETTING_VPN_SETTING_NAME, NULL);
+
+	s_vpn = nm_connection_get_setting_vpn (connection);
 
 	nm_setting_vpn_add_data_item (s_vpn, "foobar1", "blahblah1");
 	nm_setting_vpn_add_data_item (s_vpn, "foobar2", "blahblah2");
@@ -772,7 +774,14 @@ test_setting_vpn_items (void)
 	nm_setting_vpn_remove_data_item (s_vpn, "foobar3");
 	nm_setting_vpn_remove_data_item (s_vpn, "foobar4");
 
+	g_assert (!_nm_connection_aggregate (connection, NM_CONNECTION_AGGREGATE_ANY_SECRETS, NULL));
+	g_assert (!_nm_connection_aggregate (connection, NM_CONNECTION_AGGREGATE_ANY_SYSTEM_SECRET_FLAGS, NULL));
+
 	nm_setting_vpn_add_secret (s_vpn, "foobar1", "blahblah1");
+
+	g_assert (_nm_connection_aggregate (connection, NM_CONNECTION_AGGREGATE_ANY_SECRETS, NULL));
+	g_assert (_nm_connection_aggregate (connection, NM_CONNECTION_AGGREGATE_ANY_SYSTEM_SECRET_FLAGS, NULL));
+
 	nm_setting_vpn_add_secret (s_vpn, "foobar2", "blahblah2");
 	nm_setting_vpn_add_secret (s_vpn, "foobar3", "blahblah3");
 	nm_setting_vpn_add_secret (s_vpn, "foobar4", "blahblah4");
@@ -782,8 +791,25 @@ test_setting_vpn_items (void)
 	nm_setting_vpn_remove_secret (s_vpn, "foobar1");
 	nm_setting_vpn_remove_secret (s_vpn, "foobar2");
 	nm_setting_vpn_remove_secret (s_vpn, "foobar3");
+
+	g_assert (_nm_connection_aggregate (connection, NM_CONNECTION_AGGREGATE_ANY_SECRETS, NULL));
+	g_assert (_nm_connection_aggregate (connection, NM_CONNECTION_AGGREGATE_ANY_SYSTEM_SECRET_FLAGS, NULL));
+
+	nm_setting_vpn_add_data_item (s_vpn, "foobar4-flags", "blahblah4");
+
+	g_assert (_nm_connection_aggregate (connection, NM_CONNECTION_AGGREGATE_ANY_SYSTEM_SECRET_FLAGS, NULL));
+
+	nm_setting_vpn_add_data_item (s_vpn, "foobar4-flags", "2");
+
+	g_assert (!_nm_connection_aggregate (connection, NM_CONNECTION_AGGREGATE_ANY_SYSTEM_SECRET_FLAGS, NULL));
+
 	nm_setting_vpn_remove_secret (s_vpn, "foobar4");
 
+	g_assert (!_nm_connection_aggregate (connection, NM_CONNECTION_AGGREGATE_ANY_SECRETS, NULL));
+	g_assert (!_nm_connection_aggregate (connection, NM_CONNECTION_AGGREGATE_ANY_SYSTEM_SECRET_FLAGS, NULL));
+
+	nm_setting_vpn_remove_data_item (s_vpn, "foobar4-flags");
+
 	/* Try to add some blank values and make sure they are rejected */
 	NMTST_EXPECT_LIBNM_CRITICAL (NMTST_G_RETURN_MSG (key != NULL));
 	nm_setting_vpn_add_data_item (s_vpn, NULL, NULL);
@@ -1351,8 +1377,6 @@ test_setting_gsm_apn_bad_chars (void)
 	s_gsm = (NMSettingGsm *) nm_setting_gsm_new ();
 	g_assert (s_gsm);
 
-	g_object_set (s_gsm, NM_SETTING_GSM_NUMBER, "*99#", NULL);
-
 	/* Make sure a valid APN works */
 	g_object_set (s_gsm, NM_SETTING_GSM_APN, "foobar123.-baz", NULL);
 	g_assert (nm_setting_verify (NM_SETTING (s_gsm), NULL, NULL));
@@ -1382,8 +1406,6 @@ test_setting_gsm_apn_underscore (void)
 	s_gsm = (NMSettingGsm *) nm_setting_gsm_new ();
 	g_assert (s_gsm);
 
-	g_object_set (s_gsm, NM_SETTING_GSM_NUMBER, "*99#", NULL);
-
 	/* 65-character long */
 	g_object_set (s_gsm, NM_SETTING_GSM_APN, "foobar_baz", NULL);
 	nmtst_assert_setting_verifies (NM_SETTING (s_gsm));
@@ -1636,6 +1658,25 @@ test_connection_to_dbus_setting_name (void)
 	s_wsec = make_test_wsec_setting ("connection-to-dbus-setting-name");
 	nm_connection_add_setting (connection, NM_SETTING (s_wsec));
 
+	g_assert (_nm_connection_aggregate (connection, NM_CONNECTION_AGGREGATE_ANY_SECRETS, NULL));
+	g_assert (_nm_connection_aggregate (connection, NM_CONNECTION_AGGREGATE_ANY_SYSTEM_SECRET_FLAGS, NULL));
+
+	g_object_set (s_wsec,
+	              NM_SETTING_WIRELESS_SECURITY_WEP_KEY_FLAGS, NM_SETTING_SECRET_FLAG_NOT_SAVED,
+	              NM_SETTING_WIRELESS_SECURITY_LEAP_PASSWORD_FLAGS, NM_SETTING_SECRET_FLAG_NOT_SAVED,
+	              NULL);
+
+	g_assert (_nm_connection_aggregate (connection, NM_CONNECTION_AGGREGATE_ANY_SECRETS, NULL));
+	g_assert (!_nm_connection_aggregate (connection, NM_CONNECTION_AGGREGATE_ANY_SYSTEM_SECRET_FLAGS, NULL));
+
+	g_object_set (s_wsec,
+	              NM_SETTING_WIRELESS_SECURITY_WEP_KEY_FLAGS, NM_SETTING_SECRET_FLAG_NONE,
+	              NM_SETTING_WIRELESS_SECURITY_LEAP_PASSWORD_FLAGS, NM_SETTING_SECRET_FLAG_NONE,
+	              NULL);
+
+	g_assert (_nm_connection_aggregate (connection, NM_CONNECTION_AGGREGATE_ANY_SECRETS, NULL));
+	g_assert (_nm_connection_aggregate (connection, NM_CONNECTION_AGGREGATE_ANY_SYSTEM_SECRET_FLAGS, NULL));
+
 	dict = nm_connection_to_dbus (connection, NM_CONNECTION_SERIALIZE_ALL);
 
 	/* Make sure the keys of the first level dict are setting names, not
@@ -2946,7 +2987,6 @@ test_connection_good_base_types (void)
 
 	setting = nm_setting_gsm_new ();
 	g_object_set (setting,
-	              NM_SETTING_GSM_NUMBER, "*99#",
 	              NM_SETTING_GSM_APN, "metered.billing.sucks",
 	              NULL);
 	nm_connection_add_setting (connection, setting);
@@ -3267,11 +3307,110 @@ test_data_compare_secrets_new (NMSettingSecretFlags secret_flags,
 }
 
 static void
+_test_compare_secrets_check_diff (NMSetting *a,
+                                  NMSetting *b,
+                                  NMSettingCompareFlags flags,
+                                  gboolean exp_same_psk,
+                                  gboolean exp_same_psk_flags)
+{
+	gs_unref_hashtable GHashTable *h = NULL;
+	NMSettingDiffResult _RESULT_IN_A = NM_SETTING_DIFF_RESULT_IN_A;
+	NMSettingDiffResult _RESULT_IN_B = NM_SETTING_DIFF_RESULT_IN_B;
+	gboolean invert_results;
+	gboolean diff_result;
+	NMSettingSecretFlags a_psk_flags = nm_setting_wireless_security_get_psk_flags (NM_SETTING_WIRELESS_SECURITY (a));
+	NMSettingSecretFlags b_psk_flags = nm_setting_wireless_security_get_psk_flags (NM_SETTING_WIRELESS_SECURITY (b));
+	const char *a_psk = nm_setting_wireless_security_get_psk (NM_SETTING_WIRELESS_SECURITY (a));
+	const char *b_psk = nm_setting_wireless_security_get_psk (NM_SETTING_WIRELESS_SECURITY (b));
+
+	g_assert (NM_IS_SETTING_WIRELESS_SECURITY (a));
+	g_assert (NM_IS_SETTING_WIRELESS_SECURITY (b));
+
+	invert_results = nmtst_get_rand_bool ();
+	if (invert_results) {
+		_RESULT_IN_A = NM_SETTING_DIFF_RESULT_IN_B;
+		_RESULT_IN_B = NM_SETTING_DIFF_RESULT_IN_A;
+	}
+
+	diff_result = nm_setting_diff (a, b, flags, invert_results, &h);
+
+	g_assert (exp_same_psk_flags == (a_psk_flags == b_psk_flags));
+
+	if (nm_streq0 (a_psk, b_psk))
+		g_assert (exp_same_psk);
+	else {
+		if (flags == NM_SETTING_COMPARE_FLAG_EXACT)
+			g_assert (!exp_same_psk);
+		else if (flags == NM_SETTING_COMPARE_FLAG_IGNORE_AGENT_OWNED_SECRETS) {
+			if (   !NM_FLAGS_HAS (a_psk_flags, NM_SETTING_SECRET_FLAG_AGENT_OWNED)
+			    && !NM_FLAGS_HAS (b_psk_flags, NM_SETTING_SECRET_FLAG_AGENT_OWNED))
+				g_assert (!exp_same_psk);
+			else if (   !NM_FLAGS_HAS (a_psk_flags, NM_SETTING_SECRET_FLAG_AGENT_OWNED)
+			         && NM_FLAGS_HAS (b_psk_flags, NM_SETTING_SECRET_FLAG_AGENT_OWNED))
+				g_assert (!exp_same_psk);
+			else
+				g_assert (exp_same_psk);
+		} else if (flags == NM_SETTING_COMPARE_FLAG_IGNORE_NOT_SAVED_SECRETS) {
+			if (   !NM_FLAGS_HAS (a_psk_flags, NM_SETTING_SECRET_FLAG_NOT_SAVED)
+			    && !NM_FLAGS_HAS (b_psk_flags, NM_SETTING_SECRET_FLAG_NOT_SAVED))
+				g_assert (!exp_same_psk);
+			else if (   !NM_FLAGS_HAS (a_psk_flags, NM_SETTING_SECRET_FLAG_NOT_SAVED)
+			         && NM_FLAGS_HAS (b_psk_flags, NM_SETTING_SECRET_FLAG_NOT_SAVED))
+				g_assert (!exp_same_psk);
+			else
+				g_assert (exp_same_psk);
+		} else if (flags == NM_SETTING_COMPARE_FLAG_IGNORE_SECRETS)
+			g_assert (exp_same_psk);
+		else
+			g_assert_not_reached ();
+	}
+
+	g_assert (diff_result == (exp_same_psk && exp_same_psk_flags));
+	g_assert (diff_result == (!h));
+
+	if (!diff_result) {
+		if (flags == NM_SETTING_COMPARE_FLAG_EXACT)
+			g_assert (!exp_same_psk);
+		else if (   NM_IN_SET (flags, NM_SETTING_COMPARE_FLAG_IGNORE_AGENT_OWNED_SECRETS,
+		                              NM_SETTING_COMPARE_FLAG_IGNORE_NOT_SAVED_SECRETS)
+		         && (a_psk_flags != b_psk_flags)
+		         && nm_setting_wireless_security_get_psk_flags (NM_SETTING_WIRELESS_SECURITY (a)) == NM_SETTING_SECRET_FLAG_NONE)
+			g_assert (!exp_same_psk);
+		else
+			g_assert (exp_same_psk);
+
+		g_assert ((!exp_same_psk) == g_hash_table_contains (h, NM_SETTING_WIRELESS_SECURITY_PSK));
+		if (!exp_same_psk) {
+			if (nm_setting_wireless_security_get_psk (NM_SETTING_WIRELESS_SECURITY (a)))
+				g_assert_cmpint (GPOINTER_TO_UINT (g_hash_table_lookup (h, NM_SETTING_WIRELESS_SECURITY_PSK)), ==, _RESULT_IN_A);
+			else
+				g_assert_cmpint (GPOINTER_TO_UINT (g_hash_table_lookup (h, NM_SETTING_WIRELESS_SECURITY_PSK)), ==, _RESULT_IN_B);
+		}
+
+		g_assert ((!exp_same_psk_flags) == g_hash_table_contains (h, NM_SETTING_WIRELESS_SECURITY_PSK_FLAGS));
+		if (!exp_same_psk_flags) {
+			if (nm_setting_wireless_security_get_psk_flags (NM_SETTING_WIRELESS_SECURITY (a)) != NM_SETTING_SECRET_FLAG_NONE)
+				g_assert_cmpint (GPOINTER_TO_UINT (g_hash_table_lookup (h, NM_SETTING_WIRELESS_SECURITY_PSK_FLAGS)), ==, _RESULT_IN_A);
+			else
+				g_assert_cmpint (GPOINTER_TO_UINT (g_hash_table_lookup (h, NM_SETTING_WIRELESS_SECURITY_PSK_FLAGS)), ==, _RESULT_IN_B);
+		}
+
+		g_assert_cmpint (g_hash_table_size (h), ==, (!exp_same_psk) + (!exp_same_psk_flags));
+	}
+
+	g_assert (diff_result == nm_setting_compare (a, b, flags));
+	g_assert (diff_result == nm_setting_compare (b, a, flags));
+
+}
+
+static void
 test_setting_compare_secrets (gconstpointer test_data)
 {
 	const TestDataCompareSecrets *data = test_data;
-	gs_unref_object NMSetting *old = NULL, *new = NULL;
-	gboolean success;
+	gs_unref_object NMConnection *conn_old = NULL;
+	gs_unref_object NMConnection *conn_new = NULL;
+	gs_unref_object NMSetting *old = NULL;
+	gs_unref_object NMSetting *new = NULL;
 
 	/* Make sure that a connection with transient/unsaved secrets compares
 	 * successfully to the same connection without those secrets.
@@ -3284,17 +3423,45 @@ test_setting_compare_secrets (gconstpointer test_data)
 	              NULL);
 	nm_setting_set_secret_flags (old, NM_SETTING_WIRELESS_SECURITY_PSK, data->secret_flags, NULL);
 
-	/* Clear the PSK from the duplicated setting */
 	new = nm_setting_duplicate (old);
-	if (data->remove_secret) {
+	if (data->remove_secret)
 		g_object_set (new, NM_SETTING_WIRELESS_SECURITY_PSK, NULL, NULL);
 
-		success = nm_setting_compare (old, new, NM_SETTING_COMPARE_FLAG_EXACT);
-		g_assert (success == FALSE);
+	g_assert ((!data->remove_secret) == nm_setting_compare (old, new, NM_SETTING_COMPARE_FLAG_EXACT));
+	g_assert ((!data->remove_secret) == nm_setting_compare (new, old, NM_SETTING_COMPARE_FLAG_EXACT));
+
+	_test_compare_secrets_check_diff (old, new, NM_SETTING_COMPARE_FLAG_EXACT, !data->remove_secret, TRUE);
+	_test_compare_secrets_check_diff (new, old, NM_SETTING_COMPARE_FLAG_EXACT, !data->remove_secret, TRUE);
+
+	g_assert (nm_setting_compare (old, new, data->comp_flags));
+	g_assert (nm_setting_compare (new, old, data->comp_flags));
+
+	_test_compare_secrets_check_diff (old, new, data->comp_flags, TRUE, TRUE);
+	_test_compare_secrets_check_diff (new, old, data->comp_flags, TRUE, TRUE);
+
+	/* OK. Try again, but this time not only change the secret, also let the secret flags differ... */
+	if (data->secret_flags != NM_SETTING_SECRET_FLAG_NONE) {
+		nm_setting_set_secret_flags (new, NM_SETTING_WIRELESS_SECURITY_PSK, NM_SETTING_SECRET_FLAG_NONE, NULL);
+
+		_test_compare_secrets_check_diff (old, new, NM_SETTING_COMPARE_FLAG_EXACT, FALSE, FALSE);
+		_test_compare_secrets_check_diff (new, old, NM_SETTING_COMPARE_FLAG_EXACT, FALSE, FALSE);
+
+		_test_compare_secrets_check_diff (old, new, data->comp_flags, TRUE, FALSE);
+		_test_compare_secrets_check_diff (new, old, data->comp_flags, FALSE, FALSE);
+
+		nm_setting_set_secret_flags (new, NM_SETTING_WIRELESS_SECURITY_PSK, data->secret_flags, NULL);
 	}
 
-	success = nm_setting_compare (old, new, data->comp_flags);
-	g_assert (success);
+	conn_old = nmtst_create_minimal_connection ("test-compare-secrets", NULL, NM_SETTING_WIRELESS_SETTING_NAME, NULL);
+	nm_connection_add_setting (conn_old, nm_setting_duplicate (old));
+	conn_new = nm_simple_connection_new_clone (conn_old);
+	nm_connection_add_setting (conn_new, nm_setting_duplicate (new));
+
+	g_assert ((!data->remove_secret) == nm_connection_compare (conn_old, conn_new, NM_SETTING_COMPARE_FLAG_EXACT));
+	g_assert ((!data->remove_secret) == nm_connection_compare (conn_new, conn_old, NM_SETTING_COMPARE_FLAG_EXACT));
+
+	g_assert (nm_connection_compare (conn_old, conn_new, data->comp_flags));
+	g_assert (nm_connection_compare (conn_new, conn_old, data->comp_flags));
 }
 
 static void
@@ -3473,6 +3640,41 @@ test_connection_changed_cb (NMConnection *connection, gboolean *data)
 	*data = TRUE;
 }
 
+static guint32
+_netmask_to_prefix (guint32 netmask)
+{
+	guint32 prefix;
+	guint8 v;
+	const guint8 *p = (guint8 *) &netmask;
+
+	if (p[3]) {
+		prefix = 24;
+		v = p[3];
+	} else if (p[2]) {
+		prefix = 16;
+		v = p[2];
+	} else if (p[1]) {
+		prefix = 8;
+		v = p[1];
+	} else {
+		prefix = 0;
+		v = p[0];
+	}
+
+	while (v) {
+		prefix++;
+		v <<= 1;
+	}
+
+	g_assert_cmpint (prefix, <=, 32);
+
+	/* we re-implemented the netmask-to-prefix code differently. Check
+	 * that they agree. */
+	g_assert_cmpint (prefix, ==, nm_utils_ip4_netmask_to_prefix (netmask));
+
+	return prefix;
+}
+
 static void
 test_ip4_prefix_to_netmask (void)
 {
@@ -3480,7 +3682,7 @@ test_ip4_prefix_to_netmask (void)
 
 	for (i = 0; i<=32; i++) {
 		guint32 netmask = _nm_utils_ip4_prefix_to_netmask (i);
-		int plen = nm_utils_ip4_netmask_to_prefix (netmask);
+		int plen = _netmask_to_prefix (netmask);
 
 		g_assert_cmpint (i, ==, plen);
 		{
@@ -3510,7 +3712,7 @@ test_ip4_netmask_to_prefix (void)
 		guint32 netmask = _nm_utils_ip4_prefix_to_netmask (i);
 		guint32 netmask_lowest_bit = netmask & ~_nm_utils_ip4_prefix_to_netmask (i-1);
 
-		g_assert_cmpint (i, ==, nm_utils_ip4_netmask_to_prefix (netmask));
+		g_assert_cmpint (i, ==, _netmask_to_prefix (netmask));
 
 		for (j = 0; j < 2*i; j++) {
 			guint32 r = g_rand_int (rand);
@@ -3524,7 +3726,7 @@ test_ip4_netmask_to_prefix (void)
 
 			/* create an invalid netmask with holes and check that the function
 			 * returns the longest prefix. */
-			prefix_holey = nm_utils_ip4_netmask_to_prefix (netmask_holey);
+			prefix_holey = _netmask_to_prefix (netmask_holey);
 
 			g_assert_cmpint (i, ==, prefix_holey);
 		}
@@ -5054,7 +5256,7 @@ test_setting_ip4_gateway (void)
 	GVariantBuilder addrs_builder;
 	GError *error = NULL;
 
-	g_assert_cmpstr (nm_utils_inet4_ntop (addr_vals_0[0], NULL), ==, "192.168.1.10");
+	nmtst_assert_ip4_address (addr_vals_0[0], "192.168.1.10");
 
 	/* When serializing on the daemon side, ipv4.gateway is copied to the first
 	 * entry of ipv4.addresses
@@ -5096,7 +5298,7 @@ test_setting_ip4_gateway (void)
 
 		addr_array = g_variant_get_fixed_array (addr_var, &length, sizeof (guint32));
 		g_assert_cmpint (length, ==, 3);
-		g_assert_cmpstr (nm_utils_inet4_ntop (addr_array[2], NULL), ==, "192.168.1.1");
+		nmtst_assert_ip4_address (addr_array[2], "192.168.1.1");
 		g_variant_unref (addr_var);
 	}
 	g_variant_unref (value);
@@ -5203,7 +5405,7 @@ test_setting_ip6_gateway (void)
 
 		gateway_bytes = g_variant_get_fixed_array (gateway_var, &length, 1);
 		g_assert_cmpint (length, ==, 16);
-		g_assert_cmpstr (nm_utils_inet6_ntop ((struct in6_addr *) gateway_bytes, NULL), ==, "abcd::1");
+		nmtst_assert_ip6_address ((struct in6_addr *) gateway_bytes, "abcd::1");
 		g_variant_unref (gateway_var);
 	}
 	g_variant_unref (value);
@@ -5439,8 +5641,21 @@ test_nm_strquote (void)
 
 /*****************************************************************************/
 
-#define UUID_NIL        "00000000-0000-0000-0000-000000000000"
+#define UUID_NS_ZERO    "00000000-0000-0000-0000-000000000000"
 #define UUID_NS_DNS     "6ba7b810-9dad-11d1-80b4-00c04fd430c8"
+#define UUID_NS_URL     "6ba7b811-9dad-11d1-80b4-00c04fd430c8"
+#define UUID_NS_OID     "6ba7b812-9dad-11d1-80b4-00c04fd430c8"
+#define UUID_NS_X500    "6ba7b814-9dad-11d1-80b4-00c04fd430c8"
+
+static const NMUuid *
+_uuid (const char *str)
+{
+	static NMUuid u;
+
+	g_assert (str);
+	g_assert (_nm_utils_uuid_parse (str, &u));
+	return &u;
+}
 
 static void
 _test_uuid (int uuid_type, const char *expected_uuid, const char *str, gssize slen, gpointer type_args)
@@ -5452,9 +5667,17 @@ _test_uuid (int uuid_type, const char *expected_uuid, const char *str, gssize sl
 	g_assert (uuid_test);
 	g_assert (nm_utils_is_uuid (uuid_test));
 
-	if (strcmp (uuid_test, expected_uuid)) {
-		g_error ("UUID test failed: type=%d; text=%s, len=%lld, uuid=%s, expected=%s", uuid_type,
-		         str, (long long) slen, uuid_test, expected_uuid);
+	if (!nm_streq (uuid_test, expected_uuid)) {
+		g_error ("UUID test failed: type=%d; text=%s, len=%lld, ns=%s, uuid=%s, expected=%s",
+		         uuid_type,
+		         str,
+		         (long long) slen,
+		         NM_IN_SET (uuid_type, NM_UTILS_UUID_TYPE_VERSION3,
+		                               NM_UTILS_UUID_TYPE_VERSION5)
+		           ? (((const char *) type_args) ?: "(all-zero)")
+		           : (type_args ? "(unknown)" : "(null)"),
+		         uuid_test,
+		         expected_uuid);
 	}
 
 	if (slen < 0) {
@@ -5465,30 +5688,174 @@ _test_uuid (int uuid_type, const char *expected_uuid, const char *str, gssize sl
 		_test_uuid (uuid_type, expected_uuid, NULL, 0, type_args);
 	}
 
-	if (uuid_type == NM_UTILS_UUID_TYPE_VARIANT3 && !type_args) {
-		/* For NM_UTILS_UUID_TYPE_VARIANT3, a missing @type_args is equal to UUID_NIL */
-		_test_uuid (uuid_type, expected_uuid, str, slen, UUID_NIL);
+	if (   NM_IN_SET (uuid_type, NM_UTILS_UUID_TYPE_VERSION3,
+	                             NM_UTILS_UUID_TYPE_VERSION5)
+	    && !type_args) {
+		/* For version3 and version5, a missing @type_args is equal to UUID_NS_ZERO */
+		_test_uuid (uuid_type, expected_uuid, str, slen, UUID_NS_ZERO);
 	}
 }
 
+typedef struct {
+	const char *uuid3;
+	const char *uuid5;
+} ExpectedUuids;
+
 static void
 test_nm_utils_uuid_generate_from_string (void)
 {
+	const ExpectedUuids zero_uuids[] = {
+	    { .uuid3 = "19826852-5007-3022-a72a-212f66e9fac3", .uuid5 = "b6c54489-38a0-5f50-a60a-fd8d76219cae", },
+	    { .uuid3 = "9153af2e-fc8e-34f3-9e8b-81f73b33d0cb", .uuid5 = "11116e73-1c03-5de6-9130-5f9925ae8ab4", },
+	    { .uuid3 = "2f06a3ae-d78d-30d7-b898-088a0e0b76f6", .uuid5 = "1087ebe8-1ef8-5d97-8873-735b4949004d", },
+	    { .uuid3 = "aca948e0-1468-3a51-9f2e-c688a484efd7", .uuid5 = "7e57d004-2b97-5e7a-b45f-5387367791cd", },
+	    { .uuid3 = "b74e537a-53e8-3808-9abd-58546a6542bd", .uuid5 = "1dd80df1-492c-5dc5-aec2-6bf0e104f923", },
+	    { .uuid3 = "1b00958a-7d76-3d08-8aba-c66c5828658c", .uuid5 = "f797f61e-a392-5acf-af25-b46057f1c8e8", },
+	    { .uuid3 = "7ba18f7d-c9cf-3b48-a89e-ad79243135cc", .uuid5 = "e02c9780-2fc5-5d57-b92f-4cc3a64bff16", },
+	    { .uuid3 = "9baf0978-1a60-35c5-9e9b-bec8d259fd4e", .uuid5 = "94167980-f909-527e-a4af-bc3155f586d3", },
+	    { .uuid3 = "588668c0-7631-39c7-9976-c7d414adf7ba", .uuid5 = "9e3eefda-b56e-56bd-8a3a-0b8009d4a536", },
+	    { .uuid3 = "8edb3613-9612-3b32-9dd7-0a01aa8ed453", .uuid5 = "9b75648e-d38c-54e8-adee-1fb295a079c9", },
+	    { .uuid3 = "f3b34394-63a5-3773-9014-1f8a50d765b8", .uuid5 = "dd56b598-9e74-58c3-b3e8-2c623780b8ed", },
+	    { .uuid3 = "0572965f-05b8-342b-b225-d5c29d449eee", .uuid5 = "5666449a-fb7e-55b7-ae9f-0552e6513a10", },
+	    { .uuid3 = "6f7177c3-77b0-3f42-82a8-7031e25fcccf", .uuid5 = "10b38db9-82fc-528e-9ddb-1f09b7dbf907", },
+	    { .uuid3 = "d1e0f845-bc1b-368c-b8c8-49ab0b9e486b", .uuid5 = "85492596-9468-5845-9c7f-d4ae999cb751", },
+	    { .uuid3 = "46371ea3-c8a3-34d8-b2cf-2fa90bda4378", .uuid5 = "22b1c0dd-aa5d-54a4-8768-5adfd0d112bd", },
+	    { .uuid3 = "f1e6b499-9b68-343b-a5c5-ece7acc49a68", .uuid5 = "9cc429f8-200e-52a3-9e3b-ef134afa1e29", },
+	    { .uuid3 = "9ed06458-c712-31dd-aba5-6cf79879fabe", .uuid5 = "3949f95c-5d76-5ee2-af60-8e2d8fcf649d", },
+	    { .uuid3 = "4ddd5cd7-bc83-36aa-909c-4e660f57c830", .uuid5 = "0e994a02-069b-58fb-b3a4-d7dc94e90fca", },
+	    { .uuid3 = "335fa537-0909-395d-a696-6f41827dcbeb", .uuid5 = "17db3a41-de9b-5c6b-904d-833943209b3c", },
+	    { .uuid3 = "dbd58444-05ad-3edd-adc7-4393ecbcb43c", .uuid5 = "1bd906f2-05f9-5ab5-a39a-4c17a188f886", },
+	    { .uuid3 = "a1c62d82-d13c-361b-8f4e-ca91bc2f7fc5", .uuid5 = "ce6550fd-95b7-57e4-9aa7-461522666be4", },
+	    { .uuid3 = "e943d83e-3f82-307f-81ed-b7a7bcd0743e", .uuid5 = "04aa09ee-b420-57ac-8a23-5d99907fb0a1", },
+	    { .uuid3 = "cabf46dd-9f09-375c-8f6e-f2a8cf114709", .uuid5 = "8ece2c62-0c31-5c55-b7c6-155381e3780e", },
+	    { .uuid3 = "19beddf3-f2fb-340f-96ac-4f394960b7a7", .uuid5 = "5762a9f9-9a21-59ab-b0d2-2cb90027ef7f", },
+	    { .uuid3 = "08d835c2-f4ca-394c-ba7f-2494d8b60c6c", .uuid5 = "23c8409d-4b5f-5b6a-b946-41e49bad6c78", },
+	    { .uuid3 = "3b8c6847-5331-35bf-9cd9-ced50e53cd7c", .uuid5 = "e8e396be-95d5-5569-8edc-e0b64c2b7613", },
+	    { .uuid3 = "e601f160-484b-3254-8f3b-0a25c7203d8a", .uuid5 = "bc8b3cbc-ad5b-5808-a1b0-e0f7a1ad68a3", },
+	    { .uuid3 = "e5e492ed-5349-379d-b7de-a370a51e44a3", .uuid5 = "62c5ed3f-9afa-59ad-874f-a9dd8afc69d4", },
+	    { .uuid3 = "c40111f6-fe97-305e-bfce-7db730c3d2ec", .uuid5 = "66877a72-7243-59ed-b9e3-b5023b6da9c2", },
+	    { .uuid3 = "21e18ea8-95c2-362b-9ca9-25d6a0ff2dff", .uuid5 = "49a49eee-7e86-5d66-837a-8a8810cb5562", },
+	    { .uuid3 = "adab623b-1343-307f-80d8-58d005376ad9", .uuid5 = "e4a2a7ed-3bf3-53cf-a2bb-154dbb39a38c", },
+	    { .uuid3 = "67e9fc7c-dafe-356d-ac1a-a63ce3f44813", .uuid5 = "50cacfc9-f5d2-52dd-897c-a25a0927b816", },
+	    { .uuid3 = "36cc7f20-126c-3e40-94e7-737ac7486547", .uuid5 = "ca629991-3f2b-5e86-9bb7-37a335f7d809", },
+	    { .uuid3 = "fe282996-ac5e-3d13-b478-5def30007a8e", .uuid5 = "c1adf8a7-f72a-58ae-82d5-d18807f12e2e", },
+	    { .uuid3 = "3bfe339c-05ae-3233-a1a5-ebf1ead589db", .uuid5 = "6120c3cd-24e1-5ce4-987b-f8bfee2e4633", },
+	    { .uuid3 = "d1d90bc7-da4a-3cd7-a7c8-a1a89765d8ee", .uuid5 = "433d6a26-c319-5fcf-9a30-5ec6ad59d109", },
+	    { .uuid3 = "10b88a02-0102-359b-81e9-7e3b0ff7d25e", .uuid5 = "77d228d9-1b96-59e2-a07e-a8fdd4f62884", },
+	    { .uuid3 = "7da5e4f2-6df0-3aca-a1b0-b7f8b1340e1d", .uuid5 = "698259bf-a32b-5e00-9ec6-88b12278c4ad", },
+	    { .uuid3 = "cbe24d98-ca20-3058-86b6-24a6b36ceff0", .uuid5 = "60dbca63-704f-5666-9f64-f4e1a630c4aa", },
+	    { .uuid3 = "04d84e6a-b793-3993-afbf-bae7cfc42b49", .uuid5 = "79d63ec0-a39d-557d-8299-f4c97acfadc3", },
+	    { .uuid3 = "fdd157d8-a537-350a-9cc9-1930e8666c63", .uuid5 = "7df7f75e-a146-5a76-828b-bac052db312b", },
+	    { .uuid3 = "0bea36bb-24a7-3ee6-a98d-116433c14cd4", .uuid5 = "2bcca2e9-2879-53e3-b09d-cbbfd58771b2", },
+	    { .uuid3 = "52b040a4-1b84-32d2-b758-f82386f7e0f0", .uuid5 = "cb7bdca3-e9f7-50cd-b72e-73cb9ff24f62", },
+	    { .uuid3 = "0f0a4e26-e034-3021-acf2-4e886af43092", .uuid5 = "8e428e2b-5da3-5368-b760-5ca07ccbd819", },
+	    { .uuid3 = "819d3cd1-afe5-3e4a-9f0c-945e25d09879", .uuid5 = "f340ef4d-139c-567a-b0fc-7c495336674e", },
+	    { .uuid3 = "e7df1a3b-c9f8-3e5a-88d6-ba72b2a0f27b", .uuid5 = "7e3f5fd2-3c93-58d6-9f35-6e0192445b11", },
+	    { .uuid3 = "0854bedf-74ba-3f2b-b823-dc2c90d27c76", .uuid5 = "bc112b6b-c5de-5ee9-b816-808792743a20", },
+	    { .uuid3 = "a1b8c3ba-f821-32ef-a3fd-b97b3855efa8", .uuid5 = "47f8f82d-9fcd-553c-90c5-3f3cb3ad00ad", },
+	    { .uuid3 = "9458f819-079b-3033-9430-ba10f576c067", .uuid5 = "bee5c091-5f01-51fa-86bb-e9488fd3b4da", },
+	    { .uuid3 = "8e1f240a-e386-3e00-866a-6f9da1e3503f", .uuid5 = "8ea92cea-d741-566f-a44a-d51e65b4c5e4", },
+	};
+	const ExpectedUuids dns_uuids[] = {
+	    { .uuid3 = "4385125b-dd1e-3025-880f-3311517cc8d5", .uuid5 = "6af613b6-569c-5c22-9c37-2ed93f31d3af", },
+	    { .uuid3 = "afd0b036-625a-3aa8-b639-9dc8c8fff0ff", .uuid5 = "b04965e6-a9bb-591f-8f8a-1adcb2c8dc39", },
+	    { .uuid3 = "9c45c2f1-1761-3daa-ad31-1ff8703ae846", .uuid5 = "4b166dbe-d99d-5091-abdd-95b83330ed3a", },
+	    { .uuid3 = "15e0ba07-10e4-3d7f-aaff-c00fed873c88", .uuid5 = "98123fde-012f-5ff3-8b50-881449dac91a", },
+	    { .uuid3 = "bc27b4db-bc0f-34f9-ae8e-4b72f2d51b60", .uuid5 = "6ed955c6-506a-5343-9be4-2c0afae02eef", },
+	    { .uuid3 = "7586bfed-b8b8-3bb3-9c95-09a4a79dc0f7", .uuid5 = "c8691da2-158a-5ed6-8537-0e6f140801f2", },
+	    { .uuid3 = "881430b6-8d28-3175-b87d-e81f2f5978c6", .uuid5 = "a6c4fc8f-6950-51de-a9ae-2c519c465071", },
+	    { .uuid3 = "24075675-98ae-354e-89ca-0126a9ad36e3", .uuid5 = "a9f96b98-dd44-5216-ab0d-dbfc6b262edf", },
+	    { .uuid3 = "2c269ea4-dbfd-32dd-9bd7-a5c22677d18b", .uuid5 = "e99caacd-6c45-5906-bd9f-b79e62f25963", },
+	    { .uuid3 = "44eb0948-118f-3f28-87e4-f61c8f889aba", .uuid5 = "e4d80b30-151e-51b5-9f4f-18a3b82718e6", },
+	    { .uuid3 = "fc72beeb-f790-36ee-a73d-33888c9d8880", .uuid5 = "0159d6c7-973f-5e7a-a9a0-d195d0ea6fe2", },
+	    { .uuid3 = "1e46afa2-6176-3cd3-9750-3015846723df", .uuid5 = "7fef88f7-411d-5669-b42d-bf5fc7f9b58b", },
+	    { .uuid3 = "0042b01d-95bd-343f-bd9f-3186bfd63508", .uuid5 = "52524d6e-10dc-5261-aa36-8b2efcbaa5f0", },
+	    { .uuid3 = "115ff52f-d605-3b4b-98fe-c0ea57f4930c", .uuid5 = "91c274f2-9a0d-5ce6-ac3d-7529f452df21", },
+	    { .uuid3 = "ed0221e8-ac7d-393b-821d-25183567885b", .uuid5 = "0ff1e264-520d-543a-87dd-181a491e667e", },
+	    { .uuid3 = "508ef333-85a6-314c-bcf3-17ddc32b2216", .uuid5 = "23986425-d3a5-5e13-8bab-299745777a8d", },
+	    { .uuid3 = "a4715ee0-524a-37cc-beb2-a0b5030757b7", .uuid5 = "c15b38c9-9a3e-543c-a703-dd742f25b4d5", },
+	    { .uuid3 = "d1c72756-aaec-3470-a2f2-97415f44d72f", .uuid5 = "db680066-c83d-5ed7-89a4-1d79466ea62d", },
+	    { .uuid3 = "7aec2f01-586e-3d53-b8f3-6cf7e6b649a4", .uuid5 = "cadb7952-2bba-5609-88d4-8e47ec4e7920", },
+	    { .uuid3 = "3d234b88-8d6f-319a-91ea-edb6059fc825", .uuid5 = "35140057-a2a4-5adb-a500-46f8ed8b66a9", },
+	    { .uuid3 = "d2568554-93ec-30c7-9e15-f383be19e5bb", .uuid5 = "66e549b7-01e2-5d07-98d5-430f74d8d3b2", },
+	    { .uuid3 = "800e59a7-dd0f-3114-8e58-ab7e213895ca", .uuid5 = "292c8e99-2378-55aa-83d8-350e0ac3f1cc", },
+	    { .uuid3 = "3b7d03f0-e067-3d72-84f4-e410ac36ef57", .uuid5 = "0e3b230a-0509-55d8-96a0-9875f387a2be", },
+	    { .uuid3 = "8762be68-de95-391a-94a0-c5fd0446e037", .uuid5 = "4c507660-a83b-55c0-9b2b-83eccb07723d", },
+	    { .uuid3 = "2bd8b4c9-01af-3cd0-aced-94ee6e2004b8", .uuid5 = "a1b9b633-da11-58be-b1a9-5cfa2848f186", },
+	    { .uuid3 = "a627d6a4-394a-33f5-b68e-22bfb6488d01", .uuid5 = "c2708a8b-120a-56f5-a30d-990048af87cc", },
+	    { .uuid3 = "6a592510-17d9-3925-b321-4a8d4927f8d0", .uuid5 = "e7263999-68b6-5a23-b530-af25b7efd632", },
+	    { .uuid3 = "9ee72491-59c4-333c-bb93-fe733a842fdb", .uuid5 = "ce1ae2d5-3454-5952-97ff-36ff935bcfe9", },
+	    { .uuid3 = "2591c62c-0a9d-3c28-97bc-fa0401556a3c", .uuid5 = "33677b87-bc8d-5ff6-9a25-fe60225e4bf0", },
+	    { .uuid3 = "7912be1e-4562-373b-92e2-3d6d2123bc8e", .uuid5 = "ed2305ae-e8f9-5387-b860-3d80ae6c02f7", },
+	    { .uuid3 = "09370cda-89a4-3a48-b592-9c0486e0d5e4", .uuid5 = "604ed872-ae2d-5d91-8e3e-572f3a3aaaa5", },
+	    { .uuid3 = "de5980d3-a137-373c-850b-ca3e5f100779", .uuid5 = "8f8173d9-2f8d-5636-a693-24d9f79ba651", },
+	    { .uuid3 = "9441501d-f633-365a-8955-9df443edc762", .uuid5 = "36eb8d4d-b854-51f1-9fdf-3735964225d5", },
+	    { .uuid3 = "434ada18-13ce-3c08-8b40-a1a1ae030569", .uuid5 = "3493b6ca-f84b-56a9-97cc-c0bd1c46c4c0", },
+	    { .uuid3 = "a13b6160-bd23-3710-a150-41d800dd30b4", .uuid5 = "f413ea13-fcd9-5b44-9d22-1fa1f7b063a5", },
+	    { .uuid3 = "73a67c12-c5f0-3288-ad6a-c78aea0917b0", .uuid5 = "f468d924-d23b-56c2-b90f-3d1cf4b45337", },
+	    { .uuid3 = "a126ee4f-a222-357d-b71b-7d3f226c559f", .uuid5 = "8828c9d6-ed76-5c09-bf64-ba9e9cd90896", },
+	    { .uuid3 = "48f4f36b-b015-3137-9b6e-351bb175c7f7", .uuid5 = "facb7618-55ca-5c30-9cba-fd567b6c0611", },
+	    { .uuid3 = "3fe8f6a3-fe4a-3487-89d6-dd06c6ad02e3", .uuid5 = "96f3de0e-6412-5434-b406-67ef3352ab85", },
+	    { .uuid3 = "d68fa2d4-adc9-3b20-ac77-42585cd1d59f", .uuid5 = "9ebacb89-40ab-52b3-93a2-9054611d8f55", },
+	    { .uuid3 = "819f86a3-31d5-3e72-a83e-142c3a3e4832", .uuid5 = "681046ff-9129-5ade-b11c-769864e02184", },
+	    { .uuid3 = "9957b433-ddc8-3113-a3e6-5512cf13dab1", .uuid5 = "c13d0b5d-1ca3-57b6-a23f-8586bca44928", },
+	    { .uuid3 = "5aab6e0c-b7d3-379c-92e3-2bfbb5572511", .uuid5 = "7c411b5e-9d3f-50b5-9c28-62096e41c4ed", },
+	    { .uuid3 = "11c8ff30-3a7d-3547-80a7-d61b8abeeda8", .uuid5 = "f825aafe-6696-5121-b263-6b2c408b7f43", },
+	    { .uuid3 = "98799b9f-1c5e-30b3-930f-e412b862cbe4", .uuid5 = "f2b4caea-61c3-5bed-8ce7-d8b9d16e129e", },
+	    { .uuid3 = "9bdf2544-31d8-3555-94b0-6a749118a996", .uuid5 = "3593855a-6557-5736-8cab-172c6987f949", },
+	    { .uuid3 = "ddcfb9b3-e990-3985-9021-546a2711e7e5", .uuid5 = "36392431-d554-5385-b876-7bc6e1cb26b3", },
+	    { .uuid3 = "190d7a78-1484-3136-80a6-40f28852785c", .uuid5 = "7e645493-0898-5501-8155-e8578b4f5224", },
+	    { .uuid3 = "6ed693e4-7dc0-3210-856b-a6eb4cc73e13", .uuid5 = "14dc6a81-0491-5683-baaf-7582a61c5798", },
+	    { .uuid3 = "b6a14b21-e73a-3ce2-9076-a804c434f5c6", .uuid5 = "883e0a9c-e3b3-5f9c-8073-2913cbbb99ec", },
+	};
+	char i_str[30];
+	guint i;
+
 	_test_uuid (NM_UTILS_UUID_TYPE_LEGACY, "d41d8cd9-8f00-b204-e980-0998ecf8427e", "", -1, NULL);
 	_test_uuid (NM_UTILS_UUID_TYPE_LEGACY, "0cc175b9-c0f1-b6a8-31c3-99e269772661", "a", -1, NULL);
 	_test_uuid (NM_UTILS_UUID_TYPE_LEGACY, "098f6bcd-4621-d373-cade-4e832627b4f6", "test", -1, NULL);
 	_test_uuid (NM_UTILS_UUID_TYPE_LEGACY, "70350f60-27bc-e371-3f6b-76473084309b", "a\0b", 3, NULL);
 	_test_uuid (NM_UTILS_UUID_TYPE_LEGACY, "59c0547b-7fe2-1c15-2cce-e328e8bf6742", "/etc/NetworkManager/system-connections/em1", -1, NULL);
 
-	_test_uuid (NM_UTILS_UUID_TYPE_VARIANT3, "4ae71336-e44b-39bf-b9d2-752e234818a5", "", -1, NULL);
-	_test_uuid (NM_UTILS_UUID_TYPE_VARIANT3, "0531103a-d8fc-3dd4-b972-d98e4750994e", "a", -1, NULL);
-	_test_uuid (NM_UTILS_UUID_TYPE_VARIANT3, "96e17d7a-ac89-38cf-95e1-bf5098da34e1", "test", -1, NULL);
-	_test_uuid (NM_UTILS_UUID_TYPE_VARIANT3, "8156568e-4ae6-3f34-a93e-18e2c6cbbf78", "a\0b", 3, NULL);
+	_test_uuid (NM_UTILS_UUID_TYPE_VERSION3, "4ae71336-e44b-39bf-b9d2-752e234818a5", "", -1, NULL);
+	_test_uuid (NM_UTILS_UUID_TYPE_VERSION3, "0531103a-d8fc-3dd4-b972-d98e4750994e", "a", -1, NULL);
+	_test_uuid (NM_UTILS_UUID_TYPE_VERSION3, "96e17d7a-ac89-38cf-95e1-bf5098da34e1", "test", -1, NULL);
+	_test_uuid (NM_UTILS_UUID_TYPE_VERSION3, "8156568e-4ae6-3f34-a93e-18e2c6cbbf78", "a\0b", 3, NULL);
+
+	_test_uuid (NM_UTILS_UUID_TYPE_VERSION3, "c87ee674-4ddc-3efe-a74e-dfe25da5d7b3", "", -1, UUID_NS_DNS);
+	_test_uuid (NM_UTILS_UUID_TYPE_VERSION3, "4c104dd0-4821-30d5-9ce3-0e7a1f8b7c0d", "a", -1, UUID_NS_DNS);
+	_test_uuid (NM_UTILS_UUID_TYPE_VERSION3, "45a113ac-c7f2-30b0-90a5-a399ab912716", "test", -1, UUID_NS_DNS);
+	_test_uuid (NM_UTILS_UUID_TYPE_VERSION3, "002a0ada-f547-375a-bab5-896a11d1927e", "a\0b", 3, UUID_NS_DNS);
+	_test_uuid (NM_UTILS_UUID_TYPE_VERSION3, "9a75f5f2-195e-31a9-9d07-8c18b5d3b285", "test123", -1, UUID_NS_DNS);
+	_test_uuid (NM_UTILS_UUID_TYPE_VERSION3, "ec794efe-a384-3b11-a0b6-ec8995bc6acc", "x", -1, UUID_NS_DNS);
+
+	_test_uuid (NM_UTILS_UUID_TYPE_VERSION5, "a7650b9f-f19f-5300-8a13-91160ea8de2c", "a\0b", 3, NULL);
+	_test_uuid (NM_UTILS_UUID_TYPE_VERSION5, "4f3f2898-69e3-5a0d-820a-c4e87987dbce", "a", -1, UUID_NS_DNS);
+	_test_uuid (NM_UTILS_UUID_TYPE_VERSION5, "05b16a01-46c6-56dd-bd6e-c6dfb4a1427a", "x", -1, UUID_NS_DNS);
+	_test_uuid (NM_UTILS_UUID_TYPE_VERSION5, "c9ed566a-6b79-5d3a-b2b7-96a936b48cf3", "test123", -1, UUID_NS_DNS);
+
+	for (i = 0; i < G_N_ELEMENTS (zero_uuids); i++) {
+		nm_sprintf_buf (i_str, "%u", i),
+		_test_uuid (NM_UTILS_UUID_TYPE_VERSION3, zero_uuids[i].uuid3, i_str, -1, NULL);
+		_test_uuid (NM_UTILS_UUID_TYPE_VERSION5, zero_uuids[i].uuid5, i_str, -1, NULL);
+	}
+	for (i = 0; i < G_N_ELEMENTS (dns_uuids); i++) {
+		nm_sprintf_buf (i_str, "%u", i),
+		_test_uuid (NM_UTILS_UUID_TYPE_VERSION3, dns_uuids[i].uuid3, i_str, -1, UUID_NS_DNS);
+		_test_uuid (NM_UTILS_UUID_TYPE_VERSION5, dns_uuids[i].uuid5, i_str, -1, UUID_NS_DNS);
+	}
+
+	/* examples from cpython unit tests: */
+	_test_uuid (NM_UTILS_UUID_TYPE_VERSION3, "6fa459ea-ee8a-3ca4-894e-db77e160355e", "python.org", -1, UUID_NS_DNS);
+	_test_uuid (NM_UTILS_UUID_TYPE_VERSION5, "886313e1-3b8a-5372-9b90-0c9aee199e5d", "python.org", -1, UUID_NS_DNS);
+	_test_uuid (NM_UTILS_UUID_TYPE_VERSION3, "9fe8e8c4-aaa8-32a9-a55c-4535a88b748d", "http://python.org/", -1, UUID_NS_URL);
+	_test_uuid (NM_UTILS_UUID_TYPE_VERSION5, "4c565f0d-3f5a-5890-b41b-20cf47701c5e", "http://python.org/", -1, UUID_NS_URL);
+	_test_uuid (NM_UTILS_UUID_TYPE_VERSION3, "dd1a1cef-13d5-368a-ad82-eca71acd4cd1", "1.3.6.1", -1, UUID_NS_OID);
+	_test_uuid (NM_UTILS_UUID_TYPE_VERSION5, "1447fa61-5277-5fef-a9b3-fbc6e44f4af3", "1.3.6.1", -1, UUID_NS_OID);
+	_test_uuid (NM_UTILS_UUID_TYPE_VERSION3, "658d3002-db6b-3040-a1d1-8ddd7d189a4d", "c=ca", -1, UUID_NS_X500);
+	_test_uuid (NM_UTILS_UUID_TYPE_VERSION5, "cc957dd1-a972-5349-98cd-874190002798", "c=ca", -1, UUID_NS_X500);
 
-	_test_uuid (NM_UTILS_UUID_TYPE_VARIANT3, "c87ee674-4ddc-3efe-a74e-dfe25da5d7b3", "", -1, UUID_NS_DNS);
-	_test_uuid (NM_UTILS_UUID_TYPE_VARIANT3, "4c104dd0-4821-30d5-9ce3-0e7a1f8b7c0d", "a", -1, UUID_NS_DNS);
-	_test_uuid (NM_UTILS_UUID_TYPE_VARIANT3, "45a113ac-c7f2-30b0-90a5-a399ab912716", "test", -1, UUID_NS_DNS);
-	_test_uuid (NM_UTILS_UUID_TYPE_VARIANT3, "002a0ada-f547-375a-bab5-896a11d1927e", "a\0b", 3, UUID_NS_DNS);
+	_test_uuid (NM_UTILS_UUID_TYPE_VERSION5, "74738ff5-5367-5958-9aee-98fffdcd1876", "www.example.org", -1, UUID_NS_DNS);
 }
 
 /*****************************************************************************/
@@ -5505,7 +5872,7 @@ __test_uuid (const char *expected_uuid, const char *str, gssize slen, char *uuid
 	}
 	g_free (uuid_test);
 
-	uuid_test = nm_utils_uuid_generate_from_string (str, slen, NM_UTILS_UUID_TYPE_VARIANT3, NM_UTILS_UUID_NS);
+	uuid_test = nm_utils_uuid_generate_from_string (str, slen, NM_UTILS_UUID_TYPE_VERSION3, NM_UTILS_UUID_NS);
 
 	g_assert (uuid_test);
 	g_assert (nm_utils_is_uuid (uuid_test));
@@ -5522,6 +5889,15 @@ __test_uuid (const char *expected_uuid, const char *str, gssize slen, char *uuid
 static void
 test_nm_utils_uuid_generate_from_strings (void)
 {
+	const NMUuid uuid0 = { 0 };
+
+	g_assert_cmpmem (&uuid0, sizeof (uuid0), _uuid ("00000000-0000-0000-0000-000000000000"), 16);
+
+	g_assert (nm_utils_uuid_is_null (NULL));
+	g_assert (nm_utils_uuid_is_null (&uuid0));
+	g_assert ( nm_utils_uuid_is_null (_uuid ("00000000-0000-0000-0000-000000000000")));
+	g_assert (!nm_utils_uuid_is_null (_uuid ("10000000-0000-0000-0000-000000000000")));
+
 	_test_uuid ("b07c334a-399b-32de-8d50-58e4e08f98e3", "",         0, NULL);
 	_test_uuid ("b8a426cb-bcb5-30a3-bd8f-6786fea72df9", "\0",       1, "");
 	_test_uuid ("12a4a982-7aae-39e1-951e-41aeb1250959", "a\0",      2, "a");
@@ -7390,4 +7766,3 @@ int main (int argc, char **argv)
 
 	return g_test_run ();
 }
-
diff --git a/libnm-core/tests/test-keyfile.c b/libnm-core/tests/test-keyfile.c
index 78e01ce9..9b9d1c04 100644
--- a/libnm-core/tests/test-keyfile.c
+++ b/libnm-core/tests/test-keyfile.c
@@ -249,7 +249,7 @@ _keyfile_convert (NMConnection **con,
 		k0_c1_k2 = _nm_keyfile_write (k0_c1, write_handler, write_data);
 		k0_c1_k2_c3 = _nm_keyfile_read (k0_c1_k2, keyfile_name, read_handler, read_data, FALSE);
 
-		/* It is a expeced behavior, that if @k0 contains a relative path ca-cert, @k0_c1 will
+		/* It is a expected behavior, that if @k0 contains a relative path ca-cert, @k0_c1 will
 		 * contain that path as relative. But @k0_c1_k2 and @k0_c1_k2_c3 will have absolute paths.
 		 * In this case, hack up @k0_c1_k2_c3 to contain the same relative path. */
 		s1 = nm_connection_get_setting_802_1x (k0_c1);
@@ -417,7 +417,7 @@ test_8021x_cert (void)
 	g_assert_no_error (error);
 	g_assert (success);
 
-	/* test reseting ca-cert to different values and see whether we can write/read. */
+	/* test resetting ca-cert to different values and see whether we can write/read. */
 
 	nm_connection_add_setting (con, NM_SETTING (s_8021x));
 	nmtst_assert_connection_verifies_and_normalizable (con);
diff --git a/libnm-core/tests/test-setting.c b/libnm-core/tests/test-setting.c
index 4e010feb..d8784d31 100644
--- a/libnm-core/tests/test-setting.c
+++ b/libnm-core/tests/test-setting.c
@@ -45,6 +45,77 @@
 
 /*****************************************************************************/
 
+/* converts @dict to a connection. In this case, @dict must be good, without warnings, so that
+ * NM_SETTING_PARSE_FLAGS_STRICT and NM_SETTING_PARSE_FLAGS_BEST_EFFORT yield the exact same results. */
+static NMConnection *
+_connection_new_from_dbus_strict (GVariant *dict,
+                                  gboolean normalize)
+{
+	gs_unref_object NMConnection *con_x_0 = NULL;
+	gs_unref_object NMConnection *con_x_s = NULL;
+	gs_unref_object NMConnection *con_x_e = NULL;
+	gs_unref_object NMConnection *con_n_0 = NULL;
+	gs_unref_object NMConnection *con_n_s = NULL;
+	gs_unref_object NMConnection *con_n_e = NULL;
+	gs_free_error GError *error = NULL;
+	guint i;
+
+	g_assert (g_variant_is_of_type (dict, NM_VARIANT_TYPE_CONNECTION));
+
+	con_x_0 = _nm_simple_connection_new_from_dbus (dict, NM_SETTING_PARSE_FLAGS_NONE, &error);
+	nmtst_assert_success (NM_IS_CONNECTION (con_x_0), error);
+
+	con_x_s = _nm_simple_connection_new_from_dbus (dict, NM_SETTING_PARSE_FLAGS_STRICT, &error);
+	nmtst_assert_success (NM_IS_CONNECTION (con_x_s), error);
+
+	con_x_e = _nm_simple_connection_new_from_dbus (dict, NM_SETTING_PARSE_FLAGS_BEST_EFFORT, &error);
+	nmtst_assert_success (NM_IS_CONNECTION (con_x_e), error);
+
+	con_n_0 = _nm_simple_connection_new_from_dbus (dict, NM_SETTING_PARSE_FLAGS_NORMALIZE, &error);
+	nmtst_assert_success (NM_IS_CONNECTION (con_n_0), error);
+
+	con_n_s = _nm_simple_connection_new_from_dbus (dict, NM_SETTING_PARSE_FLAGS_STRICT | NM_SETTING_PARSE_FLAGS_NORMALIZE, &error);
+	nmtst_assert_success (NM_IS_CONNECTION (con_n_s), error);
+
+	con_n_e = _nm_simple_connection_new_from_dbus (dict, NM_SETTING_PARSE_FLAGS_BEST_EFFORT | NM_SETTING_PARSE_FLAGS_NORMALIZE, &error);
+	nmtst_assert_success (NM_IS_CONNECTION (con_n_e), error);
+
+	nmtst_assert_connection_verifies (con_x_0);
+	nmtst_assert_connection_verifies (con_x_e);
+	nmtst_assert_connection_verifies (con_x_s);
+
+	nmtst_assert_connection_verifies_without_normalization (con_n_0);
+	nmtst_assert_connection_verifies_without_normalization (con_n_e);
+	nmtst_assert_connection_verifies_without_normalization (con_n_s);
+
+	/* randomly compare some pairs that we created. They must all be equal,
+	 * after accounting for normalization. */
+	for (i = 0; i < 10; i++) {
+		NMConnection *cons[] = { con_x_0, con_x_s, con_x_e, con_n_0, con_n_s, con_n_e };
+		guint idx_a = (nmtst_get_rand_int () % G_N_ELEMENTS (cons));
+		guint idx_b = (nmtst_get_rand_int () % G_N_ELEMENTS (cons));
+		gboolean normalize_a, normalize_b;
+
+		if (idx_a <= 2 && idx_b <= 2) {
+			normalize_a = nmtst_get_rand_bool ();
+			normalize_b = normalize_a;
+		} else if (idx_a > 2 && idx_b > 2) {
+			normalize_a = nmtst_get_rand_bool ();
+			normalize_b = nmtst_get_rand_bool ();
+		} else {
+			normalize_a = (idx_a <= 2) ? TRUE : nmtst_get_rand_bool ();
+			normalize_b = (idx_b <= 2) ? TRUE : nmtst_get_rand_bool ();
+		}
+		nmtst_assert_connection_equals (cons[idx_a], normalize_a, cons[idx_b], normalize_b);
+	}
+
+	return (normalize)
+	       ? g_steal_pointer (&con_x_0)
+	       : g_steal_pointer (&con_n_0);
+}
+
+/*****************************************************************************/
+
 static void
 compare_blob_data (const char *test,
                    const char *key_path,
@@ -421,20 +492,17 @@ create_bond_connection (NMConnection **con, NMSettingBond **s_bond)
 }
 
 #define test_verify_options(exp, ...) \
-	G_STMT_START { \
-		const char *__opts[] = { __VA_ARGS__ , NULL }; \
-		\
-		_test_verify_options (__opts, exp); \
-	} G_STMT_END
+	_test_verify_options (NM_MAKE_STRV (__VA_ARGS__), exp)
 
 static void
-_test_verify_options (const char **options, gboolean expected_result)
+_test_verify_options (const char *const *options,
+                      gboolean expected_result)
 {
 	gs_unref_object NMConnection *con = NULL;
 	NMSettingBond *s_bond;
 	GError *error = NULL;
 	gboolean success;
-	const char **option;
+	const char *const *option;
 
 	create_bond_connection (&con, &s_bond);
 
@@ -1946,6 +2014,184 @@ test_tc_config_dbus (void)
 
 /*****************************************************************************/
 
+static void
+test_roundtrip_conversion (gconstpointer test_data)
+{
+	const int MODE = GPOINTER_TO_INT (test_data);
+	const char *ID= nm_sprintf_bufa (100, "roundtip-conversion-%d", MODE);
+	const char *UUID= "63376701-b61e-4318-bf7e-664a1c1eeaab";
+	const char *INTERFACE_NAME = nm_sprintf_bufa (100, "ifname%d", MODE);
+	guint32 ETH_MTU = nmtst_rand_select ((guint32) 0u,
+	                                     nmtst_get_rand_int ());
+	gs_unref_ptrarray GPtrArray *kf_data_arr = g_ptr_array_new_with_free_func (g_free);
+	const NMConnectionSerializationFlags dbus_serialization_flags[] = {
+		NM_CONNECTION_SERIALIZE_ALL,
+		NM_CONNECTION_SERIALIZE_NO_SECRETS,
+		NM_CONNECTION_SERIALIZE_ONLY_SECRETS,
+	};
+	guint dbus_serialization_flags_idx;
+	gs_unref_object NMConnection *con = NULL;
+	gs_free_error GError *error = NULL;
+	guint kf_data_idx;
+	NMSettingConnection *s_con = NULL;
+	NMSettingWired *s_eth = NULL;
+
+	switch (MODE) {
+	case 0:
+		con = nmtst_create_minimal_connection (ID, UUID, NM_SETTING_WIRED_SETTING_NAME, &s_con);
+		g_object_set (s_con,
+		              NM_SETTING_CONNECTION_INTERFACE_NAME,
+		              INTERFACE_NAME,
+		              NULL);
+		nmtst_connection_normalize (con);
+
+		s_eth = NM_SETTING_WIRED (nm_connection_get_setting (con, NM_TYPE_SETTING_WIRED));
+		g_assert (NM_IS_SETTING_WIRED (s_eth));
+
+		g_object_set (s_eth,
+		              NM_SETTING_WIRED_MTU,
+		              ETH_MTU,
+		              NULL);
+
+		g_ptr_array_add (kf_data_arr,
+		    g_strdup_printf ("[connection]\n"
+		                     "id=%s\n"
+		                     "uuid=%s\n"
+		                     "type=ethernet\n"
+		                     "interface-name=%s\n"
+		                     "permissions=\n"
+		                     "\n"
+		                     "[ethernet]\n"
+		                     "mac-address-blacklist=\n"
+		                     "%s" /* mtu */
+		                     "\n"
+		                     "[ipv4]\n"
+		                     "dns-search=\n"
+		                     "method=auto\n"
+		                     "\n"
+		                     "[ipv6]\n"
+		                     "addr-gen-mode=stable-privacy\n"
+		                     "dns-search=\n"
+		                     "method=auto\n"
+		                     "",
+		                     ID,
+		                     UUID,
+		                     INTERFACE_NAME,
+		                       (ETH_MTU != 0)
+		                     ? nm_sprintf_bufa (100, "mtu=%u\n", ETH_MTU)
+		                     : ""));
+
+		g_ptr_array_add (kf_data_arr,
+		    g_strdup_printf ("[connection]\n"
+		                     "id=%s\n"
+		                     "uuid=%s\n"
+		                     "type=ethernet\n"
+		                     "interface-name=%s\n"
+		                     "permissions=\n"
+		                     "\n"
+		                     "[ethernet]\n"
+		                     "mac-address-blacklist=\n"
+		                     "%s" /* mtu */
+		                     "\n"
+		                     "[ipv4]\n"
+		                     "dns-search=\n"
+		                     "method=auto\n"
+		                     "\n"
+		                     "[ipv6]\n"
+		                     "addr-gen-mode=stable-privacy\n"
+		                     "dns-search=\n"
+		                     "method=auto\n"
+		                     "",
+		                     ID,
+		                     UUID,
+		                     INTERFACE_NAME,
+		                       (ETH_MTU != 0)
+		                     ? nm_sprintf_bufa (100, "mtu=%d\n", (int) ETH_MTU)
+		                     : ""));
+
+		break;
+
+	default:
+		g_assert_not_reached ();
+	}
+
+	/* the first kf_data_arr entry is special: it is the exact result of what we expect
+	 * when converting @con to keyfile. Write @con to keyfile and compare the expected result
+	 * literally. */
+	{
+		gs_unref_keyfile GKeyFile *kf = NULL;
+
+		kf = nm_keyfile_write (con, NULL, NULL, &error);
+		nmtst_assert_success (kf, error);
+
+		/* the first kf_data_arr entry is special: it must be what the writer would
+		 * produce again. */
+		nmtst_keyfile_assert_data (kf, kf_data_arr->pdata[0], -1);
+	}
+
+	/* check that reading any of kf_data_arr yields the same result that we expect. */
+	for (kf_data_idx = 0; kf_data_idx < kf_data_arr->len; kf_data_idx++) {
+		gs_unref_object NMConnection *con2 = NULL;
+		NMSettingWired *s_eth2 = NULL;
+
+		con2 = nmtst_create_connection_from_keyfile (kf_data_arr->pdata[kf_data_idx], "/no/where/file.nmconnection");
+
+		switch (MODE) {
+		case 0:
+			s_eth2 = NM_SETTING_WIRED (nm_connection_get_setting (con2, NM_TYPE_SETTING_WIRED));
+			g_assert (NM_IS_SETTING_WIRED (s_eth2));
+
+			if (   ETH_MTU > (guint32) G_MAXINT
+			    && kf_data_idx == 1) {
+				/* older versions wrote values > 2^21 as signed integers, but the reader would
+				 * always reject such negative values for G_TYPE_UINT.
+				 *
+				 * The test case kf_data_idx #1 still writes the values in the old style.
+				 * The behavior was fixed, but such values are still rejected as invalid.
+				 *
+				 * Patch the setting so that the comparison below succeeds are usual. */
+				g_assert_cmpint (nm_setting_wired_get_mtu (s_eth2), ==, 0);
+				g_object_set (s_eth2,
+				              NM_SETTING_WIRED_MTU,
+				              ETH_MTU,
+				              NULL);
+			}
+
+			g_assert_cmpint (nm_setting_wired_get_mtu (s_eth), ==, ETH_MTU);
+			g_assert_cmpint (nm_setting_wired_get_mtu (s_eth2), ==, ETH_MTU);
+			break;
+		}
+
+		nmtst_assert_connection_equals (con, nmtst_get_rand_bool (), con2, nmtst_get_rand_bool ());
+	}
+
+	for (dbus_serialization_flags_idx = 0; dbus_serialization_flags_idx < G_N_ELEMENTS (dbus_serialization_flags); dbus_serialization_flags_idx++) {
+		NMConnectionSerializationFlags flag = dbus_serialization_flags[dbus_serialization_flags_idx];
+		gs_unref_variant GVariant *con_var = NULL;
+		gs_unref_object NMConnection *con2 = NULL;
+
+		con_var = nm_connection_to_dbus (con, flag);
+		g_assert (g_variant_is_of_type (con_var, NM_VARIANT_TYPE_CONNECTION));
+		g_assert (g_variant_is_floating (con_var));
+		g_variant_ref_sink (con_var);
+
+		if (flag == NM_CONNECTION_SERIALIZE_ALL) {
+			con2 = _connection_new_from_dbus_strict (con_var, TRUE);
+			nmtst_assert_connection_equals (con, nmtst_get_rand_bool (), con2, nmtst_get_rand_bool ());
+
+			{
+				gs_unref_keyfile GKeyFile *kf = NULL;
+
+				kf = nm_keyfile_write (con2, NULL, NULL, &error);
+				nmtst_assert_success (kf, error);
+				nmtst_keyfile_assert_data (kf, kf_data_arr->pdata[0], -1);
+			}
+		}
+	}
+}
+
+/*****************************************************************************/
+
 NMTST_DEFINE ();
 
 int
@@ -2022,5 +2268,7 @@ main (int argc, char **argv)
 	g_test_add_func ("/libnm/settings/team-port/sycn_from_config_full", test_team_port_full_config);
 #endif
 
+	g_test_add_data_func ("/libnm/settings/roundtrip-conversion/general/0", GINT_TO_POINTER (0), test_roundtrip_conversion);
+
 	return g_test_run ();
 }