about summary refs log tree commit diff
path: root/clients/cli
diff options
context:
space:
mode:
authorMichael Biebl <biebl@debian.org>2019-07-31 10:51:42 +0200
committerMichael Biebl <biebl@debian.org>2019-07-31 10:51:42 +0200
commit2e5fa45ddfbb5cffa1e78221f1cea706e2f298af (patch)
tree86f69d36c56de3074280456eddc854a780b8e04b /clients/cli
parent85563b7fc7ec2cd21e38debb9b28db342e2e8e7c (diff)
New upstream version 1.19.90 upstream/1.19.90
Diffstat (limited to 'clients/cli')
-rw-r--r--clients/cli/common.c102
-rw-r--r--clients/cli/connections.c315
-rw-r--r--clients/cli/devices.c22
-rw-r--r--clients/cli/general.c4
-rw-r--r--clients/cli/nmcli.c86
-rw-r--r--clients/cli/utils.c4
-rw-r--r--clients/cli/utils.h1
7 files changed, 242 insertions, 292 deletions
diff --git a/clients/cli/common.c b/clients/cli/common.c
index 3c1c315d..2fc8aaf6 100644
--- a/clients/cli/common.c
+++ b/clients/cli/common.c
@@ -425,36 +425,38 @@ nmc_find_connection (const GPtrArray *connections,
                      GPtrArray **out_result,
                      gboolean complete)
 {
-	NMConnection *connection;
+	NMConnection *best_candidate_uuid = NULL;
 	NMConnection *best_candidate = NULL;
+	gs_unref_ptrarray GPtrArray *result_allocated = NULL;
 	GPtrArray *result = out_result ? *out_result : NULL;
+	const guint result_inital_len = result ? result->len : 0u;
 	guint i, j;
 
 	nm_assert (connections);
 	nm_assert (filter_val);
 
 	for (i = 0; i < connections->len; i++) {
-		const char *v, *v_num;
+		gboolean match_by_uuid = FALSE;
+		NMConnection *connection;
+		const char *v;
+		const char *v_num;
 
 		connection = NM_CONNECTION (connections->pdata[i]);
 
-		/* When filter_type is NULL, compare connection ID (filter_val)
-		 * against all types. Otherwise, only compare against the specific
-		 * type. If 'path' filter type is specified, comparison against
-		 * numeric index (in addition to the whole path) is allowed.
-		 */
-		if (NM_IN_STRSET (filter_type, NULL, "id")) {
-			v = nm_connection_get_id (connection);
-			if (complete)
-				nmc_complete_strings (filter_val, v, NULL);
-			if (nm_streq0 (filter_val, v))
-				goto found;
-		}
-
 		if (NM_IN_STRSET (filter_type, NULL, "uuid")) {
 			v = nm_connection_get_uuid (connection);
 			if (complete && (filter_type || *filter_val))
-				nmc_complete_strings (filter_val, v, NULL);
+				nmc_complete_strings (filter_val, v);
+			if (nm_streq0 (filter_val, v)) {
+				match_by_uuid = TRUE;
+				goto found;
+			}
+		}
+
+		if (NM_IN_STRSET (filter_type, NULL, "id")) {
+			v = nm_connection_get_id (connection);
+			if (complete)
+				nmc_complete_strings (filter_val, v);
 			if (nm_streq0 (filter_val, v))
 				goto found;
 		}
@@ -463,7 +465,7 @@ nmc_find_connection (const GPtrArray *connections,
 			v = nm_connection_get_path (connection);
 			v_num = nm_utils_dbus_path_get_last_component (v);
 			if (complete && (filter_type || *filter_val))
-				nmc_complete_strings (filter_val, v, filter_type ? v_num : NULL, NULL);
+				nmc_complete_strings (filter_val, v, (*filter_val ? v_num : NULL));
 			if (   nm_streq0 (filter_val, v)
 			    || (filter_type && nm_streq0 (filter_val, v_num)))
 				goto found;
@@ -472,29 +474,51 @@ nmc_find_connection (const GPtrArray *connections,
 		if (NM_IN_STRSET (filter_type, NULL, "filename")) {
 			v = nm_remote_connection_get_filename (NM_REMOTE_CONNECTION (connections->pdata[i]));
 			if (complete && (filter_type || *filter_val))
-				nmc_complete_strings (filter_val, v, NULL);
+				nmc_complete_strings (filter_val, v);
 			if (nm_streq0 (filter_val, v))
 				goto found;
 		}
 
 		continue;
+
 found:
-		if (!out_result)
-			return connection;
-		if (!best_candidate)
-			best_candidate = connection;
-		if (!result)
-			result = g_ptr_array_new_with_free_func (g_object_unref);
-		for (j = 0; j < result->len; j++) {
-			if (connection == result->pdata[j])
-				break;
+		if (match_by_uuid) {
+			if (   !complete
+			    && !out_result)
+				return connection;
+			best_candidate_uuid = connection;
+		} else {
+			if (!best_candidate)
+				best_candidate = connection;
+		}
+		if (out_result) {
+			gboolean already_tracked = FALSE;
+
+			if (!result) {
+				result_allocated = g_ptr_array_new_with_free_func (g_object_unref);
+				result = result_allocated;
+			} else {
+				for (j = 0; j < result->len; j++) {
+					if (connection == result->pdata[j]) {
+						already_tracked = TRUE;
+						break;
+					}
+				}
+			}
+			if (!already_tracked) {
+				if (match_by_uuid) {
+					/* the profile is matched exactly (by UUID). We prepend it
+					 * to the list of all found profiles. */
+					g_ptr_array_insert (result, result_inital_len, g_object_ref (connection));
+				} else
+					g_ptr_array_add (result, g_object_ref (connection));
+			}
 		}
-		if (j == result->len)
-			g_ptr_array_add (result, g_object_ref (connection));
 	}
 
-	NM_SET_OUT (out_result, result);
-	return best_candidate;
+	if (result_allocated)
+		*out_result = g_steal_pointer (&result_allocated);
+	return best_candidate_uuid ?: best_candidate;
 }
 
 NMActiveConnection *
@@ -525,7 +549,7 @@ nmc_find_active_connection (const GPtrArray *active_cons,
 		if (NM_IN_STRSET (filter_type, NULL, "id")) {
 			v = nm_active_connection_get_id (candidate);
 			if (complete)
-				nmc_complete_strings (filter_val, v, NULL);
+				nmc_complete_strings (filter_val, v);
 			if (nm_streq0 (filter_val, v))
 				goto found;
 		}
@@ -533,7 +557,7 @@ nmc_find_active_connection (const GPtrArray *active_cons,
 		if (NM_IN_STRSET (filter_type, NULL, "uuid")) {
 			v = nm_active_connection_get_uuid (candidate);
 			if (complete && (filter_type || *filter_val))
-				nmc_complete_strings (filter_val, v, NULL);
+				nmc_complete_strings (filter_val, v);
 			if (nm_streq0 (filter_val, v))
 				goto found;
 		}
@@ -542,7 +566,7 @@ nmc_find_active_connection (const GPtrArray *active_cons,
 			v = con ? nm_connection_get_path (NM_CONNECTION (con)) : NULL;
 			v_num = nm_utils_dbus_path_get_last_component (v);
 			if (complete && (filter_type || *filter_val))
-				nmc_complete_strings (filter_val, v, filter_type ? v_num : NULL, NULL);
+				nmc_complete_strings (filter_val, v, filter_type ? v_num : NULL);
 			if (   nm_streq0 (filter_val, v)
 			    || (filter_type && nm_streq0 (filter_val, v_num)))
 				goto found;
@@ -551,7 +575,7 @@ nmc_find_active_connection (const GPtrArray *active_cons,
 		if (NM_IN_STRSET (filter_type, NULL, "filename")) {
 			v = nm_remote_connection_get_filename (con);
 			if (complete && (filter_type || *filter_val))
-				nmc_complete_strings (filter_val, v, NULL);
+				nmc_complete_strings (filter_val, v);
 			if (nm_streq0 (filter_val, v))
 				goto found;
 		}
@@ -560,7 +584,7 @@ nmc_find_active_connection (const GPtrArray *active_cons,
 			v = nm_object_get_path (NM_OBJECT (candidate));
 			v_num = nm_utils_dbus_path_get_last_component (v);
 			if (complete && (filter_type || *filter_val))
-				nmc_complete_strings (filter_val, v, filter_type ? v_num : NULL, NULL);
+				nmc_complete_strings (filter_val, v, filter_type ? v_num : NULL);
 			if (   nm_streq0 (filter_val, v)
 			    || (filter_type && nm_streq0 (filter_val, v_num)))
 				goto found;
@@ -1254,9 +1278,9 @@ call_cmd (NmCli *nmc, GSimpleAsyncResult *simple, const NMCCommand *cmd, int arg
 static void
 nmc_complete_help (const char *prefix)
 {
-	nmc_complete_strings (prefix, "help", NULL);
+	nmc_complete_strings (prefix, "help");
 	if (*prefix == '-')
-		nmc_complete_strings (prefix, "-help", "--help", NULL);
+		nmc_complete_strings (prefix, "-help", "--help");
 }
 
 /**
@@ -1395,7 +1419,7 @@ void
 nmc_complete_bool (const char *prefix)
 {
 	nmc_complete_strings (prefix, "true", "yes", "on",
-	                              "false", "no", "off", NULL);
+	                              "false", "no", "off");
 }
 
 /**
diff --git a/clients/cli/connections.c b/clients/cli/connections.c
index 6ee3b49f..53105f95 100644
--- a/clients/cli/connections.c
+++ b/clients/cli/connections.c
@@ -41,6 +41,8 @@
 #include "devices.h"
 #include "polkit-agent.h"
 
+/*****************************************************************************/
+
 typedef enum {
 	PROPERTY_INF_FLAG_NONE                      = 0x0,
 	PROPERTY_INF_FLAG_DISABLED                  = 0x1, /* Don't ask due to runtime decision. */
@@ -50,14 +52,13 @@ typedef enum {
 
 typedef char *(*CompEntryFunc) (const char *, int);
 
-typedef struct _OptionInfo OptionInfo;
-struct _OptionInfo {
+typedef struct _OptionInfo {
 	const NMMetaSettingInfoEditor *setting_info;
 	const char *property;
 	const char *option;
-	gboolean (*check_and_set)(NmCli *nmc, NMConnection *connection, const OptionInfo *option, const char *value, GError **error);
+	gboolean (*check_and_set)(NmCli *nmc, NMConnection *connection, const struct _OptionInfo *option, const char *value, GError **error);
 	CompEntryFunc generator_func;
-};
+} OptionInfo;
 
 /* define some prompts for connection editor */
 #define EDITOR_PROMPT_SETTING  _("Setting name? ")
@@ -96,6 +97,47 @@ NM_UTILS_LOOKUP_STR_DEFINE_STATIC (vpn_connection_state_to_string, NMVpnConnecti
 	NM_UTILS_LOOKUP_ITEM_IGNORE (NM_VPN_CONNECTION_STATE_UNKNOWN),
 )
 
+/*****************************************************************************/
+
+typedef struct {
+	NmCli *nmc;
+	char *orig_id;
+	char *orig_uuid;
+	char *new_id;
+} AddConnectionInfo;
+
+static AddConnectionInfo *
+_add_connection_info_new (NmCli *nmc,
+                          NMConnection *orig_connection,
+                          NMConnection *new_connection)
+{
+	AddConnectionInfo *info;
+
+	info = g_slice_new (AddConnectionInfo);
+	*info = (AddConnectionInfo) {
+		.nmc       = nmc,
+		.orig_id   = orig_connection ? g_strdup (nm_connection_get_id   (orig_connection)) : NULL,
+		.orig_uuid = orig_connection ? g_strdup (nm_connection_get_uuid (orig_connection)) : NULL,
+		.new_id    = g_strdup (nm_connection_get_id (new_connection)),
+	};
+	return info;
+}
+
+static void
+_add_connection_info_free (AddConnectionInfo *info)
+{
+	g_free (info->orig_id);
+	g_free (info->orig_uuid);
+	g_free (info->new_id);
+	nm_g_slice_free (info);
+}
+
+NM_AUTO_DEFINE_FCN (AddConnectionInfo *, _nm_auto_free_add_connection_info, _add_connection_info_free)
+
+#define nm_auto_free_add_connection_info nm_auto (_nm_auto_free_add_connection_info)
+
+/*****************************************************************************/
+
 /* Essentially a version of nm_setting_connection_get_connection_type() that
  * prefers an alias instead of the settings name when in pretty print mode.
  * That is so that we print "wifi" instead of "802-11-wireless" in "nmcli c". */
@@ -209,7 +251,7 @@ get_ac_device_string (NMActiveConnection *active)
 {
 	GString *dev_str;
 	const GPtrArray *devices;
-	int i;
+	guint i;
 
 	if (!active)
 		return NULL;
@@ -826,7 +868,8 @@ const NmcMetaGenericInfo *const metagen_con_active_vpn[_NMC_GENERIC_INFO_TYPE_CO
                                          NM_SETTING_PROXY_SETTING_NAME"," \
                                          NM_SETTING_TC_CONFIG_SETTING_NAME"," \
                                          NM_SETTING_SRIOV_SETTING_NAME"," \
-                                         NM_SETTING_ETHTOOL_SETTING_NAME
+                                         NM_SETTING_ETHTOOL_SETTING_NAME"," \
+                                         NM_SETTING_OVS_DPDK_SETTING_NAME \
                                          // NM_SETTING_DUMMY_SETTING_NAME
                                          // NM_SETTING_WIMAX_SETTING_NAME
 
@@ -1306,7 +1349,7 @@ nmc_connection_profile_details (NMConnection *connection, NmCli *nmc)
 	GError *error = NULL;
 	GArray *print_settings_array;
 	GPtrArray *prop_array = NULL;
-	int i;
+	guint i;
 	char *fields_str;
 	char *fields_all =    NMC_FIELDS_SETTINGS_NAMES_ALL;
 	char *fields_common = NMC_FIELDS_SETTINGS_NAMES_ALL;
@@ -1872,7 +1915,7 @@ parse_preferred_connection_order (const char *order, GError **error)
 	GArray *order_arr;
 	NmcSortOrder val;
 	gboolean inverse, unique;
-	int i;
+	guint i;
 
 	strv = nm_utils_strsplit_set (order, ":");
 	if (!strv) {
@@ -1945,7 +1988,7 @@ get_connection (NmCli *nmc,
 	}
 
 	if (*argc == 1 && nmc->complete)
-		nmc_complete_strings (**argv, "id", "uuid", "path", "filename", NULL);
+		nmc_complete_strings (**argv, "id", "uuid", "path", "filename");
 
 	if (NM_IN_STRSET (**argv, "id", "uuid", "path", "filename")) {
 		if (*argc == 1) {
@@ -2104,7 +2147,7 @@ do_connections_show (NmCli *nmc, int argc, char **argv)
 			guint i_found_cons;
 
 			if (argc == 1 && nmc->complete)
-				nmc_complete_strings (*argv, "id", "uuid", "path", "filename", "apath", NULL);
+				nmc_complete_strings (*argv, "id", "uuid", "path", "filename", "apath");
 
 			if (NM_IN_STRSET (*argv, "id", "uuid", "path", "filename", "apath")) {
 				selector = *argv;
@@ -2243,7 +2286,7 @@ get_default_active_connection (NmCli *nmc, NMDevice **device)
 	NMDevice *non_default_device = NULL;
 	NMActiveConnection *non_default_ac = NULL;
 	const GPtrArray *connections;
-	int i;
+	guint i;
 
 	g_return_val_if_fail (nmc, NULL);
 	g_return_val_if_fail (device, NULL);
@@ -2302,7 +2345,7 @@ find_device_for_connection (NmCli *nmc,
 {
 	NMSettingConnection *s_con;
 	const char *con_type;
-	int i, j;
+	guint i, j;
 
 	g_return_val_if_fail (nmc, FALSE);
 	g_return_val_if_fail (iface || ap || nsp, FALSE);
@@ -2850,7 +2893,7 @@ do_connection_up (NmCli *nmc, int argc, char **argv)
 
 	while (argc > 0) {
 		if (argc == 1 && nmc->complete)
-			nmc_complete_strings (*argv, "ifname", "ap", "passwd-file", NULL);
+			nmc_complete_strings (*argv, "ifname", "ap", "passwd-file");
 
 		if (strcmp (*argv, "ifname") == 0) {
 			argc--;
@@ -3102,7 +3145,7 @@ do_connection_down (NmCli *nmc, int argc, char **argv)
 		const char *selector = NULL;
 
 		if (arg_num == 1 && nmc->complete)
-			nmc_complete_strings (*arg_ptr, "id", "uuid", "path",  "filename", "apath", NULL);
+			nmc_complete_strings (*arg_ptr, "id", "uuid", "path",  "filename", "apath");
 
 		if (NM_IN_STRSET (*arg_ptr, "id", "uuid", "path",  "filename", "apath")) {
 			selector = *arg_ptr;
@@ -3301,7 +3344,7 @@ get_valid_properties_string (const NMMetaSettingValidPartItem *const*array,
 	const NMMetaSettingValidPartItem *const*iter = array;
 	const char *prop_name = NULL;
 	GString *str;
-	int i, j;
+	guint i, j;
 	gboolean full_match = FALSE;
 
 	g_return_val_if_fail (prefix, NULL);
@@ -3546,7 +3589,7 @@ _strip_master_prefix (const char *master, const char *(**func)(NMConnection *))
 	} else if (g_str_has_prefix (master, "id/")) {
 		master = master + strlen ("id/");
 		if (func)
-			 *func = nm_connection_get_id;
+			*func = nm_connection_get_id;
 	}
 	return master;
 }
@@ -3573,7 +3616,7 @@ normalized_master_for_slave (const GPtrArray *connections,
 	NMConnection *connection;
 	NMSettingConnection *s_con;
 	const char *con_type = NULL, *id, *uuid, *ifname;
-	int i;
+	guint i;
 	const char *found_by_id = NULL;
 	const char *out_type_by_id = NULL;
 	const char *out_master = NULL;
@@ -3785,6 +3828,7 @@ _meta_abstract_complete (const NMMetaAbstractInfo *abstract_info, const char *te
 	                                         nmc_meta_environment_arg,
 	                                         &ctx,
 	                                         text,
+	                                         NULL,
 	                                         &values_to_free);
 	if (values)
 		return values_to_free ?: g_strdupv ((char **) values);
@@ -4208,7 +4252,7 @@ set_connection_master (NmCli *nmc, NMConnection *con, const OptionInfo *option,
 
 	if (!value) {
 		g_set_error_literal (error, NMCLI_ERROR, NMC_RESULT_ERROR_USER_INPUT,
-			             _("Error: master is required"));
+		                     _("Error: master is required"));
 		return FALSE;
 	}
 
@@ -4525,11 +4569,12 @@ run_rl_generator (rl_compentry_func_t *generator_func, const char *prefix)
 }
 
 static gboolean
-complete_option (const NMMetaAbstractInfo *abstract_info, const char *prefix, NMConnection *context_connection)
+complete_option (NmCli *nmc, const NMMetaAbstractInfo *abstract_info, const char *prefix, NMConnection *context_connection)
 {
 	const OptionInfo *candidate;
 	const char *const*values;
 	gs_strfreev char **values_to_free = NULL;
+	gboolean complete_filename = FALSE;
 	const NMMetaOperationContext ctx = {
 		.connection = context_connection,
 	};
@@ -4539,7 +4584,12 @@ complete_option (const NMMetaAbstractInfo *abstract_info, const char *prefix, NM
 	                                         nmc_meta_environment_arg,
 	                                         &ctx,
 	                                         prefix,
+	                                         &complete_filename,
 	                                         &values_to_free);
+	if (complete_filename) {
+		nmc->return_value = NMC_RESULT_COMPLETE_FILE;
+		return TRUE;
+	}
 	if (values) {
 		for (; values[0]; values++)
 			g_print ("%s\n", values[0]);
@@ -4556,19 +4606,13 @@ complete_option (const NMMetaAbstractInfo *abstract_info, const char *prefix, NM
 }
 
 static void
-complete_property (const char *setting_name, const char *property, const char *prefix, NMConnection *connection)
+complete_property (NmCli *nmc, const char *setting_name, const char *property, const char *prefix, NMConnection *connection)
 {
 	const NMMetaPropertyInfo *property_info;
 
 	property_info = nm_meta_property_info_find_by_name (setting_name, property);
-	if (property_info) {
-		if (complete_option ((const NMMetaAbstractInfo *) property_info, prefix, connection))
-			return;
-	}
-
-	if (   strcmp (setting_name, NM_SETTING_BLUETOOTH_SETTING_NAME) == 0
-	         && strcmp (property, NM_SETTING_BLUETOOTH_TYPE) == 0)
-		run_rl_generator (gen_func_bt_type, prefix);
+	if (property_info)
+		complete_option (nmc, (const NMMetaAbstractInfo *) property_info, prefix, connection);
 }
 
 /*****************************************************************************/
@@ -4658,8 +4702,10 @@ nmc_read_connection_properties (NmCli *nmc,
 			if (!get_value (&value, argc, argv, option, error))
 				return FALSE;
 
-			if (!*argc && nmc->complete)
-				complete_property (setting, strv[1], value ?: "", connection);
+			if (!*argc && nmc->complete) {
+				complete_property (nmc, setting, strv[1], value ?: "", connection);
+				return TRUE;
+			}
 
 			if (!set_property (nmc->client, connection, setting_name, strv[1], value, modifier, error))
 				return FALSE;
@@ -4740,7 +4786,7 @@ nmc_read_connection_properties (NmCli *nmc,
 				return FALSE;
 
 			if (!*argc && nmc->complete)
-				complete_option (chosen, value ?: "", connection);
+				complete_option (nmc, chosen, value ?: "", connection);
 
 			if (!set_option (nmc, connection, chosen, value, error))
 				return FALSE;
@@ -4751,28 +4797,23 @@ nmc_read_connection_properties (NmCli *nmc,
 	return TRUE;
 }
 
-typedef struct {
-	NmCli *nmc;
-	char *con_name;
-} AddConnectionInfo;
-
 static void
 add_connection_cb (GObject *client,
                    GAsyncResult *result,
                    gpointer user_data)
 {
-	AddConnectionInfo *info = (AddConnectionInfo *) user_data;
+	nm_auto_free_add_connection_info AddConnectionInfo *info = user_data;
 	NmCli *nmc = info->nmc;
 	NMRemoteConnection *connection;
 	GError *error = NULL;
 	const GPtrArray *connections;
 	guint i, found;
 
-	connection = nm_client_add_connection_finish (NM_CLIENT (client), result, &error);
+	connection = nm_client_add_connection2_finish (NM_CLIENT (client), result, NULL, &error);
 	if (error) {
 		g_string_printf (nmc->return_text,
 		                 _("Error: Failed to add '%s' connection: %s"),
-		                 info->con_name, error->message);
+		                 info->new_id, error->message);
 		g_error_free (error);
 		nmc->return_value = NMC_RESULT_ERROR_CON_ACTIVATION;
 	} else {
@@ -4784,7 +4825,7 @@ add_connection_cb (GObject *client,
 
 				if ((NMConnection *) connection == candidate)
 					continue;
-				if (nm_streq0 (nm_connection_get_id (candidate), info->con_name))
+				if (nm_streq0 (nm_connection_get_id (candidate), info->new_id))
 					found++;
 			}
 			if (found > 0) {
@@ -4792,7 +4833,7 @@ add_connection_cb (GObject *client,
 				                         "Warning: There is another connection with the name '%1$s'. Reference the connection by its uuid '%2$s'\n",
 				                         "Warning: There are %3$u other connections with the name '%1$s'. Reference the connection by its uuid '%2$s'\n",
 				                         found),
-				            info->con_name,
+				            info->new_id,
 				            nm_connection_get_uuid (NM_CONNECTION (connection)),
 				            found);
 			}
@@ -4804,30 +4845,39 @@ add_connection_cb (GObject *client,
 		g_object_unref (connection);
 	}
 
-	g_free (info->con_name);
-	g_free (info);
 	quit ();
 }
 
 static void
-add_new_connection (gboolean persistent,
-                    NMClient *client,
-                    NMConnection *connection,
-                    GAsyncReadyCallback callback,
-                    gpointer user_data)
-{
-	nm_client_add_connection_async (client, connection, persistent,
-	                                NULL, callback, user_data);
+add_connection (NMClient *client,
+                NMConnection *connection,
+                gboolean temporary,
+                GAsyncReadyCallback callback,
+                gpointer user_data)
+{
+	nm_client_add_connection2 (client,
+	                           nm_connection_to_dbus (connection, NM_CONNECTION_SERIALIZE_ALL),
+	                             temporary
+	                           ? NM_SETTINGS_ADD_CONNECTION2_FLAG_IN_MEMORY
+	                           : NM_SETTINGS_ADD_CONNECTION2_FLAG_TO_DISK,
+	                           NULL,
+	                           TRUE,
+	                           NULL,
+	                           callback,
+	                           user_data);
 }
 
 static void
-update_connection (gboolean persistent,
-                   NMRemoteConnection *connection,
+update_connection (NMRemoteConnection *connection,
+                   gboolean temporary,
                    GAsyncReadyCallback callback,
                    gpointer user_data)
 {
-	nm_remote_connection_commit_changes_async (connection, persistent,
-	                                           NULL, callback, user_data);
+	nm_remote_connection_commit_changes_async (connection,
+	                                           !temporary,
+	                                           NULL,
+	                                           callback,
+	                                           user_data);
 }
 
 static gboolean
@@ -5146,7 +5196,6 @@ do_connection_add (NmCli *nmc, int argc, char **argv)
 	gs_unref_object NMConnection *connection = NULL;
 	NMSettingConnection *s_con;
 	gs_free_error GError *error = NULL;
-	AddConnectionInfo *info = NULL;
 	gboolean save_bool = TRUE;
 	gboolean seen_dash_dash = FALSE;
 	NMMetaSettingType s;
@@ -5291,19 +5340,13 @@ read_properties:
 		}
 	}
 
+	add_connection (nmc->client,
+	                connection,
+	                !save_bool,
+	                add_connection_cb,
+	                _add_connection_info_new (nmc, NULL, connection));
 	nmc->should_wait++;
 
-	info = g_malloc0 (sizeof (AddConnectionInfo));
-	info->nmc = nmc;
-	info->con_name = g_strdup (nm_connection_get_id (connection));
-
-	/* Tell the settings service to add the new connection */
-	add_new_connection (save_bool,
-	                    nmc->client,
-	                    connection,
-	                    add_connection_cb,
-	                    info);
-
 finish:
 	reset_options ();
 	return nmc->return_value;
@@ -5578,7 +5621,7 @@ gen_property_names (const char *text, int state)
 static char *
 gen_compat_devices (const char *text, int state)
 {
-	int i, j = 0;
+	guint i, j = 0;
 	const GPtrArray *devices;
 	const char **compatible_devices;
 	char *ret;
@@ -6084,7 +6127,7 @@ nmcli_editor_tab_completion (const char *text, int start, int end)
 							rl_completion_display_matches_hook = uuid_display_hook;
 							generator_func = gen_vpn_uuids;
 						} else if (   should_complete_property_values (NULL, line, &multi)
-							   && (num == 3 || multi)) {
+						           && (num == 3 || multi)) {
 							generator_func = gen_property_values;
 						} else if (should_complete_boolean (NULL, line) && num == 3)
 							generator_func = gen_func_bool_values;
@@ -6131,7 +6174,7 @@ nmcli_editor_tab_completion (const char *text, int start, int end)
 						rl_completion_display_matches_hook = uuid_display_hook;
 						generator_func = gen_vpn_uuids;
 					} else if (   should_complete_property_values (prompt_tmp, NULL, &multi)
-						   && (num <= 2 || multi)) {
+					           && (num <= 2 || multi)) {
 						generator_func = gen_property_values;
 					} else if (should_complete_boolean (prompt_tmp, NULL) && num <= 2)
 						generator_func = gen_func_bool_values;
@@ -6652,14 +6695,11 @@ add_connection_editor_cb (GObject *client,
                           GAsyncResult *result,
                           gpointer user_data)
 {
-	NMRemoteConnection *connection;
-	GError *error = NULL;
+	gs_unref_object NMRemoteConnection *connection = NULL;
+	gs_free_error GError *error = NULL;
 
-	connection = nm_client_add_connection_finish (NM_CLIENT (client), result, &error);
+	connection = nm_client_add_connection2_finish (NM_CLIENT (client), result, NULL, &error);
 	set_info_and_signal_editor_thread (error, NULL);
-
-	g_clear_object (&connection);
-	g_clear_error (&error);
 }
 
 static void
@@ -7238,7 +7278,6 @@ editor_menu_main (NmCli *nmc, NMConnection *connection, const char *connection_t
 	const NMMetaSettingValidPartItem *const*valid_settings_slave;
 	gs_free char *valid_settings_str = NULL;
 	const char *s_type = NULL;
-	AddConnectionInfo *info = NULL;
 	gboolean temp_changes;
 	GError *err1 = NULL;
 	NmcEditorMenuContext menu_ctx = { 0 };
@@ -7757,7 +7796,7 @@ editor_menu_main (NmCli *nmc, NMConnection *connection, const char *connection_t
 		case NMC_EDITOR_MAIN_CMD_SAVE:
 			/* Save the connection */
 			if (nm_connection_verify (connection, &err1)) {
-				gboolean persistent = TRUE;
+				gboolean temporary = FALSE;
 				gboolean connection_changed;
 				nm_auto_unref_gsource GSource *source = NULL;
 				gboolean timeout = FALSE;
@@ -7766,9 +7805,9 @@ editor_menu_main (NmCli *nmc, NMConnection *connection, const char *connection_t
 				/* parse argument */
 				if (cmd_arg) {
 					if (matches (cmd_arg, "temporary"))
-						persistent = FALSE;
+						temporary = TRUE;
 					else if (matches (cmd_arg, "persistent"))
-						persistent = TRUE;
+						temporary = FALSE;
 					else {
 						g_print (_("Error: invalid argument '%s'\n"), cmd_arg);
 						break;
@@ -7784,21 +7823,17 @@ editor_menu_main (NmCli *nmc, NMConnection *connection, const char *connection_t
 				}
 
 				if (!rem_con) {
-					/* Tell the settings service to add the new connection */
-					info = g_malloc0 (sizeof (AddConnectionInfo));
-					info->nmc = nmc;
-					info->con_name = g_strdup (nm_connection_get_id (connection));
-					add_new_connection (persistent,
-					                    nmc->client,
-					                    connection,
-					                    add_connection_editor_cb,
-					                    info);
+					add_connection (nmc->client,
+					                connection,
+					                temporary,
+					                add_connection_editor_cb,
+					                NULL);
 					connection_changed = TRUE;
 				} else {
 					/* Save/update already saved (existing) connection */
 					nm_connection_replace_settings_from_connection (NM_CONNECTION (rem_con),
 					                                                connection);
-					update_connection (persistent, rem_con, update_connection_editor_cb, NULL);
+					update_connection (rem_con, temporary, update_connection_editor_cb, NULL);
 
 					handler_id = g_signal_connect (rem_con,
 					                               NM_CONNECTION_CHANGED,
@@ -7814,8 +7849,10 @@ editor_menu_main (NmCli *nmc, NMConnection *connection, const char *connection_t
 				while (!nmc_editor_cb_called && !timeout)
 					g_main_context_iteration (NULL, TRUE);
 
-				while (!connection_changed && !timeout)
-					g_main_context_iteration (NULL, TRUE);
+				if (!nmc_editor_error) {
+					while (!connection_changed && !timeout)
+						g_main_context_iteration (NULL, TRUE);
+				}
 
 				if (handler_id)
 					g_signal_handler_disconnect (rem_con, handler_id);
@@ -8025,7 +8062,7 @@ static const char *
 get_ethernet_device_name (NmCli *nmc)
 {
 	const GPtrArray *devices;
-	int i;
+	guint i;
 
 	devices = nm_client_get_devices (nmc->client);
 	for (i = 0; i < devices->len; i++) {
@@ -8171,7 +8208,7 @@ do_connection_edit (NmCli *nmc, int argc, char **argv)
 
 	next_arg (nmc, &argc, &argv, NULL);
 	if (argc == 1 && nmc->complete)
-		nmc_complete_strings (*argv, "type", "con-name", "id", "uuid", "path",  "filename", NULL);
+		nmc_complete_strings (*argv, "type", "con-name", "id", "uuid", "path",  "filename");
 
 	nmc->return_value = NMC_RESULT_SUCCESS;
 
@@ -8397,35 +8434,27 @@ do_connection_modify (NmCli *nmc,
 	if (nmc->complete)
 		return nmc->return_value;
 
-	update_connection (!temporary, rc, modify_connection_cb, nmc);
+	update_connection (rc, temporary, modify_connection_cb, nmc);
 	nmc->should_wait++;
 
 	return nmc->return_value;
 }
 
-typedef struct {
-	NmCli *nmc;
-	char *orig_id;
-	char *orig_uuid;
-	char *con_id;
-} CloneConnectionInfo;
-
 static void
 clone_connection_cb (GObject *client,
                      GAsyncResult *result,
                      gpointer user_data)
 {
-	CloneConnectionInfo *info = (CloneConnectionInfo *) user_data;
+	nm_auto_free_add_connection_info AddConnectionInfo *info = user_data;
 	NmCli *nmc = info->nmc;
-	NMRemoteConnection *connection;
-	GError *error = NULL;
+	gs_unref_object NMRemoteConnection *connection = NULL;
+	gs_free_error GError *error = NULL;
 
-	connection = nm_client_add_connection_finish (NM_CLIENT (client), result, &error);
+	connection = nm_client_add_connection2_finish (NM_CLIENT (client), result, NULL, &error);
 	if (error) {
 		g_string_printf (nmc->return_text,
 		                 _("Error: Failed to add '%s' connection: %s"),
-		                 info->con_id, error->message);
-		g_error_free (error);
+		                 info->new_id, error->message);
 		nmc->return_value = NMC_RESULT_ERROR_CON_ACTIVATION;
 	} else {
 		g_print (_("%s (%s) cloned as %s (%s).\n"),
@@ -8433,13 +8462,8 @@ clone_connection_cb (GObject *client,
 		         info->orig_uuid,
 		         nm_connection_get_id (NM_CONNECTION (connection)),
 		         nm_connection_get_uuid (NM_CONNECTION (connection)));
-		g_object_unref (connection);
 	}
 
-	g_free (info->con_id);
-	g_free (info->orig_id);
-	g_free (info->orig_uuid);
-	g_slice_free (CloneConnectionInfo, info);
 	quit ();
 }
 
@@ -8448,11 +8472,9 @@ do_connection_clone (NmCli *nmc, int argc, char **argv)
 {
 	NMConnection *connection = NULL;
 	gs_unref_object NMConnection *new_connection = NULL;
-	NMSettingConnection *s_con;
-	CloneConnectionInfo *info;
 	const char *new_name;
-	gs_free char *new_name_ask = NULL;
-	char *uuid;
+	gs_free char *new_name_free = NULL;
+	gs_free char *uuid = NULL;
 	gboolean temporary = FALSE;
 	char **arg_arr = NULL;
 	int arg_num;
@@ -8493,8 +8515,8 @@ do_connection_clone (NmCli *nmc, int argc, char **argv)
 	if (argv[0])
 		new_name = *argv;
 	else if (nmc->ask) {
-		new_name = new_name_ask = nmc_readline (&nmc->nmc_config,
-		                                        _("New connection name: "));
+		new_name = new_name_free = nmc_readline (&nmc->nmc_config,
+		                                         _("New connection name: "));
 	} else {
 		g_string_printf (nmc->return_text, _("Error: <new name> argument is missing."));
 		NMC_RETURN (nmc, NMC_RESULT_ERROR_USER_INPUT);
@@ -8505,35 +8527,23 @@ do_connection_clone (NmCli *nmc, int argc, char **argv)
 		NMC_RETURN (nmc, NMC_RESULT_ERROR_USER_INPUT);
 	}
 
-	/* Copy the connection */
 	new_connection = nm_simple_connection_new_clone (connection);
 
-	s_con = nm_connection_get_setting_connection (new_connection);
-	g_assert (s_con);
 	uuid = nm_utils_uuid_generate ();
-	g_object_set (s_con,
+	g_object_set (nm_connection_get_setting_connection (new_connection),
 	              NM_SETTING_CONNECTION_ID, new_name,
 	              NM_SETTING_CONNECTION_UUID, uuid,
 	              NULL);
-	g_free (uuid);
 
-	/* Merge secrets into the new connection */
 	update_secrets_in_connection (NM_REMOTE_CONNECTION (connection), new_connection);
 
-	info = g_slice_new0 (CloneConnectionInfo);
-	info->nmc = nmc;
-	info->orig_id = g_strdup (nm_connection_get_id (connection));
-	info->orig_uuid = g_strdup (nm_connection_get_uuid (connection));
-	info->con_id = g_strdup (nm_connection_get_id (new_connection));
-
-	/* Add the new cloned connection to NetworkManager */
-	add_new_connection (!temporary,
-	                    nmc->client,
-	                    new_connection,
-	                    clone_connection_cb,
-	                    info);
-
+	add_connection (nmc->client,
+	                new_connection,
+	                temporary,
+	                clone_connection_cb,
+	                _add_connection_info_new (nmc, connection, new_connection));
 	nmc->should_wait++;
+
 	return nmc->return_value;
 }
 
@@ -8736,6 +8746,9 @@ do_connection_monitor (NmCli *nmc, int argc, char **argv)
 		}
 	}
 
+	if (nmc->complete)
+		return nmc->return_value;
+
 	for (i = 0; i < connections->len; i++)
 		connection_watch (nmc, connections->pdata[i]);
 
@@ -8745,8 +8758,6 @@ do_connection_monitor (NmCli *nmc, int argc, char **argv)
 		g_signal_connect (nmc->client, NM_CLIENT_CONNECTION_ADDED, G_CALLBACK (connection_added), nmc);
 	}
 
-	if (nmc->complete)
-		return nmc->return_value;
 	g_signal_connect (nmc->client, NM_CLIENT_CONNECTION_REMOVED, G_CALLBACK (connection_removed), nmc);
 
 	return NMC_RESULT_SUCCESS;
@@ -8819,7 +8830,6 @@ do_connection_import (NmCli *nmc, int argc, char **argv)
 	const char *type = NULL, *filename = NULL;
 	gs_free char *type_ask = NULL;
 	gs_free char *filename_ask = NULL;
-	AddConnectionInfo *info;
 	gs_unref_object NMConnection *connection = NULL;
 	NMVpnEditorPlugin *plugin;
 	gs_free char *service_type = NULL;
@@ -8867,7 +8877,7 @@ do_connection_import (NmCli *nmc, int argc, char **argv)
 			if (   argc == 1
 			    && nmc->complete) {
 				nmc_complete_strings (*argv, "wireguard");
-				complete_option ((const NMMetaAbstractInfo *) nm_meta_property_info_vpn_service_type,
+				complete_option (nmc, (const NMMetaAbstractInfo *) nm_meta_property_info_vpn_service_type,
 				                 *argv,
 				                 NULL);
 			}
@@ -8936,18 +8946,13 @@ do_connection_import (NmCli *nmc, int argc, char **argv)
 		NMC_RETURN (nmc, NMC_RESULT_ERROR_UNKNOWN);
 	}
 
-	info = g_malloc0 (sizeof (AddConnectionInfo));
-	info->nmc = nmc;
-	info->con_name = g_strdup (nm_connection_get_id (connection));
-
-	/* Add the new imported connection to NetworkManager */
-	add_new_connection (!temporary,
-	                    nmc->client,
-	                    connection,
-	                    add_connection_cb,
-	                    info);
-
+	add_connection (nmc->client,
+	                connection,
+	                temporary,
+	                add_connection_cb,
+	                _add_connection_info_new (nmc, NULL, connection));
 	nmc->should_wait++;
+
 	return nmc->return_value;
 }
 
@@ -9068,7 +9073,7 @@ finish:
 static char *
 gen_func_connection_names (const char *text, int state)
 {
-	int i;
+	guint i;
 	const GPtrArray *connections;
 	const char **connection_names;
 	char *ret;
@@ -9091,7 +9096,7 @@ gen_func_connection_names (const char *text, int state)
 static char *
 gen_func_active_connection_names (const char *text, int state)
 {
-	int i;
+	guint i;
 	const GPtrArray *acs;
 	const char **connections;
 	char *ret;
diff --git a/clients/cli/devices.c b/clients/cli/devices.c
index ad3a44c4..c00d3191 100644
--- a/clients/cli/devices.c
+++ b/clients/cli/devices.c
@@ -536,6 +536,9 @@ _metagen_device_detail_wifi_properties_get_fcn (NMC_META_GENERIC_INFO_GET_FCN_AR
 		                                         : N_("no"))
 		                                      : N_("unknown"),
 		                                      get_type);
+	case NMC_GENERIC_INFO_TYPE_DEVICE_DETAIL_WIFI_PROPERTIES_MESH:
+		return nmc_meta_generic_get_bool (NM_FLAGS_HAS (wcaps, NM_WIFI_DEVICE_CAP_MESH),
+		                                  get_type);
 	default:
 		break;
 	}
@@ -555,6 +558,7 @@ const NmcMetaGenericInfo *const metagen_device_detail_wifi_properties[_NMC_GENER
 	_METAGEN_DEVICE_DETAIL_WIFI_PROPERTIES (NMC_GENERIC_INFO_TYPE_DEVICE_DETAIL_WIFI_PROPERTIES_ADHOC, "ADHOC"),
 	_METAGEN_DEVICE_DETAIL_WIFI_PROPERTIES (NMC_GENERIC_INFO_TYPE_DEVICE_DETAIL_WIFI_PROPERTIES_2GHZ,  "2GHZ"),
 	_METAGEN_DEVICE_DETAIL_WIFI_PROPERTIES (NMC_GENERIC_INFO_TYPE_DEVICE_DETAIL_WIFI_PROPERTIES_5GHZ,  "5GHZ"),
+	_METAGEN_DEVICE_DETAIL_WIFI_PROPERTIES (NMC_GENERIC_INFO_TYPE_DEVICE_DETAIL_WIFI_PROPERTIES_MESH,  "MESH"),
 };
 
 /*****************************************************************************/
@@ -1188,6 +1192,7 @@ fill_output_access_point (gpointer data, gpointer user_data)
 	set_val_strc (arr, 3, bssid);
 	set_val_strc (arr, 4, mode == NM_802_11_MODE_ADHOC ? _("Ad-Hoc")
 	                    : mode == NM_802_11_MODE_INFRA ? _("Infra")
+	                    : mode == NM_802_11_MODE_MESH ? _("Mesh")
 	                    : _("N/A"));
 	set_val_str  (arr, 5, channel_str);
 	set_val_str  (arr, 6, freq_str);
@@ -1897,7 +1902,6 @@ create_connect_connection_for_device (AddAndActivateInfo *info)
 	nm_connection_add_setting (connection, NM_SETTING (s_con));
 	g_object_set (s_con,
 	              NM_SETTING_CONNECTION_ID, nm_device_get_iface (info->device),
-	              NM_SETTING_CONNECTION_INTERFACE_NAME, nm_device_get_iface (info->device),
 	              NULL);
 
 	nm_client_add_and_activate_connection_async (info->nmc->client,
@@ -2473,7 +2477,7 @@ do_device_set (NmCli *nmc, int argc, char **argv)
 		gboolean flag;
 
 		if (argc == 1 && nmc->complete)
-			nmc_complete_strings (*argv, "managed", "autoconnect", NULL);
+			nmc_complete_strings (*argv, "managed", "autoconnect");
 
 		if (matches (*argv, "managed")) {
 			argc--;
@@ -2997,7 +3001,7 @@ do_device_wifi_list (NmCli *nmc, int argc, char **argv)
 			}
 			rescan = *argv;
 			if (argc == 1 && nmc->complete)
-				nmc_complete_strings (rescan, "auto", "no", "yes", NULL);
+				nmc_complete_strings (rescan, "auto", "no", "yes");
 			break;
 		default:
 			g_assert_not_reached();
@@ -3179,7 +3183,7 @@ do_device_wifi_connect_network (NmCli *nmc, int argc, char **argv)
 	while (argc > 0) {
 		if (argc == 1 && nmc->complete) {
 			nmc_complete_strings (*argv, "ifname", "bssid", "password", "wep-key-type",
-			                      "name", "private", "hidden", NULL);
+			                      "name", "private", "hidden");
 		}
 
 		if (strcmp (*argv, "ifname") == 0) {
@@ -3229,7 +3233,7 @@ do_device_wifi_connect_network (NmCli *nmc, int argc, char **argv)
 				goto finish;
 			}
 			if (argc == 1 && nmc->complete)
-				nmc_complete_strings (*argv, "key", "phrase", NULL);
+				nmc_complete_strings (*argv, "key", "phrase");
 			if (strcmp (*argv, "key") == 0)
 				wep_passphrase = FALSE;
 			else if (strcmp (*argv, "phrase") == 0)
@@ -3711,7 +3715,7 @@ do_device_wifi_hotspot (NmCli *nmc, int argc, char **argv)
 	while (argc > 0) {
 		if (argc == 1 && nmc->complete) {
 			nmc_complete_strings (*argv, "ifname", "con-name", "ssid", "band",
-			                             "channel", "password", NULL);
+			                             "channel", "password");
 		}
 
 		if (strcmp (*argv, "ifname") == 0) {
@@ -3753,7 +3757,7 @@ do_device_wifi_hotspot (NmCli *nmc, int argc, char **argv)
 			}
 			band = *argv;
 			if (argc == 1 && nmc->complete)
-				nmc_complete_strings (band, "a", "bg", NULL);
+				nmc_complete_strings (band, "a", "bg");
 			if (strcmp (band, "a") && strcmp (band, "bg")) {
 				g_string_printf (nmc->return_text, _("Error: band argument value '%s' is invalid; use 'a' or 'bg'."),
 				                 band);
@@ -3935,7 +3939,7 @@ do_device_wifi_rescan (NmCli *nmc, int argc, char **argv)
 	/* Get the parameters */
 	while (argc > 0) {
 		if (argc == 1 && nmc->complete)
-			nmc_complete_strings (*argv, "ifname", "ssid", NULL);
+			nmc_complete_strings (*argv, "ifname", "ssid");
 
 		if (strcmp (*argv, "ifname") == 0) {
 			if (ifname) {
@@ -4122,7 +4126,7 @@ do_device_lldp_list (NmCli *nmc, int argc, char **argv)
 	next_arg (nmc, &argc, &argv, NULL);
 	while (argc > 0) {
 		if (argc == 1 && nmc->complete)
-			nmc_complete_strings (*argv, "ifname", NULL);
+			nmc_complete_strings (*argv, "ifname");
 
 		if (strcmp (*argv, "ifname") == 0) {
 			argc--;
diff --git a/clients/cli/general.c b/clients/cli/general.c
index d713426b..e2ce639e 100644
--- a/clients/cli/general.c
+++ b/clients/cli/general.c
@@ -683,7 +683,7 @@ do_general_logging (NmCli *nmc, int argc, char **argv)
 
 		do {
 			if (argc == 1 && nmc->complete)
-				nmc_complete_strings (*argv, "level", "domains", NULL);
+				nmc_complete_strings (*argv, "level", "domains");
 
 			if (matches (*argv, "level")) {
 				argc--;
@@ -878,7 +878,7 @@ do_networking_connectivity (NmCli *nmc, int argc, char **argv)
 	next_arg (nmc, &argc, &argv, NULL);
 	if (nmc->complete) {
 		if (argc == 1)
-			nmc_complete_strings (*argv, "check", NULL);
+			nmc_complete_strings (*argv, "check");
 		return nmc->return_value;
 	}
 
diff --git a/clients/cli/nmcli.c b/clients/cli/nmcli.c
index d7bc2a46..ad45f179 100644
--- a/clients/cli/nmcli.c
+++ b/clients/cli/nmcli.c
@@ -732,7 +732,7 @@ process_command_line (NmCli *nmc, int argc, char **argv)
 			nmc_complete_strings (argv[0], "--terse", "--pretty", "--mode", "--overview",
 			                               "--colors", "--escape",
 			                               "--fields", "--nocheck", "--get-values",
-			                               "--wait", "--version", "--help", NULL);
+			                               "--wait", "--version", "--help");
 		}
 
 		if (argv[0][1] == '-' && argv[0][2] == '\0') {
@@ -915,88 +915,6 @@ signal_handler (gpointer user_data)
 	return G_SOURCE_CONTINUE;
 }
 
-static void
-nmc_convert_strv_to_string (const GValue *src_value, GValue *dest_value)
-{
-	char **strings;
-
-	strings = g_value_get_boxed (src_value);
-	if (strings)
-		g_value_take_string (dest_value, g_strjoinv (",", strings));
-	else
-		g_value_set_string (dest_value, "");
-}
-
-static void
-nmc_convert_string_hash_to_string (const GValue *src_value, GValue *dest_value)
-{
-	GHashTable *hash;
-	GHashTableIter iter;
-	const char *key, *value;
-	GString *string;
-
-	hash = (GHashTable *) g_value_get_boxed (src_value);
-
-	string = g_string_new (NULL);
-	if (hash) {
-		g_hash_table_iter_init (&iter, hash);
-		while (g_hash_table_iter_next (&iter, (gpointer *) &key, (gpointer *) &value)) {
-			if (string->len)
-				g_string_append_c (string, ',');
-			g_string_append_printf (string, "%s=%s", key, value);
-		}
-	}
-
-	g_value_take_string (dest_value, g_string_free (string, FALSE));
-}
-
-static void
-nmc_convert_bytes_to_string (const GValue *src_value, GValue *dest_value)
-{
-	GBytes *bytes;
-	const guint8 *array;
-	gsize length;
-	GString *printable;
-	guint i = 0;
-
-	bytes = g_value_get_boxed (src_value);
-
-	printable = g_string_new ("[");
-
-	if (bytes) {
-		array = g_bytes_get_data (bytes, &length);
-		while (i < MIN (length, 35)) {
-			if (i > 0)
-				g_string_append_c (printable, ' ');
-			g_string_append_printf (printable, "0x%02X", array[i++]);
-		}
-		if (i < length)
-			g_string_append (printable, " ... ");
-	}
-	g_string_append_c (printable, ']');
-
-	g_value_take_string (dest_value, g_string_free (printable, FALSE));
-}
-
-static void
-nmc_value_transforms_register (void)
-{
-	g_value_register_transform_func (G_TYPE_STRV,
-	                                 G_TYPE_STRING,
-	                                 nmc_convert_strv_to_string);
-
-	/* This depends on the fact that all of the hash-table-valued properties
-	 * in libnm-core are string->string.
-	 */
-	g_value_register_transform_func (G_TYPE_HASH_TABLE,
-	                                 G_TYPE_STRING,
-	                                 nmc_convert_string_hash_to_string);
-
-	g_value_register_transform_func (G_TYPE_BYTES,
-	                                 G_TYPE_STRING,
-	                                 nmc_convert_bytes_to_string);
-}
-
 void
 nm_cli_spawn_pager (NmCli *nmc)
 {
@@ -1054,8 +972,6 @@ main (int argc, char *argv[])
 	/* Save terminal settings */
 	tcgetattr (STDIN_FILENO, &termios_orig);
 
-	nmc_value_transforms_register ();
-
 	nm_cli.return_text = g_string_new (_("Success"));
 	loop = g_main_loop_new (NULL, FALSE);
 
diff --git a/clients/cli/utils.c b/clients/cli/utils.c
index a8b81279..a822dd89 100644
--- a/clients/cli/utils.c
+++ b/clients/cli/utils.c
@@ -189,10 +189,10 @@ next_arg (NmCli *nmc, int *argc, char ***argv, ...)
 
 		if (nmc && nmc->complete && *argc == 1) {
 			while ((cmd_option = va_arg (args, const char *)))
-				nmc_complete_strings (**argv, cmd_option, NULL);
+				nmc_complete_strings (**argv, cmd_option);
 
 			if (***argv == '-')
-				nmc_complete_strings (**argv, "--ask", "--show-secrets", NULL);
+				nmc_complete_strings (**argv, "--ask", "--show-secrets");
 
 			va_end (args);
 			return 0;
diff --git a/clients/cli/utils.h b/clients/cli/utils.h
index b84b35bf..82b186b7 100644
--- a/clients/cli/utils.h
+++ b/clients/cli/utils.h
@@ -225,6 +225,7 @@ typedef enum {
 	NMC_GENERIC_INFO_TYPE_DEVICE_DETAIL_WIFI_PROPERTIES_ADHOC,
 	NMC_GENERIC_INFO_TYPE_DEVICE_DETAIL_WIFI_PROPERTIES_2GHZ,
 	NMC_GENERIC_INFO_TYPE_DEVICE_DETAIL_WIFI_PROPERTIES_5GHZ,
+	NMC_GENERIC_INFO_TYPE_DEVICE_DETAIL_WIFI_PROPERTIES_MESH,
 	_NMC_GENERIC_INFO_TYPE_DEVICE_DETAIL_WIFI_PROPERTIES_NUM,
 
 } NmcGenericInfoType;