summary refs log tree commit diff
path: root/clients/common
diff options
context:
space:
mode:
authorMichael Biebl <biebl@debian.org>2018-05-11 22:08:45 +0200
committerMichael Biebl <biebl@debian.org>2018-05-11 22:08:45 +0200
commitee9c73a923909e23a649407be77e25235d769e25 (patch)
treee21c923621fa278e737da693df9eb60ea31a6067 /clients/common
parentf60117b41d5433be1b4a96d82cd11d0c3dce9b63 (diff)
New upstream version 1.10.8 upstream/1.10.8
Diffstat (limited to 'clients/common')
-rw-r--r--clients/common/meson.build81
-rw-r--r--clients/common/nm-client-utils.c106
-rw-r--r--clients/common/nm-client-utils.h8
-rw-r--r--clients/common/nm-meta-setting-access.c3
-rw-r--r--clients/common/nm-meta-setting-access.h1
-rw-r--r--clients/common/nm-meta-setting-desc.c718
-rw-r--r--clients/common/nm-meta-setting-desc.h7
-rw-r--r--clients/common/nm-polkit-listener.c214
-rw-r--r--clients/common/nm-polkit-listener.h86
-rw-r--r--clients/common/nm-secret-agent-simple.c236
-rw-r--r--clients/common/nm-secret-agent-simple.h21
-rw-r--r--clients/common/nm-vpn-helpers.h2
-rw-r--r--clients/common/settings-docs.c (renamed from clients/common/settings-docs.h)21
-rw-r--r--clients/common/settings-docs.c.in (renamed from clients/common/settings-docs.h.in)21
-rw-r--r--clients/common/tests/meson.build23
-rw-r--r--clients/common/tests/test-general.c10
16 files changed, 688 insertions, 870 deletions
diff --git a/clients/common/meson.build b/clients/common/meson.build
deleted file mode 100644
index ea26bccf..00000000
--- a/clients/common/meson.build
+++ /dev/null
@@ -1,81 +0,0 @@
-common_inc = include_directories('.')
-
-nm_polkit_listener = files('nm-polkit-listener.c')
-
-deps = [
-  libnm_dep,
-  nm_core_dep
-]
-
-cflags = clients_cflags + [
-  '-DG_LOG_DOMAIN="libnmc"',
-]
-
-sources = shared_utils + files(
-  'nm-client-utils.c',
-  'nm-secret-agent-simple.c',
-  'nm-vpn-helpers.c'
-)
-
-libnmc_base = static_library(
-  'nmc-base',
-  sources: sources,
-  dependencies: deps,
-  c_args: cflags
-)
-
-libnmc_base_dep = declare_dependency(
-  include_directories: common_inc,
-  link_with: libnmc_base
-)
-
-sources = shared_meta_setting + files(
-  'nm-meta-setting-access.c',
-  'nm-meta-setting-desc.c'
-)
-
-settings_docs = 'settings-docs.h'
-
-if enable_introspection
-  settings_docs_source = custom_target(
-    settings_docs,
-    input: nm_property_docs,
-    output: settings_docs,
-    command: [xsltproc, '--output', '@OUTPUT@', join_paths(meson.current_source_dir(), 'settings-docs.xsl'), '@INPUT@']
-  )
-
-  # FIXME: if enabled the check happens even if the settings_docs_source is not set
-  '''
-  if get_option('check_settings_docs')
-    res = run_command(find_program('cmp'), '-s', settings_docs + '.in', settings_docs_source.full_path())
-    if res.returncode() != 0
-      message('The generated file ' + settings_docs_source.full_path() + ' differs from the source file ' + settings_docs + '.in' + '. You probably should copy the generated file over to the source file. You can skip this test by setting -Dcheck_settings_docs=false')
-    endif
-  endif
-  '''
-else
-  settings_docs_source = configure_file(
-    input: settings_docs + '.in',
-    output: settings_docs,
-    configuration: configuration_data()
-  )
-endif
-sources += settings_docs_source
-
-libnmc = static_library(
-  'nmc',
-  sources: sources,
-  dependencies: deps,
-  c_args: cflags,
-  link_with: libnmc_base,
-  link_depends: settings_docs_source
-)
-
-libnmc_dep = declare_dependency(
-  include_directories: common_inc,
-  link_with: libnmc
-)
-
-if (enable_introspection or enable_nmtui) and enable_tests
-  subdir('tests')
-endif
diff --git a/clients/common/nm-client-utils.c b/clients/common/nm-client-utils.c
index b4b4c1b9..b6ec92de 100644
--- a/clients/common/nm-client-utils.c
+++ b/clients/common/nm-client-utils.c
@@ -20,7 +20,6 @@
 #include "nm-default.h"
 
 #include "nm-client-utils.h"
-#include "nm-utils.h"
 
 #include "nm-device-bond.h"
 #include "nm-device-bridge.h"
@@ -70,7 +69,7 @@ nmc_string_to_bool (const char *str, gboolean *val_bool, GError **error)
 
 	if (g_strcmp0 (str, "o") == 0) {
 		g_set_error (error, 1, 0,
-		             /* TRANSLATORS: the first %s is the partial value entered by
+		             /* Translators: the first %s is the partial value entered by
 		              * the user, the second %s a list of compatible values.
 		              */
 		             _("'%s' is ambiguous (%s)"), str, "on x off");
@@ -101,7 +100,7 @@ nmc_string_to_tristate (const char *str, NMCTriStateValue *val, GError **error)
 
 	if (g_strcmp0 (str, "o") == 0) {
 		g_set_error (error, 1, 0,
-		             /* TRANSLATORS: the first %s is the partial value entered by
+		             /* Translators: the first %s is the partial value entered by
 		              * the user, the second %s a list of compatible values.
 		              */
 		             _("'%s' is ambiguous (%s)"), str, "on x off");
@@ -134,7 +133,7 @@ nmc_string_is_valid (const char *input, const char **allowed, GError **error)
 {
 	const char **p;
 	size_t input_ln, p_len;
-	gboolean prev_match = FALSE, ambiguous = FALSE;
+	gboolean prev_match = FALSE;
 	const char *ret = NULL;
 
 	g_return_val_if_fail (error == NULL || *error == NULL, NULL);
@@ -148,21 +147,19 @@ nmc_string_is_valid (const char *input, const char **allowed, GError **error)
 		if (g_ascii_strncasecmp (input, *p, input_ln) == 0) {
 			if (input_ln == p_len) {
 				ret = *p;
-				ambiguous = FALSE;
 				break;
 			}
-			if (!prev_match) {
+			if (!prev_match)
 				ret = *p;
-				prev_match = TRUE;
-			} else
-				ambiguous = TRUE;
+			else {
+				g_set_error (error, 1, 1, _("'%s' is ambiguous (%s x %s)"),
+				             input, ret, *p);
+				return NULL;
+			}
+			prev_match = TRUE;
 		}
 	}
-	if (ambiguous) {
-		g_set_error (error, 1, 1, _("'%s' is ambiguous (%s x %s)"),
-		             input, ret, *p);
-		return NULL;
-	}
+
 finish:
 	if (ret == NULL) {
 		char *valid_vals = g_strjoinv (", ", (char **) allowed);
@@ -176,6 +173,18 @@ finish:
 	return ret;
 }
 
+/*
+ * Wrapper function for g_strsplit_set() that removes empty strings
+ * from the vector as they are not useful in most cases.
+ */
+char **
+nmc_strsplit_set (const char *str, const char *delimiter, int max_tokens)
+{
+	/* remove empty strings */
+	return _nm_utils_strv_cleanup (g_strsplit_set (str, delimiter, max_tokens),
+	                               FALSE, TRUE, FALSE);
+}
+
 gboolean
 matches (const char *cmd, const char *pattern)
 {
@@ -509,72 +518,3 @@ nmc_activation_get_effective_state (NMActiveConnection *active,
 
 	return ac_state;
 }
-
-static gboolean
-can_show_graphics (void)
-{
-	static gboolean can_show_graphics_set = FALSE;
-	gboolean can_show_graphics = TRUE;
-	char *locale_str;
-
-	if (G_LIKELY (can_show_graphics_set))
-		return can_show_graphics;
-
-	if (!g_get_charset (NULL)) {
-		/* Non-UTF-8 locale */
-		locale_str = g_locale_from_utf8 ("\342\226\202\342\226\204\342\226\206\342\226\210", -1, NULL, NULL, NULL);
-		if (locale_str)
-			g_free (locale_str);
-		else
-			can_show_graphics = FALSE;
-	}
-
-	/* The linux console font typically doesn't have characters we need */
-	if (g_strcmp0 (g_getenv ("TERM"), "linux") == 0)
-		can_show_graphics = FALSE;
-
-	return can_show_graphics;
-}
-
-/**
- * nmc_wifi_strength_bars:
- * @strength: the access point strength, from 0 to 100
- *
- * Converts @strength into a 4-character-wide graphical representation of
- * strength suitable for printing to stdout. If the current locale and terminal
- * support it, this will use unicode graphics characters to represent
- * "bars". Otherwise it will use 0 to 4 asterisks.
- *
- * Returns: the graphical representation of the access point strength
- */
-const char *
-nmc_wifi_strength_bars (guint8 strength)
-{
-	if (!can_show_graphics ())
-		return nm_utils_wifi_strength_bars (strength);
-
-	if (strength > 80)
-		return /* ▂▄▆█ */ "\342\226\202\342\226\204\342\226\206\342\226\210";
-	else if (strength > 55)
-		return /* ▂▄▆_ */ "\342\226\202\342\226\204\342\226\206_";
-	else if (strength > 30)
-		return /* ▂▄__ */ "\342\226\202\342\226\204__";
-	else if (strength > 5)
-		return /* ▂___ */ "\342\226\202___";
-	else
-		return /* ____ */ "____";
-}
-
-/**
- * nmc_utils_password_subst_char:
- *
- * Returns: the string substituted when hiding actual password glyphs
- */
-const char *
-nmc_password_subst_char (void)
-{
-	if (can_show_graphics ())
-		return "\u2022"; /* Bullet */
-	else
-		return "*";
-}
diff --git a/clients/common/nm-client-utils.h b/clients/common/nm-client-utils.h
index cd662765..ac18fe94 100644
--- a/clients/common/nm-client-utils.h
+++ b/clients/common/nm-client-utils.h
@@ -32,6 +32,8 @@ typedef enum {
 
 const char *nmc_string_is_valid (const char *input, const char **allowed, GError **error);
 
+char **nmc_strsplit_set (const char *str, const char *delimiter, int max_tokens);
+
 gboolean nmc_string_to_uint (const char *str,
                              gboolean range_check,
                              unsigned long int min,
@@ -42,7 +44,7 @@ gboolean nmc_string_to_tristate (const char *str, NMCTriStateValue *val, GError
 
 gboolean matches (const char *cmd, const char *pattern);
 
-/* FIXME: don't expose this function on its own, at least not from this file. */
+/* FIXME: don't expose this function on it's own, at least not from this file. */
 const char *nmc_bond_validate_mode (const char *mode, GError **error);
 
 const char *nm_active_connection_state_reason_to_string (NMActiveConnectionStateReason reason);
@@ -54,8 +56,4 @@ NMActiveConnectionState nmc_activation_get_effective_state (NMActiveConnection *
                                                             NMDevice *device,
                                                             const char **reason);
 
-const char *nmc_wifi_strength_bars (guint8 strength);
-
-const char *nmc_password_subst_char (void);
-
 #endif /* __NM_CLIENT_UTILS_H__ */
diff --git a/clients/common/nm-meta-setting-access.c b/clients/common/nm-meta-setting-access.c
index a1bfed47..cd7ef783 100644
--- a/clients/common/nm-meta-setting-access.c
+++ b/clients/common/nm-meta-setting-access.c
@@ -232,7 +232,6 @@ nm_meta_abstract_info_get (const NMMetaAbstractInfo *abstract_info,
                            NMMetaAccessorGetType get_type,
                            NMMetaAccessorGetFlags get_flags,
                            NMMetaAccessorGetOutFlags *out_flags,
-                           gboolean *out_is_default,
                            gpointer *out_to_free)
 {
 	nm_assert (abstract_info);
@@ -241,7 +240,6 @@ nm_meta_abstract_info_get (const NMMetaAbstractInfo *abstract_info,
 	nm_assert (out_flags);
 
 	*out_flags = NM_META_ACCESSOR_GET_OUT_FLAGS_NONE;
-	NM_SET_OUT (out_is_default, FALSE);
 
 	if (!abstract_info->meta_type->get_fcn)
 		g_return_val_if_reached (NULL);
@@ -253,7 +251,6 @@ nm_meta_abstract_info_get (const NMMetaAbstractInfo *abstract_info,
 	                                          get_type,
 	                                          get_flags,
 	                                          out_flags,
-	                                          out_is_default,
 	                                          out_to_free);
 }
 
diff --git a/clients/common/nm-meta-setting-access.h b/clients/common/nm-meta-setting-access.h
index 577cad78..54fc6c84 100644
--- a/clients/common/nm-meta-setting-access.h
+++ b/clients/common/nm-meta-setting-access.h
@@ -58,7 +58,6 @@ gconstpointer nm_meta_abstract_info_get (const NMMetaAbstractInfo *abstract_info
                                          NMMetaAccessorGetType get_type,
                                          NMMetaAccessorGetFlags get_flags,
                                          NMMetaAccessorGetOutFlags *out_flags,
-                                         gboolean *out_is_default,
                                          gpointer *out_to_free);
 
 const char *const*nm_meta_abstract_info_complete (const NMMetaAbstractInfo *abstract_info,
diff --git a/clients/common/nm-meta-setting-desc.c b/clients/common/nm-meta-setting-desc.c
index ede95a10..94404e90 100644
--- a/clients/common/nm-meta-setting-desc.c
+++ b/clients/common/nm-meta-setting-desc.c
@@ -25,8 +25,10 @@
 #include <arpa/inet.h>
 
 #include "nm-common-macros.h"
+#include "nm-utils/nm-hash-utils.h"
 #include "nm-utils/nm-enum-utils.h"
 
+#include "NetworkManager.h"
 #include "nm-vpn-helpers.h"
 #include "nm-client-utils.h"
 #include "nm-meta-setting-access.h"
@@ -116,6 +118,7 @@ _parse_ip_route (int family,
                  GError **error)
 {
 	const int MAX_PREFIX = (family == AF_INET) ? 32 : 128;
+	char *plen = NULL;
 	const char *next_hop = NULL;
 	const char *canon_dest;
 	int prefix;
@@ -123,11 +126,9 @@ _parse_ip_route (int family,
 	GError *local = NULL;
 	gint64 metric = -1;
 	guint i;
-	gs_free const char **routev = NULL;
+	gs_strfreev char **routev = NULL;
 	gs_free char *str_clean = NULL;
-	gs_free char *dest_clone = NULL;
-	const char *dest;
-	const char *plen;
+	char *dest;
 	gs_unref_hashtable GHashTable *attrs = NULL;
 	GHashTable *tmp_attrs;
 #define ROUTE_SYNTAX _("The valid syntax is: 'ip[/prefix] [next-hop] [metric] [attribute=val]... [,ip[/prefix] ...]'")
@@ -137,8 +138,8 @@ _parse_ip_route (int family,
 	nm_assert (!error || !*error);
 
 	str_clean = g_strstrip (g_strdup (str));
-	routev = nm_utils_strsplit_set (str_clean, " \t");
-	if (!routev) {
+	routev = nmc_strsplit_set (str_clean, " \t", 0);
+	if (!routev || !routev[0]) {
 		g_set_error (error, 1, 0,
 		             "'%s' is not valid. %s",
 		             str, ROUTE_SYNTAX);
@@ -147,13 +148,8 @@ _parse_ip_route (int family,
 
 	dest = routev[0];
 	plen = strchr (dest, '/');  /* prefix delimiter */
-	if (plen) {
-		dest_clone = g_strdup (dest);
-		plen = &dest_clone[plen - dest];
-		dest = dest_clone;
-		*((char *) plen) = '\0';
-		plen++;
-	}
+	if (plen)
+		*plen++ = '\0';
 	prefix = MAX_PREFIX;
 	if (plen) {
 		if ((prefix = _nm_utils_ascii_str_to_int64 (plen, 10, 1, MAX_PREFIX, -1)) == -1) {
@@ -300,7 +296,7 @@ static NMTeamLinkWatcher *
 _parse_team_link_watcher (const char *str,
                           GError **error)
 {
-	gs_free const char **watcherv = NULL;
+	gs_strfreev char **watcherv = NULL;
 	gs_free char *str_clean = NULL;
 	guint i;
 	gs_free const char *name = NULL;
@@ -313,17 +309,17 @@ _parse_team_link_watcher (const char *str,
 	nm_assert (!error || !*error);
 
 	str_clean = g_strstrip (g_strdup (str));
-	watcherv = nm_utils_strsplit_set (str_clean, " \t");
-	if (!watcherv) {
+	watcherv = nmc_strsplit_set (str_clean, " \t", 0);
+	if (!watcherv || !watcherv[0]) {
 		g_set_error (error, 1, 0, "'%s' is not valid", str);
 		return NULL;
 	}
 
 	for (i = 0; watcherv[i]; i++) {
-		gs_free const char **pair = NULL;
+		gs_strfreev char **pair = NULL;
 
-		pair = nm_utils_strsplit_set (watcherv[i], "=");
-		if (!pair) {
+		pair = nmc_strsplit_set (watcherv[i], "=", 0);
+		if (!pair[0]) {
 			g_set_error (error, 1, 0, "'%s' is not valid: %s", watcherv[i],
 			             "properties should be specified as 'key=value'");
 			return NULL;
@@ -640,7 +636,7 @@ _env_warn_fcn (const NMMetaEnvironment *environment,
 	const NMMetaPropertyInfo *property_info, char **out_to_free
 
 #define ARGS_GET_FCN \
-	const NMMetaPropertyInfo *property_info, const NMMetaEnvironment *environment, gpointer environment_user_data, NMSetting *setting, NMMetaAccessorGetType get_type, NMMetaAccessorGetFlags get_flags, NMMetaAccessorGetOutFlags *out_flags, gboolean *out_is_default, gpointer *out_to_free
+	const NMMetaPropertyInfo *property_info, const NMMetaEnvironment *environment, gpointer environment_user_data, NMSetting *setting, NMMetaAccessorGetType get_type, NMMetaAccessorGetFlags get_flags, NMMetaAccessorGetOutFlags *out_flags, gpointer *out_to_free
 
 #define ARGS_SET_FCN \
 	const NMMetaPropertyInfo *property_info, const NMMetaEnvironment *environment, gpointer environment_user_data, NMSetting *setting, const char *value, GError **error
@@ -673,33 +669,6 @@ _env_warn_fcn (const NMMetaEnvironment *environment,
 		return ((*(out_to_free)) = _val); \
 	} G_STMT_END
 
-static gboolean
-property_is_default (NMSetting *setting, const char *prop_name)
-{
-	nm_auto_unset_gvalue GValue v = G_VALUE_INIT;
-	GParamSpec *pspec;
-	GHashTable *ht;
-	char **strv;
-
-	pspec = g_object_class_find_property (G_OBJECT_GET_CLASS (G_OBJECT (setting)),
-	                                      prop_name);
-	if (!G_IS_PARAM_SPEC (pspec))
-		g_return_val_if_reached (FALSE);
-
-	g_value_init (&v, pspec->value_type);
-	g_object_get_property (G_OBJECT (setting), prop_name, &v);
-
-	if (pspec->value_type == G_TYPE_STRV) {
-		strv = g_value_get_boxed (&v);
-		return !strv || !strv[0];
-	} else if (pspec->value_type == G_TYPE_HASH_TABLE) {
-		ht = g_value_get_boxed (&v);
-		return !ht || !g_hash_table_size (ht);
-	}
-
-	return g_param_value_defaults (pspec, &v);
-}
-
 static gconstpointer
 _get_fcn_nmc_with_default (ARGS_GET_FCN)
 {
@@ -708,7 +677,6 @@ _get_fcn_nmc_with_default (ARGS_GET_FCN)
 	GValue val = G_VALUE_INIT;
 
 	RETURN_UNSUPPORTED_GET_TYPE ();
-	NM_SET_OUT (out_is_default, property_is_default (setting, property_info->property_name));
 
 	if (property_info->property_typ_data->subtype.get_with_default.fcn (setting)) {
 		if (get_type == NM_META_ACCESSOR_GET_TYPE_PRETTY)
@@ -724,7 +692,6 @@ _get_fcn_nmc_with_default (ARGS_GET_FCN)
 	else
 		s_full = g_strdup (s && *s ? s : " ");
 	g_value_unset (&val);
-
 	RETURN_STR_TO_FREE (s_full);
 }
 
@@ -732,7 +699,6 @@ static gconstpointer
 _get_fcn_gobject_impl (const NMMetaPropertyInfo *property_info,
                        NMSetting *setting,
                        NMMetaAccessorGetType get_type,
-                       gboolean *out_is_default,
                        gpointer *out_to_free)
 {
 	char *s;
@@ -741,7 +707,6 @@ _get_fcn_gobject_impl (const NMMetaPropertyInfo *property_info,
 	nm_auto_unset_gvalue GValue val = G_VALUE_INIT;
 
 	RETURN_UNSUPPORTED_GET_TYPE ();
-	NM_SET_OUT (out_is_default, property_is_default (setting, property_info->property_name));
 
 	gtype_prop = _gobject_property_get_gtype (G_OBJECT (setting), property_info->property_name);
 
@@ -767,13 +732,13 @@ _get_fcn_gobject_impl (const NMMetaPropertyInfo *property_info,
 static gconstpointer
 _get_fcn_gobject (ARGS_GET_FCN)
 {
-	return _get_fcn_gobject_impl (property_info, setting, get_type, out_is_default, out_to_free);
+	return _get_fcn_gobject_impl (property_info, setting, get_type, out_to_free);
 }
 
 static gconstpointer
 _get_fcn_gobject_int (ARGS_GET_FCN)
 {
-	GParamSpec *pspec;
+	const GParamSpec *pspec;
 	nm_auto_unset_gvalue GValue gval = G_VALUE_INIT;
 	gint64 v;
 	const NMMetaUtilsIntValueInfo *value_infos;
@@ -786,7 +751,6 @@ _get_fcn_gobject_int (ARGS_GET_FCN)
 
 	g_value_init (&gval, pspec->value_type);
 	g_object_get_property (G_OBJECT (setting), property_info->property_name, &gval);
-	NM_SET_OUT (out_is_default, g_param_value_defaults (pspec, &gval));
 	switch (pspec->value_type) {
 	case G_TYPE_INT:
 		v = g_value_get_int (&gval);
@@ -826,11 +790,10 @@ _get_fcn_gobject_mtu (ARGS_GET_FCN)
 
 	if (   !property_info->property_typ_data
 	    || !property_info->property_typ_data->subtype.mtu.get_fcn)
-		return _get_fcn_gobject_impl (property_info, setting, get_type, out_is_default, out_to_free);
+		return _get_fcn_gobject_impl (property_info, setting, get_type, out_to_free);
 
 	mtu = property_info->property_typ_data->subtype.mtu.get_fcn (setting);
 	if (mtu == 0) {
-		NM_SET_OUT (out_is_default, TRUE);
 		if (get_type == NM_META_ACCESSOR_GET_TYPE_PRETTY)
 			return _("auto");
 		return "auto";
@@ -857,9 +820,9 @@ static gconstpointer
 _get_fcn_gobject_enum (ARGS_GET_FCN)
 {
 	GType gtype = 0;
+	GType gtype_prop;
 	nm_auto_unref_gtypeclass GTypeClass *gtype_class = NULL;
 	nm_auto_unref_gtypeclass GTypeClass *gtype_prop_class = NULL;
-	const struct _NMUtilsEnumValueInfo *value_infos = NULL;
 	gboolean has_gtype = FALSE;
 	nm_auto_unset_gvalue GValue gval = G_VALUE_INIT;
 	gint64 v;
@@ -870,7 +833,6 @@ _get_fcn_gobject_enum (ARGS_GET_FCN)
 	gboolean format_text_l10n = FALSE;
 	gs_free char *s = NULL;
 	char s_numeric[64];
-	GParamSpec *pspec;
 
 	RETURN_UNSUPPORTED_GET_TYPE ();
 
@@ -913,26 +875,25 @@ _get_fcn_gobject_enum (ARGS_GET_FCN)
 
 	nm_assert (format_text || format_numeric);
 
-	pspec = g_object_class_find_property (G_OBJECT_GET_CLASS (setting), property_info->property_name);
-	g_return_val_if_fail (pspec, NULL);
+	gtype_prop = _gobject_property_get_gtype (G_OBJECT (setting), property_info->property_name);
+
+	g_value_init (&gval, gtype_prop);
 
-	g_value_init (&gval, pspec->value_type);
 	g_object_get_property (G_OBJECT (setting), property_info->property_name, &gval);
-	NM_SET_OUT (out_is_default, g_param_value_defaults (pspec, &gval));
 
-	if (   pspec->value_type == G_TYPE_INT
-	    || (    G_TYPE_IS_CLASSED (pspec->value_type)
-	        &&  G_IS_ENUM_CLASS ((gtype_prop_class ?: (gtype_prop_class = g_type_class_ref (pspec->value_type)))))) {
-		if (pspec->value_type == G_TYPE_INT) {
+	if (   gtype_prop == G_TYPE_INT
+	    || (    G_TYPE_IS_CLASSED (gtype_prop)
+	        &&  G_IS_ENUM_CLASS ((gtype_prop_class ?: (gtype_prop_class = g_type_class_ref (gtype_prop)))))) {
+		if (gtype_prop == G_TYPE_INT) {
 			if (!has_gtype)
 				g_return_val_if_reached (NULL);
 			v = g_value_get_int (&gval);
 		} else
 		    v = g_value_get_enum (&gval);
-	} else if (   pspec->value_type == G_TYPE_UINT
-	           || (   G_TYPE_IS_CLASSED (pspec->value_type)
-	               && G_IS_FLAGS_CLASS ((gtype_prop_class ?: (gtype_prop_class = g_type_class_ref (pspec->value_type)))))) {
-		if (pspec->value_type == G_TYPE_UINT) {
+	} else if (   gtype_prop == G_TYPE_UINT
+	           || (   G_TYPE_IS_CLASSED (gtype_prop)
+	               && G_IS_FLAGS_CLASS ((gtype_prop_class ?: (gtype_prop_class = g_type_class_ref (gtype_prop)))))) {
+		if (gtype_prop == G_TYPE_UINT) {
 			if (!has_gtype)
 				g_return_val_if_reached (NULL);
 			v = g_value_get_uint (&gval);
@@ -942,7 +903,7 @@ _get_fcn_gobject_enum (ARGS_GET_FCN)
 		g_return_val_if_reached (NULL);
 
 	if (!has_gtype) {
-		gtype = pspec->value_type;
+		gtype = gtype_prop;
 		gtype_class = g_steal_pointer (&gtype_prop_class);
 	}
 
@@ -966,9 +927,7 @@ _get_fcn_gobject_enum (ARGS_GET_FCN)
 	/* the gobject_enum.value_infos are currently ignored for the getter. They
 	 * only declare additional aliases for the setter. */
 
-	if (property_info->property_typ_data)
-		value_infos = property_info->property_typ_data->subtype.gobject_enum.value_infos_get;
-	s = _nm_utils_enum_to_str_full (gtype, (int) v, ", ", value_infos);
+	s = nm_utils_enum_to_str (gtype, (int) v);
 
 	if (!format_numeric)
 		RETURN_STR_TO_FREE (g_steal_pointer (&s));
@@ -1210,6 +1169,39 @@ _set_fcn_gobject_mac (ARGS_SET_FCN)
 }
 
 static gboolean
+_set_fcn_gobject_secret_flags (ARGS_SET_FCN)
+{
+	char **strv = NULL, **iter;
+	unsigned long flags = 0, val_int;
+
+	g_return_val_if_fail (error == NULL || *error == NULL, FALSE);
+
+	strv = nmc_strsplit_set (value, " \t,", 0);
+	for (iter = strv; iter && *iter; iter++) {
+		if (!nmc_string_to_uint (*iter, TRUE, 0, ALL_SECRET_FLAGS, &val_int)) {
+			g_set_error (error, 1, 0, _("'%s' is not a valid flag number; use <0-%d>"),
+			             *iter, ALL_SECRET_FLAGS);
+			g_strfreev (strv);
+			return FALSE;
+		}
+		flags += val_int;
+	}
+	g_strfreev (strv);
+
+	/* Validate the flags number */
+	if (flags > ALL_SECRET_FLAGS) {
+		flags = ALL_SECRET_FLAGS;
+		_env_warn_fcn (environment, environment_user_data,
+		               NM_META_ENV_WARN_LEVEL_WARN,
+		               N_("'%s' sum is higher than all flags => all flags set"),
+		               value);
+	}
+
+	g_object_set (setting, property_info->property_name, (guint) flags, NULL);
+	return TRUE;
+}
+
+static gboolean
 _set_fcn_gobject_enum (ARGS_SET_FCN)
 {
 	GType gtype = 0;
@@ -1328,7 +1320,7 @@ _values_fcn_gobject_enum (ARGS_VALUES_FCN)
 	gboolean has_minmax = FALSE;
 	int min = G_MININT;
 	int max = G_MAXINT;
-	char **v;
+	char **v, **w;
 
 	if (property_info->property_typ_data) {
 		if (   property_info->property_typ_data->subtype.gobject_enum.min
@@ -1362,7 +1354,11 @@ _values_fcn_gobject_enum (ARGS_VALUES_FCN)
 	/* the gobject_enum.value_infos are currently ignored for the list of
 	 * values. They only declare additional (hidden) aliases for the setter. */
 
-	v = nm_utils_strv_make_deep_copied (nm_utils_enum_get_values (gtype, min, max));
+	v = (char **) nm_utils_enum_get_values (gtype, min, max);
+	if (v) {
+		for (w = v; *w; w++)
+			*w = g_strdup (*w);
+	}
 	return (const char *const*) (*out_to_free = v);
 }
 
@@ -1510,6 +1506,24 @@ vlan_priorities_to_string (NMSettingVlan *s_vlan, NMVlanPriorityMap map)
 }
 
 static char *
+ip6_privacy_to_string (NMSettingIP6ConfigPrivacy ip6_privacy, NMMetaAccessorGetType get_type)
+{
+	if (get_type != NM_META_ACCESSOR_GET_TYPE_PRETTY)
+		return g_strdup_printf ("%d", ip6_privacy);
+
+	switch (ip6_privacy) {
+	case NM_SETTING_IP6_CONFIG_PRIVACY_DISABLED:
+		return g_strdup_printf (_("%d (disabled)"), ip6_privacy);
+	case NM_SETTING_IP6_CONFIG_PRIVACY_PREFER_PUBLIC_ADDR:
+		return g_strdup_printf (_("%d (enabled, prefer public IP)"), ip6_privacy);
+	case NM_SETTING_IP6_CONFIG_PRIVACY_PREFER_TEMP_ADDR:
+		return g_strdup_printf (_("%d (enabled, prefer temporary IP)"), ip6_privacy);
+	default:
+		return g_strdup_printf (_("%d (unknown)"), ip6_privacy);
+	}
+}
+
+static char *
 secret_flags_to_string (guint32 flags, NMMetaAccessorGetType get_type)
 {
 	GString *flag_str;
@@ -1559,19 +1573,18 @@ vpn_data_item (const char *key, const char *value, gpointer user_data)
 	          const char **valid_strv, \
 	          GError **error) \
 	{ \
-		gs_free const char **strv = NULL; \
-		gsize i; \
+		char **strv = NULL, **iter; \
 		const char *item; \
-		nm_assert (!error || !*error); \
-		strv = nm_utils_strsplit_set (value, " \t,"); \
-		if (strv) { \
-			for (i = 0; strv[i]; i++) { \
-				if (!(item = nmc_string_is_valid (strv[i], valid_strv, error))) { \
-					return FALSE; \
-				} \
-				set_func (s_macro (setting), item); \
+		g_return_val_if_fail (error == NULL || *error == NULL, FALSE); \
+		strv = nmc_strsplit_set (value, " \t,", 0); \
+		for (iter = strv; iter && *iter; iter++) { \
+			if (!(item = nmc_string_is_valid (g_strstrip (*iter), valid_strv, error))) { \
+				g_strfreev (strv); \
+				return FALSE; \
 			} \
+			set_func (s_macro (setting), item); \
 		} \
+		g_strfreev (strv); \
 		return TRUE; \
 	}
 
@@ -1579,42 +1592,43 @@ vpn_data_item (const char *key, const char *value, gpointer user_data)
 	static gboolean \
 	def_func (ARGS_SET_FCN) \
 	{ \
-		gs_free const char **strv = NULL; \
-		const char **iter; \
+		char **strv = NULL, **iter; \
 		const char **(*valid_func1_p) (s_type *) = valid_func1; \
 		const char * (*valid_func2_p) (const char *, const char *, GError **) = valid_func2; \
 		const char *opt_name, *opt_val; \
 		\
-		nm_assert (!error || !*error); \
+		g_return_val_if_fail (error == NULL || *error == NULL, FALSE); \
 		\
-		strv = nm_utils_strsplit_set (value, ","); \
+		strv = nmc_strsplit_set (value, ",", 0); \
 		for (iter = strv; iter && *iter; iter++) { \
-			gs_free char *left_clone = g_strstrip (g_strdup (*iter)); \
-			char *left = left_clone; \
+			char *left = g_strstrip (*iter); \
 			char *right = strchr (left, '='); \
 			if (!right) { \
 				g_set_error (error, 1, 0, _("'%s' is not valid; use <option>=<value>"), *iter); \
+				g_strfreev (strv); \
 				return FALSE; \
 			} \
 			*right++ = '\0'; \
-			g_strchomp (left); \
 			\
 			if (valid_func1_p) { \
 				const char **valid_options = valid_func1_p (s_macro (setting)); \
-				if (!(opt_name = nmc_string_is_valid (left, valid_options, error))) { \
+				if (!(opt_name = nmc_string_is_valid (g_strstrip (left), valid_options, error))) { \
+					g_strfreev (strv); \
 					return FALSE; \
 				} \
 			} else \
-				opt_name = left;\
+				opt_name = g_strstrip (left);\
 			\
-			opt_val = g_strchug (right); \
+			opt_val = g_strstrip (right); \
 			if (valid_func2_p) { \
 				if (!(opt_val = valid_func2_p ((const char *) left, (const char *) opt_val, error))) { \
+					g_strfreev (strv); \
 					return FALSE; \
 				}\
 			}\
 			add_func (s_macro (setting), opt_name, opt_val); \
 		} \
+		g_strfreev (strv); \
 		return TRUE; \
 	}
 
@@ -1669,46 +1683,47 @@ vpn_data_item (const char *key, const char *value, gpointer user_data)
 	def_func (ARGS_SET_FCN) \
 	{ \
 		guint8 buf[32]; \
-		gs_free const char **strv = NULL; \
-		const char *const*iter; \
+		char **list = NULL, **iter; \
+		GSList *macaddr_blacklist = NULL; \
 		\
-		nm_assert (!error || !*error); \
+		g_return_val_if_fail (error == NULL || *error == NULL, FALSE); \
 		\
-		strv = nm_utils_strsplit_set (value, " \t,"); \
-		for (iter = strv; strv && *iter; iter++) { \
+		list = nmc_strsplit_set (value, " \t,", 0); \
+		for (iter = list; iter && *iter; iter++) { \
 			if (!nm_utils_hwaddr_aton (*iter, buf, ETH_ALEN)) { \
 				g_set_error (error, 1, 0, _("'%s' is not a valid MAC"), *iter); \
+				g_strfreev (list); \
+				g_slist_free (macaddr_blacklist); \
 				return FALSE; \
 			} \
 		} \
 		\
-		for (iter = strv; strv && *iter; iter++) \
+		for (iter = list; iter && *iter; iter++) \
 			add_func (s_macro (setting), *iter); \
 		\
+		g_strfreev (list); \
 		return TRUE; \
 	}
 
 
 static gboolean
-verify_string_list (const char *const*strv,
+verify_string_list (char **strv,
                     const char *prop,
                     gboolean (*validate_func) (const char *),
                     GError **error)
 {
-	const char *const*iter;
+	char **iter;
 
-	nm_assert (!error || !*error);
+	g_return_val_if_fail (error == NULL || *error == NULL, FALSE);
 
-	if (strv) {
-		for (iter = strv; *iter; iter++) {
-			if (**iter == '\0')
-				continue;
-			if (validate_func) {
-				if (!validate_func (*iter)) {
-					g_set_error (error, 1, 0, _("'%s' is not valid"),
-					             *iter);
-					return FALSE;
-				}
+	for (iter = strv; iter && *iter; iter++) {
+		if (**iter == '\0')
+			continue;
+		if (validate_func) {
+			if (!validate_func (*iter)) {
+				g_set_error (error, 1, 0, _("'%s' is not valid"),
+				             *iter);
+				return FALSE;
 			}
 		}
 	}
@@ -1764,7 +1779,7 @@ check_and_set_string (NMSetting *setting,
 {
 	const char *checked_val;
 
-	nm_assert (!error || !*error);
+	g_return_val_if_fail (error == NULL || *error == NULL, FALSE);
 
 	checked_val = nmc_string_is_valid (val, valid_strv, error);
 	if (!checked_val)
@@ -1779,7 +1794,7 @@ _set_fcn_gobject_flags (ARGS_SET_FCN)
 {
 	unsigned long val_int;
 
-	nm_assert (!error || !*error);
+	g_return_val_if_fail (error == NULL || *error == NULL, FALSE);
 
 	if (!nmc_string_to_uint (value, TRUE, 0, G_MAXUINT, &val_int)) {
 		g_set_error (error, 1, 0, _("'%s' is not a valid number (or out of range)"), value);
@@ -1799,7 +1814,7 @@ _set_fcn_gobject_ssid (ARGS_SET_FCN)
 {
 	GBytes *ssid;
 
-	nm_assert (!error || !*error);
+	g_return_val_if_fail (error == NULL || *error == NULL, FALSE);
 
 	if (strlen (value) > 32) {
 		g_set_error (error, 1, 0, _("'%s' is not valid"), value);
@@ -1815,7 +1830,7 @@ _set_fcn_gobject_ssid (ARGS_SET_FCN)
 static gboolean
 _set_fcn_gobject_ifname (ARGS_SET_FCN)
 {
-	nm_assert (!error || !*error);
+	g_return_val_if_fail (error == NULL || *error == NULL, FALSE);
 
 	if (!nm_utils_is_valid_iface_name (value, error))
 		return FALSE;
@@ -1877,13 +1892,14 @@ static gboolean
 nmc_property_set_bytes (NMSetting *setting, const char *prop, const char *value, GError **error)
 {
 	gs_free char *val_strip = NULL;
-	gs_free const char **strv = NULL;
-	const char **iter;
+	gs_strfreev char **strv = NULL;
+	const char *delimiters = " \t,";
+	char **iter;
 	GBytes *bytes;
 	GByteArray *array = NULL;
 	gboolean success = TRUE;
 
-	nm_assert (!error || !*error);
+	g_return_val_if_fail (error == NULL || *error == NULL, FALSE);
 
 	val_strip = g_strstrip (g_strdup (value));
 
@@ -1893,8 +1909,8 @@ nmc_property_set_bytes (NMSetting *setting, const char *prop, const char *value,
 		goto done;
 
 	/* Otherwise, consider the following format: AA b 0xCc D */
-	strv = nm_utils_strsplit_set (val_strip, " \t");
-	array = g_byte_array_sized_new (NM_PTRARRAY_LEN (strv));
+	strv = nmc_strsplit_set (val_strip, delimiters, 0);
+	array = g_byte_array_sized_new (g_strv_length (strv));
 	for (iter = strv; iter && *iter; iter++) {
 		int v;
 		guint8 v8;
@@ -1945,7 +1961,6 @@ _get_fcn_802_1x_ca_cert (ARGS_GET_FCN)
 		break;
 	}
 
-	NM_SET_OUT (out_is_default, !ca_cert_str || !ca_cert_str[0]);
 	RETURN_STR_TO_FREE (ca_cert_str);
 }
 
@@ -1974,7 +1989,6 @@ _get_fcn_802_1x_client_cert (ARGS_GET_FCN)
 		break;
 	}
 
-	NM_SET_OUT (out_is_default, !cert_str || !cert_str[0]);
 	RETURN_STR_TO_FREE (cert_str);
 }
 
@@ -2000,7 +2014,6 @@ _get_fcn_802_1x_phase2_ca_cert (ARGS_GET_FCN)
 		break;
 	}
 
-	NM_SET_OUT (out_is_default, !phase2_ca_cert_str || !phase2_ca_cert_str[0]);
 	RETURN_STR_TO_FREE (phase2_ca_cert_str);
 }
 
@@ -2029,7 +2042,6 @@ _get_fcn_802_1x_phase2_client_cert (ARGS_GET_FCN)
 		break;
 	}
 
-	NM_SET_OUT (out_is_default, !cert_str || !cert_str[0]);
 	RETURN_STR_TO_FREE (cert_str);
 }
 
@@ -2037,13 +2049,9 @@ static gconstpointer
 _get_fcn_802_1x_password_raw (ARGS_GET_FCN)
 {
 	NMSetting8021x *s_8021X = NM_SETTING_802_1X (setting);
-	char *str;
 
 	RETURN_UNSUPPORTED_GET_TYPE ();
-
-	str = bytes_to_string (nm_setting_802_1x_get_password_raw (s_8021X));
-	NM_SET_OUT (out_is_default, !str || !str[0]);
-	RETURN_STR_TO_FREE (str);
+	RETURN_STR_TO_FREE (bytes_to_string (nm_setting_802_1x_get_password_raw (s_8021X)));
 }
 
 static gconstpointer
@@ -2071,7 +2079,6 @@ _get_fcn_802_1x_private_key (ARGS_GET_FCN)
 		break;
 	}
 
-	NM_SET_OUT (out_is_default, !key_str || !key_str[0]);
 	RETURN_STR_TO_FREE (key_str);
 }
 
@@ -2100,7 +2107,6 @@ _get_fcn_802_1x_phase2_private_key (ARGS_GET_FCN)
 		break;
 	}
 
-	NM_SET_OUT (out_is_default, !key_str || !key_str[0]);
 	RETURN_STR_TO_FREE (key_str);
 }
 
@@ -2108,16 +2114,15 @@ _get_fcn_802_1x_phase2_private_key (ARGS_GET_FCN)
 	static gboolean \
 	def_func (ARGS_SET_FCN) \
 	{ \
-		const char **strv = NULL; \
-		gsize i; \
+		char **strv = NULL; \
+		guint i = 0; \
 		\
-		nm_assert (error == NULL || *error == NULL); \
+		g_return_val_if_fail (error == NULL || *error == NULL, FALSE); \
 		\
-		strv = nm_utils_strsplit_set (value, " \t,"); \
-		if (strv) { \
-			for (i = 0; strv[i]; i++) \
-				set_func (NM_SETTING_802_1X (setting), strv[i++]); \
-		} \
+		strv = nmc_strsplit_set (value, " \t,", 0); \
+		while (strv && strv[i]) \
+			set_func (NM_SETTING_802_1X (setting), strv[i++]); \
+		g_strfreev (strv); \
 		return TRUE; \
 	}
 
@@ -2144,27 +2149,29 @@ _get_fcn_802_1x_phase2_private_key (ARGS_GET_FCN)
 	static gboolean \
 	def_func (ARGS_SET_FCN) \
 	{ \
-		gs_free char *path = NULL; \
+		char **strv = NULL; \
+		char *val_strip = g_strstrip (g_strdup (value)); \
+		char *p = val_strip; \
+		const char *path, *password; \
 		gs_free char *password_free = NULL; \
-		char *password; \
 		NMSetting8021xCKScheme scheme = NM_SETTING_802_1X_CK_SCHEME_PATH; \
+		gboolean success; \
 		\
-		value = nm_str_skip_leading_spaces (value); \
-		\
-		if (strncmp (value, NM_SETTING_802_1X_CERT_SCHEME_PREFIX_PKCS11, NM_STRLEN (NM_SETTING_802_1X_CERT_SCHEME_PREFIX_PKCS11)) == 0) \
+		if (strncmp (val_strip, NM_SETTING_802_1X_CERT_SCHEME_PREFIX_PKCS11, NM_STRLEN (NM_SETTING_802_1X_CERT_SCHEME_PREFIX_PKCS11)) == 0) \
 			scheme = NM_SETTING_802_1X_CK_SCHEME_PKCS11; \
-		else if (strncmp (value, NM_SETTING_802_1X_CERT_SCHEME_PREFIX_PATH, NM_STRLEN (NM_SETTING_802_1X_CERT_SCHEME_PREFIX_PATH)) == 0) \
-			value += NM_STRLEN (NM_SETTING_802_1X_CERT_SCHEME_PREFIX_PATH); \
+		else if (strncmp (val_strip, NM_SETTING_802_1X_CERT_SCHEME_PREFIX_PATH, NM_STRLEN (NM_SETTING_802_1X_CERT_SCHEME_PREFIX_PATH)) == 0) \
+			p += NM_STRLEN (NM_SETTING_802_1X_CERT_SCHEME_PREFIX_PATH); \
 		\
-		path = g_strdup (value); \
-		password = path + strcspn (path, " \t"); \
-		if (password[0] != '\0') { \
-			password[0] = '\0'; \
-			while (NM_IN_SET (password[0], ' ', '\t')) \
-				password++; \
-		} else \
+		strv = nmc_strsplit_set (p, " \t,", 2); \
+		path = strv[0]; \
+		if (g_strv_length (strv) == 2) \
+			password = strv[1]; \
+		else \
 			password = password_free = g_strdup (pwd_func (NM_SETTING_802_1X (setting))); \
-		return set_func (NM_SETTING_802_1X (setting), path, password, scheme, NULL, error); \
+		success = set_func (NM_SETTING_802_1X (setting), path, password, scheme, NULL, error); \
+		g_free (val_strip); \
+		g_strfreev (strv); \
+		return success; \
 	}
 
 DEFINE_SETTER_STR_LIST_MULTI (check_and_add_eap_method,
@@ -2294,7 +2301,6 @@ _get_fcn_bond_options (ARGS_GET_FCN)
 	}
 	g_string_truncate (bond_options_s, bond_options_s->len-1);  /* chop off trailing ',' */
 
-	NM_SET_OUT (out_is_default, bond_options_s->len == 0);
 	RETURN_STR_TO_FREE (g_string_free (bond_options_s, FALSE));
 }
 
@@ -2398,9 +2404,6 @@ _get_fcn_connection_permissions (ARGS_GET_FCN)
 		if (nm_setting_connection_get_permission (s_con, i, &perm_type, &perm_item, NULL))
 			g_string_append_printf (perm, "%s:%s,", perm_type, perm_item);
 	}
-
-	NM_SET_OUT (out_is_default, perm->len == 0);
-
 	if (perm->len > 0) {
 		g_string_truncate (perm, perm->len-1); /* remove trailing , */
 		RETURN_STR_TO_FREE (g_string_free (perm, FALSE));
@@ -2500,20 +2503,25 @@ permissions_valid (const char *perm)
 static gboolean
 _set_fcn_connection_permissions (ARGS_SET_FCN)
 {
-	gs_free const char **strv = NULL;
-	gsize i;
+	char **strv = NULL;
+	guint i = 0;
 
-	nm_assert (!error || !*error);
+	g_return_val_if_fail (error == NULL || *error == NULL, FALSE);
 
-	strv = nm_utils_strsplit_set (value, " \t,");
-	if (!verify_string_list (strv, property_info->property_name, permissions_valid, error))
+	strv = nmc_strsplit_set (value, " \t,", 0);
+	if (!verify_string_list (strv, property_info->property_name, permissions_valid, error)) {
+		g_strfreev (strv);
 		return FALSE;
+	}
 
 	for (i = 0; strv && strv[i]; i++) {
-		const char *user = strv[i];
+		const char *user;
+
+		if (strncmp (strv[i], PERM_USER_PREFIX, strlen (PERM_USER_PREFIX)) == 0)
+			user = strv[i]+strlen (PERM_USER_PREFIX);
+		else
+			user = strv[i];
 
-		if (strncmp (user, PERM_USER_PREFIX, NM_STRLEN (PERM_USER_PREFIX)) == 0)
-			user += NM_STRLEN (PERM_USER_PREFIX);
 		nm_setting_connection_add_permission (NM_SETTING_CONNECTION (setting), "user", user, NULL);
 	}
 
@@ -2541,7 +2549,7 @@ DEFINE_REMOVER_INDEX_OR_VALUE (_remove_fcn_connection_permissions,
 static gboolean
 _set_fcn_connection_master (ARGS_SET_FCN)
 {
-	nm_assert (!error || !*error);
+	g_return_val_if_fail (error == NULL || *error == NULL, FALSE);
 
 	if (!value)
 		;
@@ -2627,13 +2635,15 @@ _complete_fcn_connection_master (ARGS_COMPLETE_FCN)
 static gboolean
 _set_fcn_connection_secondaries (ARGS_SET_FCN)
 {
-	gs_free const char **strv = NULL;
-	const char *const*iter;
+	gs_strfreev char **strv = NULL;
+	char **iter;
 
-	strv = nm_utils_strsplit_set (value, " \t,");
+	strv = nmc_strsplit_set (value, " \t,", 0);
 	if (strv) {
-		for (iter = strv; *iter; iter++)
-			nm_setting_connection_add_secondary (NM_SETTING_CONNECTION (setting), *iter);
+		for (iter = strv; *iter; iter++) {
+			if (**iter)
+				nm_setting_connection_add_secondary (NM_SETTING_CONNECTION (setting), *iter);
+		}
 	}
 	return TRUE;
 }
@@ -2680,11 +2690,9 @@ _get_fcn_connection_metered (ARGS_GET_FCN)
 		break;
 	case NM_METERED_UNKNOWN:
 	default:
-		NM_SET_OUT (out_is_default, TRUE);
 		s = N_("unknown");
 		break;
 	}
-
 	if (get_type == NM_META_ACCESSOR_GET_TYPE_PRETTY)
 		return _(s);
 	return s;
@@ -2822,21 +2830,19 @@ DEFINE_DCB_UINT_GETTER (_get_fcn_dcb_priority_traffic_class, nm_setting_dcb_get_
 static gboolean
 _set_fcn_dcb_flags (ARGS_SET_FCN)
 {
+	char **strv = NULL, **iter;
 	NMSettingDcbFlags flags = NM_SETTING_DCB_FLAG_NONE;
 	long int t;
 
-	nm_assert (!error || !*error);
+	g_return_val_if_fail (error == NULL || *error == NULL, FALSE);
 
 	/* Check for overall hex numeric value */
 	t = _nm_utils_ascii_str_to_int64 (value, 0, 0, DCB_ALL_FLAGS, -1);
 	if (t != -1)
 		flags = (guint) t;
 	else {
-		gs_free const char **strv = NULL;
-		const char *const*iter;
-
 		/* Check for individual flag numbers */
-		strv = nm_utils_strsplit_set (value, " \t,");
+		strv = nmc_strsplit_set (value, " \t,", 0);
 		for (iter = strv; iter && *iter; iter++) {
 			t = _nm_utils_ascii_str_to_int64 (*iter, 0, 0, DCB_ALL_FLAGS, -1);
 
@@ -2859,6 +2865,7 @@ _set_fcn_dcb_flags (ARGS_SET_FCN)
 				return FALSE;
 			}
 		}
+		g_strfreev (strv);
 	}
 
 	/* Validate the flags according to the property spec */
@@ -2935,7 +2942,7 @@ _set_fcn_dcb_priority_flow_control (ARGS_SET_FCN)
 	guint i = 0;
 	guint nums[8] = { 0, 0, 0, 0, 0, 0, 0, 0 };
 
-	nm_assert (!error || !*error);
+	g_return_val_if_fail (error == NULL || *error == NULL, FALSE);
 
 	if (!dcb_parse_uint_array (value, 1, 0, nums, error))
 		return FALSE;
@@ -2953,7 +2960,7 @@ _set_fcn_dcb_priority_group_id (ARGS_SET_FCN)
 	guint i = 0;
 	guint nums[8] = { 0, 0, 0, 0, 0, 0, 0, 0 };
 
-	nm_assert (!error || !*error);
+	g_return_val_if_fail (error == NULL || *error == NULL, FALSE);
 
 	if (!dcb_parse_uint_array (value, 7, 15, nums, error))
 		return FALSE;
@@ -2971,7 +2978,7 @@ _set_fcn_dcb_priority_group_bandwidth (ARGS_SET_FCN)
 	guint i = 0, sum = 0;
 	guint nums[8] = { 0, 0, 0, 0, 0, 0, 0, 0 };
 
-	nm_assert (!error || !*error);
+	g_return_val_if_fail (error == NULL || *error == NULL, FALSE);
 
 	if (!dcb_parse_uint_array (value, 100, 0, nums, error))
 		return FALSE;
@@ -2996,7 +3003,7 @@ _set_fcn_dcb_priority_bandwidth (ARGS_SET_FCN)
 	guint i = 0;
 	guint nums[8] = { 0, 0, 0, 0, 0, 0, 0, 0 };
 
-	nm_assert (!error || !*error);
+	g_return_val_if_fail (error == NULL || *error == NULL, FALSE);
 
 	if (!dcb_parse_uint_array (value, 100, 0, nums, error))
 		return FALSE;
@@ -3014,7 +3021,7 @@ _set_fcn_dcb_priority_strict (ARGS_SET_FCN)
 	guint i = 0;
 	guint nums[8] = { 0, 0, 0, 0, 0, 0, 0, 0 };
 
-	nm_assert (!error || !*error);
+	g_return_val_if_fail (error == NULL || *error == NULL, FALSE);
 
 	if (!dcb_parse_uint_array (value, 1, 0, nums, error))
 		return FALSE;
@@ -3032,7 +3039,7 @@ _set_fcn_dcb_priority_traffic_class (ARGS_SET_FCN)
 	guint i = 0;
 	guint nums[8] = { 0, 0, 0, 0, 0, 0, 0, 0 };
 
-	nm_assert (!error || !*error);
+	g_return_val_if_fail (error == NULL || *error == NULL, FALSE);
 
 	if (!dcb_parse_uint_array (value, 7, 0, nums, error))
 		return FALSE;
@@ -3049,7 +3056,7 @@ _set_fcn_gsm_sim_operator_id (ARGS_SET_FCN)
 {
 	const char *p = value;
 
-	nm_assert (!error || !*error);
+	g_return_val_if_fail (error == NULL || *error == NULL, FALSE);
 
 	if (strlen (value) != 5 && strlen (value) != 6) {
 		g_set_error_literal (error, 1, 0, _("SIM operator ID must be a 5 or 6 number MCCMNC code"));
@@ -3075,7 +3082,7 @@ _set_fcn_infiniband_p_key (ARGS_SET_FCN)
 	const gint64 INVALID = G_MININT64;
 	gint64 p_key;
 
-	nm_assert (!error || !*error);
+	g_return_val_if_fail (error == NULL || *error == NULL, FALSE);
 
 	if (nm_streq (value, "default"))
 		p_key = -1;
@@ -3102,14 +3109,12 @@ _get_fcn_infiniband_p_key (ARGS_GET_FCN)
 
 	p_key = nm_setting_infiniband_get_p_key (s_infiniband);
 	if (p_key == -1) {
-		NM_SET_OUT (out_is_default, TRUE);
 		if (get_type != NM_META_ACCESSOR_GET_TYPE_PRETTY)
 			return "default";
 		else
 			return _("default");
-	}
-
-	RETURN_STR_TO_FREE (g_strdup_printf ("0x%04x", p_key));
+	} else
+		RETURN_STR_TO_FREE (g_strdup_printf ("0x%04x", p_key));
 }
 
 static gconstpointer
@@ -3136,7 +3141,6 @@ _get_fcn_ip_config_addresses (ARGS_GET_FCN)
 		                        nm_ip_address_get_prefix (addr));
 	}
 
-	NM_SET_OUT (out_is_default, num_addresses == 0);
 	RETURN_STR_TO_FREE (g_string_free (printable, FALSE));
 }
 
@@ -3208,7 +3212,6 @@ _get_fcn_ip_config_routes (ARGS_GET_FCN)
 		}
 	}
 
-	NM_SET_OUT (out_is_default, num_routes == 0);
 	RETURN_STR_TO_FREE (g_string_free (printable, FALSE));
 }
 
@@ -3234,22 +3237,22 @@ _set_fcn_ip4_config_method (ARGS_SET_FCN)
 static gboolean
 _set_fcn_ip4_config_dns (ARGS_SET_FCN)
 {
-	const char **strv = NULL;
-	const char *const*iter;
-	in_addr_t ip4_addr;
+	char **strv = NULL, **iter, *addr;
+	guint32 ip4_addr;
 
-	nm_assert (!error || !*error);
+	g_return_val_if_fail (error == NULL || *error == NULL, FALSE);
 
-	strv = nm_utils_strsplit_set (value, " \t,");
+	strv = nmc_strsplit_set (value, " \t,", 0);
 	for (iter = strv; iter && *iter; iter++) {
-		gs_free char *addr = g_strstrip (g_strdup (*iter));
-
+		addr = g_strstrip (*iter);
 		if (inet_pton (AF_INET, addr, &ip4_addr) < 1) {
 			g_set_error (error, 1, 0, _("invalid IPv4 address '%s'"), addr);
+			g_strfreev (strv);
 			return FALSE;
 		}
 		nm_setting_ip_config_add_dns (NM_SETTING_IP_CONFIG (setting), addr);
 	}
+	g_strfreev (strv);
 	return TRUE;
 }
 
@@ -3280,19 +3283,21 @@ DEFINE_REMOVER_INDEX_OR_VALUE (_remove_fcn_ipv4_config_dns,
 static gboolean
 _set_fcn_ip4_config_dns_search (ARGS_SET_FCN)
 {
-	gs_free const char **strv = NULL;
-	gsize i;
+	char **strv = NULL;
+	guint i = 0;
 
-	nm_assert (!error || !*error);
+	g_return_val_if_fail (error == NULL || *error == NULL, FALSE);
 
-	strv = nm_utils_strsplit_set (value, " \t,");
-	if (!verify_string_list (strv, property_info->property_name, nmc_util_is_domain, error))
+	strv = nmc_strsplit_set (value, " \t,", 0);
+	if (!verify_string_list (strv, property_info->property_name, nmc_util_is_domain, error)) {
+		g_strfreev (strv);
 		return FALSE;
-
-	if (strv) {
-		for (i = 0; strv[i]; i++)
-			nm_setting_ip_config_add_dns_search (NM_SETTING_IP_CONFIG (setting), strv[i]);
 	}
+
+	while (strv && strv[i])
+		nm_setting_ip_config_add_dns_search (NM_SETTING_IP_CONFIG (setting), strv[i++]);
+	g_strfreev (strv);
+
 	return TRUE;
 }
 
@@ -3319,17 +3324,17 @@ DEFINE_REMOVER_INDEX_OR_VALUE (_remove_fcn_ipv4_config_dns_search,
 static gboolean
 _set_fcn_ip4_config_dns_options (ARGS_SET_FCN)
 {
-	gs_free const char **strv = NULL;
-	gsize i;
+	char **strv = NULL;
+	guint i = 0;
 
-	nm_assert (!error || !*error);
+	g_return_val_if_fail (error == NULL || *error == NULL, FALSE);
 
 	nm_setting_ip_config_clear_dns_options (NM_SETTING_IP_CONFIG (setting), TRUE);
-	strv = nm_utils_strsplit_set (value, " \t,");
-	if (strv) {
-		for (i = 0; strv[i]; i++)
-			nm_setting_ip_config_add_dns_option (NM_SETTING_IP_CONFIG (setting), strv[i]);
-	}
+	strv = nmc_strsplit_set (value, " \t,", 0);
+	while (strv && strv[i])
+		nm_setting_ip_config_add_dns_option (NM_SETTING_IP_CONFIG (setting), strv[i++]);
+	g_strfreev (strv);
+
 	return TRUE;
 }
 
@@ -3356,12 +3361,12 @@ DEFINE_REMOVER_INDEX_OR_VALUE (_remove_fcn_ipv4_config_dns_options,
 static gboolean
 _set_fcn_ip4_config_addresses (ARGS_SET_FCN)
 {
-	gs_free const char **strv = NULL;
+	gs_strfreev char **strv = NULL;
 	const char *const*iter;
 	NMIPAddress *ip4addr;
 
-	strv = nm_utils_strsplit_set (value, ",");
-	for (iter = strv; *iter; iter++) {
+	strv = nmc_strsplit_set (value, ",", 0);
+	for (iter = (const char *const*) strv; *iter; iter++) {
 		ip4addr = _parse_ip_address (AF_INET, *iter, error);
 		if (!ip4addr)
 			return FALSE;
@@ -3416,12 +3421,12 @@ _set_fcn_ip4_config_gateway (ARGS_SET_FCN)
 static gboolean
 _set_fcn_ip4_config_routes (ARGS_SET_FCN)
 {
-	gs_free const char **strv = NULL;
+	gs_strfreev char **strv = NULL;
 	const char *const*iter;
 	NMIPRoute *ip4route;
 
-	strv = nm_utils_strsplit_set (value, ",");
-	for (iter = strv; *iter; iter++) {
+	strv = nmc_strsplit_set (value, ",", 0);
+	for (iter = (const char *const*) strv; *iter; iter++) {
 		ip4route = _parse_ip_route (AF_INET, *iter, error);
 		if (!ip4route)
 			return FALSE;
@@ -3455,6 +3460,14 @@ DEFINE_REMOVER_INDEX_OR_VALUE (_remove_fcn_ipv4_config_routes,
                                nm_setting_ip_config_remove_route,
                                _validate_and_remove_ipv4_route)
 
+static gconstpointer
+_get_fcn_ip6_config_ip6_privacy (ARGS_GET_FCN)
+{
+	NMSettingIP6Config *s_ip6 = NM_SETTING_IP6_CONFIG (setting);
+	RETURN_UNSUPPORTED_GET_TYPE ();
+	RETURN_STR_TO_FREE (ip6_privacy_to_string (nm_setting_ip6_config_get_ip6_privacy (s_ip6), get_type));
+}
+
 static const char *ipv6_valid_methods[] = {
 	NM_SETTING_IP6_CONFIG_METHOD_IGNORE,
 	NM_SETTING_IP6_CONFIG_METHOD_AUTO,
@@ -3478,22 +3491,22 @@ _set_fcn_ip6_config_method (ARGS_SET_FCN)
 static gboolean
 _set_fcn_ip6_config_dns (ARGS_SET_FCN)
 {
-	gs_free const char **strv = NULL;
-	const char *const*iter;
+	char **strv = NULL, **iter, *addr;
 	struct in6_addr ip6_addr;
 
-	nm_assert (!error || !*error);
+	g_return_val_if_fail (error == NULL || *error == NULL, FALSE);
 
-	strv = nm_utils_strsplit_set (value, " \t,");
+	strv = nmc_strsplit_set (value, " \t,", 0);
 	for (iter = strv; iter && *iter; iter++) {
-		gs_free char *addr  = g_strstrip (g_strdup (*iter));
-
+		addr = g_strstrip (*iter);
 		if (inet_pton (AF_INET6, addr, &ip6_addr) < 1) {
 			g_set_error (error, 1, 0, _("invalid IPv6 address '%s'"), addr);
+			g_strfreev (strv);
 			return FALSE;
 		}
 		nm_setting_ip_config_add_dns (NM_SETTING_IP_CONFIG (setting), addr);
 	}
+	g_strfreev (strv);
 	return TRUE;
 }
 
@@ -3524,19 +3537,21 @@ DEFINE_REMOVER_INDEX_OR_VALUE (_remove_fcn_ipv6_config_dns,
 static gboolean
 _set_fcn_ip6_config_dns_search (ARGS_SET_FCN)
 {
-	gs_free const char **strv = NULL;
-	gsize i;
+	char **strv = NULL;
+	guint i = 0;
 
-	nm_assert (!error || !*error);
+	g_return_val_if_fail (error == NULL || *error == NULL, FALSE);
 
-	strv = nm_utils_strsplit_set (value, " \t,");
-	if (!verify_string_list (strv, property_info->property_name, nmc_util_is_domain, error))
+	strv = nmc_strsplit_set (value, " \t,", 0);
+	if (!verify_string_list (strv, property_info->property_name, nmc_util_is_domain, error)) {
+		g_strfreev (strv);
 		return FALSE;
-
-	if (strv) {
-		for (i = 0; strv[i]; i++)
-			nm_setting_ip_config_add_dns_search (NM_SETTING_IP_CONFIG (setting), strv[i]);
 	}
+
+	while (strv && strv[i])
+		nm_setting_ip_config_add_dns_search (NM_SETTING_IP_CONFIG (setting), strv[i++]);
+	g_strfreev (strv);
+
 	return TRUE;
 }
 
@@ -3563,17 +3578,17 @@ DEFINE_REMOVER_INDEX_OR_VALUE (_remove_fcn_ipv6_config_dns_search,
 static gboolean
 _set_fcn_ip6_config_dns_options (ARGS_SET_FCN)
 {
-	gs_free const char **strv = NULL;
-	gsize i;
+	char **strv = NULL;
+	guint i = 0;
 
-	nm_assert (!error || !*error);
+	g_return_val_if_fail (error == NULL || *error == NULL, FALSE);
 
 	nm_setting_ip_config_clear_dns_options (NM_SETTING_IP_CONFIG (setting), TRUE);
-	strv = nm_utils_strsplit_set (value, " \t,");
-	if (strv) {
-		for (i = 0; strv[i]; i++)
-			nm_setting_ip_config_add_dns_option (NM_SETTING_IP_CONFIG (setting), strv[i]);
-	}
+	strv = nmc_strsplit_set (value, " \t,", 0);
+	while (strv && strv[i])
+		nm_setting_ip_config_add_dns_option (NM_SETTING_IP_CONFIG (setting), strv[i++]);
+	g_strfreev (strv);
+
 	return TRUE;
 }
 
@@ -3607,12 +3622,12 @@ _dns_options_is_default (NMSettingIPConfig *setting)
 static gboolean
 _set_fcn_ip6_config_addresses (ARGS_SET_FCN)
 {
-	gs_free const char **strv = NULL;
+	gs_strfreev char **strv = NULL;
 	const char *const*iter;
 	NMIPAddress *ip6addr;
 
-	strv = nm_utils_strsplit_set (value, ",");
-	for (iter = strv; strv && *iter; iter++) {
+	strv = nmc_strsplit_set (value, ",", 0);
+	for (iter = (const char *const*) strv; *iter; iter++) {
 		ip6addr = _parse_ip_address (AF_INET6, *iter, error);
 		if (!ip6addr)
 			return FALSE;
@@ -3667,12 +3682,12 @@ _set_fcn_ip6_config_gateway (ARGS_SET_FCN)
 static gboolean
 _set_fcn_ip6_config_routes (ARGS_SET_FCN)
 {
-	gs_free const char **strv = NULL;
+	gs_strfreev char **strv = NULL;
 	const char *const*iter;
 	NMIPRoute *ip6route;
 
-	strv = nm_utils_strsplit_set (value, ",");
-	for (iter = strv; strv && *iter; iter++) {
+	strv = nmc_strsplit_set (value, ",", 0);
+	for (iter = (const char *const*) strv; *iter; iter++) {
 		ip6route = _parse_ip_route (AF_INET6, *iter, error);
 		if (!ip6route)
 			return FALSE;
@@ -3706,6 +3721,29 @@ DEFINE_REMOVER_INDEX_OR_VALUE (_remove_fcn_ipv6_config_routes,
                                nm_setting_ip_config_remove_route,
                                _validate_and_remove_ipv6_route)
 
+static gboolean
+_set_fcn_ip6_config_ip6_privacy (ARGS_SET_FCN)
+{
+	unsigned long val_int;
+
+	g_return_val_if_fail (error == NULL || *error == NULL, FALSE);
+
+	if (!nmc_string_to_uint (value, FALSE, 0, 0, &val_int)) {
+		g_set_error (error, 1, 0, _("'%s' is not a number"), value);
+		return FALSE;
+	}
+
+	if (   val_int != NM_SETTING_IP6_CONFIG_PRIVACY_DISABLED
+	    && val_int != NM_SETTING_IP6_CONFIG_PRIVACY_PREFER_PUBLIC_ADDR
+	    && val_int != NM_SETTING_IP6_CONFIG_PRIVACY_PREFER_TEMP_ADDR) {
+		g_set_error (error, 1, 0, _("'%s' is not valid; use 0, 1, or 2"), value);
+		return FALSE;
+	}
+
+	g_object_set (setting, property_info->property_name, val_int, NULL);
+	return TRUE;
+}
+
 static gconstpointer
 _get_fcn_olpc_mesh_ssid (ARGS_GET_FCN)
 {
@@ -3721,7 +3759,6 @@ _get_fcn_olpc_mesh_ssid (ARGS_GET_FCN)
 		                                  g_bytes_get_size (ssid));
 	}
 
-	NM_SET_OUT (out_is_default, !ssid_str);
 	RETURN_STR_TO_FREE (ssid_str);
 }
 
@@ -3730,7 +3767,7 @@ _set_fcn_olpc_mesh_channel (ARGS_SET_FCN)
 {
 	unsigned long chan_int;
 
-	nm_assert (!error || !*error);
+	g_return_val_if_fail (error == NULL || *error == NULL, FALSE);
 
 	if (!nmc_string_to_uint (value, TRUE, 1, 13, &chan_int)) {
 		g_set_error (error, 1, 0, _("'%s' is not a valid channel; use <1-13>"), value);
@@ -3777,7 +3814,6 @@ _get_fcn_tc_config_qdiscs (ARGS_GET_FCN)
 		}
 	}
 
-	NM_SET_OUT (out_is_default, num_qdiscs == 0);
 	RETURN_STR_TO_FREE (g_string_free (printable, FALSE));
 }
 
@@ -3854,7 +3890,6 @@ _get_fcn_tc_config_tfilters (ARGS_GET_FCN)
 		}
 	}
 
-	NM_SET_OUT (out_is_default, num_tfilters == 0);
 	RETURN_STR_TO_FREE (g_string_free (printable, FALSE));
 }
 
@@ -3934,15 +3969,18 @@ _is_valid_team_runner_tx_hash_element (const char *tx_hash_element,
 static gboolean
 _set_fcn_team_runner_tx_hash (ARGS_SET_FCN)
 {
-	gs_free const char **strv = NULL;
-	const char *const*iter;
+	char **strv = NULL;
+	char *const*iter;
 
-	nm_assert (!error || !*error);
+	g_return_val_if_fail (error == NULL || *error == NULL, FALSE);
 
-	strv = nm_utils_strsplit_set (value, " \t,");
+	strv = _nm_utils_strv_cleanup (g_strsplit_set (value, " \t,", 0),
+	                               TRUE, TRUE, TRUE);
 	for (iter = strv; strv && *iter; iter++) {
-		if (!_is_valid_team_runner_tx_hash_element (*iter, error))
+		if (!_is_valid_team_runner_tx_hash_element (*iter, error)) {
+			g_strfreev (strv);
 			return FALSE;
+		}
 	}
 
 	while (nm_setting_team_get_num_runner_tx_hash (NM_SETTING_TEAM (setting)))
@@ -3950,6 +3988,7 @@ _set_fcn_team_runner_tx_hash (ARGS_SET_FCN)
 
 	for (iter = strv; strv && *iter; iter++)
 		nm_setting_team_add_runner_tx_hash (NM_SETTING_TEAM (setting), *iter);
+	g_strfreev (strv);
 
 	return TRUE;
 }
@@ -3999,20 +4038,19 @@ _get_fcn_team_link_watchers (ARGS_GET_FCN)
 		}
 	}
 
-	NM_SET_OUT (out_is_default, num_watchers == 0);
 	RETURN_STR_TO_FREE (g_string_free (printable, FALSE));
 }
 
 static gboolean
 _set_fcn_team_link_watchers (ARGS_SET_FCN)
 {
-	gs_free const char **strv = NULL;
+	gs_strfreev char **strv = NULL;
 	const char *const*iter;
 	NMTeamLinkWatcher *watcher;
 
 	nm_setting_team_clear_link_watchers (NM_SETTING_TEAM (setting));
-	strv = nm_utils_strsplit_set (value, ",");
-	for (iter = strv; strv && *iter; iter++) {
+	strv = nmc_strsplit_set (value, ",", 0);
+	for (iter = (const char *const*) strv; *iter; iter++) {
 		watcher = _parse_team_link_watcher (*iter, error);
 		if (!watcher)
 			return FALSE;
@@ -4073,20 +4111,19 @@ _get_fcn_team_port_link_watchers (ARGS_GET_FCN)
 		}
 	}
 
-	NM_SET_OUT (out_is_default, num_watchers == 0);
 	RETURN_STR_TO_FREE (g_string_free (printable, FALSE));
 }
 
 static gboolean
 _set_fcn_team_port_link_watchers (ARGS_SET_FCN)
 {
-	gs_free const char **strv = NULL;
+	gs_strfreev char **strv = NULL;
 	const char *const*iter;
 	NMTeamLinkWatcher *watcher;
 
 	nm_setting_team_port_clear_link_watchers (NM_SETTING_TEAM_PORT (setting));
-	strv = nm_utils_strsplit_set (value, ",");
-	for (iter = strv; strv && *iter; iter++) {
+	strv = nmc_strsplit_set (value, ",", 0);
+	for (iter = (const char *const*) strv; *iter; iter++) {
 		watcher = _parse_team_link_watcher (*iter, error);
 		if (!watcher)
 			return FALSE;
@@ -4126,39 +4163,24 @@ static gconstpointer
 _get_fcn_vlan_flags (ARGS_GET_FCN)
 {
 	NMSettingVlan *s_vlan = NM_SETTING_VLAN (setting);
-	guint32 flags;
-
 	RETURN_UNSUPPORTED_GET_TYPE ();
-
-	flags = nm_setting_vlan_get_flags (s_vlan);
-	NM_SET_OUT (out_is_default, flags == 0);
-	RETURN_STR_TO_FREE (vlan_flags_to_string (flags, get_type));
+	RETURN_STR_TO_FREE (vlan_flags_to_string (nm_setting_vlan_get_flags (s_vlan), get_type));
 }
 
 static gconstpointer
 _get_fcn_vlan_ingress_priority_map (ARGS_GET_FCN)
 {
 	NMSettingVlan *s_vlan = NM_SETTING_VLAN (setting);
-	char *str;
-
 	RETURN_UNSUPPORTED_GET_TYPE ();
-
-	str = vlan_priorities_to_string (s_vlan, NM_VLAN_INGRESS_MAP);
-	NM_SET_OUT (out_is_default, !str || !str[0]);
-	RETURN_STR_TO_FREE (str);
+	RETURN_STR_TO_FREE (vlan_priorities_to_string (s_vlan, NM_VLAN_INGRESS_MAP));
 }
 
 static gconstpointer
 _get_fcn_vlan_egress_priority_map (ARGS_GET_FCN)
 {
 	NMSettingVlan *s_vlan = NM_SETTING_VLAN (setting);
-	char *str;
-
 	RETURN_UNSUPPORTED_GET_TYPE ();
-
-	str = vlan_priorities_to_string (s_vlan, NM_VLAN_EGRESS_MAP);
-	NM_SET_OUT (out_is_default, !str || !str[0]);
-	RETURN_STR_TO_FREE (str);
+	RETURN_STR_TO_FREE (vlan_priorities_to_string (s_vlan, NM_VLAN_EGRESS_MAP));
 }
 
 static gboolean
@@ -4281,7 +4303,7 @@ _get_fcn_vpn_data (ARGS_GET_FCN)
 
 	data_item_str = g_string_new (NULL);
 	nm_setting_vpn_foreach_data_item (s_vpn, &vpn_data_item, data_item_str);
-	NM_SET_OUT (out_is_default, data_item_str->len == 0);
+
 	RETURN_STR_TO_FREE (g_string_free (data_item_str, FALSE));
 }
 
@@ -4295,7 +4317,7 @@ _get_fcn_vpn_secrets (ARGS_GET_FCN)
 
 	secret_str = g_string_new (NULL);
 	nm_setting_vpn_foreach_secret (s_vpn, &vpn_data_item, secret_str);
-	NM_SET_OUT (out_is_default, secret_str->len == 0);
+
 	RETURN_STR_TO_FREE (g_string_free (secret_str, FALSE));
 }
 
@@ -4362,18 +4384,20 @@ DEFINE_REMOVER_INDEX_OR_VALUE (_remove_fcn_wired_mac_address_blacklist,
 static gboolean
 _set_fcn_wired_s390_subchannels (ARGS_SET_FCN)
 {
-	gs_free const char **strv = NULL;
-	gsize len;
+	char **strv = NULL;
+	int len;
 
-	strv = nm_utils_strsplit_set (value, " ,\t");
-	len = NM_PTRARRAY_LEN (strv);
+	strv = nmc_strsplit_set (value, " ,\t", 0);
+	len = g_strv_length (strv);
 	if (len != 2 && len != 3) {
 		g_set_error (error, 1, 0, _("'%s' is not valid; 2 or 3 strings should be provided"),
 		             value);
+		g_strfreev (strv);
 		return FALSE;
 	}
 
 	g_object_set (setting, property_info->property_name, strv, NULL);
+	g_strfreev (strv);
 	return TRUE;
 }
 
@@ -4437,7 +4461,6 @@ _get_fcn_wireless_ssid (ARGS_GET_FCN)
 		                                  g_bytes_get_size (ssid));
 	}
 
-	NM_SET_OUT (out_is_default, !ssid_str || !ssid_str[0]);
 	RETURN_STR_TO_FREE (ssid_str);
 }
 
@@ -4446,7 +4469,7 @@ _set_fcn_wireless_channel (ARGS_SET_FCN)
 {
 	unsigned long chan_int;
 
-	nm_assert (!error || !*error);
+	g_return_val_if_fail (error == NULL || *error == NULL, FALSE);
 
 	if (!nmc_string_to_uint (value, FALSE, 0, 0, &chan_int)) {
 		g_set_error (error, 1, 0, _("'%s' is not a valid channel"), value);
@@ -4492,23 +4515,39 @@ DEFINE_REMOVER_INDEX_OR_VALUE (_remove_fcn_wireless_mac_address_blacklist,
                                _validate_and_remove_wifi_mac_blacklist_item)
 
 static gconstpointer
-_get_fcn_wireless_security_wep_key (ARGS_GET_FCN)
+_get_fcn_wireless_security_wep_key0 (ARGS_GET_FCN)
 {
 	NMSettingWirelessSecurity *s_wireless_sec = NM_SETTING_WIRELESS_SECURITY (setting);
-	char *key;
-	guint index;
 
 	RETURN_UNSUPPORTED_GET_TYPE ();
+	RETURN_STR_TO_FREE (g_strdup (nm_setting_wireless_security_get_wep_key (s_wireless_sec, 0)));
+}
 
-	nm_assert (g_str_has_prefix (property_info->property_name, "wep-key"));
-	nm_assert (NM_IN_SET (property_info->property_name[7], '0', '1', '2', '3'));
-	nm_assert (property_info->property_name[8] == '\0');
+static gconstpointer
+_get_fcn_wireless_security_wep_key1 (ARGS_GET_FCN)
+{
+	NMSettingWirelessSecurity *s_wireless_sec = NM_SETTING_WIRELESS_SECURITY (setting);
+
+	RETURN_UNSUPPORTED_GET_TYPE ();
+	RETURN_STR_TO_FREE (g_strdup (nm_setting_wireless_security_get_wep_key (s_wireless_sec, 1)));
+}
 
-	index = property_info->property_name[7] - '0';
+static gconstpointer
+_get_fcn_wireless_security_wep_key2 (ARGS_GET_FCN)
+{
+	NMSettingWirelessSecurity *s_wireless_sec = NM_SETTING_WIRELESS_SECURITY (setting);
 
-	key = g_strdup (nm_setting_wireless_security_get_wep_key (s_wireless_sec, index));
-	NM_SET_OUT (out_is_default, !key);
-	RETURN_STR_TO_FREE (key);
+	RETURN_UNSUPPORTED_GET_TYPE ();
+	RETURN_STR_TO_FREE (g_strdup (nm_setting_wireless_security_get_wep_key (s_wireless_sec, 2)));
+}
+
+static gconstpointer
+_get_fcn_wireless_security_wep_key3 (ARGS_GET_FCN)
+{
+	NMSettingWirelessSecurity *s_wireless_sec = NM_SETTING_WIRELESS_SECURITY (setting);
+
+	RETURN_UNSUPPORTED_GET_TYPE ();
+	RETURN_STR_TO_FREE (g_strdup (nm_setting_wireless_security_get_wep_key (s_wireless_sec, 3)));
 }
 
 static const char *wifi_sec_valid_protos[] = { "wpa", "rsn", NULL };
@@ -4626,7 +4665,7 @@ _set_fcn_wireless_wep_key (ARGS_SET_FCN)
 	NMWepKeyType type;
 	guint32 prev_idx, idx;
 
-	nm_assert (!error || !*error);
+	g_return_val_if_fail (error == NULL || *error == NULL, FALSE);
 
 	/* Get currently set type */
 	type = nm_setting_wireless_security_get_wep_key_type (NM_SETTING_WIRELESS_SECURITY (setting));
@@ -4859,8 +4898,7 @@ static const NMMetaPropertyType _pt_gobject_mac = {
 
 static const NMMetaPropertyType _pt_gobject_secret_flags = {
 	.get_fcn =                      _get_fcn_gobject_secret_flags,
-	.set_fcn =                      _set_fcn_gobject_enum,
-	.values_fcn =                   _values_fcn_gobject_enum,
+	.set_fcn =                      _set_fcn_gobject_secret_flags,
 };
 
 static const NMMetaPropertyType _pt_gobject_enum = {
@@ -4877,7 +4915,7 @@ static const NMMetaPropertyType _pt_gobject_devices = {
 
 /*****************************************************************************/
 
-#include "settings-docs.h"
+#include "settings-docs.c"
 
 /*****************************************************************************/
 
@@ -5565,14 +5603,6 @@ static const NMMetaPropertyInfo *const property_infos_CONNECTION[] = {
 			                            | NM_META_PROPERTY_TYP_FLAG_ENUM_GET_PRETTY_TEXT,
 		),
 	),
-	PROPERTY_INFO_WITH_DESC (NM_SETTING_CONNECTION_MDNS,
-		.property_type =                &_pt_gobject_enum,
-		.property_typ_data = DEFINE_PROPERTY_TYP_DATA (
-			PROPERTY_TYP_DATA_SUBTYPE (gobject_enum,
-				.get_gtype =            nm_setting_connection_mdns_get_type,
-			),
-		),
-	),
 	NULL
 };
 
@@ -6055,18 +6085,9 @@ static const NMMetaPropertyInfo *const property_infos_IP6_CONFIG[] = {
 		.property_type =                &_pt_gobject_bool,
 	),
 	PROPERTY_INFO_WITH_DESC (NM_SETTING_IP6_CONFIG_IP6_PRIVACY,
-		.property_type =                &_pt_gobject_enum,
-		.property_typ_data = DEFINE_PROPERTY_TYP_DATA_SUBTYPE (gobject_enum,
-			.value_infos_get =          ENUM_VALUE_INFOS (
-				{
-					.value = NM_SETTING_IP6_CONFIG_PRIVACY_PREFER_PUBLIC_ADDR,
-					.nick = "enabled, prefer public IP",
-				},
-				{
-					.value = NM_SETTING_IP6_CONFIG_PRIVACY_PREFER_TEMP_ADDR,
-					.nick = "enabled, prefer temporary IP",
-				}
-			),
+		.property_type = DEFINE_PROPERTY_TYPE (
+			.get_fcn =                  _get_fcn_ip6_config_ip6_privacy,
+			.set_fcn =                  _set_fcn_ip6_config_ip6_privacy,
 		),
 	),
 	PROPERTY_INFO_WITH_DESC (NM_SETTING_IP6_CONFIG_ADDR_GEN_MODE,
@@ -6153,14 +6174,6 @@ static const NMMetaPropertyInfo *const property_infos_IP_TUNNEL[] = {
 	PROPERTY_INFO_WITH_DESC (NM_SETTING_IP_TUNNEL_MTU,
 		.property_type =                &_pt_gobject_mtu,
 	),
-	PROPERTY_INFO_WITH_DESC (NM_SETTING_IP_TUNNEL_FLAGS,
-		.property_type =                &_pt_gobject_enum,
-		.property_typ_data = DEFINE_PROPERTY_TYP_DATA (
-			PROPERTY_TYP_DATA_SUBTYPE (gobject_enum,
-				.get_gtype =            nm_ip_tunnel_flags_get_type,
-			),
-		),
-	),
 	NULL
 };
 
@@ -7323,28 +7336,28 @@ static const NMMetaPropertyInfo *const property_infos_WIRELESS_SECURITY[] = {
 	PROPERTY_INFO_WITH_DESC (NM_SETTING_WIRELESS_SECURITY_WEP_KEY0,
 		.is_secret =                    TRUE,
 		.property_type = DEFINE_PROPERTY_TYPE (
-			.get_fcn =                  _get_fcn_wireless_security_wep_key,
+			.get_fcn =                  _get_fcn_wireless_security_wep_key0,
 			.set_fcn =                  _set_fcn_wireless_wep_key,
 		),
 	),
 	PROPERTY_INFO_WITH_DESC (NM_SETTING_WIRELESS_SECURITY_WEP_KEY1,
 		.is_secret =                    TRUE,
 		.property_type = DEFINE_PROPERTY_TYPE (
-			.get_fcn =                  _get_fcn_wireless_security_wep_key,
+			.get_fcn =                  _get_fcn_wireless_security_wep_key1,
 			.set_fcn =                  _set_fcn_wireless_wep_key,
 		),
 	),
 	PROPERTY_INFO_WITH_DESC (NM_SETTING_WIRELESS_SECURITY_WEP_KEY2,
 		.is_secret =                    TRUE,
 		.property_type = DEFINE_PROPERTY_TYPE (
-			.get_fcn =                  _get_fcn_wireless_security_wep_key,
+			.get_fcn =                  _get_fcn_wireless_security_wep_key2,
 			.set_fcn =                  _set_fcn_wireless_wep_key,
 		),
 	),
 	PROPERTY_INFO_WITH_DESC (NM_SETTING_WIRELESS_SECURITY_WEP_KEY3,
 		.is_secret =                    TRUE,
 		.property_type = DEFINE_PROPERTY_TYPE (
-			.get_fcn =                  _get_fcn_wireless_security_wep_key,
+			.get_fcn =                  _get_fcn_wireless_security_wep_key3,
 			.set_fcn =                  _set_fcn_wireless_wep_key,
 		),
 	),
@@ -7389,14 +7402,6 @@ static const NMMetaPropertyInfo *const property_infos_WIRELESS_SECURITY[] = {
 			),
 		),
 	),
-	PROPERTY_INFO_WITH_DESC (NM_SETTING_WIRELESS_SECURITY_FILS,
-		.property_type =                &_pt_gobject_enum,
-		.property_typ_data = DEFINE_PROPERTY_TYP_DATA (
-			PROPERTY_TYP_DATA_SUBTYPE (gobject_enum,
-				.get_gtype =            nm_setting_wireless_security_fils_get_type,
-			),
-		),
-	),
 	NULL
 };
 
@@ -7894,7 +7899,6 @@ _meta_type_setting_info_editor_get_fcn (const NMMetaAbstractInfo *abstract_info,
                                         NMMetaAccessorGetType get_type,
                                         NMMetaAccessorGetFlags get_flags,
                                         NMMetaAccessorGetOutFlags *out_flags,
-                                        gboolean *out_is_default,
                                         gpointer *out_to_free)
 {
 	const NMMetaSettingInfoEditor *info = (const NMMetaSettingInfoEditor *) abstract_info;
@@ -7920,7 +7924,6 @@ _meta_type_property_info_get_fcn (const NMMetaAbstractInfo *abstract_info,
                                   NMMetaAccessorGetType get_type,
                                   NMMetaAccessorGetFlags get_flags,
                                   NMMetaAccessorGetOutFlags *out_flags,
-                                  gboolean *out_is_default,
                                   gpointer *out_to_free)
 {
 	const NMMetaPropertyInfo *info = (const NMMetaPropertyInfo *) abstract_info;
@@ -7936,10 +7939,8 @@ _meta_type_property_info_get_fcn (const NMMetaAbstractInfo *abstract_info,
 	nm_assert (out_to_free);
 
 	if (   info->is_secret
-	    && !NM_FLAGS_HAS (get_flags, NM_META_ACCESSOR_GET_FLAGS_SHOW_SECRETS)) {
-		NM_SET_OUT (out_is_default, TRUE);
+	    && !NM_FLAGS_HAS (get_flags, NM_META_ACCESSOR_GET_FLAGS_SHOW_SECRETS))
 		return _get_text_hidden (get_type);
-	}
 
 	return info->property_type->get_fcn (info,
 	                                     environment,
@@ -7948,7 +7949,6 @@ _meta_type_property_info_get_fcn (const NMMetaAbstractInfo *abstract_info,
 	                                     get_type,
 	                                     get_flags,
 	                                     out_flags,
-	                                     out_is_default,
 	                                     out_to_free);
 
 }
diff --git a/clients/common/nm-meta-setting-desc.h b/clients/common/nm-meta-setting-desc.h
index 3bacaed9..e61b1fc4 100644
--- a/clients/common/nm-meta-setting-desc.h
+++ b/clients/common/nm-meta-setting-desc.h
@@ -181,7 +181,7 @@ typedef struct _NMMetaPropertyTypDataNested NMMetaPropertyTypDataNested;
 
 /* this gives some context information for virtual functions.
  * This command actually violates layering, and should be considered
- * a hack. In the future, try to replace its use. */
+ * a hack. In the future, try to replace it's use. */
 struct _NMMetaOperationContext {
 	NMConnection *connection;
 };
@@ -199,7 +199,6 @@ struct _NMMetaPropertyType {
 	                          NMMetaAccessorGetType get_type,
 	                          NMMetaAccessorGetFlags get_flags,
 	                          NMMetaAccessorGetOutFlags *out_flags,
-	                          gboolean *out_is_default,
 	                          gpointer *out_to_free);
 	gboolean (*set_fcn) (const NMMetaPropertyInfo *property_info,
 	                     const NMMetaEnvironment *environment,
@@ -242,8 +241,7 @@ struct _NMMetaPropertyTypData {
 			GType (*get_gtype) (void);
 			int min;
 			int max;
-			const struct _NMUtilsEnumValueInfo *value_infos_get; /* nicks for get function */
-			const struct _NMUtilsEnumValueInfo *value_infos;     /* nicks for set function */
+			const struct _NMUtilsEnumValueInfo *value_infos;
 			void (*pre_set_notify) (const NMMetaPropertyInfo *property_info,
 			                        const NMMetaEnvironment *environment,
 			                        gpointer environment_user_data,
@@ -364,7 +362,6 @@ struct _NMMetaType {
 	                          NMMetaAccessorGetType get_type,
 	                          NMMetaAccessorGetFlags get_flags,
 	                          NMMetaAccessorGetOutFlags *out_flags,
-	                          gboolean *out_is_defalt,
 	                          gpointer *out_to_free);
 	const char *const*(*complete_fcn) (const NMMetaAbstractInfo *info,
 	                                   const NMMetaEnvironment *environment,
diff --git a/clients/common/nm-polkit-listener.c b/clients/common/nm-polkit-listener.c
index 300cf11e..69f49062 100644
--- a/clients/common/nm-polkit-listener.c
+++ b/clients/common/nm-polkit-listener.c
@@ -33,15 +33,15 @@
 
 #include "nm-default.h"
 
-#include "nm-polkit-listener.h"
-
 #include <string.h>
 #include <stdio.h>
 #include <stdlib.h>
 
-#if WITH_POLKIT_AGENT
+#include "nm-polkit-listener.h"
+
+G_DEFINE_TYPE (NMPolkitListener, nm_polkit_listener, POLKIT_AGENT_TYPE_LISTENER)
 
-/*****************************************************************************/
+#define NM_POLKIT_LISTENER_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), NM_TYPE_POLKIT_LISTENER, NMPolkitListenerPrivate))
 
 typedef struct {
 	gpointer reg_handle;  /* handle of polkit agent registration */
@@ -56,28 +56,14 @@ typedef struct {
 	char *icon_name;
 	char *identity;
 
-	const NMPolkitListenVtable *vtable;
-	gpointer vtable_user_data;
+	/* callbacks */
+	NMPolkitListenerOnRequestFunc on_request_callback;
+	NMPolkitListenerOnShowInfoFunc on_show_info_callback;
+	NMPolkitListenerOnShowErrorFunc on_show_error_callback;
+	NMPolkitListenerOnCompletedFunc on_completed_callback;
+	gpointer request_callback_data;
 } NMPolkitListenerPrivate;
 
-G_DEFINE_TYPE (NMPolkitListener, nm_polkit_listener, POLKIT_AGENT_TYPE_LISTENER)
-
-#define NM_POLKIT_LISTENER_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), NM_TYPE_POLKIT_LISTENER, NMPolkitListenerPrivate))
-
-/*****************************************************************************/
-
-void
-nm_polkit_listener_set_vtable (NMPolkitListener *self,
-                               const NMPolkitListenVtable *vtable,
-                               gpointer user_data)
-{
-	NMPolkitListenerPrivate *priv = NM_POLKIT_LISTENER_GET_PRIVATE (self);
-
-	priv->vtable = vtable;
-	priv->vtable_user_data = user_data;
-}
-
-/*****************************************************************************/
 
 static void
 on_request (PolkitAgentSession *session,
@@ -85,21 +71,20 @@ on_request (PolkitAgentSession *session,
             gboolean echo_on,
             gpointer user_data)
 {
-	NMPolkitListener *self = NM_POLKIT_LISTENER (user_data);
-	NMPolkitListenerPrivate *priv = NM_POLKIT_LISTENER_GET_PRIVATE (self);
-	gs_free char *response = NULL;
-
-	if (priv->vtable && priv->vtable->on_request) {
-		response = priv->vtable->on_request (self,
-		                                     request, priv->action_id,
-		                                     priv->message, priv->icon_name,
-		                                     priv->identity, echo_on,
-		                                     priv->vtable_user_data);
+	NMPolkitListenerPrivate *priv = NM_POLKIT_LISTENER_GET_PRIVATE (user_data);
+	char *response = NULL;
+
+	if (priv->on_request_callback) {
+		response = priv->on_request_callback (request, priv->action_id,
+		                                      priv->message, priv->icon_name,
+		                                      priv->identity, echo_on,
+		                                      priv->request_callback_data);
 	}
 
-	if (response)
+	if (response) {
 		polkit_agent_session_response (session, response);
-	else {
+		g_free (response);
+	} else {
 		//FIXME: polkit_agent_session_cancel() should emit "completed", but it doesn't work for me ???
 		//polkit_agent_session_cancel (session);
 		polkit_agent_session_response (session, "");
@@ -111,13 +96,10 @@ on_show_info (PolkitAgentSession *session,
               const char *text,
               gpointer user_data)
 {
-	NMPolkitListener *self = NM_POLKIT_LISTENER (user_data);
-	NMPolkitListenerPrivate *priv = NM_POLKIT_LISTENER_GET_PRIVATE (self);
+	NMPolkitListenerPrivate *priv = NM_POLKIT_LISTENER_GET_PRIVATE (user_data);
 
-	if (priv->vtable && priv->vtable->on_show_info) {
-		priv->vtable->on_show_info (self, text,
-		                            priv->vtable_user_data);
-	}
+	if (priv->on_show_info_callback)
+		priv->on_show_info_callback (text);
 }
 
 static void
@@ -125,13 +107,10 @@ on_show_error (PolkitAgentSession *session,
                const char *text,
                gpointer user_data)
 {
-	NMPolkitListener *self = NM_POLKIT_LISTENER (user_data);
-	NMPolkitListenerPrivate *priv = NM_POLKIT_LISTENER_GET_PRIVATE (self);
+	NMPolkitListenerPrivate *priv = NM_POLKIT_LISTENER_GET_PRIVATE (user_data);
 
-	if (priv->vtable && priv->vtable->on_show_error) {
-		priv->vtable->on_show_error (self, text,
-		                             priv->vtable_user_data);
-	}
+	if (priv->on_show_error_callback)
+		priv->on_show_error_callback (text);
 }
 
 static void
@@ -139,13 +118,10 @@ on_completed (PolkitAgentSession *session,
               gboolean gained_authorization,
               gpointer user_data)
 {
-	NMPolkitListener *self = NM_POLKIT_LISTENER (user_data);
-	NMPolkitListenerPrivate *priv = NM_POLKIT_LISTENER_GET_PRIVATE (self);
+	NMPolkitListenerPrivate *priv = NM_POLKIT_LISTENER_GET_PRIVATE (user_data);
 
-	if (priv->vtable->on_completed) {
-		priv->vtable->on_completed (self, gained_authorization,
-		                            priv->vtable_user_data);
-	}
+	if (priv->on_completed_callback)
+		priv->on_completed_callback (gained_authorization);
 
 	g_simple_async_result_complete_in_idle (priv->simple);
 
@@ -169,8 +145,7 @@ on_completed (PolkitAgentSession *session,
 static void
 on_cancelled (GCancellable *cancellable, gpointer user_data)
 {
-	NMPolkitListener *self = NM_POLKIT_LISTENER (user_data);
-	NMPolkitListenerPrivate *priv = NM_POLKIT_LISTENER_GET_PRIVATE (self);
+	NMPolkitListenerPrivate *priv = NM_POLKIT_LISTENER_GET_PRIVATE (user_data);
 
 	polkit_agent_session_cancel (priv->active_session);
 }
@@ -289,37 +264,62 @@ initiate_authentication_finish (PolkitAgentListener *listener,
 	return !g_simple_async_result_propagate_error (G_SIMPLE_ASYNC_RESULT (result), error);
 }
 
-/*****************************************************************************/
 
 static void
 nm_polkit_listener_init (NMPolkitListener *agent)
 {
 }
 
+static void
+nm_polkit_listener_finalize (GObject *object)
+{
+	NMPolkitListenerPrivate *priv = NM_POLKIT_LISTENER_GET_PRIVATE (object);
+
+	if (priv->reg_handle)
+		polkit_agent_listener_unregister (priv->reg_handle);
+
+	g_free (priv->action_id);
+	g_free (priv->message);
+	g_free (priv->icon_name);
+	g_free (priv->identity);
+
+	G_OBJECT_CLASS (nm_polkit_listener_parent_class)->finalize (object);
+}
+
+static void
+nm_polkit_listener_class_init (NMPolkitListenerClass *klass)
+{
+	GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
+	PolkitAgentListenerClass *pkal_class = POLKIT_AGENT_LISTENER_CLASS (klass);
+
+	g_type_class_add_private (klass, sizeof (NMPolkitListenerPrivate));
+
+	gobject_class->finalize = nm_polkit_listener_finalize;
+
+	pkal_class->initiate_authentication = initiate_authentication;
+	pkal_class->initiate_authentication_finish = initiate_authentication_finish;
+}
+
 /**
  * nm_polkit_listener_new:
  * @for_session: %TRUE for registering the polkit agent for the user session,
  *   %FALSE for registering it for the running process
- * @vtable: mandatory callbacks
- * @user_data: user-data pointer for callbacks
  * @error: location to store error, or %NULL
  *
  * Creates a new #NMPolkitListener and registers it as a polkit agent.
  *
  * Returns: a new #NMPolkitListener
  */
-NMPolkitListener *
-nm_polkit_listener_new (gboolean for_session,
-                        GError **error)
+PolkitAgentListener *
+nm_polkit_listener_new (gboolean for_session, GError **error)
 {
-	NMPolkitListener *listener;
+	PolkitAgentListener *listener;
 	PolkitSubject* session;
 	NMPolkitListenerPrivate *priv;
 
-	g_return_val_if_fail (!error || !*error, NULL);
+	g_return_val_if_fail (error == NULL || *error == NULL, NULL);
 
 	listener = g_object_new (NM_TYPE_POLKIT_LISTENER, NULL);
-
 	priv = NM_POLKIT_LISTENER_GET_PRIVATE (listener);
 
 	if (for_session) {
@@ -329,8 +329,7 @@ nm_polkit_listener_new (gboolean for_session,
 	} else
 		session = polkit_unix_process_new_for_owner (getpid (), 0, getuid ());
 
-	priv->reg_handle = polkit_agent_listener_register (POLKIT_AGENT_LISTENER (listener),
-	                                                   POLKIT_AGENT_REGISTER_FLAGS_NONE,
+	priv->reg_handle = polkit_agent_listener_register (listener, POLKIT_AGENT_REGISTER_FLAGS_NONE,
 	                                                   session, NULL, NULL, error);
 	if (!priv->reg_handle) {
 		g_object_unref (listener);
@@ -341,34 +340,77 @@ nm_polkit_listener_new (gboolean for_session,
 	return listener;
 }
 
-static void
-nm_polkit_listener_finalize (GObject *object)
+/**
+ * nm_polkit_listener_set_request_callback:
+ * @self: a #NMPolkitListener object
+ * @request_callback: callback to install for polkit requests
+ * @request_callback_data: usaer data passed to request_callback when it is called
+ *
+ * Set a callback for "request" signal. The callback will be invoked when polkit
+ * requests an authorization.
+ */
+void
+nm_polkit_listener_set_request_callback (NMPolkitListener *self,
+                                         NMPolkitListenerOnRequestFunc request_callback,
+                                         gpointer request_callback_data)
 {
-	NMPolkitListenerPrivate *priv = NM_POLKIT_LISTENER_GET_PRIVATE (object);
+	NMPolkitListenerPrivate *priv;
 
-	if (priv->reg_handle)
-		polkit_agent_listener_unregister (priv->reg_handle);
+	g_return_if_fail (NM_IS_POLKIT_LISTENER (self));
 
-	g_free (priv->action_id);
-	g_free (priv->message);
-	g_free (priv->icon_name);
-	g_free (priv->identity);
+	priv = NM_POLKIT_LISTENER_GET_PRIVATE (self);
 
-	G_OBJECT_CLASS (nm_polkit_listener_parent_class)->finalize (object);
+	priv->on_request_callback = request_callback;
+	priv->request_callback_data = request_callback_data;
 }
 
-static void
-nm_polkit_listener_class_init (NMPolkitListenerClass *klass)
+/**
+ * nm_polkit_listener_set_show_info_callback:
+ * @self: a #NMPolkitListener object
+ * @show_info_callback: callback to install for polkit show info trigger
+ *
+ * Set a callback for "show-info" signal. The callback will be invoked when polkit
+ * has an info text to display.
+ */
+void
+nm_polkit_listener_set_show_info_callback (NMPolkitListener *self,
+                                           NMPolkitListenerOnShowInfoFunc show_info_callback)
 {
-	GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
-	PolkitAgentListenerClass *pkal_class = POLKIT_AGENT_LISTENER_CLASS (klass);
+	g_return_if_fail (NM_IS_POLKIT_LISTENER (self));
 
-	g_type_class_add_private (klass, sizeof (NMPolkitListenerPrivate));
+	NM_POLKIT_LISTENER_GET_PRIVATE (self)->on_show_info_callback = show_info_callback;
+}
 
-	gobject_class->finalize = nm_polkit_listener_finalize;
+/**
+ * nm_polkit_listener_set_show_error_callback:
+ * @self: a #NMPolkitListener object
+ * @show_error_callback: callback to install for polkit show error trigger
+ *
+ * Set a callback for "show-error" signal. The callback will be invoked when polkit
+ * has an error text to display.
+ */
+void
+nm_polkit_listener_set_show_error_callback (NMPolkitListener *self,
+                                            NMPolkitListenerOnShowErrorFunc show_error_callback)
+{
+	g_return_if_fail (NM_IS_POLKIT_LISTENER (self));
 
-	pkal_class->initiate_authentication = initiate_authentication;
-	pkal_class->initiate_authentication_finish = initiate_authentication_finish;
+	NM_POLKIT_LISTENER_GET_PRIVATE (self)->on_show_error_callback = show_error_callback;
 }
 
-#endif /* WITH_POLKIT_AGENT */
+/**
+ * nm_polkit_listener_set_completed_callback:
+ * @self: a #NMPolkitListener object
+ * @completed_callback: callback to install for polkit completing authorization
+ *
+ * Set a callback for "completed" signal. The callback will be invoked when polkit
+ * completed the request.
+ */
+void
+nm_polkit_listener_set_completed_callback (NMPolkitListener *self,
+                                           NMPolkitListenerOnCompletedFunc completed_callback)
+{
+	g_return_if_fail (NM_IS_POLKIT_LISTENER (self));
+
+	NM_POLKIT_LISTENER_GET_PRIVATE (self)->on_completed_callback = completed_callback;
+}
diff --git a/clients/common/nm-polkit-listener.h b/clients/common/nm-polkit-listener.h
index ea13acdd..a8256460 100644
--- a/clients/common/nm-polkit-listener.h
+++ b/clients/common/nm-polkit-listener.h
@@ -19,64 +19,6 @@
 #ifndef __NM_POLKIT_LISTENER_H__
 #define __NM_POLKIT_LISTENER_H__
 
-#if WITH_POLKIT_AGENT
-
-typedef struct _NMPolkitListener NMPolkitListener;
-typedef struct _NMPolkitListenerClass NMPolkitListenerClass;
-
-typedef struct {
-
-	/*
-	 * @request: the request asked by polkit agent
-	 * @action_id: the action_id of the polkit request
-	 * @message: the message of the polkit request
-	 * @icon_name: the icon name of the polkit request
-	 * @user: user name
-	 * @echo_on: whether the response to the request should be echoed to the screen
-	 * @user_data: user data for the callback
-	 *
-	 * Called as a result of a request by polkit. The function should obtain response
-	 * to the request from user, i.e. get the password required.
-	 */
-	char *(*on_request) (NMPolkitListener *self,
-	                     const char *request,
-	                     const char *action_id,
-	                     const char *message,
-	                     const char *icon_name,
-	                     const char *user,
-	                     gboolean echo_on,
-	                     gpointer user_data);
-
-	/*
-	 * @text: the info text from polkit
-	 *
-	 * Called as a result of show-info signal by polkit.
-	 */
-	void (*on_show_info) (NMPolkitListener *self,
-	                      const char *text,
-	                      gpointer user_data);
-
-	/*
-	 * @text: the error text from polkit
-	 *
-	 * Called as a result of show-error signal by polkit.
-	 */
-	void (*on_show_error) (NMPolkitListener *self,
-	                       const char *text,
-	                       gpointer user_data);
-
-	/*
-	 * @gained_authorization: whether the autorization was successful
-	 *
-	 * Called as a result of completed signal by polkit.
-	 */
-	void (*on_completed) (NMPolkitListener *self,
-	                      gboolean gained_authorization,
-	                      gpointer user_data);
-} NMPolkitListenVtable;
-
-/*****************************************************************************/
-
 #define POLKIT_AGENT_I_KNOW_API_IS_SUBJECT_TO_CHANGE
 #include <polkitagent/polkitagent.h>
 
@@ -130,23 +72,27 @@ typedef void (*NMPolkitListenerOnShowErrorFunc) (const char *text);
 typedef void (*NMPolkitListenerOnCompletedFunc) (gboolean gained_authorization);
 
 
-struct _NMPolkitListener {
+typedef struct {
 	PolkitAgentListener parent;
-};
 
-struct _NMPolkitListenerClass {
-	PolkitAgentListenerClass parent;
-};
+} NMPolkitListener;
 
-GType nm_polkit_listener_get_type (void);
+typedef struct {
+	PolkitAgentListenerClass parent;
 
-NMPolkitListener *nm_polkit_listener_new (gboolean for_session,
-                                          GError **error);
+} NMPolkitListenerClass;
 
-void nm_polkit_listener_set_vtable (NMPolkitListener *self,
-                                    const NMPolkitListenVtable *vtable,
-                                    gpointer user_data);
+GType nm_polkit_listener_get_type (void);
 
-#endif
+PolkitAgentListener* nm_polkit_listener_new     (gboolean for_session, GError **error);
+void nm_polkit_listener_set_request_callback    (NMPolkitListener *self,
+                                                 NMPolkitListenerOnRequestFunc request_callback,
+                                                 gpointer request_callback_data);
+void nm_polkit_listener_set_show_info_callback  (NMPolkitListener *self,
+                                                 NMPolkitListenerOnShowInfoFunc show_info_callback);
+void nm_polkit_listener_set_show_error_callback (NMPolkitListener *self,
+                                                 NMPolkitListenerOnShowErrorFunc show_error_callback);
+void nm_polkit_listener_set_completed_callback  (NMPolkitListener *self,
+                                                 NMPolkitListenerOnCompletedFunc completed_callback);
 
 #endif /* __NM_POLKIT_LISTENER_H__ */
diff --git a/clients/common/nm-secret-agent-simple.c b/clients/common/nm-secret-agent-simple.c
index 4db57ca5..4ef1be23 100644
--- a/clients/common/nm-secret-agent-simple.c
+++ b/clients/common/nm-secret-agent-simple.c
@@ -33,6 +33,9 @@
 
 #include <string.h>
 
+#include "nm-utils/nm-hash-utils.h"
+
+#include "NetworkManager.h"
 #include "nm-vpn-service-plugin.h"
 
 #include "nm-vpn-helpers.h"
@@ -146,6 +149,7 @@ strv_has (gchar **haystack,
 
 typedef struct {
 	NMSecretAgentSimpleSecret base;
+
 	NMSetting *setting;
 	char *property;
 } NMSecretAgentSimpleSecretReal;
@@ -155,10 +159,11 @@ nm_secret_agent_simple_secret_free (NMSecretAgentSimpleSecret *secret)
 {
 	NMSecretAgentSimpleSecretReal *real = (NMSecretAgentSimpleSecretReal *)secret;
 
-	g_free ((char *) secret->pretty_name);
-	g_free ((char *) secret->entry_id);
+	g_free (secret->name);
+	g_free (secret->prop_name);
 	g_free (secret->value);
-	g_free ((char *) secret->vpn_type);
+	g_free (secret->vpn_property);
+	g_free (secret->vpn_type);
 	g_free (real->property);
 	g_clear_object (&real->setting);
 
@@ -166,45 +171,33 @@ nm_secret_agent_simple_secret_free (NMSecretAgentSimpleSecret *secret)
 }
 
 static NMSecretAgentSimpleSecret *
-nm_secret_agent_simple_secret_new (NMSecretAgentSecretType secret_type,
-                                   const char *pretty_name,
+nm_secret_agent_simple_secret_new (const char *name,
                                    NMSetting  *setting,
                                    const char *property,
-                                   const char *vpn_type)
+                                   const char *vpn_property,
+                                   const char *vpn_type,
+                                   gboolean    password)
 {
 	NMSecretAgentSimpleSecretReal *real;
-	const char *vpn_prefix;
-	const char *value;
-
-	nm_assert (property);
-	nm_assert (NM_IS_SETTING (setting));
 
 	real = g_slice_new0 (NMSecretAgentSimpleSecretReal);
-	*((NMSecretAgentSecretType *) &real->base.secret_type) = secret_type;
-	real->setting = g_object_ref (setting);
-	real->base.pretty_name = g_strdup (pretty_name);
-	real->property = g_strdup (property);
-	switch (secret_type) {
-	case NM_SECRET_AGENT_SECRET_TYPE_PROPERTY:
-	case NM_SECRET_AGENT_SECRET_TYPE_SECRET:
-		nm_assert (!vpn_type);
-		nm_assert (g_object_class_find_property (G_OBJECT_GET_CLASS (setting), property));
-		nm_assert ((secret_type == NM_SECRET_AGENT_SECRET_TYPE_SECRET) == nm_setting_get_secret_flags (setting, property, NULL, NULL));
-		real->base.entry_id = g_strdup_printf ("%s.%s", nm_setting_get_name (setting), property);
-		g_object_get (setting, property, &real->base.value, NULL);
-		real->base.is_secret = (secret_type != NM_SECRET_AGENT_SECRET_TYPE_PROPERTY);
-		break;
-	case NM_SECRET_AGENT_SECRET_TYPE_VPN_SECRET:
-		vpn_prefix = NM_SECRET_AGENT_ENTRY_ID_PREFX_VPN_SECRET;
-		value = nm_setting_vpn_get_secret (NM_SETTING_VPN (setting), property);
-		real->base.entry_id = g_strdup_printf ("%s%s", vpn_prefix, property);
-		nm_assert (vpn_type);
-		real->base.vpn_type = g_strdup (vpn_type);
-		real->base.value = g_strdup (value);
-		real->base.is_secret = TRUE;
-		break;
+	real->base.name = g_strdup (name);
+	real->base.prop_name = vpn_property ?
+	                         g_strdup_printf ("%s.%s.%s", nm_setting_get_name (setting), property, vpn_property) :
+	                         g_strdup_printf ("%s.%s", nm_setting_get_name (setting), property);
+	real->base.vpn_property = g_strdup (vpn_property);
+	real->base.vpn_type = g_strdup (vpn_type);
+	real->base.password = password;
+
+	if (setting) {
+		real->setting = g_object_ref (setting);
+		real->property = g_strdup (property);
+
+		if (vpn_property)
+			real->base.value = g_strdup (nm_setting_vpn_get_secret (NM_SETTING_VPN (setting), vpn_property));
+		else
+			g_object_get (setting, property, &real->base.value, NULL);
 	}
-	nm_assert (real->base.entry_id);
 
 	return &real->base;
 }
@@ -229,33 +222,37 @@ add_8021x_secrets (NMSecretAgentSimpleRequest *request,
 		 * is not visible here since we only care about phase2 authentication
 		 * (and don't even care of which one)
 		 */
-		secret = nm_secret_agent_simple_secret_new (NM_SECRET_AGENT_SECRET_TYPE_PROPERTY,
-		                                            _("Username"),
+		secret = nm_secret_agent_simple_secret_new (_("Username"),
 		                                            NM_SETTING (s_8021x),
 		                                            NM_SETTING_802_1X_IDENTITY,
-		                                            NULL);
+		                                            NULL,
+		                                            NULL,
+		                                            FALSE);
 		g_ptr_array_add (secrets, secret);
-		secret = nm_secret_agent_simple_secret_new (NM_SECRET_AGENT_SECRET_TYPE_SECRET,
-		                                            _("Password"),
+		secret = nm_secret_agent_simple_secret_new (_("Password"),
 		                                            NM_SETTING (s_8021x),
 		                                            NM_SETTING_802_1X_PASSWORD,
-		                                            NULL);
+		                                            NULL,
+		                                            NULL,
+		                                            TRUE);
 		g_ptr_array_add (secrets, secret);
 		return TRUE;
 	}
 
 	if (!strcmp (eap_method, "tls")) {
-		secret = nm_secret_agent_simple_secret_new (NM_SECRET_AGENT_SECRET_TYPE_PROPERTY,
-		                                            _("Identity"),
+		secret = nm_secret_agent_simple_secret_new (_("Identity"),
 		                                            NM_SETTING (s_8021x),
 		                                            NM_SETTING_802_1X_IDENTITY,
-		                                            NULL);
+		                                            NULL,
+		                                            NULL,
+		                                            FALSE);
 		g_ptr_array_add (secrets, secret);
-		secret = nm_secret_agent_simple_secret_new (NM_SECRET_AGENT_SECRET_TYPE_SECRET,
-		                                            _("Private key password"),
+		secret = nm_secret_agent_simple_secret_new (_("Private key password"),
 		                                            NM_SETTING (s_8021x),
 		                                            NM_SETTING_802_1X_PRIVATE_KEY_PASSWORD,
-		                                            NULL);
+		                                            NULL,
+		                                            NULL,
+		                                            TRUE);
 		g_ptr_array_add (secrets, secret);
 		return TRUE;
 	}
@@ -275,11 +272,12 @@ add_wireless_secrets (NMSecretAgentSimpleRequest *request,
 		return FALSE;
 
 	if (!strcmp (key_mgmt, "wpa-none") || !strcmp (key_mgmt, "wpa-psk")) {
-		secret = nm_secret_agent_simple_secret_new (NM_SECRET_AGENT_SECRET_TYPE_SECRET,
-		                                            _("Password"),
+		secret = nm_secret_agent_simple_secret_new (_("Password"),
 		                                            NM_SETTING (s_wsec),
 		                                            NM_SETTING_WIRELESS_SECURITY_PSK,
-		                                            NULL);
+		                                            NULL,
+		                                            NULL,
+		                                            TRUE);
 		g_ptr_array_add (secrets, secret);
 		return TRUE;
 	}
@@ -290,11 +288,12 @@ add_wireless_secrets (NMSecretAgentSimpleRequest *request,
 
 		index = nm_setting_wireless_security_get_wep_tx_keyidx (s_wsec);
 		key = g_strdup_printf ("wep-key%d", index);
-		secret = nm_secret_agent_simple_secret_new (NM_SECRET_AGENT_SECRET_TYPE_SECRET,
-		                                            _("Key"),
+		secret = nm_secret_agent_simple_secret_new (_("Key"),
 		                                            NM_SETTING (s_wsec),
 		                                            key,
-		                                            NULL);
+		                                            NULL,
+		                                            NULL,
+		                                            TRUE);
 		g_free (key);
 
 		g_ptr_array_add (secrets, secret);
@@ -303,11 +302,12 @@ add_wireless_secrets (NMSecretAgentSimpleRequest *request,
 
 	if (!strcmp (key_mgmt, "iee8021x")) {
 		if (!g_strcmp0 (nm_setting_wireless_security_get_auth_alg (s_wsec), "leap")) {
-			secret = nm_secret_agent_simple_secret_new (NM_SECRET_AGENT_SECRET_TYPE_SECRET,
-			                                            _("Password"),
+			secret = nm_secret_agent_simple_secret_new (_("Password"),
 			                                            NM_SETTING (s_wsec),
 			                                            NM_SETTING_WIRELESS_SECURITY_LEAP_PASSWORD,
-			                                            NULL);
+			                                            NULL,
+			                                            NULL,
+			                                            TRUE);
 			g_ptr_array_add (secrets, secret);
 			return TRUE;
 		} else
@@ -327,23 +327,26 @@ add_pppoe_secrets (NMSecretAgentSimpleRequest *request,
 	NMSettingPppoe *s_pppoe = nm_connection_get_setting_pppoe (request->connection);
 	NMSecretAgentSimpleSecret *secret;
 
-	secret = nm_secret_agent_simple_secret_new (NM_SECRET_AGENT_SECRET_TYPE_PROPERTY,
-	                                            _("Username"),
+	secret = nm_secret_agent_simple_secret_new (_("Username"),
 	                                            NM_SETTING (s_pppoe),
 	                                            NM_SETTING_PPPOE_USERNAME,
-	                                            NULL);
+	                                            NULL,
+	                                            NULL,
+	                                            FALSE);
 	g_ptr_array_add (secrets, secret);
-	secret = nm_secret_agent_simple_secret_new (NM_SECRET_AGENT_SECRET_TYPE_PROPERTY,
-	                                            _("Service"),
+	secret = nm_secret_agent_simple_secret_new (_("Service"),
 	                                            NM_SETTING (s_pppoe),
 	                                            NM_SETTING_PPPOE_SERVICE,
-	                                            NULL);
+	                                            NULL,
+	                                            NULL,
+	                                            FALSE);
 	g_ptr_array_add (secrets, secret);
-	secret = nm_secret_agent_simple_secret_new (NM_SECRET_AGENT_SECRET_TYPE_SECRET,
-	                                            _("Password"),
+	secret = nm_secret_agent_simple_secret_new (_("Password"),
 	                                            NM_SETTING (s_pppoe),
 	                                            NM_SETTING_PPPOE_PASSWORD,
-	                                            NULL);
+	                                            NULL,
+	                                            NULL,
+	                                            TRUE);
 	g_ptr_array_add (secrets, secret);
 	return TRUE;
 }
@@ -368,27 +371,23 @@ add_vpn_secret_helper (GPtrArray *secrets, NMSettingVpn *s_vpn, const char *name
 	NMSettingSecretFlags flags;
 	int i;
 
+	/* Check for duplicates */
+	for (i = 0; i < secrets->len; i++) {
+		secret = secrets->pdata[i];
+
+		if (g_strcmp0 (secret->vpn_property, name) == 0)
+			return;
+	}
+
 	flags = get_vpn_secret_flags (s_vpn, name);
 	if (   flags & NM_SETTING_SECRET_FLAG_AGENT_OWNED
 	    || flags & NM_SETTING_SECRET_FLAG_NOT_SAVED) {
-		secret = nm_secret_agent_simple_secret_new (NM_SECRET_AGENT_SECRET_TYPE_VPN_SECRET,
-		                                            ui_name,
+		secret = nm_secret_agent_simple_secret_new (ui_name,
 		                                            NM_SETTING (s_vpn),
+		                                            NM_SETTING_VPN_SECRETS,
 		                                            name,
-		                                            nm_setting_vpn_get_service_type (s_vpn));
-
-		/* Check for duplicates */
-		for (i = 0; i < secrets->len; i++) {
-			NMSecretAgentSimpleSecret *s = secrets->pdata[i];
-
-			if (   s->secret_type == secret->secret_type
-			    && nm_streq0 (s->vpn_type, secret->vpn_type)
-			    && nm_streq0 (s->entry_id, secret->entry_id)) {
-				nm_secret_agent_simple_secret_free (secret);
-				return;
-			}
-		}
-
+		                                            nm_setting_vpn_get_service_type (s_vpn),
+		                                            TRUE);
 		g_ptr_array_add (secrets, secret);
 	}
 }
@@ -470,6 +469,10 @@ request_secrets_from_ui (NMSecretAgentSimpleRequest *request)
 
 		ok = add_wireless_secrets (request, secrets);
 	} else if (nm_connection_is_type (request->connection, NM_SETTING_WIRED_SETTING_NAME)) {
+		NMSettingConnection *s_con;
+
+		s_con = nm_connection_get_setting_connection (request->connection);
+
 		title = _("Wired 802.1X authentication");
 		msg = g_strdup_printf (_("Secrets are required to access the wired network '%s'"),
 		                       nm_connection_get_id (request->connection));
@@ -488,22 +491,24 @@ request_secrets_from_ui (NMSecretAgentSimpleRequest *request)
 			title = _("PIN code required");
 			msg = g_strdup (_("PIN code is needed for the mobile broadband device"));
 
-			secret = nm_secret_agent_simple_secret_new (NM_SECRET_AGENT_SECRET_TYPE_PROPERTY,
-			                                            _("PIN"),
+			secret = nm_secret_agent_simple_secret_new (_("PIN"),
 			                                            NM_SETTING (s_gsm),
 			                                            NM_SETTING_GSM_PIN,
-			                                            NULL);
+			                                            NULL,
+			                                            NULL,
+			                                            FALSE);
 			g_ptr_array_add (secrets, secret);
 		} else {
 			title = _("Mobile broadband network password");
 			msg = g_strdup_printf (_("A password is required to connect to '%s'."),
 			                       nm_connection_get_id (request->connection));
 
-			secret = nm_secret_agent_simple_secret_new (NM_SECRET_AGENT_SECRET_TYPE_SECRET,
-			                                            _("Password"),
+			secret = nm_secret_agent_simple_secret_new (_("Password"),
 			                                            NM_SETTING (s_gsm),
 			                                            NM_SETTING_GSM_PASSWORD,
-			                                            NULL);
+			                                            NULL,
+			                                            NULL,
+			                                            TRUE);
 			g_ptr_array_add (secrets, secret);
 		}
 	} else if (nm_connection_is_type (request->connection, NM_SETTING_MACSEC_SETTING_NAME)) {
@@ -514,11 +519,12 @@ request_secrets_from_ui (NMSecretAgentSimpleRequest *request)
 
 		if (nm_setting_macsec_get_mode (s_macsec) == NM_SETTING_MACSEC_MODE_PSK) {
 			title = _("MACsec PSK authentication");
-			secret = nm_secret_agent_simple_secret_new (NM_SECRET_AGENT_SECRET_TYPE_SECRET,
-			                                            _("MKA CAK"),
+			secret = nm_secret_agent_simple_secret_new (_("MKA CAK"),
 			                                            NM_SETTING (s_macsec),
 			                                            NM_SETTING_MACSEC_MKA_CAK,
-			                                            NULL);
+			                                            NULL,
+			                                            NULL,
+			                                            TRUE);
 			g_ptr_array_add (secrets, secret);
 		} else {
 			title = _("MACsec EAP authentication");
@@ -531,11 +537,12 @@ request_secrets_from_ui (NMSecretAgentSimpleRequest *request)
 		msg = g_strdup_printf (_("A password is required to connect to '%s'."),
 		                       nm_connection_get_id (request->connection));
 
-		secret = nm_secret_agent_simple_secret_new (NM_SECRET_AGENT_SECRET_TYPE_SECRET,
-		                                            _("Password"),
+		secret = nm_secret_agent_simple_secret_new (_("Password"),
 		                                            NM_SETTING (s_cdma),
 		                                            NM_SETTING_CDMA_PASSWORD,
-		                                            NULL);
+		                                            NULL,
+		                                            NULL,
+		                                            TRUE);
 		g_ptr_array_add (secrets, secret);
 	} else if (nm_connection_is_type (request->connection, NM_SETTING_BLUETOOTH_SETTING_NAME)) {
 		NMSetting *setting = NULL;
@@ -553,15 +560,20 @@ request_secrets_from_ui (NMSecretAgentSimpleRequest *request)
 			msg = g_strdup_printf (_("A password is required to connect to '%s'."),
 			                       nm_connection_get_id (request->connection));
 
-			secret = nm_secret_agent_simple_secret_new (NM_SECRET_AGENT_SECRET_TYPE_SECRET,
-			                                            _("Password"),
+			secret = nm_secret_agent_simple_secret_new (_("Password"),
 			                                            setting,
 			                                            "password",
-			                                            NULL);
+			                                            NULL,
+			                                            NULL,
+			                                            TRUE);
 			g_ptr_array_add (secrets, secret);
 		} else
 			ok = FALSE;
 	} else if (nm_connection_is_type (request->connection, NM_SETTING_VPN_SETTING_NAME)) {
+		NMSettingConnection *s_con;
+
+		s_con = nm_connection_get_setting_connection (request->connection);
+
 		title = _("VPN password required");
 		msg = NULL;
 
@@ -603,6 +615,8 @@ nm_secret_agent_simple_get_secrets (NMSecretAgentOld                 *agent,
 	NMSecretAgentSimple *self = NM_SECRET_AGENT_SIMPLE (agent);
 	NMSecretAgentSimplePrivate *priv = NM_SECRET_AGENT_SIMPLE_GET_PRIVATE (self);
 	NMSecretAgentSimpleRequest *request;
+	NMSettingConnection *s_con;
+	const char *connection_type;
 	char *request_id;
 	GError *error;
 
@@ -618,6 +632,9 @@ nm_secret_agent_simple_get_secrets (NMSecretAgentOld                 *agent,
 		return;
 	}
 
+	s_con = nm_connection_get_setting_connection (connection);
+	connection_type = nm_setting_connection_get_connection_type (s_con);
+
 	if (!(flags & NM_SECRET_AGENT_GET_SECRETS_FLAG_ALLOW_INTERACTION)) {
 		/* We don't do stored passwords */
 		error = g_error_new (NM_SECRET_AGENT_ERROR, NM_SECRET_AGENT_ERROR_NO_SECRETS,
@@ -675,7 +692,9 @@ nm_secret_agent_simple_response (NMSecretAgentSimple *self,
 		GHashTable *settings;
 		GHashTableIter iter;
 		const char *name;
-		gboolean has_vpn = FALSE;
+		const char *vpn_secrets_base_name = NULL;
+
+		g_variant_builder_init (&vpn_secrets_builder, G_VARIANT_TYPE ("a{ss}"));
 
 		settings = g_hash_table_new (nm_str_hash, g_str_equal);
 		for (i = 0; i < secrets->len; i++) {
@@ -688,27 +707,22 @@ nm_secret_agent_simple_response (NMSecretAgentSimple *self,
 				                     setting_builder);
 			}
 
-			switch (secret->base.secret_type) {
-			case NM_SECRET_AGENT_SECRET_TYPE_PROPERTY:
-			case NM_SECRET_AGENT_SECRET_TYPE_SECRET:
+			if (secret->base.vpn_property) {
+				/* VPN secrets need slightly different treatment.
+				 * "secrets" property is actually a hash table of secrets. */
+				vpn_secrets_base_name = secret->property;
+				g_variant_builder_add (&vpn_secrets_builder, "{ss}",
+				                       secret->base.vpn_property, secret->base.value);
+			} else {
 				g_variant_builder_add (setting_builder, "{sv}",
 				                       secret->property,
 				                       g_variant_new_string (secret->base.value));
-				break;
-			case NM_SECRET_AGENT_SECRET_TYPE_VPN_SECRET:
-				if (!has_vpn) {
-					g_variant_builder_init (&vpn_secrets_builder, G_VARIANT_TYPE ("a{ss}"));
-					has_vpn = TRUE;
-				}
-				g_variant_builder_add (&vpn_secrets_builder, "{ss}",
-				                       secret->property, secret->base.value);
-				break;
 			}
 		}
 
-		if (has_vpn) {
+		if (vpn_secrets_base_name) {
 			g_variant_builder_add (setting_builder, "{sv}",
-			                       "secrets",
+			                       vpn_secrets_base_name,
 			                       g_variant_builder_end (&vpn_secrets_builder));
 		}
 
diff --git a/clients/common/nm-secret-agent-simple.h b/clients/common/nm-secret-agent-simple.h
index 505987df..2989723d 100644
--- a/clients/common/nm-secret-agent-simple.h
+++ b/clients/common/nm-secret-agent-simple.h
@@ -19,6 +19,7 @@
 #ifndef __NM_SECRET_AGENT_SIMPLE_H__
 #define __NM_SECRET_AGENT_SIMPLE_H__
 
+#include "NetworkManager.h"
 #include "nm-secret-agent-old.h"
 
 #define NM_TYPE_SECRET_AGENT_SIMPLE            (nm_secret_agent_simple_get_type ())
@@ -41,25 +42,13 @@ typedef struct {
 
 } NMSecretAgentSimpleClass;
 
-typedef enum {
-	NM_SECRET_AGENT_SECRET_TYPE_PROPERTY,
-	NM_SECRET_AGENT_SECRET_TYPE_SECRET,
-	NM_SECRET_AGENT_SECRET_TYPE_VPN_SECRET,
-} NMSecretAgentSecretType;
-
 typedef struct {
-	const NMSecretAgentSecretType secret_type;
-	const char *pretty_name;
-	const char *entry_id;
-	char *value;
-	const char *vpn_type;
-	gboolean is_secret;
+	char *name, *prop_name, *value;
+	char *vpn_property;
+	char *vpn_type;
+	gboolean password;
 } NMSecretAgentSimpleSecret;
 
-#define NM_SECRET_AGENT_ENTRY_ID_PREFX_VPN_SECRET "vpn.secret."
-
-#define NM_SECRET_AGENT_VPN_TYPE_OPENCONNECT  NM_DBUS_INTERFACE".openconnect"
-
 GType nm_secret_agent_simple_get_type (void);
 
 NMSecretAgentOld *nm_secret_agent_simple_new                 (const char          *name);
diff --git a/clients/common/nm-vpn-helpers.h b/clients/common/nm-vpn-helpers.h
index 4c15faa1..9e3b8539 100644
--- a/clients/common/nm-vpn-helpers.h
+++ b/clients/common/nm-vpn-helpers.h
@@ -19,6 +19,8 @@
 #ifndef __NM_VPN_HELPERS_H__
 #define __NM_VPN_HELPERS_H__
 
+#include "NetworkManager.h"
+
 typedef struct {
 	const char *name;
 	const char *ui_name;
diff --git a/clients/common/settings-docs.h b/clients/common/settings-docs.c
index 622f7d49..bf5753c5 100644
--- a/clients/common/settings-docs.h
+++ b/clients/common/settings-docs.c
@@ -22,7 +22,6 @@
 #define DESCRIBE_DOC_NM_SETTING_WIRELESS_SSID N_("SSID of the Wi-Fi network. Must be specified.")
 #define DESCRIBE_DOC_NM_SETTING_WIRELESS_TX_POWER N_("If non-zero, directs the device to use the specified transmit power. Units are dBm.  This property is highly driver dependent and not all devices support setting a static transmit power.")
 #define DESCRIBE_DOC_NM_SETTING_WIRELESS_SECURITY_AUTH_ALG N_("When WEP is used (ie, key-mgmt = \"none\" or \"ieee8021x\") indicate the 802.11 authentication algorithm required by the AP here.  One of \"open\" for Open System, \"shared\" for Shared Key, or \"leap\" for Cisco LEAP.  When using Cisco LEAP (ie, key-mgmt = \"ieee8021x\" and auth-alg = \"leap\") the \"leap-username\" and \"leap-password\" properties must be specified.")
-#define DESCRIBE_DOC_NM_SETTING_WIRELESS_SECURITY_FILS N_("Indicates whether Fast Initial Link Setup (802.11ai) must be enabled for the connection.  One of NM_SETTING_WIRELESS_SECURITY_FILS_DEFAULT (0) (use global default value), NM_SETTING_WIRELESS_SECURITY_FILS_DISABLE (1) (disable FILS), NM_SETTING_WIRELESS_SECURITY_FILS_OPTIONAL (2) (enable FILS if the supplicant and the access point support it) or NM_SETTING_WIRELESS_SECURITY_FILS_REQUIRED (3) (enable FILS and fail if not supported).  When set to NM_SETTING_WIRELESS_SECURITY_FILS_DEFAULT (0) and no global default is set, FILS will be optionally enabled.")
 #define DESCRIBE_DOC_NM_SETTING_WIRELESS_SECURITY_GROUP N_("A list of group/broadcast encryption algorithms which prevents connections to Wi-Fi networks that do not utilize one of the algorithms in the list.  For maximum compatibility leave this property empty.  Each list element may be one of \"wep40\", \"wep104\", \"tkip\", or \"ccmp\".")
 #define DESCRIBE_DOC_NM_SETTING_WIRELESS_SECURITY_KEY_MGMT N_("Key management used for the connection.  One of \"none\" (WEP), \"ieee8021x\" (Dynamic WEP), \"wpa-none\" (Ad-Hoc WPA-PSK), \"wpa-psk\" (infrastructure WPA-PSK), or \"wpa-eap\" (WPA-Enterprise).  This property must be set for any Wi-Fi connection that uses security.")
 #define DESCRIBE_DOC_NM_SETTING_WIRELESS_SECURITY_LEAP_PASSWORD N_("The login password for legacy LEAP connections (ie, key-mgmt = \"ieee8021x\" and auth-alg = \"leap\").")
@@ -119,7 +118,7 @@
 #define DESCRIBE_DOC_NM_SETTING_BRIDGE_FORWARD_DELAY N_("The Spanning Tree Protocol (STP) forwarding delay, in seconds.")
 #define DESCRIBE_DOC_NM_SETTING_BRIDGE_GROUP_FORWARD_MASK N_("A mask of group addresses to forward. Usually, group addresses in the range from 01:80:C2:00:00:00 to 01:80:C2:00:00:0F are not forwarded according to standards. This property is a mask of 16 bits, each corresponding to a group address in that range that must be forwarded. The mask can't have bits 0, 1 or 2 set because they are used for STP, MAC pause frames and LACP.")
 #define DESCRIBE_DOC_NM_SETTING_BRIDGE_HELLO_TIME N_("The Spanning Tree Protocol (STP) hello time, in seconds.")
-#define DESCRIBE_DOC_NM_SETTING_BRIDGE_MAC_ADDRESS N_("If specified, the MAC address of bridge. When creating a new bridge, this MAC address will be set. If this field is left unspecified, the \"ethernet.cloned-mac-address\" is referred instead to generate the initial MAC address. Note that setting \"ethernet.cloned-mac-address\" anyway overwrites the MAC address of the bridge later while activating the bridge. Hence, this property is deprecated. Deprecated: 1")
+#define DESCRIBE_DOC_NM_SETTING_BRIDGE_MAC_ADDRESS N_("If specified, the MAC address of bridge. When creating a new bridge, this MAC address will be set. If this field is left unspecified, the \"ethernet.cloned-mac-address\" is referred instead to generate the initial MAC address. Note that setting \"ethernet.cloned-mac-address\" anyway overwrites the MAC address of the bridge later while activating the bridge. Hence, this property is deprecated.")
 #define DESCRIBE_DOC_NM_SETTING_BRIDGE_MAX_AGE N_("The Spanning Tree Protocol (STP) maximum message age, in seconds.")
 #define DESCRIBE_DOC_NM_SETTING_BRIDGE_MULTICAST_SNOOPING N_("Controls whether IGMP snooping is enabled for this bridge. Note that if snooping was automatically disabled due to hash collisions, the system may refuse to enable the feature until the collisions are resolved.")
 #define DESCRIBE_DOC_NM_SETTING_BRIDGE_NAME N_("The setting's name, which uniquely identifies the setting within the connection.  Each setting type has a name unique to that type, for example \"ppp\" or \"wireless\" or \"wired\".")
@@ -136,23 +135,22 @@
 #define DESCRIBE_DOC_NM_SETTING_CDMA_PASSWORD_FLAGS N_("Flags indicating how to handle the \"password\" property.")
 #define DESCRIBE_DOC_NM_SETTING_CDMA_USERNAME N_("The username used to authenticate with the network, if required.  Many providers do not require a username, or accept any username.  But if a username is required, it is specified here.")
 #define DESCRIBE_DOC_NM_SETTING_CONNECTION_AUTH_RETRIES N_("The number of retries for the authentication. Zero means to try indefinitely; -1 means to use a global default. If the global default is not set, the authentication retries for 3 times before failing the connection. Currently this only applies to 802-1x authentication.")
-#define DESCRIBE_DOC_NM_SETTING_CONNECTION_AUTOCONNECT N_("Whether or not the connection should be automatically connected by NetworkManager when the resources for the connection are available. TRUE to automatically activate the connection, FALSE to require manual intervention to activate the connection. Note that autoconnect is not implemented for VPN profiles. See \"secondaries\" as an alternative to automatically connect VPN profiles.")
+#define DESCRIBE_DOC_NM_SETTING_CONNECTION_AUTOCONNECT N_("Whether or not the connection should be automatically connected by NetworkManager when the resources for the connection are available. TRUE to automatically activate the connection, FALSE to require manual intervention to activate the connection.")
 #define DESCRIBE_DOC_NM_SETTING_CONNECTION_AUTOCONNECT_PRIORITY N_("The autoconnect priority. If the connection is set to autoconnect, connections with higher priority will be preferred. Defaults to 0. The higher number means higher priority.")
 #define DESCRIBE_DOC_NM_SETTING_CONNECTION_AUTOCONNECT_RETRIES N_("The number of times a connection should be tried when autoactivating before giving up. Zero means forever, -1 means the global default (4 times if not overridden). Setting this to 1 means to try activation only once before blocking autoconnect. Note that after a timeout, NetworkManager will try to autoconnect again.")
-#define DESCRIBE_DOC_NM_SETTING_CONNECTION_AUTOCONNECT_SLAVES N_("Whether or not slaves of this connection should be automatically brought up when NetworkManager activates this connection. This only has a real effect for master connections. The properties \"autoconnect\", \"autoconnect-priority\" and \"autoconnect-retries\" are unrelated to this setting. The permitted values are: 0: leave slave connections untouched, 1: activate all the slave connections with this connection, -1: default. If -1 (default) is set, global connection.autoconnect-slaves is read to determine the real value. If it is default as well, this fallbacks to 0.")
+#define DESCRIBE_DOC_NM_SETTING_CONNECTION_AUTOCONNECT_SLAVES N_("Whether or not slaves of this connection should be automatically brought up when NetworkManager activates this connection. This only has a real effect for master connections. The permitted values are: 0: leave slave connections untouched, 1: activate all the slave connections with this connection, -1: default. If -1 (default) is set, global connection.autoconnect-slaves is read to determine the real value. If it is default as well, this fallbacks to 0.")
 #define DESCRIBE_DOC_NM_SETTING_CONNECTION_GATEWAY_PING_TIMEOUT N_("If greater than zero, delay success of IP addressing until either the timeout is reached, or an IP gateway replies to a ping.")
 #define DESCRIBE_DOC_NM_SETTING_CONNECTION_ID N_("A human readable unique identifier for the connection, like \"Work Wi-Fi\" or \"T-Mobile 3G\".")
 #define DESCRIBE_DOC_NM_SETTING_CONNECTION_INTERFACE_NAME N_("The name of the network interface this connection is bound to. If not set, then the connection can be attached to any interface of the appropriate type (subject to restrictions imposed by other settings). For software devices this specifies the name of the created device. For connection types where interface names cannot easily be made persistent (e.g. mobile broadband or USB Ethernet), this property should not be used. Setting this property restricts the interfaces a connection can be used with, and if interface names change or are reordered the connection may be applied to the wrong interface.")
 #define DESCRIBE_DOC_NM_SETTING_CONNECTION_LLDP N_("Whether LLDP is enabled for the connection.")
 #define DESCRIBE_DOC_NM_SETTING_CONNECTION_MASTER N_("Interface name of the master device or UUID of the master connection.")
-#define DESCRIBE_DOC_NM_SETTING_CONNECTION_MDNS N_("Whether mDNS is enabled for the connection. The permitted values are: yes: register hostname and resolving for the connection, no: disable mDNS for the interface, resolve: do not register hostname but allow resolving of mDNS host names. When updating this property on a currently activated connection, the change takes effect immediately. This feature requires a plugin which supports mDNS. One such plugin is dns-systemd-resolved.")
 #define DESCRIBE_DOC_NM_SETTING_CONNECTION_METERED N_("Whether the connection is metered. When updating this property on a currently activated connection, the change takes effect immediately.")
 #define DESCRIBE_DOC_NM_SETTING_CONNECTION_NAME N_("The setting's name, which uniquely identifies the setting within the connection.  Each setting type has a name unique to that type, for example \"ppp\" or \"wireless\" or \"wired\".")
 #define DESCRIBE_DOC_NM_SETTING_CONNECTION_PERMISSIONS N_("An array of strings defining what access a given user has to this connection.  If this is NULL or empty, all users are allowed to access this connection; otherwise users are allowed if and only if they are in this list.  When this is not empty, the connection can be active only when one of the specified users is logged into an active session.  Each entry is of the form \"[type]:[id]:[reserved]\"; for example, \"user:dcbw:blah\". At this time only the \"user\" [type] is allowed.  Any other values are ignored and reserved for future use.  [id] is the username that this permission refers to, which may not contain the \":\" character. Any [reserved] information present must be ignored and is reserved for future use.  All of [type], [id], and [reserved] must be valid UTF-8.")
 #define DESCRIBE_DOC_NM_SETTING_CONNECTION_READ_ONLY N_("FALSE if the connection can be modified using the provided settings service's D-Bus interface with the right privileges, or TRUE if the connection is read-only and cannot be modified.")
 #define DESCRIBE_DOC_NM_SETTING_CONNECTION_SECONDARIES N_("List of connection UUIDs that should be activated when the base connection itself is activated. Currently only VPN connections are supported.")
 #define DESCRIBE_DOC_NM_SETTING_CONNECTION_SLAVE_TYPE N_("Setting name of the device type of this slave's master connection (eg, \"bond\"), or NULL if this connection is not a slave.")
-#define DESCRIBE_DOC_NM_SETTING_CONNECTION_STABLE_ID N_("Token to generate stable IDs for the connection. The stable-id is used for generating IPv6 stable private addresses with ipv6.addr-gen-mode=stable-privacy. It is also used to seed the generated cloned MAC address for ethernet.cloned-mac-address=stable and wifi.cloned-mac-address=stable. It is also used as DHCP client identifier with ipv4.dhcp-client-id=stable. Note that also the interface name of the activating connection and a per-host secret key is included into the address generation so that the same stable-id on different hosts/devices yields different addresses. If the value is unset, an ID unique for the connection is used. Specifying a stable-id allows multiple connections to generate the same addresses. Another use is to generate IDs at runtime via dynamic substitutions. The '$' character is treated special to perform dynamic substitutions at runtime. Currently supported are \"${CONNECTION}\", \"${BOOT}\", \"${RANDOM}\". These effectively create unique IDs per-connection, per-boot, or every time. Any unrecognized patterns following '$' are treated verbatim, however are reserved for future use. You are thus advised to avoid '$' or escape it as \"$$\". For example, set it to \"${CONNECTION}/${BOOT}\" to create a unique id for this connection that changes with every reboot. Note that two connections only use the same effective id if their stable-id is also identical before performing dynamic substitutions.")
+#define DESCRIBE_DOC_NM_SETTING_CONNECTION_STABLE_ID N_("Token to generate stable IDs for the connection. The stable-id is used for generating IPv6 stable private addresses with ipv6.addr-gen-mode=stable-privacy. It is also used to seed the generated cloned MAC address for ethernet.cloned-mac-address=stable and wifi.cloned-mac-address=stable. Note that also the interface name of the activating connection and a per-host secret key is included into the address generation so that the same stable-id on different hosts/devices yields different addresses. If the value is unset, an ID unique for the connection is used. Specifying a stable-id allows multiple connections to generate the same addresses. Another use is to generate IDs at runtime via dynamic substitutions. The '$' character is treated special to perform dynamic substitutions at runtime. Currently supported are \"${CONNECTION}\", \"${BOOT}\", \"${RANDOM}\". These effectively create unique IDs per-connection, per-boot, or every time. Any unrecognized patterns following '$' are treated verbatim, however are reserved for future use. You are thus advised to avoid '$' or escape it as \"$$\". For example, set it to \"${CONNECTION}/${BOOT}\" to create a unique id for this connection that changes with every reboot. Note that two connections only use the same effective id if their stable-id is also identical before performing dynamic substitutions.")
 #define DESCRIBE_DOC_NM_SETTING_CONNECTION_TIMESTAMP N_("The time, in seconds since the Unix Epoch, that the connection was last _successfully_ fully activated. NetworkManager updates the connection timestamp periodically when the connection is active to ensure that an active connection has the latest timestamp. The property is only meant for reading (changes to this property will not be preserved).")
 #define DESCRIBE_DOC_NM_SETTING_CONNECTION_TYPE N_("Base type of the connection. For hardware-dependent connections, should contain the setting name of the hardware-type specific setting (ie, \"802-3-ethernet\" or \"802-11-wireless\" or \"bluetooth\", etc), and for non-hardware dependent connections like VPN or otherwise, should contain the setting name of that setting type (ie, \"vpn\" or \"bridge\", etc).")
 #define DESCRIBE_DOC_NM_SETTING_CONNECTION_UUID N_("A universally unique identifier for the connection, for example generated with libuuid.  It should be assigned when the connection is created, and never changed as long as the connection still applies to the same network.  For example, it should not be changed when the \"id\" property or NMSettingIP4Config changes, but might need to be re-created when the Wi-Fi SSID, mobile broadband network provider, or \"type\" property changes. The UUID must be in the format \"2815492f-7e56-435e-b2e9-246bd7cdc664\" (ie, contains only hexadecimal characters and \"-\").")
@@ -196,7 +194,6 @@
 #define DESCRIBE_DOC_NM_SETTING_INFINIBAND_PARENT N_("The interface name of the parent device of this device. Normally NULL, but if the \"p_key\" property is set, then you must specify the base device by setting either this property or \"mac-address\".")
 #define DESCRIBE_DOC_NM_SETTING_INFINIBAND_TRANSPORT_MODE N_("The IP-over-InfiniBand transport mode. Either \"datagram\" or \"connected\".")
 #define DESCRIBE_DOC_NM_SETTING_IP_TUNNEL_ENCAPSULATION_LIMIT N_("How many additional levels of encapsulation are permitted to be prepended to packets. This property applies only to IPv6 tunnels.")
-#define DESCRIBE_DOC_NM_SETTING_IP_TUNNEL_FLAGS N_("Tunnel flags. Currently the following values are supported: NM_IP_TUNNEL_FLAG_IP6_IGN_ENCAP_LIMIT (0x1), NM_IP_TUNNEL_FLAG_IP6_USE_ORIG_TCLASS (0x2), NM_IP_TUNNEL_FLAG_IP6_USE_ORIG_FLOWLABEL (0x4), NM_IP_TUNNEL_FLAG_IP6_MIP6_DEV (0x8), NM_IP_TUNNEL_FLAG_IP6_RCV_DSCP_COPY (0x10), NM_IP_TUNNEL_FLAG_IP6_USE_ORIG_FWMARK (0x20). They are valid only for IPv6 tunnels.")
 #define DESCRIBE_DOC_NM_SETTING_IP_TUNNEL_FLOW_LABEL N_("The flow label to assign to tunnel packets. This property applies only to IPv6 tunnels.")
 #define DESCRIBE_DOC_NM_SETTING_IP_TUNNEL_INPUT_KEY N_("The key used for tunnel input packets; the property is valid only for certain tunnel modes (GRE, IP6GRE). If empty, no key is used.")
 #define DESCRIBE_DOC_NM_SETTING_IP_TUNNEL_LOCAL N_("The local endpoint of the tunnel; the value can be empty, otherwise it must contain an IPv4 or IPv6 address.")
@@ -210,8 +207,8 @@
 #define DESCRIBE_DOC_NM_SETTING_IP_TUNNEL_TOS N_("The type of service (IPv4) or traffic class (IPv6) field to be set on tunneled packets.")
 #define DESCRIBE_DOC_NM_SETTING_IP_TUNNEL_TTL N_("The TTL to assign to tunneled packets. 0 is a special value meaning that packets inherit the TTL value.")
 #define DESCRIBE_DOC_NM_SETTING_IP4_CONFIG_ADDRESSES N_("Array of IP addresses.")
-#define DESCRIBE_DOC_NM_SETTING_IP4_CONFIG_DAD_TIMEOUT N_("Timeout in milliseconds used to check for the presence of duplicate IP addresses on the network.  If an address conflict is detected, the activation will fail.  A zero value means that no duplicate address detection is performed, -1 means the default value (either configuration ipvx.dad-timeout override or zero).  A value greater than zero is a timeout in milliseconds. The property is currently implemented only for IPv4.")
-#define DESCRIBE_DOC_NM_SETTING_IP4_CONFIG_DHCP_CLIENT_ID N_("A string sent to the DHCP server to identify the local machine which the DHCP server may use to customize the DHCP lease and options. When the property is a hex string ('aa:bb:cc') it is interpreted as a binary client ID, in which case the first byte is assumed to be the 'type' field as per RFC 2132 section 9.14 and the remaining bytes may be an hardware address (e.g. '01:xx:xx:xx:xx:xx:xx' where 1 is the Ethernet ARP type and the rest is a MAC address). If the property is not a hex string it is considered as a non-hardware-address client ID and the 'type' field is set to 0. The special values \"mac\" and \"perm-mac\" are supported, which use the current or permanent MAC address of the device to generate a client identifier with type ethernet type (01). Currently, these options only work for ethernet type of links. The special value \"stable\" is supported to generate a type 0 client identifier based on the stable-id (see connection.stable-id). If unset, a globally configured default is used. If still unset, the client-id from the last lease is reused.")
+#define DESCRIBE_DOC_NM_SETTING_IP4_CONFIG_DAD_TIMEOUT N_("Timeout in milliseconds used to check for the presence of duplicate IP addresses on the network.  If an address conflict is detected, the activation will fail.  A zero value means that no duplicate address detection is performed, -1 means the default value (either configuration ipvx.dad-timeout override or 3 seconds).  A value greater than zero is a timeout in milliseconds.")
+#define DESCRIBE_DOC_NM_SETTING_IP4_CONFIG_DHCP_CLIENT_ID N_("A string sent to the DHCP server to identify the local machine which the DHCP server may use to customize the DHCP lease and options. When the property is a hex string ('aa:bb:cc') it is interpreted as a binary client ID, in which case the first byte is assumed to be the 'type' field as per RFC 2132 section 9.14 and the remaining bytes may be an hardware address (e.g. '01:xx:xx:xx:xx:xx:xx' where 1 is the Ethernet ARP type and the rest is a MAC address). If the property is not a hex string it is considered as a non-hardware-address client ID and the 'type' field is set to 0.")
 #define DESCRIBE_DOC_NM_SETTING_IP4_CONFIG_DHCP_FQDN N_("If the \"dhcp-send-hostname\" property is TRUE, then the specified FQDN will be sent to the DHCP server when acquiring a lease. This property and \"dhcp-hostname\" are mutually exclusive and cannot be set at the same time.")
 #define DESCRIBE_DOC_NM_SETTING_IP4_CONFIG_DHCP_HOSTNAME N_("If the \"dhcp-send-hostname\" property is TRUE, then the specified name will be sent to the DHCP server when acquiring a lease. This property and \"dhcp-fqdn\" are mutually exclusive and cannot be set at the same time.")
 #define DESCRIBE_DOC_NM_SETTING_IP4_CONFIG_DHCP_SEND_HOSTNAME N_("If TRUE, a hostname is sent to the DHCP server when acquiring a lease. Some DHCP servers use this hostname to update DNS databases, essentially providing a static hostname for the computer.  If the \"dhcp-hostname\" property is NULL and this property is TRUE, the current persistent hostname of the computer is sent.")
@@ -219,7 +216,7 @@
 #define DESCRIBE_DOC_NM_SETTING_IP4_CONFIG_DNS N_("Array of IP addresses of DNS servers.")
 #define DESCRIBE_DOC_NM_SETTING_IP4_CONFIG_DNS_OPTIONS N_("Array of DNS options as described in man 5 resolv.conf. NULL means that the options are unset and left at the default. In this case NetworkManager will use default options. This is distinct from an empty list of properties.")
 #define DESCRIBE_DOC_NM_SETTING_IP4_CONFIG_DNS_PRIORITY N_("Intra-connection DNS priority. The relative priority to be used when determining the order of DNS servers in resolv.conf.  A lower value means that servers will be on top of the file.  Zero selects the default value, which is 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 same connection profile. For that, just specify the DNS servers in the desired order. When multiple devices have configurations with the same priority, the one with an active default route will be preferred. Note that when using dns=dnsmasq the order is meaningless since dnsmasq forwards queries to all known servers at the same time. Negative values have the special effect of excluding other configurations with a greater priority value; so in presence of at least a negative priority, only DNS servers from connections with the lowest priority value will be used.")
-#define DESCRIBE_DOC_NM_SETTING_IP4_CONFIG_DNS_SEARCH N_("Array of DNS search domains. Domains starting with a tilde ('~') are considered 'routing' domains and are used only to decide the interface over which a query must be forwarded; they are not used to complete unqualified host names.")
+#define DESCRIBE_DOC_NM_SETTING_IP4_CONFIG_DNS_SEARCH N_("Array of DNS search domains.")
 #define DESCRIBE_DOC_NM_SETTING_IP4_CONFIG_GATEWAY N_("The gateway associated with this configuration. This is only meaningful if \"addresses\" is also set.")
 #define DESCRIBE_DOC_NM_SETTING_IP4_CONFIG_IGNORE_AUTO_DNS N_("When \"method\" is set to \"auto\" and this property to TRUE, automatically configured nameservers and search domains are ignored and only nameservers and search domains specified in the \"dns\" and \"dns-search\" properties, if any, are used.")
 #define DESCRIBE_DOC_NM_SETTING_IP4_CONFIG_IGNORE_AUTO_ROUTES N_("When \"method\" is set to \"auto\" and this property to TRUE, automatically configured routes are ignored and only routes specified in the \"routes\" property, if any, are used.")
@@ -232,14 +229,14 @@
 #define DESCRIBE_DOC_NM_SETTING_IP4_CONFIG_ROUTES N_("Array of IP routes.")
 #define DESCRIBE_DOC_NM_SETTING_IP6_CONFIG_ADDR_GEN_MODE N_("Configure method for creating the address for use with RFC4862 IPv6 Stateless Address Autoconfiguration. The permitted values are: NM_SETTING_IP6_CONFIG_ADDR_GEN_MODE_EUI64 (0) or NM_SETTING_IP6_CONFIG_ADDR_GEN_MODE_STABLE_PRIVACY (1). If the property is set to EUI64, the addresses will be generated using the interface tokens derived from hardware address. This makes the host part of the address to stay constant, making it possible to track host's presence when it changes networks. The address changes when the interface hardware is replaced. The value of stable-privacy enables use of cryptographically secure hash of a secret host-specific key along with the connection's stable-id and the network address as specified by RFC7217. This makes it impossible to use the address track host's presence, and makes the address stable when the network interface hardware is replaced. On D-Bus, the absence of an addr-gen-mode setting equals enabling stable-privacy. For keyfile plugin, the absence of the setting on disk means EUI64 so that the property doesn't change on upgrade from older versions. Note that this setting is distinct from the Privacy Extensions as configured by \"ip6-privacy\" property and it does not affect the temporary addresses configured with this option.")
 #define DESCRIBE_DOC_NM_SETTING_IP6_CONFIG_ADDRESSES N_("Array of IP addresses.")
-#define DESCRIBE_DOC_NM_SETTING_IP6_CONFIG_DAD_TIMEOUT N_("Timeout in milliseconds used to check for the presence of duplicate IP addresses on the network.  If an address conflict is detected, the activation will fail.  A zero value means that no duplicate address detection is performed, -1 means the default value (either configuration ipvx.dad-timeout override or zero).  A value greater than zero is a timeout in milliseconds. The property is currently implemented only for IPv4.")
+#define DESCRIBE_DOC_NM_SETTING_IP6_CONFIG_DAD_TIMEOUT N_("Timeout in milliseconds used to check for the presence of duplicate IP addresses on the network.  If an address conflict is detected, the activation will fail.  A zero value means that no duplicate address detection is performed, -1 means the default value (either configuration ipvx.dad-timeout override or 3 seconds).  A value greater than zero is a timeout in milliseconds.")
 #define DESCRIBE_DOC_NM_SETTING_IP6_CONFIG_DHCP_HOSTNAME N_("If the \"dhcp-send-hostname\" property is TRUE, then the specified name will be sent to the DHCP server when acquiring a lease. This property and \"dhcp-fqdn\" are mutually exclusive and cannot be set at the same time.")
 #define DESCRIBE_DOC_NM_SETTING_IP6_CONFIG_DHCP_SEND_HOSTNAME N_("If TRUE, a hostname is sent to the DHCP server when acquiring a lease. Some DHCP servers use this hostname to update DNS databases, essentially providing a static hostname for the computer.  If the \"dhcp-hostname\" property is NULL and this property is TRUE, the current persistent hostname of the computer is sent.")
 #define DESCRIBE_DOC_NM_SETTING_IP6_CONFIG_DHCP_TIMEOUT N_("A timeout for a DHCP transaction in seconds.")
 #define DESCRIBE_DOC_NM_SETTING_IP6_CONFIG_DNS N_("Array of IP addresses of DNS servers.")
 #define DESCRIBE_DOC_NM_SETTING_IP6_CONFIG_DNS_OPTIONS N_("Array of DNS options as described in man 5 resolv.conf. NULL means that the options are unset and left at the default. In this case NetworkManager will use default options. This is distinct from an empty list of properties.")
 #define DESCRIBE_DOC_NM_SETTING_IP6_CONFIG_DNS_PRIORITY N_("Intra-connection DNS priority. The relative priority to be used when determining the order of DNS servers in resolv.conf.  A lower value means that servers will be on top of the file.  Zero selects the default value, which is 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 same connection profile. For that, just specify the DNS servers in the desired order. When multiple devices have configurations with the same priority, the one with an active default route will be preferred. Note that when using dns=dnsmasq the order is meaningless since dnsmasq forwards queries to all known servers at the same time. Negative values have the special effect of excluding other configurations with a greater priority value; so in presence of at least a negative priority, only DNS servers from connections with the lowest priority value will be used.")
-#define DESCRIBE_DOC_NM_SETTING_IP6_CONFIG_DNS_SEARCH N_("Array of DNS search domains. Domains starting with a tilde ('~') are considered 'routing' domains and are used only to decide the interface over which a query must be forwarded; they are not used to complete unqualified host names.")
+#define DESCRIBE_DOC_NM_SETTING_IP6_CONFIG_DNS_SEARCH N_("Array of DNS search domains.")
 #define DESCRIBE_DOC_NM_SETTING_IP6_CONFIG_GATEWAY N_("The gateway associated with this configuration. This is only meaningful if \"addresses\" is also set.")
 #define DESCRIBE_DOC_NM_SETTING_IP6_CONFIG_IGNORE_AUTO_DNS N_("When \"method\" is set to \"auto\" and this property to TRUE, automatically configured nameservers and search domains are ignored and only nameservers and search domains specified in the \"dns\" and \"dns-search\" properties, if any, are used.")
 #define DESCRIBE_DOC_NM_SETTING_IP6_CONFIG_IGNORE_AUTO_ROUTES N_("When \"method\" is set to \"auto\" and this property to TRUE, automatically configured routes are ignored and only routes specified in the \"routes\" property, if any, are used.")
diff --git a/clients/common/settings-docs.h.in b/clients/common/settings-docs.c.in
index 622f7d49..bf5753c5 100644
--- a/clients/common/settings-docs.h.in
+++ b/clients/common/settings-docs.c.in
@@ -22,7 +22,6 @@
 #define DESCRIBE_DOC_NM_SETTING_WIRELESS_SSID N_("SSID of the Wi-Fi network. Must be specified.")
 #define DESCRIBE_DOC_NM_SETTING_WIRELESS_TX_POWER N_("If non-zero, directs the device to use the specified transmit power. Units are dBm.  This property is highly driver dependent and not all devices support setting a static transmit power.")
 #define DESCRIBE_DOC_NM_SETTING_WIRELESS_SECURITY_AUTH_ALG N_("When WEP is used (ie, key-mgmt = \"none\" or \"ieee8021x\") indicate the 802.11 authentication algorithm required by the AP here.  One of \"open\" for Open System, \"shared\" for Shared Key, or \"leap\" for Cisco LEAP.  When using Cisco LEAP (ie, key-mgmt = \"ieee8021x\" and auth-alg = \"leap\") the \"leap-username\" and \"leap-password\" properties must be specified.")
-#define DESCRIBE_DOC_NM_SETTING_WIRELESS_SECURITY_FILS N_("Indicates whether Fast Initial Link Setup (802.11ai) must be enabled for the connection.  One of NM_SETTING_WIRELESS_SECURITY_FILS_DEFAULT (0) (use global default value), NM_SETTING_WIRELESS_SECURITY_FILS_DISABLE (1) (disable FILS), NM_SETTING_WIRELESS_SECURITY_FILS_OPTIONAL (2) (enable FILS if the supplicant and the access point support it) or NM_SETTING_WIRELESS_SECURITY_FILS_REQUIRED (3) (enable FILS and fail if not supported).  When set to NM_SETTING_WIRELESS_SECURITY_FILS_DEFAULT (0) and no global default is set, FILS will be optionally enabled.")
 #define DESCRIBE_DOC_NM_SETTING_WIRELESS_SECURITY_GROUP N_("A list of group/broadcast encryption algorithms which prevents connections to Wi-Fi networks that do not utilize one of the algorithms in the list.  For maximum compatibility leave this property empty.  Each list element may be one of \"wep40\", \"wep104\", \"tkip\", or \"ccmp\".")
 #define DESCRIBE_DOC_NM_SETTING_WIRELESS_SECURITY_KEY_MGMT N_("Key management used for the connection.  One of \"none\" (WEP), \"ieee8021x\" (Dynamic WEP), \"wpa-none\" (Ad-Hoc WPA-PSK), \"wpa-psk\" (infrastructure WPA-PSK), or \"wpa-eap\" (WPA-Enterprise).  This property must be set for any Wi-Fi connection that uses security.")
 #define DESCRIBE_DOC_NM_SETTING_WIRELESS_SECURITY_LEAP_PASSWORD N_("The login password for legacy LEAP connections (ie, key-mgmt = \"ieee8021x\" and auth-alg = \"leap\").")
@@ -119,7 +118,7 @@
 #define DESCRIBE_DOC_NM_SETTING_BRIDGE_FORWARD_DELAY N_("The Spanning Tree Protocol (STP) forwarding delay, in seconds.")
 #define DESCRIBE_DOC_NM_SETTING_BRIDGE_GROUP_FORWARD_MASK N_("A mask of group addresses to forward. Usually, group addresses in the range from 01:80:C2:00:00:00 to 01:80:C2:00:00:0F are not forwarded according to standards. This property is a mask of 16 bits, each corresponding to a group address in that range that must be forwarded. The mask can't have bits 0, 1 or 2 set because they are used for STP, MAC pause frames and LACP.")
 #define DESCRIBE_DOC_NM_SETTING_BRIDGE_HELLO_TIME N_("The Spanning Tree Protocol (STP) hello time, in seconds.")
-#define DESCRIBE_DOC_NM_SETTING_BRIDGE_MAC_ADDRESS N_("If specified, the MAC address of bridge. When creating a new bridge, this MAC address will be set. If this field is left unspecified, the \"ethernet.cloned-mac-address\" is referred instead to generate the initial MAC address. Note that setting \"ethernet.cloned-mac-address\" anyway overwrites the MAC address of the bridge later while activating the bridge. Hence, this property is deprecated. Deprecated: 1")
+#define DESCRIBE_DOC_NM_SETTING_BRIDGE_MAC_ADDRESS N_("If specified, the MAC address of bridge. When creating a new bridge, this MAC address will be set. If this field is left unspecified, the \"ethernet.cloned-mac-address\" is referred instead to generate the initial MAC address. Note that setting \"ethernet.cloned-mac-address\" anyway overwrites the MAC address of the bridge later while activating the bridge. Hence, this property is deprecated.")
 #define DESCRIBE_DOC_NM_SETTING_BRIDGE_MAX_AGE N_("The Spanning Tree Protocol (STP) maximum message age, in seconds.")
 #define DESCRIBE_DOC_NM_SETTING_BRIDGE_MULTICAST_SNOOPING N_("Controls whether IGMP snooping is enabled for this bridge. Note that if snooping was automatically disabled due to hash collisions, the system may refuse to enable the feature until the collisions are resolved.")
 #define DESCRIBE_DOC_NM_SETTING_BRIDGE_NAME N_("The setting's name, which uniquely identifies the setting within the connection.  Each setting type has a name unique to that type, for example \"ppp\" or \"wireless\" or \"wired\".")
@@ -136,23 +135,22 @@
 #define DESCRIBE_DOC_NM_SETTING_CDMA_PASSWORD_FLAGS N_("Flags indicating how to handle the \"password\" property.")
 #define DESCRIBE_DOC_NM_SETTING_CDMA_USERNAME N_("The username used to authenticate with the network, if required.  Many providers do not require a username, or accept any username.  But if a username is required, it is specified here.")
 #define DESCRIBE_DOC_NM_SETTING_CONNECTION_AUTH_RETRIES N_("The number of retries for the authentication. Zero means to try indefinitely; -1 means to use a global default. If the global default is not set, the authentication retries for 3 times before failing the connection. Currently this only applies to 802-1x authentication.")
-#define DESCRIBE_DOC_NM_SETTING_CONNECTION_AUTOCONNECT N_("Whether or not the connection should be automatically connected by NetworkManager when the resources for the connection are available. TRUE to automatically activate the connection, FALSE to require manual intervention to activate the connection. Note that autoconnect is not implemented for VPN profiles. See \"secondaries\" as an alternative to automatically connect VPN profiles.")
+#define DESCRIBE_DOC_NM_SETTING_CONNECTION_AUTOCONNECT N_("Whether or not the connection should be automatically connected by NetworkManager when the resources for the connection are available. TRUE to automatically activate the connection, FALSE to require manual intervention to activate the connection.")
 #define DESCRIBE_DOC_NM_SETTING_CONNECTION_AUTOCONNECT_PRIORITY N_("The autoconnect priority. If the connection is set to autoconnect, connections with higher priority will be preferred. Defaults to 0. The higher number means higher priority.")
 #define DESCRIBE_DOC_NM_SETTING_CONNECTION_AUTOCONNECT_RETRIES N_("The number of times a connection should be tried when autoactivating before giving up. Zero means forever, -1 means the global default (4 times if not overridden). Setting this to 1 means to try activation only once before blocking autoconnect. Note that after a timeout, NetworkManager will try to autoconnect again.")
-#define DESCRIBE_DOC_NM_SETTING_CONNECTION_AUTOCONNECT_SLAVES N_("Whether or not slaves of this connection should be automatically brought up when NetworkManager activates this connection. This only has a real effect for master connections. The properties \"autoconnect\", \"autoconnect-priority\" and \"autoconnect-retries\" are unrelated to this setting. The permitted values are: 0: leave slave connections untouched, 1: activate all the slave connections with this connection, -1: default. If -1 (default) is set, global connection.autoconnect-slaves is read to determine the real value. If it is default as well, this fallbacks to 0.")
+#define DESCRIBE_DOC_NM_SETTING_CONNECTION_AUTOCONNECT_SLAVES N_("Whether or not slaves of this connection should be automatically brought up when NetworkManager activates this connection. This only has a real effect for master connections. The permitted values are: 0: leave slave connections untouched, 1: activate all the slave connections with this connection, -1: default. If -1 (default) is set, global connection.autoconnect-slaves is read to determine the real value. If it is default as well, this fallbacks to 0.")
 #define DESCRIBE_DOC_NM_SETTING_CONNECTION_GATEWAY_PING_TIMEOUT N_("If greater than zero, delay success of IP addressing until either the timeout is reached, or an IP gateway replies to a ping.")
 #define DESCRIBE_DOC_NM_SETTING_CONNECTION_ID N_("A human readable unique identifier for the connection, like \"Work Wi-Fi\" or \"T-Mobile 3G\".")
 #define DESCRIBE_DOC_NM_SETTING_CONNECTION_INTERFACE_NAME N_("The name of the network interface this connection is bound to. If not set, then the connection can be attached to any interface of the appropriate type (subject to restrictions imposed by other settings). For software devices this specifies the name of the created device. For connection types where interface names cannot easily be made persistent (e.g. mobile broadband or USB Ethernet), this property should not be used. Setting this property restricts the interfaces a connection can be used with, and if interface names change or are reordered the connection may be applied to the wrong interface.")
 #define DESCRIBE_DOC_NM_SETTING_CONNECTION_LLDP N_("Whether LLDP is enabled for the connection.")
 #define DESCRIBE_DOC_NM_SETTING_CONNECTION_MASTER N_("Interface name of the master device or UUID of the master connection.")
-#define DESCRIBE_DOC_NM_SETTING_CONNECTION_MDNS N_("Whether mDNS is enabled for the connection. The permitted values are: yes: register hostname and resolving for the connection, no: disable mDNS for the interface, resolve: do not register hostname but allow resolving of mDNS host names. When updating this property on a currently activated connection, the change takes effect immediately. This feature requires a plugin which supports mDNS. One such plugin is dns-systemd-resolved.")
 #define DESCRIBE_DOC_NM_SETTING_CONNECTION_METERED N_("Whether the connection is metered. When updating this property on a currently activated connection, the change takes effect immediately.")
 #define DESCRIBE_DOC_NM_SETTING_CONNECTION_NAME N_("The setting's name, which uniquely identifies the setting within the connection.  Each setting type has a name unique to that type, for example \"ppp\" or \"wireless\" or \"wired\".")
 #define DESCRIBE_DOC_NM_SETTING_CONNECTION_PERMISSIONS N_("An array of strings defining what access a given user has to this connection.  If this is NULL or empty, all users are allowed to access this connection; otherwise users are allowed if and only if they are in this list.  When this is not empty, the connection can be active only when one of the specified users is logged into an active session.  Each entry is of the form \"[type]:[id]:[reserved]\"; for example, \"user:dcbw:blah\". At this time only the \"user\" [type] is allowed.  Any other values are ignored and reserved for future use.  [id] is the username that this permission refers to, which may not contain the \":\" character. Any [reserved] information present must be ignored and is reserved for future use.  All of [type], [id], and [reserved] must be valid UTF-8.")
 #define DESCRIBE_DOC_NM_SETTING_CONNECTION_READ_ONLY N_("FALSE if the connection can be modified using the provided settings service's D-Bus interface with the right privileges, or TRUE if the connection is read-only and cannot be modified.")
 #define DESCRIBE_DOC_NM_SETTING_CONNECTION_SECONDARIES N_("List of connection UUIDs that should be activated when the base connection itself is activated. Currently only VPN connections are supported.")
 #define DESCRIBE_DOC_NM_SETTING_CONNECTION_SLAVE_TYPE N_("Setting name of the device type of this slave's master connection (eg, \"bond\"), or NULL if this connection is not a slave.")
-#define DESCRIBE_DOC_NM_SETTING_CONNECTION_STABLE_ID N_("Token to generate stable IDs for the connection. The stable-id is used for generating IPv6 stable private addresses with ipv6.addr-gen-mode=stable-privacy. It is also used to seed the generated cloned MAC address for ethernet.cloned-mac-address=stable and wifi.cloned-mac-address=stable. It is also used as DHCP client identifier with ipv4.dhcp-client-id=stable. Note that also the interface name of the activating connection and a per-host secret key is included into the address generation so that the same stable-id on different hosts/devices yields different addresses. If the value is unset, an ID unique for the connection is used. Specifying a stable-id allows multiple connections to generate the same addresses. Another use is to generate IDs at runtime via dynamic substitutions. The '$' character is treated special to perform dynamic substitutions at runtime. Currently supported are \"${CONNECTION}\", \"${BOOT}\", \"${RANDOM}\". These effectively create unique IDs per-connection, per-boot, or every time. Any unrecognized patterns following '$' are treated verbatim, however are reserved for future use. You are thus advised to avoid '$' or escape it as \"$$\". For example, set it to \"${CONNECTION}/${BOOT}\" to create a unique id for this connection that changes with every reboot. Note that two connections only use the same effective id if their stable-id is also identical before performing dynamic substitutions.")
+#define DESCRIBE_DOC_NM_SETTING_CONNECTION_STABLE_ID N_("Token to generate stable IDs for the connection. The stable-id is used for generating IPv6 stable private addresses with ipv6.addr-gen-mode=stable-privacy. It is also used to seed the generated cloned MAC address for ethernet.cloned-mac-address=stable and wifi.cloned-mac-address=stable. Note that also the interface name of the activating connection and a per-host secret key is included into the address generation so that the same stable-id on different hosts/devices yields different addresses. If the value is unset, an ID unique for the connection is used. Specifying a stable-id allows multiple connections to generate the same addresses. Another use is to generate IDs at runtime via dynamic substitutions. The '$' character is treated special to perform dynamic substitutions at runtime. Currently supported are \"${CONNECTION}\", \"${BOOT}\", \"${RANDOM}\". These effectively create unique IDs per-connection, per-boot, or every time. Any unrecognized patterns following '$' are treated verbatim, however are reserved for future use. You are thus advised to avoid '$' or escape it as \"$$\". For example, set it to \"${CONNECTION}/${BOOT}\" to create a unique id for this connection that changes with every reboot. Note that two connections only use the same effective id if their stable-id is also identical before performing dynamic substitutions.")
 #define DESCRIBE_DOC_NM_SETTING_CONNECTION_TIMESTAMP N_("The time, in seconds since the Unix Epoch, that the connection was last _successfully_ fully activated. NetworkManager updates the connection timestamp periodically when the connection is active to ensure that an active connection has the latest timestamp. The property is only meant for reading (changes to this property will not be preserved).")
 #define DESCRIBE_DOC_NM_SETTING_CONNECTION_TYPE N_("Base type of the connection. For hardware-dependent connections, should contain the setting name of the hardware-type specific setting (ie, \"802-3-ethernet\" or \"802-11-wireless\" or \"bluetooth\", etc), and for non-hardware dependent connections like VPN or otherwise, should contain the setting name of that setting type (ie, \"vpn\" or \"bridge\", etc).")
 #define DESCRIBE_DOC_NM_SETTING_CONNECTION_UUID N_("A universally unique identifier for the connection, for example generated with libuuid.  It should be assigned when the connection is created, and never changed as long as the connection still applies to the same network.  For example, it should not be changed when the \"id\" property or NMSettingIP4Config changes, but might need to be re-created when the Wi-Fi SSID, mobile broadband network provider, or \"type\" property changes. The UUID must be in the format \"2815492f-7e56-435e-b2e9-246bd7cdc664\" (ie, contains only hexadecimal characters and \"-\").")
@@ -196,7 +194,6 @@
 #define DESCRIBE_DOC_NM_SETTING_INFINIBAND_PARENT N_("The interface name of the parent device of this device. Normally NULL, but if the \"p_key\" property is set, then you must specify the base device by setting either this property or \"mac-address\".")
 #define DESCRIBE_DOC_NM_SETTING_INFINIBAND_TRANSPORT_MODE N_("The IP-over-InfiniBand transport mode. Either \"datagram\" or \"connected\".")
 #define DESCRIBE_DOC_NM_SETTING_IP_TUNNEL_ENCAPSULATION_LIMIT N_("How many additional levels of encapsulation are permitted to be prepended to packets. This property applies only to IPv6 tunnels.")
-#define DESCRIBE_DOC_NM_SETTING_IP_TUNNEL_FLAGS N_("Tunnel flags. Currently the following values are supported: NM_IP_TUNNEL_FLAG_IP6_IGN_ENCAP_LIMIT (0x1), NM_IP_TUNNEL_FLAG_IP6_USE_ORIG_TCLASS (0x2), NM_IP_TUNNEL_FLAG_IP6_USE_ORIG_FLOWLABEL (0x4), NM_IP_TUNNEL_FLAG_IP6_MIP6_DEV (0x8), NM_IP_TUNNEL_FLAG_IP6_RCV_DSCP_COPY (0x10), NM_IP_TUNNEL_FLAG_IP6_USE_ORIG_FWMARK (0x20). They are valid only for IPv6 tunnels.")
 #define DESCRIBE_DOC_NM_SETTING_IP_TUNNEL_FLOW_LABEL N_("The flow label to assign to tunnel packets. This property applies only to IPv6 tunnels.")
 #define DESCRIBE_DOC_NM_SETTING_IP_TUNNEL_INPUT_KEY N_("The key used for tunnel input packets; the property is valid only for certain tunnel modes (GRE, IP6GRE). If empty, no key is used.")
 #define DESCRIBE_DOC_NM_SETTING_IP_TUNNEL_LOCAL N_("The local endpoint of the tunnel; the value can be empty, otherwise it must contain an IPv4 or IPv6 address.")
@@ -210,8 +207,8 @@
 #define DESCRIBE_DOC_NM_SETTING_IP_TUNNEL_TOS N_("The type of service (IPv4) or traffic class (IPv6) field to be set on tunneled packets.")
 #define DESCRIBE_DOC_NM_SETTING_IP_TUNNEL_TTL N_("The TTL to assign to tunneled packets. 0 is a special value meaning that packets inherit the TTL value.")
 #define DESCRIBE_DOC_NM_SETTING_IP4_CONFIG_ADDRESSES N_("Array of IP addresses.")
-#define DESCRIBE_DOC_NM_SETTING_IP4_CONFIG_DAD_TIMEOUT N_("Timeout in milliseconds used to check for the presence of duplicate IP addresses on the network.  If an address conflict is detected, the activation will fail.  A zero value means that no duplicate address detection is performed, -1 means the default value (either configuration ipvx.dad-timeout override or zero).  A value greater than zero is a timeout in milliseconds. The property is currently implemented only for IPv4.")
-#define DESCRIBE_DOC_NM_SETTING_IP4_CONFIG_DHCP_CLIENT_ID N_("A string sent to the DHCP server to identify the local machine which the DHCP server may use to customize the DHCP lease and options. When the property is a hex string ('aa:bb:cc') it is interpreted as a binary client ID, in which case the first byte is assumed to be the 'type' field as per RFC 2132 section 9.14 and the remaining bytes may be an hardware address (e.g. '01:xx:xx:xx:xx:xx:xx' where 1 is the Ethernet ARP type and the rest is a MAC address). If the property is not a hex string it is considered as a non-hardware-address client ID and the 'type' field is set to 0. The special values \"mac\" and \"perm-mac\" are supported, which use the current or permanent MAC address of the device to generate a client identifier with type ethernet type (01). Currently, these options only work for ethernet type of links. The special value \"stable\" is supported to generate a type 0 client identifier based on the stable-id (see connection.stable-id). If unset, a globally configured default is used. If still unset, the client-id from the last lease is reused.")
+#define DESCRIBE_DOC_NM_SETTING_IP4_CONFIG_DAD_TIMEOUT N_("Timeout in milliseconds used to check for the presence of duplicate IP addresses on the network.  If an address conflict is detected, the activation will fail.  A zero value means that no duplicate address detection is performed, -1 means the default value (either configuration ipvx.dad-timeout override or 3 seconds).  A value greater than zero is a timeout in milliseconds.")
+#define DESCRIBE_DOC_NM_SETTING_IP4_CONFIG_DHCP_CLIENT_ID N_("A string sent to the DHCP server to identify the local machine which the DHCP server may use to customize the DHCP lease and options. When the property is a hex string ('aa:bb:cc') it is interpreted as a binary client ID, in which case the first byte is assumed to be the 'type' field as per RFC 2132 section 9.14 and the remaining bytes may be an hardware address (e.g. '01:xx:xx:xx:xx:xx:xx' where 1 is the Ethernet ARP type and the rest is a MAC address). If the property is not a hex string it is considered as a non-hardware-address client ID and the 'type' field is set to 0.")
 #define DESCRIBE_DOC_NM_SETTING_IP4_CONFIG_DHCP_FQDN N_("If the \"dhcp-send-hostname\" property is TRUE, then the specified FQDN will be sent to the DHCP server when acquiring a lease. This property and \"dhcp-hostname\" are mutually exclusive and cannot be set at the same time.")
 #define DESCRIBE_DOC_NM_SETTING_IP4_CONFIG_DHCP_HOSTNAME N_("If the \"dhcp-send-hostname\" property is TRUE, then the specified name will be sent to the DHCP server when acquiring a lease. This property and \"dhcp-fqdn\" are mutually exclusive and cannot be set at the same time.")
 #define DESCRIBE_DOC_NM_SETTING_IP4_CONFIG_DHCP_SEND_HOSTNAME N_("If TRUE, a hostname is sent to the DHCP server when acquiring a lease. Some DHCP servers use this hostname to update DNS databases, essentially providing a static hostname for the computer.  If the \"dhcp-hostname\" property is NULL and this property is TRUE, the current persistent hostname of the computer is sent.")
@@ -219,7 +216,7 @@
 #define DESCRIBE_DOC_NM_SETTING_IP4_CONFIG_DNS N_("Array of IP addresses of DNS servers.")
 #define DESCRIBE_DOC_NM_SETTING_IP4_CONFIG_DNS_OPTIONS N_("Array of DNS options as described in man 5 resolv.conf. NULL means that the options are unset and left at the default. In this case NetworkManager will use default options. This is distinct from an empty list of properties.")
 #define DESCRIBE_DOC_NM_SETTING_IP4_CONFIG_DNS_PRIORITY N_("Intra-connection DNS priority. The relative priority to be used when determining the order of DNS servers in resolv.conf.  A lower value means that servers will be on top of the file.  Zero selects the default value, which is 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 same connection profile. For that, just specify the DNS servers in the desired order. When multiple devices have configurations with the same priority, the one with an active default route will be preferred. Note that when using dns=dnsmasq the order is meaningless since dnsmasq forwards queries to all known servers at the same time. Negative values have the special effect of excluding other configurations with a greater priority value; so in presence of at least a negative priority, only DNS servers from connections with the lowest priority value will be used.")
-#define DESCRIBE_DOC_NM_SETTING_IP4_CONFIG_DNS_SEARCH N_("Array of DNS search domains. Domains starting with a tilde ('~') are considered 'routing' domains and are used only to decide the interface over which a query must be forwarded; they are not used to complete unqualified host names.")
+#define DESCRIBE_DOC_NM_SETTING_IP4_CONFIG_DNS_SEARCH N_("Array of DNS search domains.")
 #define DESCRIBE_DOC_NM_SETTING_IP4_CONFIG_GATEWAY N_("The gateway associated with this configuration. This is only meaningful if \"addresses\" is also set.")
 #define DESCRIBE_DOC_NM_SETTING_IP4_CONFIG_IGNORE_AUTO_DNS N_("When \"method\" is set to \"auto\" and this property to TRUE, automatically configured nameservers and search domains are ignored and only nameservers and search domains specified in the \"dns\" and \"dns-search\" properties, if any, are used.")
 #define DESCRIBE_DOC_NM_SETTING_IP4_CONFIG_IGNORE_AUTO_ROUTES N_("When \"method\" is set to \"auto\" and this property to TRUE, automatically configured routes are ignored and only routes specified in the \"routes\" property, if any, are used.")
@@ -232,14 +229,14 @@
 #define DESCRIBE_DOC_NM_SETTING_IP4_CONFIG_ROUTES N_("Array of IP routes.")
 #define DESCRIBE_DOC_NM_SETTING_IP6_CONFIG_ADDR_GEN_MODE N_("Configure method for creating the address for use with RFC4862 IPv6 Stateless Address Autoconfiguration. The permitted values are: NM_SETTING_IP6_CONFIG_ADDR_GEN_MODE_EUI64 (0) or NM_SETTING_IP6_CONFIG_ADDR_GEN_MODE_STABLE_PRIVACY (1). If the property is set to EUI64, the addresses will be generated using the interface tokens derived from hardware address. This makes the host part of the address to stay constant, making it possible to track host's presence when it changes networks. The address changes when the interface hardware is replaced. The value of stable-privacy enables use of cryptographically secure hash of a secret host-specific key along with the connection's stable-id and the network address as specified by RFC7217. This makes it impossible to use the address track host's presence, and makes the address stable when the network interface hardware is replaced. On D-Bus, the absence of an addr-gen-mode setting equals enabling stable-privacy. For keyfile plugin, the absence of the setting on disk means EUI64 so that the property doesn't change on upgrade from older versions. Note that this setting is distinct from the Privacy Extensions as configured by \"ip6-privacy\" property and it does not affect the temporary addresses configured with this option.")
 #define DESCRIBE_DOC_NM_SETTING_IP6_CONFIG_ADDRESSES N_("Array of IP addresses.")
-#define DESCRIBE_DOC_NM_SETTING_IP6_CONFIG_DAD_TIMEOUT N_("Timeout in milliseconds used to check for the presence of duplicate IP addresses on the network.  If an address conflict is detected, the activation will fail.  A zero value means that no duplicate address detection is performed, -1 means the default value (either configuration ipvx.dad-timeout override or zero).  A value greater than zero is a timeout in milliseconds. The property is currently implemented only for IPv4.")
+#define DESCRIBE_DOC_NM_SETTING_IP6_CONFIG_DAD_TIMEOUT N_("Timeout in milliseconds used to check for the presence of duplicate IP addresses on the network.  If an address conflict is detected, the activation will fail.  A zero value means that no duplicate address detection is performed, -1 means the default value (either configuration ipvx.dad-timeout override or 3 seconds).  A value greater than zero is a timeout in milliseconds.")
 #define DESCRIBE_DOC_NM_SETTING_IP6_CONFIG_DHCP_HOSTNAME N_("If the \"dhcp-send-hostname\" property is TRUE, then the specified name will be sent to the DHCP server when acquiring a lease. This property and \"dhcp-fqdn\" are mutually exclusive and cannot be set at the same time.")
 #define DESCRIBE_DOC_NM_SETTING_IP6_CONFIG_DHCP_SEND_HOSTNAME N_("If TRUE, a hostname is sent to the DHCP server when acquiring a lease. Some DHCP servers use this hostname to update DNS databases, essentially providing a static hostname for the computer.  If the \"dhcp-hostname\" property is NULL and this property is TRUE, the current persistent hostname of the computer is sent.")
 #define DESCRIBE_DOC_NM_SETTING_IP6_CONFIG_DHCP_TIMEOUT N_("A timeout for a DHCP transaction in seconds.")
 #define DESCRIBE_DOC_NM_SETTING_IP6_CONFIG_DNS N_("Array of IP addresses of DNS servers.")
 #define DESCRIBE_DOC_NM_SETTING_IP6_CONFIG_DNS_OPTIONS N_("Array of DNS options as described in man 5 resolv.conf. NULL means that the options are unset and left at the default. In this case NetworkManager will use default options. This is distinct from an empty list of properties.")
 #define DESCRIBE_DOC_NM_SETTING_IP6_CONFIG_DNS_PRIORITY N_("Intra-connection DNS priority. The relative priority to be used when determining the order of DNS servers in resolv.conf.  A lower value means that servers will be on top of the file.  Zero selects the default value, which is 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 same connection profile. For that, just specify the DNS servers in the desired order. When multiple devices have configurations with the same priority, the one with an active default route will be preferred. Note that when using dns=dnsmasq the order is meaningless since dnsmasq forwards queries to all known servers at the same time. Negative values have the special effect of excluding other configurations with a greater priority value; so in presence of at least a negative priority, only DNS servers from connections with the lowest priority value will be used.")
-#define DESCRIBE_DOC_NM_SETTING_IP6_CONFIG_DNS_SEARCH N_("Array of DNS search domains. Domains starting with a tilde ('~') are considered 'routing' domains and are used only to decide the interface over which a query must be forwarded; they are not used to complete unqualified host names.")
+#define DESCRIBE_DOC_NM_SETTING_IP6_CONFIG_DNS_SEARCH N_("Array of DNS search domains.")
 #define DESCRIBE_DOC_NM_SETTING_IP6_CONFIG_GATEWAY N_("The gateway associated with this configuration. This is only meaningful if \"addresses\" is also set.")
 #define DESCRIBE_DOC_NM_SETTING_IP6_CONFIG_IGNORE_AUTO_DNS N_("When \"method\" is set to \"auto\" and this property to TRUE, automatically configured nameservers and search domains are ignored and only nameservers and search domains specified in the \"dns\" and \"dns-search\" properties, if any, are used.")
 #define DESCRIBE_DOC_NM_SETTING_IP6_CONFIG_IGNORE_AUTO_ROUTES N_("When \"method\" is set to \"auto\" and this property to TRUE, automatically configured routes are ignored and only routes specified in the \"routes\" property, if any, are used.")
diff --git a/clients/common/tests/meson.build b/clients/common/tests/meson.build
deleted file mode 100644
index cc357cdc..00000000
--- a/clients/common/tests/meson.build
+++ /dev/null
@@ -1,23 +0,0 @@
-test_unit = 'test-general'
-
-deps = [
-  libnm_dep,
-  libnmc_dep,
-  libnmc_base_dep,
-  nm_core_dep
-]
-
-exe = executable(
-  'clients-' + test_unit,
-  test_unit + '.c',
-  dependencies: deps,
-  c_args: clients_cflags + [
-    '-DNETWORKMANAGER_COMPILATION_TEST',
-  ],
-)
-
-test(
-  'clients/' + test_unit,
-  test_script,
-  args: test_args + [exe.full_path()]
-)
diff --git a/clients/common/tests/test-general.c b/clients/common/tests/test-general.c
index 8f96eb26..64efd14d 100644
--- a/clients/common/tests/test-general.c
+++ b/clients/common/tests/test-general.c
@@ -19,6 +19,10 @@
 
 #include "nm-default.h"
 
+#include "NetworkManager.h"
+
+#include "nm-utils/nm-hash-utils.h"
+
 #include "nm-meta-setting-access.h"
 
 #include "nm-utils/nm-test-utils.h"
@@ -86,7 +90,7 @@ test_client_meta_check (void)
 				g_assert (pi->setting_info == info);
 				g_assert (pi->property_name);
 
-				g_assert (g_hash_table_add (property_names, (gpointer) pi->property_name));
+				g_assert (nm_g_hash_table_add (property_names, (gpointer) pi->property_name));
 
 				g_assert_cmpstr (pi->property_name, ==, pi->meta_type->get_name ((const NMMetaAbstractInfo *) pi, FALSE));
 				g_assert_cmpstr (pi->property_name, ==, pi->meta_type->get_name ((const NMMetaAbstractInfo *) pi, TRUE));
@@ -100,14 +104,14 @@ test_client_meta_check (void)
 
 		if (info->valid_parts) {
 			gsize i, l;
-			gs_unref_hashtable GHashTable *dup = g_hash_table_new (nm_direct_hash, NULL);
+			gs_unref_hashtable GHashTable *dup = g_hash_table_new (NULL, NULL);
 
 			l = NM_PTRARRAY_LEN (info->valid_parts);
 			g_assert (l >= 2);
 
 			for (i = 0; info->valid_parts[i]; i++) {
 				g_assert (info->valid_parts[i]->setting_info);
-				g_assert (g_hash_table_add (dup, (gpointer) info->valid_parts[i]->setting_info));
+				g_assert (nm_g_hash_table_add (dup, (gpointer) info->valid_parts[i]->setting_info));
 
 				if (i == 0) {
 					g_assert (info->valid_parts[i]->setting_info == &nm_meta_setting_infos_editor[NM_META_SETTING_TYPE_CONNECTION]);