summary refs log tree commit diff
path: root/clients/cli
diff options
context:
space:
mode:
Diffstat (limited to 'clients/cli')
-rw-r--r--clients/cli/agent.c20
-rw-r--r--clients/cli/agent.h20
-rw-r--r--clients/cli/common.c150
-rw-r--r--clients/cli/common.h28
-rw-r--r--clients/cli/connections.c405
-rw-r--r--clients/cli/connections.h20
-rw-r--r--clients/cli/devices.c918
-rw-r--r--clients/cli/devices.h20
-rw-r--r--clients/cli/general.c176
-rw-r--r--clients/cli/general.h20
-rw-r--r--clients/cli/meson.build8
-rw-r--r--clients/cli/nmcli.c29
-rw-r--r--clients/cli/nmcli.h25
-rw-r--r--clients/cli/polkit-agent.c20
-rw-r--r--clients/cli/polkit-agent.h20
-rw-r--r--clients/cli/settings.c39
-rw-r--r--clients/cli/settings.h22
-rw-r--r--clients/cli/utils.c22
-rw-r--r--clients/cli/utils.h28
19 files changed, 1204 insertions, 786 deletions
diff --git a/clients/cli/agent.c b/clients/cli/agent.c
index 6c116153..f4057df9 100644
--- a/clients/cli/agent.c
+++ b/clients/cli/agent.c
@@ -1,22 +1,6 @@
+// SPDX-License-Identifier: GPL-2.0+
 /*
- *  nmcli - command-line tool for controlling NetworkManager
- *  Functions for running NM secret agent.
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License along
- * with this program; if not, write to the Free Software Foundation, Inc.,
- * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
- *
- * Copyright 2014 Red Hat, Inc.
+ * Copyright (C) 2014 Red Hat, Inc.
  */
 
 #include "nm-default.h"
diff --git a/clients/cli/agent.h b/clients/cli/agent.h
index 70ea0d9b..aad56bba 100644
--- a/clients/cli/agent.h
+++ b/clients/cli/agent.h
@@ -1,22 +1,6 @@
+// SPDX-License-Identifier: GPL-2.0+
 /*
- *  nmcli - command-line tool for controlling NetworkManager
- *  Functions for running NM secret agent.
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License along
- * with this program; if not, write to the Free Software Foundation, Inc.,
- * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
- *
- * Copyright 2014 Red Hat, Inc.
+ * Copyright (C) 2014 Red Hat, Inc.
  */
 
 #ifndef __NMC_AGENT_H__
diff --git a/clients/cli/common.c b/clients/cli/common.c
index 2fc8aaf6..04ccf8dc 100644
--- a/clients/cli/common.c
+++ b/clients/cli/common.c
@@ -1,22 +1,6 @@
+// SPDX-License-Identifier: GPL-2.0+
 /*
- *  nmcli - command-line tool for controlling NetworkManager
- *  Common functions and data shared between files.
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License along
- * with this program; if not, write to the Free Software Foundation, Inc.,
- * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
- *
- * Copyright 2012 - 2018 Red Hat, Inc.
+ * Copyright (C) 2012 - 2018 Red Hat, Inc.
  */
 
 #include "nm-default.h"
@@ -1201,14 +1185,13 @@ nmc_parse_lldp_capabilities (guint value)
 static void
 command_done (GObject *object, GAsyncResult *res, gpointer user_data)
 {
-	GSimpleAsyncResult *simple = (GSimpleAsyncResult *)res;
+	GTask *task = G_TASK (res);
 	NmCli *nmc = user_data;
-	GError *error = NULL;
+	gs_free_error GError *error = NULL;
 
-	if (g_simple_async_result_propagate_error (simple, &error)) {
+	if (!g_task_propagate_boolean (task, &error)) {
 		nmc->return_value = error->code;
 		g_string_assign (nmc->return_text, error->message);
-		g_error_free (error);
 	}
 
 	if (!nmc->should_wait)
@@ -1216,40 +1199,42 @@ command_done (GObject *object, GAsyncResult *res, gpointer user_data)
 }
 
 typedef struct {
-	NmCli *nmc;
 	const NMCCommand *cmd;
 	int argc;
 	char **argv;
-	GSimpleAsyncResult *simple;
+	GTask *task;
 } CmdCall;
 
 static void
-call_cmd (NmCli *nmc, GSimpleAsyncResult *simple, const NMCCommand *cmd, int argc, char **argv);
+call_cmd (NmCli *nmc, GTask *task, const NMCCommand *cmd, int argc, char **argv);
 
 static void
 got_client (GObject *source_object, GAsyncResult *res, gpointer user_data)
 {
-	GError *error = NULL;
+	gs_unref_object GTask *task = NULL;
+	gs_free_error GError *error = NULL;
 	CmdCall *call = user_data;
-	NmCli *nmc = call->nmc;
+	NmCli *nmc;
+
+	task = g_steal_pointer (&call->task);
+	nmc = g_task_get_task_data (task);
 
 	nmc->should_wait--;
 	nmc->client = nm_client_new_finish (res, &error);
 
 	if (!nmc->client) {
-		g_simple_async_result_set_error (call->simple, NMCLI_ERROR, NMC_RESULT_ERROR_UNKNOWN,
-		                                 _("Error: Could not create NMClient object: %s."), error->message);
-		g_error_free (error);
-		g_simple_async_result_complete (call->simple);
+		g_task_return_new_error (task, NMCLI_ERROR, NMC_RESULT_ERROR_UNKNOWN,
+		                         _("Error: Could not create NMClient object: %s."),
+		                         error->message);
 	} else {
-		call_cmd (nmc, call->simple, call->cmd, call->argc, call->argv);
+		call_cmd (nmc, g_steal_pointer (&task), call->cmd, call->argc, call->argv);
 	}
 
 	g_slice_free (CmdCall, call);
 }
 
 static void
-call_cmd (NmCli *nmc, GSimpleAsyncResult *simple, const NMCCommand *cmd, int argc, char **argv)
+call_cmd (NmCli *nmc, GTask *task, const NMCCommand *cmd, int argc, char **argv)
 {
 	CmdCall *call;
 
@@ -1257,20 +1242,23 @@ call_cmd (NmCli *nmc, GSimpleAsyncResult *simple, const NMCCommand *cmd, int arg
 
 		/* Check whether NetworkManager is running */
 		if (cmd->needs_nm_running && !nm_client_get_nm_running (nmc->client)) {
-			g_simple_async_result_set_error (simple, NMCLI_ERROR, NMC_RESULT_ERROR_NM_NOT_RUNNING,
-			                                 _("Error: NetworkManager is not running."));
-		} else
+			g_task_return_new_error (task, NMCLI_ERROR, NMC_RESULT_ERROR_NM_NOT_RUNNING,
+			                         _("Error: NetworkManager is not running."));
+		} else {
 			nmc->return_value = cmd->func (nmc, argc, argv);
-		g_simple_async_result_complete_in_idle (simple);
-		g_object_unref (simple);
+			g_task_return_boolean (task, TRUE);
+		}
+
+		g_object_unref (task);
 	} else {
+		nm_assert (nmc->client == NULL);
+
 		nmc->should_wait++;
 		call = g_slice_new0 (CmdCall);
-		call->nmc = nmc;
 		call->cmd = cmd;
 		call->argc = argc;
 		call->argv = argv;
-		call->simple = simple;
+		call->task = task;
 		nm_client_new_async (NULL, got_client, call);
 	}
 }
@@ -1306,16 +1294,13 @@ void
 nmc_do_cmd (NmCli *nmc, const NMCCommand cmds[], const char *cmd, int argc, char **argv)
 {
 	const NMCCommand *c;
-	GSimpleAsyncResult *simple;
+	gs_unref_object GTask *task = NULL;
 
-	simple = g_simple_async_result_new (NULL,
-	                                    command_done,
-	                                    nmc,
-	                                    nmc_do_cmd);
+	task = nm_g_task_new (NULL, NULL, nmc_do_cmd, command_done, nmc);
+	g_task_set_task_data (task, nmc, NULL);
 
 	if (argc == 0 && nmc->complete) {
-		g_simple_async_result_complete_in_idle (simple);
-		g_object_unref (simple);
+		g_task_return_boolean (task, TRUE);
 		return;
 	}
 
@@ -1325,8 +1310,7 @@ nmc_do_cmd (NmCli *nmc, const NMCCommand cmds[], const char *cmd, int argc, char
 				g_print ("%s\n", c->cmd);
 		}
 		nmc_complete_help (cmd);
-		g_simple_async_result_complete_in_idle (simple);
-		g_object_unref (simple);
+		g_task_return_boolean (task, TRUE);
 		return;
 	}
 
@@ -1341,32 +1325,26 @@ nmc_do_cmd (NmCli *nmc, const NMCCommand cmds[], const char *cmd, int argc, char
 			nmc_complete_help (*(argv+1));
 		if (!nmc->complete && c->usage && nmc_arg_is_help (*(argv+1))) {
 			c->usage ();
-			g_simple_async_result_complete_in_idle (simple);
-			g_object_unref (simple);
+			g_task_return_boolean (task, TRUE);
 		} else {
-			call_cmd (nmc, simple, c, argc, argv);
+			call_cmd (nmc, g_steal_pointer (&task), c, argc, argv);
 		}
 	} else if (cmd) {
 		/* Not a known command. */
 		if (nmc_arg_is_help (cmd) && c->usage) {
 			c->usage ();
-			g_simple_async_result_complete_in_idle (simple);
-			g_object_unref (simple);
+			g_task_return_boolean (task, TRUE);
 		} else {
-			g_simple_async_result_set_error (simple, NMCLI_ERROR, NMC_RESULT_ERROR_USER_INPUT,
-			                                 _("Error: argument '%s' not understood. Try passing --help instead."), cmd);
-			g_simple_async_result_complete_in_idle (simple);
-			g_object_unref (simple);
+			g_task_return_new_error (task, NMCLI_ERROR, NMC_RESULT_ERROR_USER_INPUT,
+			                         _("Error: argument '%s' not understood. Try passing --help instead."), cmd);
 		}
 	} else if (c->func) {
 		/* No command, run the default handler. */
-		call_cmd (nmc, simple, c, argc, argv);
+		call_cmd (nmc, g_steal_pointer (&task), c, argc, argv);
 	} else {
 		/* No command and no default handler. */
-		g_simple_async_result_set_error (simple, NMCLI_ERROR, NMC_RESULT_ERROR_USER_INPUT,
-		                                 _("Error: missing argument. Try passing --help."));
-		g_simple_async_result_complete_in_idle (simple);
-		g_object_unref (simple);
+		g_task_return_new_error (task, NMCLI_ERROR, NMC_RESULT_ERROR_USER_INPUT,
+		                         _("Error: missing argument. Try passing --help."));
 	}
 }
 
@@ -1434,10 +1412,56 @@ nmc_error_get_simple_message (GError *error)
 	/* Return a clear message instead of the obscure D-Bus policy error */
 	if (g_error_matches (error, G_DBUS_ERROR, G_DBUS_ERROR_ACCESS_DENIED))
 		return _("access denied");
+	if (g_error_matches (error, G_DBUS_ERROR, G_DBUS_ERROR_SERVICE_UNKNOWN))
+		return _("NetworkManager is not running");
 	else
 		return error->message;
 }
 
+GVariant *
+nmc_dbus_call_sync (NmCli *nmc,
+                    const char *object_path,
+                    const char *interface_name,
+                    const char *method_name,
+                    GVariant *parameters,
+                    const GVariantType *reply_type,
+                    GError **error)
+{
+	gs_unref_object GDBusConnection *connection = NULL;
+	gs_free_error GError *local = NULL;
+	GVariant *result;
+
+	if (nmc->timeout == -1)
+		nmc->timeout = 90;
+
+	connection = g_bus_get_sync (G_BUS_TYPE_SYSTEM, NULL, &local);
+	if (!connection) {
+		g_set_error (error,
+		             NMCLI_ERROR,
+		             NMC_RESULT_ERROR_UNKNOWN,
+		             _("Error: error connecting to system bus: %s"),
+		             local->message);
+		return NULL;
+	}
+
+	result = g_dbus_connection_call_sync (connection,
+	                                      "org.freedesktop.NetworkManager",
+	                                      object_path,
+	                                      interface_name,
+	                                      method_name,
+	                                      parameters,
+	                                      reply_type,
+	                                      G_DBUS_CALL_FLAGS_NONE,
+	                                      nmc->timeout * 1000,
+	                                      NULL,
+	                                      error);
+
+	if (error && *error)
+		g_dbus_error_strip_remote_error (*error);
+
+	return result;
+}
+
 /*****************************************************************************/
 
 NM_UTILS_LOOKUP_STR_DEFINE (nm_connectivity_to_string, NMConnectivityState,
diff --git a/clients/cli/common.h b/clients/cli/common.h
index 688f2819..f8fad8c6 100644
--- a/clients/cli/common.h
+++ b/clients/cli/common.h
@@ -1,22 +1,6 @@
+// SPDX-License-Identifier: GPL-2.0+
 /*
- *  nmcli - command-line tool for controlling NetworkManager
- *  Common functions and data shared between files.
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License along
- * with this program; if not, write to the Free Software Foundation, Inc.,
- * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
- *
- * Copyright 2012 - 2014 Red Hat, Inc.
+ * Copyright (C) 2012 - 2014 Red Hat, Inc.
  */
 
 #ifndef NMC_COMMON_H
@@ -102,4 +86,12 @@ extern const NmcMetaGenericInfo *const metagen_dhcp_config[];
 
 const char *nm_connectivity_to_string (NMConnectivityState connectivity);
 
+GVariant *nmc_dbus_call_sync (NmCli *nmc,
+                              const char *object_path,
+                              const char *interface_name,
+                              const char *method_name,
+                              GVariant *parameters,
+                              const GVariantType *reply_type,
+                              GError **error);
+
 #endif /* NMC_COMMON_H */
diff --git a/clients/cli/connections.c b/clients/cli/connections.c
index e365980e..a77c2482 100644
--- a/clients/cli/connections.c
+++ b/clients/cli/connections.c
@@ -1,20 +1,6 @@
-/* nmcli - command-line tool to control NetworkManager
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License along
- * with this program; if not, write to the Free Software Foundation, Inc.,
- * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
- *
- * Copyright 2010 - 2018 Red Hat, Inc.
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * Copyright (C) 2010 - 2018 Red Hat, Inc.
  */
 
 #include "nm-default.h"
@@ -657,6 +643,7 @@ _metagen_con_active_general_get_fcn (NMC_META_GENERIC_INFO_GET_FCN_ARGS)
 	case NMC_GENERIC_INFO_TYPE_CON_ACTIVE_GENERAL_UUID:
 		return nm_active_connection_get_uuid (ac);
 	case NMC_GENERIC_INFO_TYPE_CON_ACTIVE_GENERAL_DEVICES:
+	case NMC_GENERIC_INFO_TYPE_CON_ACTIVE_GENERAL_IP_IFACE:
 		{
 			GString *str = NULL;
 			const GPtrArray *devices;
@@ -665,10 +652,15 @@ _metagen_con_active_general_get_fcn (NMC_META_GENERIC_INFO_GET_FCN_ARGS)
 			devices = nm_active_connection_get_devices (ac);
 			if (devices) {
 				for (i = 0; i < devices->len; i++) {
-					NMDevice *device = devices->pdata[i];
+					NMDevice *device = g_ptr_array_index (devices, i);
 					const char *iface;
 
-					iface = nm_device_get_iface (device);
+					if (info->info_type == NMC_GENERIC_INFO_TYPE_CON_ACTIVE_GENERAL_DEVICES) {
+						iface = nm_device_get_iface (device);
+					} else {
+						iface = nm_device_get_ip_iface (device);
+					}
+
 					if (!iface)
 						continue;
 					if (!s) {
@@ -720,6 +712,7 @@ const NmcMetaGenericInfo *const metagen_con_active_general[_NMC_GENERIC_INFO_TYP
 	_METAGEN_CON_ACTIVE_GENERAL (NMC_GENERIC_INFO_TYPE_CON_ACTIVE_GENERAL_NAME,        "NAME"),
 	_METAGEN_CON_ACTIVE_GENERAL (NMC_GENERIC_INFO_TYPE_CON_ACTIVE_GENERAL_UUID,        "UUID"),
 	_METAGEN_CON_ACTIVE_GENERAL (NMC_GENERIC_INFO_TYPE_CON_ACTIVE_GENERAL_DEVICES,     "DEVICES"),
+	_METAGEN_CON_ACTIVE_GENERAL (NMC_GENERIC_INFO_TYPE_CON_ACTIVE_GENERAL_IP_IFACE,    "IP-IFACE"),
 	_METAGEN_CON_ACTIVE_GENERAL (NMC_GENERIC_INFO_TYPE_CON_ACTIVE_GENERAL_STATE,       "STATE"),
 	_METAGEN_CON_ACTIVE_GENERAL (NMC_GENERIC_INFO_TYPE_CON_ACTIVE_GENERAL_DEFAULT,     "DEFAULT"),
 	_METAGEN_CON_ACTIVE_GENERAL (NMC_GENERIC_INFO_TYPE_CON_ACTIVE_GENERAL_DEFAULT6,    "DEFAULT6"),
@@ -2933,7 +2926,8 @@ do_connection_up (NmCli *nmc, int argc, char **argv)
 			pwds = *argv;
 		}
 		else if (!nmc->complete) {
-			g_printerr (_("Unknown parameter: %s\n"), *argv);
+			g_string_printf (nmc->return_text, _("Error: invalid extra argument '%s'."), *argv);
+			return NMC_RESULT_ERROR_USER_INPUT;
 		}
 
 		next_arg (nmc, &argc, &argv, NULL);
@@ -3135,7 +3129,7 @@ do_connection_down (NmCli *nmc, int argc, char **argv)
 		}
 		if (arg_num == 0) {
 			g_string_printf (nmc->return_text, _("Error: No connection specified."));
-			NMC_RETURN (nmc, NMC_RESULT_ERROR_USER_INPUT);
+			return NMC_RESULT_ERROR_USER_INPUT;
 		}
 	}
 
@@ -3153,7 +3147,7 @@ do_connection_down (NmCli *nmc, int argc, char **argv)
 			arg_ptr++;
 			if (!arg_num) {
 				g_string_printf (nmc->return_text, _("Error: %s argument is missing."), selector);
-				NMC_RETURN (nmc, NMC_RESULT_ERROR_USER_INPUT);
+				return NMC_RESULT_ERROR_USER_INPUT;
 			}
 		}
 
@@ -3174,7 +3168,7 @@ do_connection_down (NmCli *nmc, int argc, char **argv)
 
 	if (!found_active_cons) {
 		g_string_printf (nmc->return_text, _("Error: no active connection provided."));
-		NMC_RETURN (nmc, NMC_RESULT_ERROR_NOT_FOUND);
+		return NMC_RESULT_ERROR_NOT_FOUND;
 	}
 	nm_assert (found_active_cons->len > 0);
 
@@ -3320,6 +3314,21 @@ get_valid_settings_array (const char *con_type)
 	return NULL;
 }
 
+static char *
+_construct_property_name (const char *setting_name,
+                          const char *property_name,
+                          NMMetaAccessorModifier modifier)
+{
+	return g_strdup_printf ("%s%s.%s\n",
+	                        (  modifier == NM_META_ACCESSOR_MODIFIER_ADD
+	                         ? "+"
+	                         : (  modifier == NM_META_ACCESSOR_MODIFIER_DEL
+	                            ? "-"
+	                            : "")),
+	                        setting_name,
+	                        property_name);
+}
+
 /* get_valid_properties_string:
  * @array: base properties for the current connection type
  * @array_slv: slave properties (or ipv4/ipv6 ones) for the current connection type
@@ -3337,7 +3346,7 @@ get_valid_settings_array (const char *con_type)
 static char *
 get_valid_properties_string (const NMMetaSettingValidPartItem *const*array,
                              const NMMetaSettingValidPartItem *const*array_slv,
-                             char modifier,
+                             NMMetaAccessorModifier modifier,
                              const char *prefix,
                              const char *postfix)
 {
@@ -3379,32 +3388,26 @@ get_valid_properties_string (const NMMetaSettingValidPartItem *const*array,
 
 			/* Search the array with the arguments of the current property */
 			for (j = 0; j < setting_info->properties_num; j++) {
-				char *new;
+				gs_free char *ss1 = NULL;
 				const char *arg_name;
 
 				arg_name = setting_info->properties[j]->property_name;
 
 				/* If required, expand the alias too */
-				if (!postfix && setting_info->alias) {
-					if (modifier)
-						g_string_append_c (str, modifier);
-					new = g_strdup_printf ("%s.%s\n",
-					                       setting_info->alias,
-					                       arg_name);
-					g_string_append (str, new);
-					g_free (new);
+				if (   !postfix
+				    && setting_info->alias) {
+					gs_free char *ss2 = NULL;
+
+					ss2 = _construct_property_name (setting_info->alias, arg_name, modifier);
+					g_string_append (str, ss2);
 				}
 
-				if (postfix && !g_str_has_prefix (arg_name, postfix))
+				if (   postfix
+				    && !g_str_has_prefix (arg_name, postfix))
 					continue;
 
-				if (modifier)
-					g_string_append_c (str, modifier);
-				new = g_strdup_printf ("%s.%s\n",
-				                       prop_name,
-				                       arg_name);
-				g_string_append (str, new);
-				g_free (new);
+				ss1 = _construct_property_name (prop_name, arg_name, modifier);
+				g_string_append (str, ss1);
 			}
 		}
 	}
@@ -3723,50 +3726,56 @@ static char *
 unique_master_iface_ifname (const GPtrArray *connections,
                             const char *try_name)
 {
-	NMConnection *connection;
 	char *new_name;
-	unsigned num = 1;
-	int i = 0;
-	const char *ifname = NULL;
+	guint num = 0;
+	guint i;
 
 	new_name = g_strdup (try_name);
-	while (i < connections->len) {
-		connection = NM_CONNECTION (connections->pdata[i]);
-		ifname = nm_connection_get_interface_name (connection);
-		if (g_strcmp0 (new_name, ifname) == 0) {
+
+again:
+	for (i = 0; i < connections->len; i++) {
+		NMConnection *connection = connections->pdata[i];
+
+		if (nm_streq0 (new_name, nm_connection_get_interface_name (connection))) {
+			num++;
 			g_free (new_name);
-			new_name = g_strdup_printf ("%s%d", try_name, num++);
-			i = 0;
-		} else
-			i++;
+			new_name = g_strdup_printf ("%s%u", try_name, num);
+			goto again;
+		}
 	}
 	return new_name;
 }
 
 static void
-set_default_interface_name (NmCli *nmc, NMSettingConnection *s_con)
+set_default_interface_name (NmCli *nmc,
+                            NMSettingConnection *s_con)
 {
-	const GPtrArray *connections;
-	char *ifname = NULL;
-	const char *con_type = nm_setting_connection_get_connection_type (s_con);
+	const char *default_name;
+	const char *con_type;
 
 	if (nm_setting_connection_get_interface_name (s_con))
 		return;
 
-	connections = nm_client_get_connections (nmc->client);
+	con_type = nm_setting_connection_get_connection_type (s_con);
 
 	/* Set a sensible bond/team/bridge interface name by default */
-	if (g_strcmp0 (con_type, NM_SETTING_BOND_SETTING_NAME) == 0)
-		ifname = unique_master_iface_ifname (connections, "nm-bond");
-	else if (g_strcmp0 (con_type, NM_SETTING_TEAM_SETTING_NAME) == 0)
-		ifname = unique_master_iface_ifname (connections, "nm-team");
-	else if (g_strcmp0 (con_type, NM_SETTING_BRIDGE_SETTING_NAME) == 0)
-		ifname = unique_master_iface_ifname (connections, "nm-bridge");
+	if (nm_streq0 (con_type, NM_SETTING_BOND_SETTING_NAME))
+		default_name = "nm-bond";
+	else if (nm_streq0 (con_type, NM_SETTING_TEAM_SETTING_NAME))
+		default_name = "nm-team";
+	else if (nm_streq0 (con_type, NM_SETTING_BRIDGE_SETTING_NAME))
+		default_name = "nm-bridge";
 	else
-		return;
+		default_name = NULL;
+
+	if (default_name) {
+		const GPtrArray *connections;
+		gs_free char *ifname = NULL;
 
-	g_object_set (s_con, NM_SETTING_CONNECTION_INTERFACE_NAME, ifname, NULL);
-	g_free (ifname);
+		connections = nm_client_get_connections (nmc->client);
+		ifname = unique_master_iface_ifname (connections, default_name);
+		g_object_set (s_con, NM_SETTING_CONNECTION_INTERFACE_NAME, ifname, NULL);
+	}
 }
 
 /*****************************************************************************/
@@ -4004,7 +4013,7 @@ set_property (NMClient *client,
               const char *setting_name,
               const char *property,
               const char *value,
-              char modifier,
+              NMMetaAccessorModifier modifier,
               GError **error)
 {
 	gs_free char *property_name = NULL;
@@ -4012,7 +4021,9 @@ set_property (NMClient *client,
 	NMSetting *setting;
 
 	nm_assert (setting_name && setting_name[0]);
-	nm_assert (NM_IN_SET (modifier, '\0', '+', '-'));
+	nm_assert (NM_IN_SET (modifier, NM_META_ACCESSOR_MODIFIER_SET,
+	                                NM_META_ACCESSOR_MODIFIER_ADD,
+	                                NM_META_ACCESSOR_MODIFIER_DEL));
 
 	setting = nm_connection_get_setting_by_name (connection, setting_name);
 	if (!setting) {
@@ -4032,14 +4043,15 @@ set_property (NMClient *client,
 	if (!nmc_setting_set_property (client,
 	                               setting,
 	                               property_name,
-	                               (  (modifier == '-' && !value)
-	                                ? '\0'
+	                               (  (   modifier == NM_META_ACCESSOR_MODIFIER_DEL
+	                                   && !value)
+	                                ? NM_META_ACCESSOR_MODIFIER_SET
 	                                : modifier),
 	                               value,
 	                               &local)) {
 		g_set_error (error, NMCLI_ERROR, NMC_RESULT_ERROR_USER_INPUT,
 		             _("Error: failed to %s %s.%s: %s."),
-		             (  modifier != '-'
+		             (  modifier != NM_META_ACCESSOR_MODIFIER_DEL
 		              ? "modify"
 		              : "remove a value from"),
 		             setting_name,
@@ -4069,8 +4081,15 @@ set_option (NmCli *nmc, NMConnection *connection, const NMMetaAbstractInfo *abst
 	if (option && option->check_and_set) {
 		return option->check_and_set (nmc, connection, option, value, error);
 	} else if (value) {
-		return set_property (nmc->client, connection, setting_name, property_name,
-		                     value, inf_flags & NM_META_PROPERTY_INF_FLAG_MULTI ? '+' : '\0', error);
+		return set_property (nmc->client,
+		                     connection,
+		                     setting_name,
+		                     property_name,
+		                     value,
+		                       inf_flags & NM_META_PROPERTY_INF_FLAG_MULTI
+		                     ? NM_META_ACCESSOR_MODIFIER_ADD
+		                     : NM_META_ACCESSOR_MODIFIER_SET,
+		                     error);
 	} else if (inf_flags & NM_META_PROPERTY_INF_FLAG_REQD) {
 		g_set_error (error, NMCLI_ERROR, NMC_RESULT_ERROR_USER_INPUT,
 	                     _("Error: '%s' is mandatory."), option_name);
@@ -4191,9 +4210,13 @@ set_connection_type (NmCli *nmc, NMConnection *con, const OptionInfo *option, co
 	}
 
 	if (slave_type) {
-		if (!set_property (nmc->client, con, NM_SETTING_CONNECTION_SETTING_NAME,
-		                   NM_SETTING_CONNECTION_SLAVE_TYPE, slave_type,
-		                   '\0', error)) {
+		if (!set_property (nmc->client,
+		                   con,
+		                   NM_SETTING_CONNECTION_SETTING_NAME,
+		                   NM_SETTING_CONNECTION_SLAVE_TYPE,
+		                   slave_type,
+		                   NM_META_ACCESSOR_MODIFIER_SET,
+		                   error)) {
 			return FALSE;
 		}
 		enable_options (NM_SETTING_CONNECTION_SETTING_NAME, NM_SETTING_CONNECTION_MASTER, master);
@@ -4208,7 +4231,13 @@ set_connection_type (NmCli *nmc, NMConnection *con, const OptionInfo *option, co
 		                 NM_SETTING_CONNECTION_INTERFACE_NAME);
 	}
 
-	if (!set_property (nmc->client, con, option->setting_info->general->setting_name, option->property, value, '\0', error))
+	if (!set_property (nmc->client,
+	                   con,
+	                   option->setting_info->general->setting_name,
+	                   option->property,
+	                   value,
+	                   NM_META_ACCESSOR_MODIFIER_SET,
+	                   error))
 		return FALSE;
 
 	if (!con_settings (con, &type_settings, &slv_settings, error))
@@ -4237,7 +4266,13 @@ set_connection_iface (NmCli *nmc, NMConnection *con, const OptionInfo *option, c
 		}
 	}
 
-	return set_property (nmc->client, con, option->setting_info->general->setting_name, option->property, value, '\0', error);
+	return set_property (nmc->client,
+	                     con,
+	                     option->setting_info->general->setting_name,
+	                     option->property,
+	                     value,
+	                     NM_META_ACCESSOR_MODIFIER_SET,
+	                     error);
 }
 
 static gboolean
@@ -4260,13 +4295,23 @@ set_connection_master (NmCli *nmc, NMConnection *con, const OptionInfo *option,
 	connections = nm_client_get_connections (nmc->client);
 	value = normalized_master_for_slave (connections, value, slave_type, &slave_type);
 
-	if (!set_property (nmc->client, con, NM_SETTING_CONNECTION_SETTING_NAME,
-	                   NM_SETTING_CONNECTION_SLAVE_TYPE, slave_type,
-	                   '\0', error)) {
+	if (!set_property (nmc->client,
+	                   con,
+	                   NM_SETTING_CONNECTION_SETTING_NAME,
+	                   NM_SETTING_CONNECTION_SLAVE_TYPE,
+	                   slave_type,
+	                   NM_META_ACCESSOR_MODIFIER_SET,
+	                   error)) {
 		return FALSE;
 	}
 
-	return set_property (nmc->client, con, option->setting_info->general->setting_name, option->property, value, '\0', error);
+	return set_property (nmc->client,
+	                     con,
+	                     option->setting_info->general->setting_name,
+	                     option->property,
+	                     value,
+	                     NM_META_ACCESSOR_MODIFIER_SET,
+	                     error);
 }
 
 static gboolean
@@ -4380,7 +4425,13 @@ set_bluetooth_type (NmCli *nmc, NMConnection *con, const OptionInfo *option, con
 		return FALSE;
 	}
 
-	return set_property (nmc->client, con, option->setting_info->general->setting_name, option->property, value, '\0', error);
+	return set_property (nmc->client,
+	                     con,
+	                     option->setting_info->general->setting_name,
+	                     option->property,
+	                     value,
+	                     NM_META_ACCESSOR_MODIFIER_SET,
+	                     error);
 }
 
 static gboolean
@@ -4399,8 +4450,13 @@ set_ip4_address (NmCli *nmc, NMConnection *con, const OptionInfo *option, const
 		              NM_SETTING_IP_CONFIG_METHOD, NM_SETTING_IP4_CONFIG_METHOD_MANUAL,
 		              NULL);
 	}
-	return set_property (nmc->client, con, option->setting_info->general->setting_name, option->property, value,
-	                     '+', error);
+	return set_property (nmc->client,
+	                     con,
+	                     option->setting_info->general->setting_name,
+	                     option->property,
+	                     value,
+	                     NM_META_ACCESSOR_MODIFIER_ADD,
+	                     error);
 }
 
 static gboolean
@@ -4419,8 +4475,13 @@ set_ip6_address (NmCli *nmc, NMConnection *con, const OptionInfo *option, const
 		              NM_SETTING_IP_CONFIG_METHOD, NM_SETTING_IP6_CONFIG_METHOD_MANUAL,
 		              NULL);
 	}
-	return set_property (nmc->client, con, option->setting_info->general->setting_name, option->property, value,
-	                     '+', error);
+	return set_property (nmc->client,
+	                     con,
+	                     option->setting_info->general->setting_name,
+	                     option->property,
+	                     value,
+	                     NM_META_ACCESSOR_MODIFIER_ADD,
+	                     error);
 }
 
 /*****************************************************************************/
@@ -4492,7 +4553,7 @@ option_relevant (NMConnection *connection, const NMMetaAbstractInfo *abstract_in
 
 static void
 complete_property_name (NmCli *nmc, NMConnection *connection,
-                        char modifier,
+                        NMMetaAccessorModifier modifier,
                         const char *prefix,
                         const char *postfix)
 {
@@ -4515,7 +4576,7 @@ complete_property_name (NmCli *nmc, NMConnection *connection,
 	if (word_list)
 		g_print ("%s", word_list);
 
-	if (modifier != '\0')
+	if (modifier != NM_META_ACCESSOR_MODIFIER_SET)
 		return;
 
 	for (s = 0; s < _NM_META_SETTING_TYPE_NUM; s++) {
@@ -4644,20 +4705,18 @@ nmc_read_connection_properties (NmCli *nmc,
                                 char ***argv,
                                 GError **error)
 {
-	const char *option;
-	const char *value = NULL;
-	GError *local = NULL;
-
 	/* First check if we have a slave-type, as this would mean we will not
 	 * have ip properties but possibly others, slave-type specific.
 	 */
 	/* Go through arguments and set properties */
 	do {
-		const NMMetaAbstractInfo *chosen = NULL;
-		gs_strfreev char **strv = NULL;
 		const NMMetaSettingValidPartItem *const*type_settings;
 		const NMMetaSettingValidPartItem *const*slv_settings;
-		char modifier = '\0';
+		NMMetaAccessorModifier modifier;
+		const char *option_orig;
+		const char *option;
+		const char *value = NULL;
+		const char *tmp;
 
 		if (!con_settings (connection, &type_settings, &slv_settings, error))
 			return FALSE;
@@ -4665,54 +4724,58 @@ nmc_read_connection_properties (NmCli *nmc,
 		ensure_settings (connection, slv_settings);
 		ensure_settings (connection, type_settings);
 
-		option = **argv;
-		if (!option) {
+		option_orig = **argv;
+		if (!option_orig) {
 			g_set_error_literal (error, NMCLI_ERROR, NMC_RESULT_ERROR_USER_INPUT,
 			                     _("Error: <setting>.<property> argument is missing."));
 			return FALSE;
 		}
 
-		if (option[0] == '+' || option[0] == '-')
-			modifier = *option;
+		switch (option_orig[0]) {
+		case '+': modifier = NM_META_ACCESSOR_MODIFIER_ADD; option = &option_orig[1]; break;
+		case '-': modifier = NM_META_ACCESSOR_MODIFIER_DEL; option = &option_orig[1]; break;
+		default:  modifier = NM_META_ACCESSOR_MODIFIER_SET; option = option_orig;     break;
+		}
+
+		if ((tmp = strchr (option, '.'))) {
+			gs_free char *option_sett = g_strndup (option, tmp - option);
+			const char *option_prop = &tmp[1];
+			const char *option_sett_expanded;
+			GError *local = NULL;
 
-		strv = g_strsplit (option, ".", 2);
-		if (g_strv_length (strv) == 2) {
 			/* This seems like a <setting>.<property> (such as "connection.id" or "bond.mode"),
 			 * optionally prefixed with "+| or "-". */
-			char *setting = strv[0];
-			const char *setting_name;
 
-			if (modifier)
-				setting++;
+			if (   *argc == 1
+			    && nmc->complete)
+				complete_property_name (nmc, connection, modifier, option_sett, option_prop);
 
-			if (*argc == 1 && nmc->complete)
-				complete_property_name (nmc, connection, modifier, setting, strv[1]);
-
-			setting_name = check_valid_name (setting, type_settings, slv_settings, &local);
-			if (!setting_name) {
+			option_sett_expanded = check_valid_name (option_sett, type_settings, slv_settings, &local);
+			if (!option_sett_expanded) {
 				g_set_error (error, NMCLI_ERROR, NMC_RESULT_ERROR_USER_INPUT,
 				             _("Error: invalid or not allowed setting '%s': %s."),
-				             setting, local->message);
+				             option_sett, local->message);
 				g_clear_error (&local);
 				return FALSE;
 			}
 
 			(*argc)--;
 			(*argv)++;
-			if (!get_value (&value, argc, argv, option, error))
+			if (!get_value (&value, argc, argv, option_orig, error))
 				return FALSE;
 
 			if (!*argc && nmc->complete) {
-				complete_property (nmc, setting, strv[1], value ?: "", connection);
+				complete_property (nmc, option_sett, option_prop, value ?: "", connection);
 				return TRUE;
 			}
 
-			if (!set_property (nmc->client, connection, setting_name, strv[1], value, modifier, error))
+			if (!set_property (nmc->client, connection, option_sett_expanded, option_prop, value, modifier, error))
 				return FALSE;
 		} else {
-			NMMetaSettingType s;
+			const NMMetaAbstractInfo *chosen = NULL;
 			const char *chosen_setting_name = NULL;
 			const char *chosen_option = NULL;
+			NMMetaSettingType s;
 
 			/* Let's see if this is an property alias (such as "id", "mode", "type" or "con-name")*/
 			for (s = 0; s < _NM_META_SETTING_TYPE_NUM; s++) {
@@ -4768,8 +4831,6 @@ nmc_read_connection_properties (NmCli *nmc,
 			}
 
 			if (!chosen) {
-				if (modifier)
-					option++;
 				if (*argc == 1 && nmc->complete)
 					complete_property_name (nmc, connection, modifier, option, NULL);
 				g_set_error (error, NMCLI_ERROR, NMC_RESULT_ERROR_USER_INPUT,
@@ -4782,7 +4843,7 @@ nmc_read_connection_properties (NmCli *nmc,
 
 			(*argc)--;
 			(*argv)++;
-			if (!get_value (&value, argc, argv, option, error))
+			if (!get_value (&value, argc, argv, option_orig, error))
 				return FALSE;
 
 			if (!*argc && nmc->complete)
@@ -5270,11 +5331,12 @@ read_properties:
 		const char *ifname = nm_setting_connection_get_interface_name (s_con);
 		const char *type = nm_setting_connection_get_connection_type (s_con);
 		const char *slave_type = nm_setting_connection_get_slave_type (s_con);
-		char *try_name, *default_name;
 
 		/* If only bother when there's a type, which is not guaranteed at this point.
 		 * Otherwise the validation will fail anyway. */
 		if (type) {
+			gs_free char *try_name = NULL;
+			gs_free char *default_name = NULL;
 			const GPtrArray *connections;
 
 			connections = nm_client_get_connections (nmc->client);
@@ -5282,9 +5344,7 @@ read_properties:
 			           ? g_strdup_printf ("%s-%s", get_name_alias_toplevel (type, slave_type), ifname)
 			           : g_strdup (get_name_alias_toplevel (type, slave_type));
 			default_name = nmc_unique_connection_name (connections, try_name);
-			g_free (try_name);
 			g_object_set (s_con, NM_SETTING_CONNECTION_ID, default_name, NULL);
-			g_free (default_name);
 		}
 	}
 
@@ -6980,8 +7040,8 @@ property_edit_submenu (NmCli *nmc,
 			                                       curr_setting,
 			                                       prop_name,
 			                                         (cmdsub == NMC_EDITOR_SUB_CMD_SET)
-			                                       ? '\0'
-			                                       : '+',
+			                                       ? NM_META_ACCESSOR_MODIFIER_SET
+			                                       : NM_META_ACCESSOR_MODIFIER_ADD,
 			                                       prop_val_user,
 			                                       &tmp_err);
 			if (!set_result) {
@@ -6997,7 +7057,12 @@ property_edit_submenu (NmCli *nmc,
 			                              _("Edit '%s' value: "),
 			                              prop_name);
 
-			if (!nmc_setting_set_property (nmc->client, curr_setting, prop_name, '\0', prop_val_user, &tmp_err)) {
+			if (!nmc_setting_set_property (nmc->client,
+			                               curr_setting,
+			                               prop_name,
+			                               NM_META_ACCESSOR_MODIFIER_SET,
+			                               prop_val_user,
+			                               &tmp_err)) {
 				g_print (_("Error: failed to set '%s' property: %s\n"), prop_name, tmp_err->message);
 				g_clear_error (&tmp_err);
 			}
@@ -7008,8 +7073,8 @@ property_edit_submenu (NmCli *nmc,
 			                               curr_setting,
 			                               prop_name,
 			                               (  cmd_property_arg
-			                                ? '-'
-			                                : '\0'),
+			                                ? NM_META_ACCESSOR_MODIFIER_DEL
+			                                : NM_META_ACCESSOR_MODIFIER_SET),
 			                               cmd_property_arg,
 			                               &tmp_err)) {
 				g_print (_("Error: %s\n"), tmp_err->message);
@@ -7363,7 +7428,12 @@ editor_menu_main (NmCli *nmc, NMConnection *connection, const char *connection_t
 					                              _("Enter '%s' value: "),
 					                              prop_name);
 
-					if (!nmc_setting_set_property (nmc->client, menu_ctx.curr_setting, prop_name, '+', prop_val_user, &tmp_err)) {
+					if (!nmc_setting_set_property (nmc->client,
+					                               menu_ctx.curr_setting,
+					                               prop_name,
+					                               NM_META_ACCESSOR_MODIFIER_ADD,
+					                               prop_val_user,
+					                               &tmp_err)) {
 						g_print (_("Error: failed to set '%s' property: %s\n"), prop_name, tmp_err->message);
 						g_clear_error (&tmp_err);
 					}
@@ -7427,7 +7497,9 @@ editor_menu_main (NmCli *nmc, NMConnection *connection, const char *connection_t
 				if (!nmc_setting_set_property (nmc->client,
 				                               ss,
 				                               prop_name,
-				                               cmd_arg_v ? '+' : '\0',
+				                                 cmd_arg_v
+				                               ? NM_META_ACCESSOR_MODIFIER_ADD
+				                               : NM_META_ACCESSOR_MODIFIER_SET,
 				                               cmd_arg_v,
 				                               &tmp_err)) {
 					g_print (_("Error: failed to set '%s' property: %s\n"),
@@ -7526,7 +7598,12 @@ editor_menu_main (NmCli *nmc, NMConnection *connection, const char *connection_t
 					if (!prop_name)
 						break;
 
-					if (!nmc_setting_set_property (nmc->client, menu_ctx.curr_setting, prop_name, '\0', NULL, &tmp_err)) {
+					if (!nmc_setting_set_property (nmc->client,
+					                               menu_ctx.curr_setting,
+					                               prop_name,
+					                               NM_META_ACCESSOR_MODIFIER_SET,
+					                               NULL,
+					                               &tmp_err)) {
 						g_print (_("Error: failed to remove value of '%s': %s\n"), prop_name,
 						         tmp_err->message);
 						g_clear_error (&tmp_err);
@@ -7572,11 +7649,16 @@ editor_menu_main (NmCli *nmc, NMConnection *connection, const char *connection_t
 					}
 				} else {
 					gs_free char *prop_name = NULL;
-					gs_free GError *tmp_err = NULL;
+					gs_free_error GError *tmp_err = NULL;
 
 					prop_name = is_property_valid (ss, cmd_arg_p, &tmp_err);
 					if (prop_name) {
-						if (!nmc_setting_set_property (nmc->client, ss, prop_name, '\0', NULL, &tmp_err)) {
+						if (!nmc_setting_set_property (nmc->client,
+						                               ss,
+						                               prop_name,
+						                               NM_META_ACCESSOR_MODIFIER_SET,
+						                               NULL,
+						                               &tmp_err)) {
 							g_print (_("Error: failed to remove value of '%s': %s\n"),
 							         prop_name,
 							         tmp_err->message);
@@ -7931,6 +8013,7 @@ editor_menu_main (NmCli *nmc, NMConnection *connection, const char *connection_t
 				ap_nsp = ap_nsp && ap_nsp[0] == '/' ? ap_nsp + 1 : ap_nsp;
 
 			if (is_connection_dirty (connection, rem_con)) {
+				/* TRANSLATORS: do not translate 'save', leave it as it is */
 				g_print (_("Error: connection is not saved. Type 'save' first.\n"));
 				break;
 			}
@@ -8220,7 +8303,7 @@ do_connection_edit (NmCli *nmc, int argc, char **argv)
 	else {
 		if (!nmc_parse_args (exp_args, TRUE, &argc, &argv, &error)) {
 			g_string_assign (nmc->return_text, error->message);
-			NMC_RETURN (nmc, error->code);
+			return error->code;
 		}
 	}
 
@@ -8250,7 +8333,7 @@ do_connection_edit (NmCli *nmc, int argc, char **argv)
 		} else {
 			g_string_printf (nmc->return_text,
 			                 _("Error: only one of 'id', 'filename', uuid, or 'path' can be provided."));
-			NMC_RETURN (nmc, NMC_RESULT_ERROR_USER_INPUT);
+			return NMC_RESULT_ERROR_USER_INPUT;
 		}
 	}
 
@@ -8264,7 +8347,7 @@ do_connection_edit (NmCli *nmc, int argc, char **argv)
 
 		if (!found_con) {
 			g_string_printf (nmc->return_text, _("Error: Unknown connection '%s'."), con);
-			NMC_RETURN (nmc, NMC_RESULT_ERROR_NOT_FOUND);
+			return NMC_RESULT_ERROR_NOT_FOUND;
 		}
 
 		/* Duplicate the connection and use that so that we need not
@@ -8354,10 +8437,13 @@ do_connection_edit (NmCli *nmc, int argc, char **argv)
 	else
 		g_print (_("Adding a new '%s' connection"), connection_type);
 	g_print ("\n\n");
+	/* TRANSLATORS: do not translate 'help', leave it as it is */
 	g_print (_("Type 'help' or '?' for available commands."));
 	g_print ("\n");
+	/* TRANSLATORS: do not translate 'print', leave it as it is */
 	g_print (_("Type 'print' to show all the connection properties."));
 	g_print ("\n");
+	/* TRANSLATORS: do not translate 'describe', leave it as it is */
 	g_print (_("Type 'describe [<setting>.<prop>]' for detailed property description."));
 	g_print ("\n\n");
 
@@ -8418,7 +8504,7 @@ do_connection_modify (NmCli *nmc,
 	connection = get_connection (nmc, &argc, &argv, NULL, NULL, NULL, &error);
 	if (!connection) {
 		g_string_printf (nmc->return_text, _("Error: %s."), error->message);
-		NMC_RETURN (nmc, error->code);
+		return error->code;
 	}
 
 	rc = nm_client_get_connection_by_uuid (nmc->client,
@@ -8426,12 +8512,12 @@ do_connection_modify (NmCli *nmc,
 	if (!rc) {
 		g_string_printf (nmc->return_text, _("Error: Unknown connection '%s'."),
 		                 nm_connection_get_uuid (connection));
-		NMC_RETURN (nmc, NMC_RESULT_ERROR_NOT_FOUND);
+		return NMC_RESULT_ERROR_NOT_FOUND;
 	}
 
 	if (!nmc_read_connection_properties (nmc, NM_CONNECTION (rc), &argc, &argv, &error)) {
 		g_string_assign (nmc->return_text, error->message);
-		NMC_RETURN (nmc, error->code);
+		return error->code;
 	}
 
 	if (nmc->complete)
@@ -8509,7 +8595,7 @@ do_connection_clone (NmCli *nmc, int argc, char **argv)
 	connection = get_connection (nmc, argc_ptr, argv_ptr, NULL, NULL, NULL, &error);
 	if (!connection) {
 		g_string_printf (nmc->return_text, _("Error: %s."), error->message);
-		NMC_RETURN (nmc, error->code);
+		return error->code;
 	}
 
 	if (nmc->complete)
@@ -8522,12 +8608,12 @@ do_connection_clone (NmCli *nmc, int argc, char **argv)
 		                                         _("New connection name: "));
 	} else {
 		g_string_printf (nmc->return_text, _("Error: <new name> argument is missing."));
-		NMC_RETURN (nmc, NMC_RESULT_ERROR_USER_INPUT);
+		return NMC_RESULT_ERROR_USER_INPUT;
 	}
 
 	if (next_arg (nmc->ask ? NULL : nmc, argc_ptr, argv_ptr, NULL) == 0) {
 		g_string_printf (nmc->return_text, _("Error: unknown extra argument: '%s'."), *argv);
-		NMC_RETURN (nmc, NMC_RESULT_ERROR_USER_INPUT);
+		return NMC_RESULT_ERROR_USER_INPUT;
 	}
 
 	new_connection = nm_simple_connection_new_clone (connection);
@@ -8769,17 +8855,24 @@ do_connection_monitor (NmCli *nmc, int argc, char **argv)
 static NMCResultCode
 do_connection_reload (NmCli *nmc, int argc, char **argv)
 {
-	GError *error = NULL;
+	gs_unref_variant GVariant *result = NULL;
+	gs_free_error GError *error = NULL;
 
 	next_arg (nmc, &argc, &argv, NULL);
 	if (nmc->complete)
 		return nmc->return_value;
 
-	if (!nm_client_reload_connections (nmc->client, NULL, &error)) {
+	result = nmc_dbus_call_sync (nmc,
+	                             "/org/freedesktop/NetworkManager/Settings",
+	                             "org.freedesktop.NetworkManager.Settings",
+	                             "ReloadConnections",
+	                             g_variant_new ("()"),
+	                             G_VARIANT_TYPE("(b)"),
+	                             &error);
+	if (error) {
 		g_string_printf (nmc->return_text, _("Error: failed to reload connections: %s."),
 		                 nmc_error_get_simple_message (error));
 		nmc->return_value = NMC_RESULT_ERROR_UNKNOWN;
-		g_clear_error (&error);
 	}
 
 	return nmc->return_value;
@@ -8858,7 +8951,7 @@ do_connection_import (NmCli *nmc, int argc, char **argv)
 			filename = nm_strstrip (filename_ask);
 		} else {
 			g_string_printf (nmc->return_text, _("Error: No arguments provided."));
-			NMC_RETURN (nmc, NMC_RESULT_ERROR_USER_INPUT);
+			return NMC_RESULT_ERROR_USER_INPUT;
 		}
 	}
 
@@ -8874,7 +8967,7 @@ do_connection_import (NmCli *nmc, int argc, char **argv)
 			argv++;
 			if (!argc) {
 				g_string_printf (nmc->return_text, _("Error: %s argument is missing."), *(argv-1));
-				NMC_RETURN (nmc, NMC_RESULT_ERROR_USER_INPUT);
+				return NMC_RESULT_ERROR_USER_INPUT;
 			}
 
 			if (   argc == 1
@@ -8895,7 +8988,7 @@ do_connection_import (NmCli *nmc, int argc, char **argv)
 			argv++;
 			if (!argc) {
 				g_string_printf (nmc->return_text, _("Error: %s argument is missing."), *(argv-1));
-				NMC_RETURN (nmc, NMC_RESULT_ERROR_USER_INPUT);
+				return NMC_RESULT_ERROR_USER_INPUT;
 			}
 			if (argc == 1 && nmc->complete)
 				nmc->return_value = NMC_RESULT_COMPLETE_FILE;
@@ -8904,8 +8997,8 @@ do_connection_import (NmCli *nmc, int argc, char **argv)
 			else
 				g_printerr (_("Warning: 'file' already specified, ignoring extra one.\n"));
 		} else {
-			g_string_printf (nmc->return_text, _("Unknown parameter: %s"), *argv);
-			NMC_RETURN (nmc, NMC_RESULT_ERROR_USER_INPUT);
+			g_string_printf (nmc->return_text, _("Error: invalid extra argument '%s'."), *argv);
+			return NMC_RESULT_ERROR_USER_INPUT;
 		}
 
 		next_arg (nmc, &argc, &argv, NULL);
@@ -8916,11 +9009,11 @@ do_connection_import (NmCli *nmc, int argc, char **argv)
 
 	if (!type) {
 		g_string_printf (nmc->return_text, _("Error: 'type' argument is required."));
-		NMC_RETURN (nmc, NMC_RESULT_ERROR_USER_INPUT);
+		return NMC_RESULT_ERROR_USER_INPUT;
 	}
 	if (!filename) {
 		g_string_printf (nmc->return_text, _("Error: 'file' argument is required."));
-		NMC_RETURN (nmc, NMC_RESULT_ERROR_USER_INPUT);
+		return NMC_RESULT_ERROR_USER_INPUT;
 	}
 
 	if (nm_streq (type, "wireguard"))
@@ -8929,7 +9022,7 @@ do_connection_import (NmCli *nmc, int argc, char **argv)
 		service_type = nm_vpn_plugin_info_list_find_service_type (nm_vpn_get_plugin_infos (), type);
 		if (!service_type) {
 			g_string_printf (nmc->return_text, _("Error: failed to find VPN plugin for %s."), type);
-			NMC_RETURN (nmc, NMC_RESULT_ERROR_UNKNOWN);
+			return NMC_RESULT_ERROR_UNKNOWN;
 		}
 
 		/* Import VPN configuration */
@@ -8937,7 +9030,7 @@ do_connection_import (NmCli *nmc, int argc, char **argv)
 		if (!plugin) {
 			g_string_printf (nmc->return_text, _("Error: failed to load VPN plugin: %s."),
 			                 error->message);
-			NMC_RETURN (nmc, NMC_RESULT_ERROR_UNKNOWN);
+			return NMC_RESULT_ERROR_UNKNOWN;
 		}
 
 		connection = nm_vpn_editor_plugin_import (plugin, filename, &error);
@@ -8946,7 +9039,7 @@ do_connection_import (NmCli *nmc, int argc, char **argv)
 	if (!connection) {
 		g_string_printf (nmc->return_text, _("Error: failed to import '%s': %s."),
 		                 filename, error->message);
-		NMC_RETURN (nmc, NMC_RESULT_ERROR_UNKNOWN);
+		return NMC_RESULT_ERROR_UNKNOWN;
 	}
 
 	add_connection (nmc->client,
@@ -9169,7 +9262,7 @@ static const NMCCommand connection_cmds[] = {
 	{ "add",      do_connection_add,        usage_connection_add,      TRUE,   TRUE },
 	{ "edit",     do_connection_edit,       usage_connection_edit,     TRUE,   TRUE },
 	{ "delete",   do_connection_delete,     usage_connection_delete,   TRUE,   TRUE },
-	{ "reload",   do_connection_reload,     usage_connection_reload,   TRUE,   TRUE },
+	{ "reload",   do_connection_reload,     usage_connection_reload,   FALSE,  FALSE },
 	{ "load",     do_connection_load,       usage_connection_load,     TRUE,   TRUE },
 	{ "modify",   do_connection_modify,     usage_connection_modify,   TRUE,   TRUE },
 	{ "clone",    do_connection_clone,      usage_connection_clone,    TRUE,   TRUE },
diff --git a/clients/cli/connections.h b/clients/cli/connections.h
index 122a7e27..7fa9d448 100644
--- a/clients/cli/connections.h
+++ b/clients/cli/connections.h
@@ -1,20 +1,6 @@
-/* nmcli - command-line tool to control NetworkManager
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License along
- * with this program; if not, write to the Free Software Foundation, Inc.,
- * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
- *
- * (C) Copyright 2010 - 2018 Red Hat, Inc.
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * Copyright (C) 2010 - 2018 Red Hat, Inc.
  */
 
 #ifndef NMC_CONNECTIONS_H
diff --git a/clients/cli/devices.c b/clients/cli/devices.c
index c00d3191..c99efd0d 100644
--- a/clients/cli/devices.c
+++ b/clients/cli/devices.c
@@ -1,20 +1,6 @@
-/* nmcli - command-line tool to control NetworkManager
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License along
- * with this program; if not, write to the Free Software Foundation, Inc.,
- * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
- *
- * Copyright 2010 - 2018 Red Hat, Inc.
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * Copyright (C) 2010 - 2018 Red Hat, Inc.
  */
 
 #include "nm-default.h"
@@ -169,6 +155,8 @@ _metagen_device_detail_general_get_fcn (NMC_META_GENERIC_INFO_GET_FCN_ARGS)
 		return nm_device_get_type_description (d);
 	case NMC_GENERIC_INFO_TYPE_DEVICE_DETAIL_GENERAL_NM_TYPE:
 		return G_OBJECT_TYPE_NAME (d);
+	case NMC_GENERIC_INFO_TYPE_DEVICE_DETAIL_GENERAL_DBUS_PATH:
+		return nm_object_get_path (NM_OBJECT (d));
 	case NMC_GENERIC_INFO_TYPE_DEVICE_DETAIL_GENERAL_VENDOR:
 		return nm_device_get_vendor (d);
 	case NMC_GENERIC_INFO_TYPE_DEVICE_DETAIL_GENERAL_PRODUCT:
@@ -250,6 +238,7 @@ const NmcMetaGenericInfo *const metagen_device_detail_general[_NMC_GENERIC_INFO_
 	_METAGEN_DEVICE_DETAIL_GENERAL (NMC_GENERIC_INFO_TYPE_DEVICE_DETAIL_GENERAL_DEVICE,            "DEVICE"),
 	_METAGEN_DEVICE_DETAIL_GENERAL (NMC_GENERIC_INFO_TYPE_DEVICE_DETAIL_GENERAL_TYPE,              "TYPE"),
 	_METAGEN_DEVICE_DETAIL_GENERAL (NMC_GENERIC_INFO_TYPE_DEVICE_DETAIL_GENERAL_NM_TYPE,           "NM-TYPE"),
+	_METAGEN_DEVICE_DETAIL_GENERAL (NMC_GENERIC_INFO_TYPE_DEVICE_DETAIL_GENERAL_DBUS_PATH,         "DBUS-PATH"),
 	_METAGEN_DEVICE_DETAIL_GENERAL (NMC_GENERIC_INFO_TYPE_DEVICE_DETAIL_GENERAL_VENDOR,            "VENDOR"),
 	_METAGEN_DEVICE_DETAIL_GENERAL (NMC_GENERIC_INFO_TYPE_DEVICE_DETAIL_GENERAL_PRODUCT,           "PRODUCT"),
 	_METAGEN_DEVICE_DETAIL_GENERAL (NMC_GENERIC_INFO_TYPE_DEVICE_DETAIL_GENERAL_DRIVER,            "DRIVER"),
@@ -539,6 +528,9 @@ _metagen_device_detail_wifi_properties_get_fcn (NMC_META_GENERIC_INFO_GET_FCN_AR
 	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);
+	case NMC_GENERIC_INFO_TYPE_DEVICE_DETAIL_WIFI_PROPERTIES_IBSS_RSN:
+		return nmc_meta_generic_get_bool (NM_FLAGS_HAS (wcaps, NM_WIFI_DEVICE_CAP_IBSS_RSN),
+		                                  get_type);
 	default:
 		break;
 	}
@@ -549,16 +541,55 @@ _metagen_device_detail_wifi_properties_get_fcn (NMC_META_GENERIC_INFO_GET_FCN_AR
 const NmcMetaGenericInfo *const metagen_device_detail_wifi_properties[_NMC_GENERIC_INFO_TYPE_DEVICE_DETAIL_WIFI_PROPERTIES_NUM + 1] = {
 #define _METAGEN_DEVICE_DETAIL_WIFI_PROPERTIES(type, name) \
 	[type] = NMC_META_GENERIC(name, .info_type = type, .get_fcn = _metagen_device_detail_wifi_properties_get_fcn)
-	_METAGEN_DEVICE_DETAIL_WIFI_PROPERTIES (NMC_GENERIC_INFO_TYPE_DEVICE_DETAIL_WIFI_PROPERTIES_WEP,   "WEP"),
-	_METAGEN_DEVICE_DETAIL_WIFI_PROPERTIES (NMC_GENERIC_INFO_TYPE_DEVICE_DETAIL_WIFI_PROPERTIES_WPA,   "WPA"),
-	_METAGEN_DEVICE_DETAIL_WIFI_PROPERTIES (NMC_GENERIC_INFO_TYPE_DEVICE_DETAIL_WIFI_PROPERTIES_WPA2,  "WPA2"),
-	_METAGEN_DEVICE_DETAIL_WIFI_PROPERTIES (NMC_GENERIC_INFO_TYPE_DEVICE_DETAIL_WIFI_PROPERTIES_TKIP,  "TKIP"),
-	_METAGEN_DEVICE_DETAIL_WIFI_PROPERTIES (NMC_GENERIC_INFO_TYPE_DEVICE_DETAIL_WIFI_PROPERTIES_CCMP,  "CCMP"),
-	_METAGEN_DEVICE_DETAIL_WIFI_PROPERTIES (NMC_GENERIC_INFO_TYPE_DEVICE_DETAIL_WIFI_PROPERTIES_AP,    "AP"),
-	_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"),
+	_METAGEN_DEVICE_DETAIL_WIFI_PROPERTIES (NMC_GENERIC_INFO_TYPE_DEVICE_DETAIL_WIFI_PROPERTIES_WEP,      "WEP"),
+	_METAGEN_DEVICE_DETAIL_WIFI_PROPERTIES (NMC_GENERIC_INFO_TYPE_DEVICE_DETAIL_WIFI_PROPERTIES_WPA,      "WPA"),
+	_METAGEN_DEVICE_DETAIL_WIFI_PROPERTIES (NMC_GENERIC_INFO_TYPE_DEVICE_DETAIL_WIFI_PROPERTIES_WPA2,     "WPA2"),
+	_METAGEN_DEVICE_DETAIL_WIFI_PROPERTIES (NMC_GENERIC_INFO_TYPE_DEVICE_DETAIL_WIFI_PROPERTIES_TKIP,     "TKIP"),
+	_METAGEN_DEVICE_DETAIL_WIFI_PROPERTIES (NMC_GENERIC_INFO_TYPE_DEVICE_DETAIL_WIFI_PROPERTIES_CCMP,     "CCMP"),
+	_METAGEN_DEVICE_DETAIL_WIFI_PROPERTIES (NMC_GENERIC_INFO_TYPE_DEVICE_DETAIL_WIFI_PROPERTIES_AP,       "AP"),
+	_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"),
+	_METAGEN_DEVICE_DETAIL_WIFI_PROPERTIES (NMC_GENERIC_INFO_TYPE_DEVICE_DETAIL_WIFI_PROPERTIES_IBSS_RSN, "IBSS-RSN"),
+};
+
+
+/*****************************************************************************/
+
+static gconstpointer
+_metagen_device_detail_interface_flags_get_fcn (NMC_META_GENERIC_INFO_GET_FCN_ARGS)
+{
+	NMDevice *d = target;
+	NMDeviceInterfaceFlags flags;
+
+	NMC_HANDLE_COLOR (NM_META_COLOR_NONE);
+
+	flags = nm_device_get_interface_flags (d);
+
+	switch (info->info_type) {
+	case NMC_GENERIC_INFO_TYPE_DEVICE_DETAIL_INTERFACE_FLAGS_UP:
+		return nmc_meta_generic_get_bool (NM_FLAGS_HAS (flags, NM_DEVICE_INTERFACE_FLAG_UP),
+		                                  get_type);
+	case NMC_GENERIC_INFO_TYPE_DEVICE_DETAIL_INTERFACE_FLAGS_LOWER_UP:
+		return nmc_meta_generic_get_bool (NM_FLAGS_HAS (flags, NM_DEVICE_INTERFACE_FLAG_LOWER_UP),
+		                                  get_type);
+	case NMC_GENERIC_INFO_TYPE_DEVICE_DETAIL_INTERFACE_FLAGS_CARRIER:
+		return nmc_meta_generic_get_bool (NM_FLAGS_HAS (flags, NM_DEVICE_INTERFACE_FLAG_CARRIER),
+		                                  get_type);
+	default:
+		break;
+	}
+
+	g_return_val_if_reached (NULL);
+}
+
+const NmcMetaGenericInfo *const metagen_device_detail_interface_flags[_NMC_GENERIC_INFO_TYPE_DEVICE_DETAIL_INTERFACE_FLAGS_NUM + 1] = {
+#define _METAGEN_DEVICE_DETAIL_INTERFACE_FLAGS(type, name) \
+	[type] = NMC_META_GENERIC(name, .info_type = type, .get_fcn = _metagen_device_detail_interface_flags_get_fcn)
+	_METAGEN_DEVICE_DETAIL_INTERFACE_FLAGS (NMC_GENERIC_INFO_TYPE_DEVICE_DETAIL_INTERFACE_FLAGS_UP,       "UP"),
+	_METAGEN_DEVICE_DETAIL_INTERFACE_FLAGS (NMC_GENERIC_INFO_TYPE_DEVICE_DETAIL_INTERFACE_FLAGS_LOWER_UP, "LOWER-UP"),
+	_METAGEN_DEVICE_DETAIL_INTERFACE_FLAGS (NMC_GENERIC_INFO_TYPE_DEVICE_DETAIL_INTERFACE_FLAGS_CARRIER,  "CARRIER"),
 };
 
 /*****************************************************************************/
@@ -593,7 +624,7 @@ const NmcMetaGenericInfo *const nmc_fields_dev_wifi_list[] = {
 	NMC_META_GENERIC ("DBUS-PATH"),   /* 16 */
 	NULL,
 };
-#define NMC_FIELDS_DEV_WIFI_LIST_COMMON        "IN-USE,SSID,MODE,CHAN,RATE,SIGNAL,BARS,SECURITY"
+#define NMC_FIELDS_DEV_WIFI_LIST_COMMON        "IN-USE,BSSID,SSID,MODE,CHAN,RATE,SIGNAL,BARS,SECURITY"
 #define NMC_FIELDS_DEV_WIFI_LIST_FOR_DEV_LIST  "NAME,"NMC_FIELDS_DEV_WIFI_LIST_COMMON
 
 const NmcMetaGenericInfo *const nmc_fields_dev_wimax_list[] = {
@@ -641,23 +672,24 @@ const NmcMetaGenericInfo *const nmc_fields_dev_show_bluetooth[] = {
 
 /* Available sections for 'device show' */
 const NmcMetaGenericInfo *const nmc_fields_dev_show_sections[] = {
-	NMC_META_GENERIC_WITH_NESTED ("GENERAL",           metagen_device_detail_general),        /* 0 */
-	NMC_META_GENERIC_WITH_NESTED ("CAPABILITIES",      metagen_device_detail_capabilities),   /* 1 */
-	NMC_META_GENERIC_WITH_NESTED ("WIFI-PROPERTIES",   metagen_device_detail_wifi_properties), /* 2 */
-	NMC_META_GENERIC_WITH_NESTED ("AP",                nmc_fields_dev_wifi_list + 1),         /* 3 */
-	NMC_META_GENERIC_WITH_NESTED ("WIRED-PROPERTIES",  metagen_device_detail_wired_properties), /* 4 */
-	NMC_META_GENERIC_WITH_NESTED ("WIMAX-PROPERTIES",  metagen_device_detail_wimax_properties), /* 5 */
-	NMC_META_GENERIC_WITH_NESTED ("NSP",               nmc_fields_dev_wimax_list + 1),        /* 6 */
-	NMC_META_GENERIC_WITH_NESTED ("IP4",               metagen_ip4_config),                   /* 7 */
-	NMC_META_GENERIC_WITH_NESTED ("DHCP4",             metagen_dhcp_config),                  /* 8 */
-	NMC_META_GENERIC_WITH_NESTED ("IP6",               metagen_ip6_config),                   /* 9 */
-	NMC_META_GENERIC_WITH_NESTED ("DHCP6",             metagen_dhcp_config),                  /* 10 */
-	NMC_META_GENERIC_WITH_NESTED ("BOND",              nmc_fields_dev_show_master_prop + 1),  /* 11 */
-	NMC_META_GENERIC_WITH_NESTED ("TEAM",              nmc_fields_dev_show_team_prop + 1),    /* 12 */
-	NMC_META_GENERIC_WITH_NESTED ("BRIDGE",            nmc_fields_dev_show_master_prop + 1),  /* 13 */
-	NMC_META_GENERIC_WITH_NESTED ("VLAN",              nmc_fields_dev_show_vlan_prop + 1),    /* 14 */
-	NMC_META_GENERIC_WITH_NESTED ("BLUETOOTH",         nmc_fields_dev_show_bluetooth + 1),    /* 15 */
-	NMC_META_GENERIC_WITH_NESTED ("CONNECTIONS",       metagen_device_detail_connections),    /* 16 */
+	NMC_META_GENERIC_WITH_NESTED ("GENERAL",           metagen_device_detail_general),          /* 0 */
+	NMC_META_GENERIC_WITH_NESTED ("CAPABILITIES",      metagen_device_detail_capabilities),     /* 1 */
+	NMC_META_GENERIC_WITH_NESTED ("INTERFACE-FLAGS",   metagen_device_detail_interface_flags),  /* 2 */
+	NMC_META_GENERIC_WITH_NESTED ("WIFI-PROPERTIES",   metagen_device_detail_wifi_properties),  /* 3 */
+	NMC_META_GENERIC_WITH_NESTED ("AP",                nmc_fields_dev_wifi_list + 1),           /* 4 */
+	NMC_META_GENERIC_WITH_NESTED ("WIRED-PROPERTIES",  metagen_device_detail_wired_properties), /* 5 */
+	NMC_META_GENERIC_WITH_NESTED ("WIMAX-PROPERTIES",  metagen_device_detail_wimax_properties), /* 6 */
+	NMC_META_GENERIC_WITH_NESTED ("NSP",               nmc_fields_dev_wimax_list + 1),          /* 7 */
+	NMC_META_GENERIC_WITH_NESTED ("IP4",               metagen_ip4_config),                     /* 8 */
+	NMC_META_GENERIC_WITH_NESTED ("DHCP4",             metagen_dhcp_config),                    /* 9 */
+	NMC_META_GENERIC_WITH_NESTED ("IP6",               metagen_ip6_config),                     /* 10 */
+	NMC_META_GENERIC_WITH_NESTED ("DHCP6",             metagen_dhcp_config),                    /* 11 */
+	NMC_META_GENERIC_WITH_NESTED ("BOND",              nmc_fields_dev_show_master_prop + 1),    /* 12 */
+	NMC_META_GENERIC_WITH_NESTED ("TEAM",              nmc_fields_dev_show_team_prop + 1),      /* 13 */
+	NMC_META_GENERIC_WITH_NESTED ("BRIDGE",            nmc_fields_dev_show_master_prop + 1),    /* 14 */
+	NMC_META_GENERIC_WITH_NESTED ("VLAN",              nmc_fields_dev_show_vlan_prop + 1),      /* 15 */
+	NMC_META_GENERIC_WITH_NESTED ("BLUETOOTH",         nmc_fields_dev_show_bluetooth + 1),      /* 16 */
+	NMC_META_GENERIC_WITH_NESTED ("CONNECTIONS",       metagen_device_detail_connections),      /* 17 */
 	NULL,
 };
 #define NMC_FIELDS_DEV_SHOW_SECTIONS_COMMON  "GENERAL.DEVICE,GENERAL.TYPE,GENERAL.HWADDR,GENERAL.MTU,GENERAL.STATE,"\
@@ -706,6 +738,7 @@ usage (void)
 	              "                         [bssid <BSSID>] [name <name>] [private yes|no] [hidden yes|no]\n\n"
 	              "  wifi hotspot [ifname <ifname>] [con-name <name>] [ssid <SSID>] [band a|bg] [channel <channel>] [password <password>]\n\n"
 	              "  wifi rescan [ifname <ifname>] [[ssid <SSID to scan>] ...]\n\n"
+	              "  wifi show-password [ifname <ifname>]\n\n"
 	              "  lldp [list [ifname <ifname>]]\n\n"
 	              ));
 }
@@ -756,7 +789,7 @@ usage_device_reapply (void)
 	              "ARGUMENTS := <ifname>\n"
 	              "\n"
 	              "Attempts to update device with changes to the currently active connection\n"
-                      "made since it was last applied.\n\n"));
+	              "made since it was last applied.\n\n"));
 }
 
 static void
@@ -1470,6 +1503,20 @@ show_device_info (NMDevice *device, NmCli *nmc)
 			continue;
 		}
 
+		if (nmc_fields_dev_show_sections[section_idx]->nested == metagen_device_detail_interface_flags) {
+			gs_free char *f = section_fld ? g_strdup_printf ("INTERFACE-FLAGS.%s", section_fld) : NULL;
+
+			nmc_print (&nmc->nmc_config,
+			           (gpointer[]) { device, NULL },
+			           NULL,
+			           NULL,
+			           NMC_META_GENERIC_GROUP ("INTERFACE-FLAGS", metagen_device_detail_interface_flags, N_("NAME")),
+			           f,
+			           NULL);
+			was_output = TRUE;
+			continue;
+		}
+
 		if (nmc_fields_dev_show_sections[section_idx]->nested == metagen_device_detail_wifi_properties) {
 			if (NM_IS_DEVICE_WIFI (device)) {
 				gs_free char *f = section_fld ? g_strdup_printf ("WIFI-PROPERTIES.%s", section_fld) : NULL;
@@ -1493,7 +1540,7 @@ show_device_info (NMDevice *device, NmCli *nmc)
 			GPtrArray *aps;
 
 			/* section AP */
-			if (!strcasecmp (nmc_fields_dev_show_sections[section_idx]->name, nmc_fields_dev_show_sections[3]->name)) {
+			if (!strcasecmp (nmc_fields_dev_show_sections[section_idx]->name, nmc_fields_dev_show_sections[4]->name)) {
 				NMC_OUTPUT_DATA_DEFINE_SCOPED (out);
 
 				if (state == NM_DEVICE_STATE_ACTIVATED) {
@@ -1551,42 +1598,42 @@ show_device_info (NMDevice *device, NmCli *nmc)
 		dhcp6 = nm_device_get_dhcp6_config (device);
 
 		/* IP4 */
-		if (cfg4 && !strcasecmp (nmc_fields_dev_show_sections[section_idx]->name, nmc_fields_dev_show_sections[7]->name))
+		if (cfg4 && !strcasecmp (nmc_fields_dev_show_sections[section_idx]->name, nmc_fields_dev_show_sections[8]->name))
 			was_output = print_ip_config (cfg4, AF_INET, &nmc->nmc_config, section_fld);
 
 		/* DHCP4 */
-		if (dhcp4 && !strcasecmp (nmc_fields_dev_show_sections[section_idx]->name, nmc_fields_dev_show_sections[8]->name))
+		if (dhcp4 && !strcasecmp (nmc_fields_dev_show_sections[section_idx]->name, nmc_fields_dev_show_sections[9]->name))
 			was_output = print_dhcp_config (dhcp4, AF_INET, &nmc->nmc_config, section_fld);
 
 		/* IP6 */
-		if (cfg6 && !strcasecmp (nmc_fields_dev_show_sections[section_idx]->name, nmc_fields_dev_show_sections[9]->name))
+		if (cfg6 && !strcasecmp (nmc_fields_dev_show_sections[section_idx]->name, nmc_fields_dev_show_sections[10]->name))
 			was_output = print_ip_config (cfg6, AF_INET6, &nmc->nmc_config, section_fld);
 
 		/* DHCP6 */
-		if (dhcp6 && !strcasecmp (nmc_fields_dev_show_sections[section_idx]->name, nmc_fields_dev_show_sections[10]->name))
+		if (dhcp6 && !strcasecmp (nmc_fields_dev_show_sections[section_idx]->name, nmc_fields_dev_show_sections[11]->name))
 			was_output = print_dhcp_config (dhcp6, AF_INET6, &nmc->nmc_config, section_fld);
 
 		/* Bond specific information */
 		if (NM_IS_DEVICE_BOND (device)) {
-			if (!strcasecmp (nmc_fields_dev_show_sections[section_idx]->name, nmc_fields_dev_show_sections[11]->name))
-				was_output = print_bond_bridge_info (device, nmc, nmc_fields_dev_show_sections[11]->name, section_fld);
+			if (!strcasecmp (nmc_fields_dev_show_sections[section_idx]->name, nmc_fields_dev_show_sections[12]->name))
+				was_output = print_bond_bridge_info (device, nmc, nmc_fields_dev_show_sections[12]->name, section_fld);
 		}
 
 		/* Team specific information */
 		if (NM_IS_DEVICE_TEAM (device)) {
-			if (!strcasecmp (nmc_fields_dev_show_sections[section_idx]->name, nmc_fields_dev_show_sections[12]->name))
-				was_output = print_team_info (device, nmc, nmc_fields_dev_show_sections[12]->name, section_fld);
+			if (!strcasecmp (nmc_fields_dev_show_sections[section_idx]->name, nmc_fields_dev_show_sections[13]->name))
+				was_output = print_team_info (device, nmc, nmc_fields_dev_show_sections[13]->name, section_fld);
 		}
 
 		/* Bridge specific information */
 		if (NM_IS_DEVICE_BRIDGE (device)) {
-			if (!strcasecmp (nmc_fields_dev_show_sections[section_idx]->name, nmc_fields_dev_show_sections[13]->name))
-				was_output = print_bond_bridge_info (device, nmc, nmc_fields_dev_show_sections[13]->name, section_fld);
+			if (!strcasecmp (nmc_fields_dev_show_sections[section_idx]->name, nmc_fields_dev_show_sections[14]->name))
+				was_output = print_bond_bridge_info (device, nmc, nmc_fields_dev_show_sections[14]->name, section_fld);
 		}
 
 		/* VLAN-specific information */
 		if ((NM_IS_DEVICE_VLAN (device))) {
-			if (!strcasecmp (nmc_fields_dev_show_sections[section_idx]->name, nmc_fields_dev_show_sections[14]->name)) {
+			if (!strcasecmp (nmc_fields_dev_show_sections[section_idx]->name, nmc_fields_dev_show_sections[15]->name)) {
 				char * vlan_id_str = g_strdup_printf ("%u", nm_device_vlan_get_vlan_id (NM_DEVICE_VLAN (device)));
 				NMDevice *parent = nm_device_vlan_get_parent (NM_DEVICE_VLAN (device));
 				NMC_OUTPUT_DATA_DEFINE_SCOPED (out);
@@ -1598,7 +1645,7 @@ show_device_info (NMDevice *device, NmCli *nmc)
 				g_ptr_array_add (out.output_data, arr);
 
 				arr = nmc_dup_fields_array (tmpl, NMC_OF_FLAG_SECTION_PREFIX);
-				set_val_strc (arr, 0, nmc_fields_dev_show_sections[14]->name);  /* "VLAN" */
+				set_val_strc (arr, 0, nmc_fields_dev_show_sections[15]->name);  /* "VLAN" */
 				set_val_strc (arr, 1, parent ? nm_device_get_iface (parent) : NULL);
 				set_val_str  (arr, 2, vlan_id_str);
 				g_ptr_array_add (out.output_data, arr);
@@ -1611,7 +1658,7 @@ show_device_info (NMDevice *device, NmCli *nmc)
 		}
 
 		if (NM_IS_DEVICE_BT (device)) {
-			if (!strcasecmp (nmc_fields_dev_show_sections[section_idx]->name, nmc_fields_dev_show_sections[15]->name)) {
+			if (!strcasecmp (nmc_fields_dev_show_sections[section_idx]->name, nmc_fields_dev_show_sections[16]->name)) {
 				NMC_OUTPUT_DATA_DEFINE_SCOPED (out);
 
 				tmpl = (const NMMetaAbstractInfo *const*) nmc_fields_dev_show_bluetooth;
@@ -1621,7 +1668,7 @@ show_device_info (NMDevice *device, NmCli *nmc)
 				g_ptr_array_add (out.output_data, arr);
 
 				arr = nmc_dup_fields_array (tmpl, NMC_OF_FLAG_SECTION_PREFIX);
-				set_val_strc (arr, 0, nmc_fields_dev_show_sections[15]->name);  /* "BLUETOOTH" */
+				set_val_strc (arr, 0, nmc_fields_dev_show_sections[16]->name);  /* "BLUETOOTH" */
 				set_val_str (arr, 1, bluetooth_caps_to_string (nm_device_bt_get_capabilities (NM_DEVICE_BT (device))));
 				g_ptr_array_add (out.output_data, arr);
 
@@ -1681,9 +1728,9 @@ do_devices_status (NmCli *nmc, int argc, char **argv)
 	if (nmc->complete)
 		return nmc->return_value;
 
-	while (argc > 0) {
-		g_printerr (_("Unknown parameter: %s\n"), *argv);
-		next_arg (nmc, &argc, &argv, NULL);
+	if (argc) {
+		g_string_printf (nmc->return_text, _("Error: invalid extra argument '%s'."), *argv);
+		return NMC_RESULT_ERROR_USER_INPUT;
 	}
 
 	if (!nmc->required_fields || strcasecmp (nmc->required_fields, "common") == 0)
@@ -1741,7 +1788,7 @@ do_device_show (NmCli *nmc, int argc, char **argv)
 		int i;
 
 		/* nmc_do_cmd() should not call this with argc=0. */
-		g_assert (!nmc->complete);
+		nm_assert (!nmc->complete);
 
 		/* Show details for all devices */
 		for (i = 0; devices[i]; i++) {
@@ -1780,33 +1827,56 @@ progress_cb (gpointer user_data)
 	return TRUE;
 }
 
-static void connected_state_cb (NMDevice *device, NMActiveConnection *active);
+typedef struct {
+	NmCli *nmc;
+	NMDevice *device;
+	NMActiveConnection *active;
+	char *specific_object;
+	bool hotspot:1;
+	bool create:1;
+} AddAndActivateInfo;
 
-static void
-device_state_cb (NMDevice *device, GParamSpec *pspec, gpointer user_data)
+static AddAndActivateInfo *
+add_and_activate_info_new (NmCli *nmc,
+                           NMDevice *device,
+                           gboolean hotspot,
+                           gboolean create,
+                           const char *specific_object)
 {
-	NMActiveConnection *active = (NMActiveConnection *) user_data;
+	AddAndActivateInfo *info;
 
-	connected_state_cb (device, active);
+	info = g_slice_new (AddAndActivateInfo);
+	*info = (AddAndActivateInfo) {
+		.nmc             = nmc,
+		.device          = g_object_ref (device),
+		.hotspot         = hotspot,
+		.create          = create,
+		.specific_object = g_strdup (specific_object),
+	};
+	return info;
 }
 
 static void
-active_state_cb (NMActiveConnection *active, GParamSpec *pspec, gpointer user_data)
+add_and_activate_info_free (AddAndActivateInfo *info)
 {
-	NMDevice *device = (NMDevice *) user_data;
-
-	connected_state_cb (device, active);
+	g_object_unref (info->device);
+	g_clear_object (&info->active);
+	g_free (info->specific_object);
+	nm_g_slice_free (info);
 }
 
+NM_AUTO_DEFINE_FCN0 (AddAndActivateInfo *, _nm_auto_free_add_and_activate_info, add_and_activate_info_free)
+#define nm_auto_free_add_and_activate_info nm_auto (_nm_auto_free_add_and_activate_info)
+
 static void
-connected_state_cb (NMDevice *device, NMActiveConnection *active)
+connected_state_cb (AddAndActivateInfo *info)
 {
 	NMDeviceState state;
 	NMDeviceStateReason reason;
 	NMActiveConnectionState ac_state;
 
-	state = nm_device_get_state (device);
-	ac_state = nm_active_connection_get_state (active);
+	state = nm_device_get_state (info->device);
+	ac_state = nm_active_connection_get_state (info->active);
 
 	if (ac_state == NM_ACTIVE_CONNECTION_STATE_ACTIVATING)
 		return;
@@ -1814,42 +1884,36 @@ connected_state_cb (NMDevice *device, NMActiveConnection *active)
 	if (state == NM_DEVICE_STATE_ACTIVATED) {
 		nmc_terminal_erase_line ();
 		g_print (_("Device '%s' successfully activated with '%s'.\n"),
-		         nm_device_get_iface (device),
-		         nm_active_connection_get_uuid (active));
+		         nm_device_get_iface (info->device),
+		         nm_active_connection_get_uuid (info->active));
+
+		if (info->hotspot)
+			g_print (_("Hint: \"nmcli dev wifi show-password\" shows the Wi-Fi name and password.\n"));
 	} else if (   state <= NM_DEVICE_STATE_DISCONNECTED
 	           || state >= NM_DEVICE_STATE_DEACTIVATING) {
-		reason = nm_device_get_state_reason (device);
+		reason = nm_device_get_state_reason (info->device);
 		g_print (_("Error: Connection activation failed: (%d) %s.\n"),
 		         reason, gettext (nmc_device_reason_to_string (reason)));
-	} else
+	} else {
 		return;
+	}
 
-	g_signal_handlers_disconnect_by_func (active, G_CALLBACK (active_state_cb), device);
-	g_signal_handlers_disconnect_by_func (device, G_CALLBACK (device_state_cb), active);
-
-	g_object_unref (active);
-	g_object_unref (device);
+	g_signal_handlers_disconnect_by_func (info->active, G_CALLBACK (connected_state_cb), info);
+	g_signal_handlers_disconnect_by_func (info->device, G_CALLBACK (connected_state_cb), info);
+	add_and_activate_info_free (info);
 
 	quit ();
 }
 
-typedef struct {
-	NmCli *nmc;
-	NMDevice *device;
-	gboolean hotspot;
-	gboolean create;
-} AddAndActivateInfo;
-
 static void
 add_and_activate_cb (GObject *client,
                      GAsyncResult *result,
                      gpointer user_data)
 {
-	AddAndActivateInfo *info = (AddAndActivateInfo *) user_data;
+	nm_auto_free_add_and_activate_info AddAndActivateInfo *info = user_data;
 	NmCli *nmc = info->nmc;
-	NMDevice *device = info->device;
-	NMActiveConnection *active;
-	GError *error = NULL;
+	gs_unref_object NMActiveConnection *active = NULL;
+	gs_free_error GError *error = NULL;
 
 	if (info->create)
 		active = nm_client_add_and_activate_connection_finish (NM_CLIENT (client), result, &error);
@@ -1857,37 +1921,35 @@ add_and_activate_cb (GObject *client,
 		active = nm_client_activate_connection_finish (NM_CLIENT (client), result, &error);
 
 	if (error) {
-		if (info->hotspot)
+		if (info->hotspot) {
 			g_string_printf (nmc->return_text, _("Error: Failed to setup a Wi-Fi hotspot: %s"),
 			                 error->message);
-		else if (info->create)
+		} else if (info->create) {
 			g_string_printf (nmc->return_text, _("Error: Failed to add/activate new connection: %s"),
 			                 error->message);
-		else
+		} else {
 			g_string_printf (nmc->return_text, _("Error: Failed to activate connection: %s"),
 			                 error->message);
-		g_error_free (error);
+		}
 		nmc->return_value = NMC_RESULT_ERROR_CON_ACTIVATION;
 		quit ();
-	} else {
-		if (nmc->nowait_flag) {
-			g_object_unref (active);
-			quit ();
-		} else {
-			g_object_ref (device);
-			g_signal_connect (device, "notify::state", G_CALLBACK (device_state_cb), active);
-			g_signal_connect (active, "notify::state", G_CALLBACK (active_state_cb), device);
+		return;
+	}
 
-			connected_state_cb (device, active);
+	if (nmc->nowait_flag) {
+		quit ();
+		return;
+	}
 
-			g_timeout_add_seconds (nmc->timeout, timeout_cb, nmc);  /* Exit if timeout expires */
+	if (nmc->nmc_config.print_output == NMC_PRINT_PRETTY)
+		progress_id = g_timeout_add (120, progress_cb, info->device);
 
-			if (nmc->nmc_config.print_output == NMC_PRINT_PRETTY)
-				progress_id = g_timeout_add (120, progress_cb, device);
-		}
-	}
+	info->active = g_steal_pointer (&active);
+	g_signal_connect_swapped (info->device, "notify::state", G_CALLBACK (connected_state_cb), info);
+	g_signal_connect_swapped (info->active, "notify::state", G_CALLBACK (connected_state_cb), info);
+	connected_state_cb (g_steal_pointer (&info));
 
-	g_free (info);
+	g_timeout_add_seconds (nmc->timeout, timeout_cb, nmc);  /* Exit if timeout expires */
 }
 
 static void
@@ -1916,12 +1978,10 @@ create_connect_connection_for_device (AddAndActivateInfo *info)
 static void
 connect_device_cb (GObject *client, GAsyncResult *result, gpointer user_data)
 {
-	AddAndActivateInfo *info = (AddAndActivateInfo *) user_data;
+	nm_auto_free_add_and_activate_info AddAndActivateInfo *info = user_data;
 	NmCli *nmc = info->nmc;
-	NMActiveConnection *active;
+	gs_unref_object NMActiveConnection *active = NULL;
 	GError *error = NULL;
-	const GPtrArray *devices;
-	NMDevice *device;
 
 	active = nm_client_activate_connection_finish (NM_CLIENT (client), result, &error);
 
@@ -1929,7 +1989,7 @@ connect_device_cb (GObject *client, GAsyncResult *result, gpointer user_data)
 		/* If no connection existed for the device, create one and activate it */
 		if (g_error_matches (error, NM_MANAGER_ERROR, NM_MANAGER_ERROR_UNKNOWN_CONNECTION)) {
 			info->create = TRUE;
-			create_connect_connection_for_device (info);
+			create_connect_connection_for_device (g_steal_pointer (&info));
 			return;
 		}
 
@@ -1938,42 +1998,30 @@ connect_device_cb (GObject *client, GAsyncResult *result, gpointer user_data)
 		g_error_free (error);
 		nmc->return_value = NMC_RESULT_ERROR_CON_ACTIVATION;
 		quit ();
-	} else {
-		g_assert (active);
-		devices = nm_active_connection_get_devices (active);
-		if (devices->len == 0) {
-			g_string_printf (nmc->return_text, _("Error: Device activation failed: device was disconnected"));
-			nmc->return_value = NMC_RESULT_ERROR_CON_ACTIVATION;
-			g_object_unref (active);
-			quit ();
-			g_free (info);
-			return;
-		}
+		return;
+	}
 
-		device = g_ptr_array_index (devices, 0);
+	nm_assert (NM_IS_ACTIVE_CONNECTION (active));
 
-		if (nmc->nowait_flag) {
-			g_object_unref (active);
-			quit ();
-		} else {
-			if (nmc->secret_agent) {
-				NMRemoteConnection *connection = nm_active_connection_get_connection (active);
+	if (nmc->nowait_flag) {
+		quit ();
+		return;
+	}
 
-				nm_secret_agent_simple_enable (nmc->secret_agent,
-				                               nm_connection_get_path (NM_CONNECTION (connection)));
-			}
+	if (nmc->secret_agent) {
+		NMRemoteConnection *connection = nm_active_connection_get_connection (active);
 
-			g_object_ref (device);
-			g_signal_connect (device, "notify::state", G_CALLBACK (device_state_cb), active);
-			g_signal_connect (active, "notify::state", G_CALLBACK (active_state_cb), device);
+		nm_secret_agent_simple_enable (nmc->secret_agent,
+		                               nm_connection_get_path (NM_CONNECTION (connection)));
+	}
 
-			connected_state_cb (device, active);
+	info->active = g_steal_pointer (&active);
+	g_signal_connect_swapped (info->device, "notify::state", G_CALLBACK (connected_state_cb), info);
+	g_signal_connect_swapped (info->active, "notify::state", G_CALLBACK (connected_state_cb), info);
+	connected_state_cb (g_steal_pointer (&info));
 
-			/* Start timer not to loop forever if "notify::state" signal is not issued */
-			g_timeout_add_seconds (nmc->timeout, timeout_cb, nmc);
-		}
-	}
-	g_free (info);
+	/* Start timer not to loop forever if "notify::state" signal is not issued */
+	g_timeout_add_seconds (nmc->timeout, timeout_cb, nmc);
 }
 
 static NMCResultCode
@@ -2018,10 +2066,7 @@ do_device_connect (NmCli *nmc, int argc, char **argv)
 		                  nmc);
 	}
 
-	info = g_malloc0 (sizeof (AddAndActivateInfo));
-	info->nmc = nmc;
-	info->device = device;
-	info->hotspot = FALSE;
+	info = add_and_activate_info_new (nmc, device, FALSE, FALSE, NULL);
 
 	nm_client_activate_connection_async (nmc->client,
 	                                     NULL,  /* let NM find a connection automatically */
@@ -3004,7 +3049,7 @@ do_device_wifi_list (NmCli *nmc, int argc, char **argv)
 				nmc_complete_strings (rescan, "auto", "no", "yes");
 			break;
 		default:
-			g_assert_not_reached();
+			nm_assert_not_reached();
 			break;
 		}
 	}
@@ -3027,8 +3072,10 @@ do_device_wifi_list (NmCli *nmc, int argc, char **argv)
 	if (nmc->complete)
 		return nmc->return_value;
 
-	if (argc)
-		g_printerr (_("Unknown parameter: %s\n"), *argv);
+	if (argc) {
+		g_string_printf (nmc->return_text, _("Error: invalid extra argument '%s'."), *argv);
+		return NMC_RESULT_ERROR_USER_INPUT;
+	}
 
 	if (rescan == NULL || strcmp (rescan, "auto") == 0) {
 		rescan_cutoff = NM_MAX (nm_utils_get_timestamp_msec () - 30 * NM_UTILS_MSEC_PER_SECOND, 0);
@@ -3116,18 +3163,78 @@ do_device_wifi_list (NmCli *nmc, int argc, char **argv)
 	return nmc->return_value;
 }
 
+static void
+activate_update2_cb (GObject *source_object, GAsyncResult *res, gpointer user_data)
+{
+	NMRemoteConnection *remote_con = NM_REMOTE_CONNECTION (source_object);
+	AddAndActivateInfo *info = user_data;
+	NmCli *nmc = info->nmc;
+	gs_unref_variant GVariant *ret = NULL;
+	GError *error = NULL;
+
+	ret = nm_remote_connection_update2_finish (remote_con, res, &error);
+
+	if (!ret) {
+		g_string_printf (nmc->return_text, _("Error: %s."), error->message);
+		nmc->return_value = NMC_RESULT_ERROR_UNKNOWN;
+		g_error_free (error);
+		quit ();
+		add_and_activate_info_free (info);
+		return;
+	}
+
+	nm_client_activate_connection_async (nmc->client,
+	                                     NM_CONNECTION (remote_con),
+	                                     info->device,
+	                                     info->specific_object,
+	                                     NULL,
+	                                     add_and_activate_cb,
+	                                     info);
+}
+
+static void
+save_and_activate_connection (NmCli *nmc,
+                              NMDevice *device,
+                              NMConnection *connection,
+                              gboolean hotspot,
+                              const char *specific_object)
+{
+	AddAndActivateInfo *info;
+
+	info = add_and_activate_info_new (nmc, device, hotspot,
+	                                  !NM_IS_REMOTE_CONNECTION (connection),
+	                                  specific_object);
+
+	if (NM_IS_REMOTE_CONNECTION (connection)) {
+		nm_remote_connection_update2 (NM_REMOTE_CONNECTION (connection),
+		                              nm_connection_to_dbus (connection, NM_CONNECTION_SERIALIZE_ALL),
+		                              NM_SETTINGS_UPDATE2_FLAG_BLOCK_AUTOCONNECT,
+		                              NULL,
+		                              NULL,
+		                              activate_update2_cb,
+		                              info);
+	} else {
+		nm_client_add_and_activate_connection_async (nmc->client,
+		                                             connection,
+		                                             info->device,
+		                                             info->specific_object,
+		                                             NULL,
+		                                             add_and_activate_cb,
+		                                             info);
+	}
+}
+
 static NMCResultCode
-do_device_wifi_connect_network (NmCli *nmc, int argc, char **argv)
+do_device_wifi_connect (NmCli *nmc, int argc, char **argv)
 {
 	NMDevice *device = NULL;
 	NMAccessPoint *ap = NULL;
 	NM80211ApFlags ap_flags;
 	NM80211ApSecurityFlags ap_wpa_flags;
 	NM80211ApSecurityFlags ap_rsn_flags;
-	NMConnection *connection = NULL;
+	gs_unref_object NMConnection *connection = NULL;
 	NMSettingConnection *s_con;
 	NMSettingWireless *s_wifi;
-	AddAndActivateInfo *info;
 	const char *param_user = NULL;
 	const char *ifname = NULL;
 	const char *bssid = NULL;
@@ -3144,7 +3251,6 @@ do_device_wifi_connect_network (NmCli *nmc, int argc, char **argv)
 	char *passwd_ask = NULL;
 	const GPtrArray *avail_cons;
 	gboolean name_match = FALSE;
-	gboolean existing_con = FALSE;
 	int i;
 
 	/* Set default timeout waiting for operation completion. */
@@ -3165,7 +3271,7 @@ do_device_wifi_connect_network (NmCli *nmc, int argc, char **argv)
 		next_arg (nmc, &argc, &argv, NULL);
 	} else {
 		/* nmc_do_cmd() should not call this with argc=0. */
-		g_assert (!nmc->complete);
+		nm_assert (!nmc->complete);
 
 		if (nmc->ask) {
 			ssid_ask = nmc_readline (&nmc->nmc_config, _("SSID or BSSID: "));
@@ -3291,7 +3397,9 @@ do_device_wifi_connect_network (NmCli *nmc, int argc, char **argv)
 				goto finish;
 			}
 		} else if (!nmc->complete) {
-			g_printerr (_("Unknown parameter: %s\n"), *argv);
+			g_string_printf (nmc->return_text, _("Error: invalid extra argument '%s'."), *argv);
+			nmc->return_value = NMC_RESULT_ERROR_USER_INPUT;
+			goto finish;
 		}
 
 		next_arg (nmc, &argc, &argv, NULL);
@@ -3377,7 +3485,7 @@ do_device_wifi_connect_network (NmCli *nmc, int argc, char **argv)
 
 	avail_cons = nm_device_get_available_connections (device);
 	for (i = 0; i < avail_cons->len; i++) {
-		NMRemoteConnection *avail_con = g_ptr_array_index (avail_cons, i);
+		NMConnection *avail_con = g_ptr_array_index (avail_cons, i);
 		const char *id = nm_connection_get_id (NM_CONNECTION (avail_con));
 
 		if (con_name) {
@@ -3391,22 +3499,21 @@ do_device_wifi_connect_network (NmCli *nmc, int argc, char **argv)
 			/* ap has been checked against bssid1, bssid2 and the ssid
 			 * and now avail_con has been checked against ap.
 			 */
-			connection = NM_CONNECTION (avail_con);
-			existing_con = TRUE;
+			connection = g_object_ref (avail_con);
 			break;
 		}
 	}
 
-	if (name_match && !existing_con) {
+	if (name_match && !connection) {
 		g_string_printf (nmc->return_text, _("Error: Connection '%s' exists but properties don't match."), con_name);
 		nmc->return_value = NMC_RESULT_ERROR_NOT_FOUND;
 		goto finish;
 	}
 
-	if (!existing_con) {
+	if (!connection) {
 		/* If there are some connection data from user, create a connection and
 		 * fill them into proper settings. */
-		if (con_name || private || bssid2_arr || password || hidden)
+		if (con_name || private || bssid2_arr || hidden)
 			connection = nm_simple_connection_new ();
 
 		if (con_name || private) {
@@ -3518,28 +3625,8 @@ do_device_wifi_connect_network (NmCli *nmc, int argc, char **argv)
 	nmc->nowait_flag = (nmc->timeout == 0);
 	nmc->should_wait++;
 
-	info = g_malloc0 (sizeof (AddAndActivateInfo));
-	info->nmc = nmc;
-	info->device = device;
-	info->hotspot = FALSE;
-	info->create = !existing_con;
-	if (existing_con) {
-		nm_client_activate_connection_async (nmc->client,
-		                                     connection,
-		                                     device,
-		                                     nm_object_get_path (NM_OBJECT (ap)),
-		                                     NULL,
-		                                     add_and_activate_cb,
-		                                     info);
-	} else {
-		nm_client_add_and_activate_connection_async (nmc->client,
-		                                             connection,
-		                                             device,
-		                                             nm_object_get_path (NM_OBJECT (ap)),
-		                                             NULL,
-		                                             add_and_activate_cb,
-		                                             info);
-	}
+	save_and_activate_connection (nmc, device, connection, FALSE,
+	                              nm_object_get_path (NM_OBJECT (ap)));
 
 finish:
 	if (bssid1_arr)
@@ -3553,19 +3640,17 @@ finish:
 }
 
 static GBytes *
-generate_ssid_for_hotspot (const char *ssid)
+generate_ssid_for_hotspot (void)
 {
 	GBytes *ssid_bytes;
-	char *hotspot_ssid = NULL;
+	char *ssid = NULL;
 
-	if (!ssid) {
-		hotspot_ssid = g_strdup_printf ("Hotspot-%s", g_get_host_name ());
-		if (strlen (hotspot_ssid) > 32)
-			hotspot_ssid[32] = '\0';
-		ssid = hotspot_ssid;
-	}
+	ssid = g_strdup_printf ("Hotspot-%s", g_get_host_name ());
+	if (strlen (ssid) > 32)
+		ssid[32] = '\0';
 	ssid_bytes = g_bytes_new (ssid, strlen (ssid));
-	g_free (hotspot_ssid);
+	g_free (ssid);
+
 	return ssid_bytes;
 }
 
@@ -3679,30 +3764,125 @@ set_wireless_security_for_hotspot (NMSettingWirelessSecurity *s_wsec,
 	return TRUE;
 }
 
+static NMConnection *
+find_hotspot_conn (NMDevice *device,
+                   const GPtrArray *connections,
+                   const char *con_name,
+                   GBytes *ssid_bytes,
+                   const char *wifi_mode,
+                   const char *band,
+                   gint64 channel_int)
+{
+	NMConnection *connection;
+	NMSettingWireless *s_wifi;
+	int i;
+
+        for (i = 0; i < connections->len; i++) {
+                connection = NM_CONNECTION (connections->pdata[i]);
+
+		s_wifi = nm_connection_get_setting_wireless (connection);
+		if (!s_wifi)
+			continue;
+
+		if (   channel_int != -1
+		    && nm_setting_wireless_get_channel (s_wifi) != channel_int)
+			continue;
+
+		if (g_strcmp0 (nm_setting_wireless_get_mode (s_wifi), wifi_mode) != 0)
+			continue;
+
+		if (band && g_strcmp0 (nm_setting_wireless_get_band (s_wifi), band) != 0)
+			continue;
+
+		if (ssid_bytes && !g_bytes_equal (nm_setting_wireless_get_ssid (s_wifi), ssid_bytes))
+			continue;
+
+		if (!nm_device_connection_compatible (device, connection, NULL))
+			continue;
+
+		return g_object_ref (connection);
+	}
+
+	return NULL;
+}
+
+static NMConnection *
+create_hotspot_conn (const GPtrArray *connections,
+                     const char *con_name,
+                     GBytes *ssid_bytes,
+                     const char *wifi_mode,
+                     const char *band,
+                     gint64 channel_int)
+{
+	char *default_name = NULL;
+	NMConnection *connection;
+	NMSettingConnection *s_con;
+	NMSettingWireless *s_wifi;
+	NMSettingWirelessSecurity *s_wsec;
+	NMSettingIPConfig *s_ip4, *s_ip6;
+	NMSettingProxy *s_proxy;
+
+	connection = nm_simple_connection_new ();
+	s_con =  (NMSettingConnection *) nm_setting_connection_new ();
+	nm_connection_add_setting (connection, NM_SETTING (s_con));
+	if (!con_name)
+		con_name = default_name = nmc_unique_connection_name (connections, "Hotspot");
+	g_object_set (s_con,
+	              NM_SETTING_CONNECTION_ID, con_name,
+	              NM_SETTING_CONNECTION_AUTOCONNECT, FALSE,
+	              NULL);
+	g_free (default_name);
+
+	s_wifi = (NMSettingWireless *) nm_setting_wireless_new ();
+	nm_connection_add_setting (connection, NM_SETTING (s_wifi));
+
+	g_object_set (s_wifi, NM_SETTING_WIRELESS_MODE, wifi_mode,
+	                      NM_SETTING_WIRELESS_SSID, ssid_bytes,
+	                      NULL);
+
+	if (channel_int != -1) {
+		g_object_set (s_wifi,
+		              NM_SETTING_WIRELESS_CHANNEL, (guint32) channel_int,
+		              NM_SETTING_WIRELESS_BAND, band,
+		              NULL);
+	}
+
+	s_wsec = (NMSettingWirelessSecurity *) nm_setting_wireless_security_new ();
+	nm_connection_add_setting (connection, NM_SETTING (s_wsec));
+
+	s_ip4 = (NMSettingIPConfig *) nm_setting_ip4_config_new ();
+	nm_connection_add_setting (connection, NM_SETTING (s_ip4));
+	g_object_set (s_ip4, NM_SETTING_IP_CONFIG_METHOD, NM_SETTING_IP4_CONFIG_METHOD_SHARED, NULL);
+
+	s_ip6 = (NMSettingIPConfig *) nm_setting_ip6_config_new ();
+	nm_connection_add_setting (connection, NM_SETTING (s_ip6));
+	g_object_set (s_ip6, NM_SETTING_IP_CONFIG_METHOD, NM_SETTING_IP6_CONFIG_METHOD_IGNORE, NULL);
+
+	s_proxy = (NMSettingProxy *) nm_setting_proxy_new ();
+	nm_connection_add_setting (connection, NM_SETTING (s_proxy));
+	g_object_set (s_proxy, NM_SETTING_PROXY_METHOD, (int) NM_SETTING_PROXY_METHOD_NONE, NULL);
+
+	return connection;
+}
+
 static NMCResultCode
 do_device_wifi_hotspot (NmCli *nmc, int argc, char **argv)
 {
-	AddAndActivateInfo *info;
 	const char *ifname = NULL;
 	const char *con_name = NULL;
-	char *default_name = NULL;
-	const char *ssid = NULL;
+	gs_unref_bytes GBytes *ssid_bytes = NULL;
 	const char *wifi_mode;
 	const char *band = NULL;
 	const char *channel = NULL;
-	unsigned long channel_int;
+	gint64 channel_int = -1;
 	const char *password = NULL;
 	gboolean show_password = FALSE;
 	NMDevice *device = NULL;
 	gs_free NMDevice **devices = NULL;
 	NMDeviceWifiCapabilities caps;
-	NMConnection *connection = NULL;
-	NMSettingConnection *s_con;
-	NMSettingWireless *s_wifi;
+	gs_unref_object NMConnection *connection = NULL;
+	const GPtrArray *connections;
 	NMSettingWirelessSecurity *s_wsec;
-	NMSettingIPConfig *s_ip4, *s_ip6;
-	NMSettingProxy *s_proxy;
-	GBytes *ssid_bytes;
 	GError *error = NULL;
 
 	/* Set default timeout waiting for operation completion. */
@@ -3743,11 +3923,11 @@ do_device_wifi_hotspot (NmCli *nmc, int argc, char **argv)
 				g_string_printf (nmc->return_text, _("Error: %s argument is missing."), *(argv-1));
 				return NMC_RESULT_ERROR_USER_INPUT;
 			}
-			ssid = *argv;
-			if (strlen (ssid) > 32) {
+			if (strlen (*argv) > 32) {
 				g_string_printf (nmc->return_text, _("Error: ssid is too long."));
 				return NMC_RESULT_ERROR_USER_INPUT;
 			}
+			ssid_bytes = g_bytes_new (*argv, strlen (*argv));
 		} else if (strcmp (*argv, "band") == 0) {
 			argc--;
 			argv++;
@@ -3784,7 +3964,7 @@ do_device_wifi_hotspot (NmCli *nmc, int argc, char **argv)
 		} else if (nmc_arg_is_option (*argv, "show-password")) {
 			show_password = TRUE;
 		} else {
-			g_string_printf (nmc->return_text, _("Error: Unknown parameter %s."), *argv);
+			g_string_printf (nmc->return_text, _("Error: invalid extra argument '%s'."), *argv);
 			return NMC_RESULT_ERROR_USER_INPUT;
 		}
 
@@ -3803,21 +3983,24 @@ do_device_wifi_hotspot (NmCli *nmc, int argc, char **argv)
 			channel = "7";
 	}
 	if (channel) {
+		unsigned long int value;
+
 		if (!band) {
 			g_string_printf (nmc->return_text, _("Error: channel requires band too."));
 			return NMC_RESULT_ERROR_USER_INPUT;
 		}
-		if (   !nmc_string_to_uint (channel, TRUE, 1, 5825, &channel_int)
-		    || !nm_utils_wifi_is_channel_valid (channel_int, band)) {
+		if (   !nmc_string_to_uint (channel, TRUE, 1, 5825, &value)
+		    || !nm_utils_wifi_is_channel_valid (value, band)) {
 			g_string_printf (nmc->return_text, _("Error: channel '%s' not valid for band '%s'."),
 			                 channel, band);
 			return NMC_RESULT_ERROR_USER_INPUT;
 		}
+
+		channel_int = value;
 	}
 
 	/* Find Wi-Fi device. When no ifname is provided, the first Wi-Fi is used. */
 	device = find_wifi_device_by_iface (devices, ifname, NULL);
-
 	if (!device) {
 		if (ifname)
 			g_string_printf (nmc->return_text, _("Error: Device '%s' is not a Wi-Fi device."), ifname);
@@ -3838,69 +4021,34 @@ do_device_wifi_hotspot (NmCli *nmc, int argc, char **argv)
 		return NMC_RESULT_ERROR_UNKNOWN;
 	}
 
-	/* Create a connection with appropriate parameters */
-	connection = nm_simple_connection_new ();
-	s_con =  (NMSettingConnection *) nm_setting_connection_new ();
-	nm_connection_add_setting (connection, NM_SETTING (s_con));
-	if (!con_name)
-		con_name = default_name = nmc_unique_connection_name (nm_client_get_connections (nmc->client), "Hotspot");
-	g_object_set (s_con,
-                      NM_SETTING_CONNECTION_ID, con_name,
-	              NM_SETTING_CONNECTION_AUTOCONNECT, FALSE,
-	              NULL);
-	g_free (default_name);
-
-	s_wifi = (NMSettingWireless *) nm_setting_wireless_new ();
-	nm_connection_add_setting (connection, NM_SETTING (s_wifi));
-	ssid_bytes = generate_ssid_for_hotspot (ssid);
-	g_object_set (s_wifi, NM_SETTING_WIRELESS_MODE, wifi_mode,
-	                      NM_SETTING_WIRELESS_SSID, ssid_bytes,
-	                      NULL);
-	g_bytes_unref (ssid_bytes);
-	if (channel)
-		g_object_set (s_wifi,
-		              NM_SETTING_WIRELESS_CHANNEL, (guint32) channel_int,
-		              NM_SETTING_WIRELESS_BAND, band,
-		              NULL);
-
-	s_wsec = (NMSettingWirelessSecurity *) nm_setting_wireless_security_new ();
-	nm_connection_add_setting (connection, NM_SETTING (s_wsec));
-	if (!set_wireless_security_for_hotspot (s_wsec, wifi_mode, caps, password, show_password, &error)) {
-		g_object_unref (connection);
-		g_string_printf (nmc->return_text, _("Error: Invalid 'password': %s."), error->message);
-		g_clear_error (&error);
-		return NMC_RESULT_ERROR_UNKNOWN;
+	connections = nm_client_get_connections (nmc->client);
+	connection = find_hotspot_conn (device, connections, con_name, ssid_bytes,
+	                                wifi_mode, band, channel_int);
+	if (!connection) {
+		/* Create a connection with appropriate parameters */
+		if (!ssid_bytes)
+			ssid_bytes = generate_ssid_for_hotspot ();
+		connection = create_hotspot_conn (connections, con_name, ssid_bytes,
+		                                  wifi_mode, band, channel_int);
 	}
 
-	s_ip4 = (NMSettingIPConfig *) nm_setting_ip4_config_new ();
-	nm_connection_add_setting (connection, NM_SETTING (s_ip4));
-	g_object_set (s_ip4, NM_SETTING_IP_CONFIG_METHOD, NM_SETTING_IP4_CONFIG_METHOD_SHARED, NULL);
-
-	s_ip6 = (NMSettingIPConfig *) nm_setting_ip6_config_new ();
-	nm_connection_add_setting (connection, NM_SETTING (s_ip6));
-	g_object_set (s_ip6, NM_SETTING_IP_CONFIG_METHOD, NM_SETTING_IP6_CONFIG_METHOD_IGNORE, NULL);
+	if (password || !NM_IS_REMOTE_CONNECTION (connection)) {
+		s_wsec = nm_connection_get_setting_wireless_security (connection);
+		g_return_val_if_fail (s_wsec, NMC_RESULT_ERROR_UNKNOWN);
 
-	s_proxy = (NMSettingProxy *) nm_setting_proxy_new ();
-	nm_connection_add_setting (connection, NM_SETTING (s_proxy));
-	g_object_set (s_proxy, NM_SETTING_PROXY_METHOD, (int) NM_SETTING_PROXY_METHOD_NONE, NULL);
+		if (!set_wireless_security_for_hotspot (s_wsec, wifi_mode, caps, password, show_password, &error)) {
+			g_object_unref (connection);
+			g_string_printf (nmc->return_text, _("Error: Invalid 'password': %s."), error->message);
+			g_clear_error (&error);
+			return NMC_RESULT_ERROR_UNKNOWN;
+		}
+	}
 
 	/* Activate the connection now */
 	nmc->nowait_flag = (nmc->timeout == 0);
 	nmc->should_wait++;
 
-	info = g_malloc0 (sizeof (AddAndActivateInfo));
-	info->nmc = nmc;
-	info->device = device;
-	info->hotspot = TRUE;
-	info->create = TRUE;
-
-	nm_client_add_and_activate_connection_async (nmc->client,
-	                                             connection,
-	                                             device,
-	                                             NULL,
-	                                             NULL,
-	                                             add_and_activate_cb,
-	                                             info);
+	save_and_activate_connection (nmc, device, connection, TRUE, NULL);
 
 	return nmc->return_value;
 }
@@ -3966,8 +4114,11 @@ do_device_wifi_rescan (NmCli *nmc, int argc, char **argv)
 				goto finish;
 			}
 			g_ptr_array_add (ssids, *argv);
-		} else if (!nmc->complete)
-			g_printerr (_("Unknown parameter: %s\n"), *argv);
+		} else if (!nmc->complete) {
+			g_string_printf (nmc->return_text, _("Error: invalid extra argument '%s'."), *argv);
+			nmc->return_value = NMC_RESULT_ERROR_USER_INPUT;
+			goto finish;
+		}
 
 		next_arg (nmc, &argc, &argv, NULL);
 	}
@@ -4012,12 +4163,221 @@ finish:
 	return nmc->return_value;
 }
 
+static void
+string_append_mecard (GString *string, const char *tag, const char *text)
+{
+	const char *p;
+	bool is_hex = TRUE;
+	int start;
+
+	if (!text)
+		return;
+
+	g_string_append (string, tag);
+	start = string->len;
+
+	for (p = text; *p; p++) {
+		if (!g_ascii_isxdigit (*p))
+			is_hex = FALSE;
+		if (strchr ("\\\":;,", *p))
+			g_string_append_c (string, '\\');
+		g_string_append_c (string, *p);
+	}
+
+	if (is_hex) {
+		g_string_insert_c (string, start, '\"');
+		g_string_append_c (string, '\"');
+	}
+	g_string_append_c (string, ';');
+}
+
+static void
+print_wifi_connection (const NmcConfig *nmc_config, NMConnection *connection)
+{
+	NMSettingWireless *s_wireless;
+	NMSettingWirelessSecurity *s_wsec;
+	const char *key_mgmt = NULL;
+	const char *psk = NULL;
+	const char *type = NULL;
+	GBytes *ssid_bytes;
+	char *ssid;
+	GString *string;
+
+	s_wireless = nm_connection_get_setting_wireless (connection);
+	g_return_if_fail (s_wireless);
+
+	ssid_bytes = nm_setting_wireless_get_ssid (s_wireless);
+	g_return_if_fail (ssid_bytes);
+	ssid = nm_utils_ssid_to_utf8 (g_bytes_get_data (ssid_bytes, NULL),
+	                              g_bytes_get_size (ssid_bytes));
+	g_return_if_fail (ssid);
+	g_print ("SSID: %s\n", ssid);
+
+	string = g_string_sized_new (64);
+	g_string_append (string, "WIFI:");
+
+	s_wsec = nm_connection_get_setting_wireless_security (connection);
+	if (s_wsec) {
+		key_mgmt = nm_setting_wireless_security_get_key_mgmt (s_wsec);
+		psk = nm_setting_wireless_security_get_psk (s_wsec);
+	}
+
+	if (key_mgmt == NULL) {
+		type = "nopass";
+		g_print ("%s: %s\n", _("Security"), _("None"));
+	} else if (   strcmp (key_mgmt, "none") == 0
+	           || strcmp (key_mgmt, "ieee8021x") == 0) {
+		type = "WEP";
+		g_print ("%s: WEP\n", _("Security"));
+	} else if (   strcmp (key_mgmt, "wpa-none") == 0
+	           || strcmp (key_mgmt, "wpa-psk") == 0
+	           || strcmp (key_mgmt, "sae") == 0) {
+		type = "WPA";
+		g_print ("%s: WPA\n", _("Security"));
+	}
+
+	if (psk)
+		g_print ("%s: %s\n", _("Password"), psk);
+
+	string_append_mecard(string, "T:", type);
+	string_append_mecard(string, "S:", ssid);
+	string_append_mecard(string, "P:", psk);
+
+	if (nm_setting_wireless_get_hidden (s_wireless))
+		g_string_append (string, "H:true;");
+
+	g_string_append_c (string, ';');
+	if (nmc_config->use_colors)
+		nmc_print_qrcode (string->str);
+	g_string_free (string, TRUE);
+
+	g_print ("\n");
+}
+
+static gboolean
+wifi_show_device (const NmcConfig *nmc_config, NMDevice *device, GError **error)
+{
+	NMActiveConnection *active_conn;
+	gs_unref_object NMConnection *connection = NULL;
+	gs_unref_variant GVariant *secrets = NULL;
+
+	if (!NM_IS_DEVICE_WIFI (device)) {
+		g_set_error (error, NMCLI_ERROR, 0,
+		             _("Error: Device '%s' is not a Wi-Fi device."),
+		             nm_device_get_iface (device));
+		return FALSE;
+	}
+
+	connection = nm_device_get_applied_connection (device, 0, NULL, NULL, error);
+	if (!connection)
+		return FALSE;
+
+	active_conn = nm_device_get_active_connection (device);
+	if (!active_conn) {
+		g_set_error (error, NMCLI_ERROR, 0,
+		             _("no active connection on device '%s'"),
+		             nm_device_get_iface (device));
+		return FALSE;
+	}
+
+	secrets = nm_remote_connection_get_secrets (nm_active_connection_get_connection (active_conn),
+	                                            NM_SETTING_WIRELESS_SECURITY_SETTING_NAME,
+	                                            NULL,
+	                                            NULL);
+	if (secrets && !nm_connection_update_secrets (connection,
+	                                              NM_SETTING_WIRELESS_SECURITY_SETTING_NAME,
+	                                              secrets,
+	                                              error)) {
+		return FALSE;
+	}
+
+	print_wifi_connection (nmc_config, connection);
+
+	return TRUE;
+}
+
+static NMCResultCode
+do_device_wifi_show_password (NmCli *nmc, int argc, char **argv)
+{
+	const char *ifname = NULL;
+	gs_free NMDevice **devices = NULL;
+	gs_free_error GError *error = NULL;
+	gboolean found = FALSE;
+	int i;
+
+	devices = nmc_get_devices_sorted (nmc->client);
+
+	next_arg (nmc, &argc, &argv, NULL);
+	while (argc > 0) {
+		if (argc == 1 && nmc->complete)
+			nmc_complete_strings (*argv, "ifname");
+
+		if (strcmp (*argv, "ifname") == 0) {
+			if (ifname) {
+				g_string_printf (nmc->return_text,
+				                 _("Error: '%s' cannot repeat."),
+				                 *(argv-1));
+				return NMC_RESULT_ERROR_USER_INPUT;
+			}
+			argc--;
+			argv++;
+			if (!argc) {
+				g_string_printf (nmc->return_text,
+				                 _("Error: %s argument is missing."),
+				                 *(argv-1));
+				return NMC_RESULT_ERROR_USER_INPUT;
+			}
+			ifname = *argv;
+			if (argc == 1 && nmc->complete)
+				complete_device (devices, ifname, TRUE);
+		} else if (!nmc->complete) {
+			g_string_printf (nmc->return_text,
+			                 _("Error: invalid extra argument '%s'."),
+			                 *argv);
+			return NMC_RESULT_ERROR_USER_INPUT;
+		}
+
+		next_arg (nmc, &argc, &argv, NULL);
+	}
+
+	if (nmc->complete)
+		return nmc->return_value;
+
+	for (i = 0; devices[i]; i++) {
+		if (ifname && g_strcmp0 (nm_device_get_iface (devices[i]), ifname) != 0)
+			continue;
+
+		if (wifi_show_device (&nmc->nmc_config, devices[i], &error)) {
+			found = TRUE;
+		} else {
+			if (ifname) {
+				g_string_printf (nmc->return_text,
+				                 _("%s"), error->message);
+				return NMC_RESULT_ERROR_UNKNOWN;
+			}
+			g_clear_error (&error);
+		}
+
+		if (ifname)
+			break;
+	}
+
+	if (!found) {
+		g_string_printf (nmc->return_text,
+		                 _("Error: No Wi-Fi device found."));
+		return NMC_RESULT_ERROR_UNKNOWN;
+	}
+
+	return nmc->return_value;
+}
+
 static NMCCommand device_wifi_cmds[] = {
-	{ "list",     do_device_wifi_list,            NULL,             TRUE,   TRUE },
-	{ "connect",  do_device_wifi_connect_network, NULL,             TRUE,   TRUE },
-	{ "hotspot",  do_device_wifi_hotspot,         NULL,             TRUE,   TRUE },
-	{ "rescan",   do_device_wifi_rescan,          NULL,             TRUE,   TRUE },
-	{ NULL,       do_device_wifi_list,            NULL,             TRUE,   TRUE },
+	{ "list",           do_device_wifi_list,           NULL,  TRUE,  TRUE },
+	{ "connect",        do_device_wifi_connect,        NULL,  TRUE,  TRUE },
+	{ "hotspot",        do_device_wifi_hotspot,        NULL,  TRUE,  TRUE },
+	{ "rescan",         do_device_wifi_rescan,         NULL,  TRUE,  TRUE },
+	{ "show-password",  do_device_wifi_show_password,  NULL,  TRUE,  TRUE },
+	{ NULL,             do_device_wifi_list,           NULL,  TRUE,  TRUE },
 };
 
 static NMCResultCode
diff --git a/clients/cli/devices.h b/clients/cli/devices.h
index 7a05b50b..055d56e7 100644
--- a/clients/cli/devices.h
+++ b/clients/cli/devices.h
@@ -1,20 +1,6 @@
-/* nmcli - command-line tool to control NetworkManager
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License along
- * with this program; if not, write to the Free Software Foundation, Inc.,
- * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
- *
- * (C) Copyright 2010 - 2018 Red Hat, Inc.
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * Copyright (C) 2010 - 2018 Red Hat, Inc.
  */
 
 #ifndef NMC_DEVICES_H
diff --git a/clients/cli/general.c b/clients/cli/general.c
index e2ce639e..123cc5b4 100644
--- a/clients/cli/general.c
+++ b/clients/cli/general.c
@@ -1,20 +1,6 @@
-/* nmcli - command-line tool to control NetworkManager
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License along
- * with this program; if not, write to the Free Software Foundation, Inc.,
- * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
- *
- * Copyright 2010 - 2018 Red Hat, Inc.
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * Copyright (C) 2010 - 2018 Red Hat, Inc.
  */
 
 #include "nm-default.h"
@@ -367,6 +353,38 @@ usage_general_permissions (void)
 }
 
 static void
+usage_general_reload (void)
+{
+	g_printerr (_("Usage: nmcli general reload { ARGUMENTS | help }\n"
+	              "\n"
+	              "ARGUMENTS := [<flag>[,<flag>...]]\n"
+	              "\n"
+	              "Reload NetworkManager's configuration and perform certain updates, like\n"
+	              "flushing caches or rewriting external state to disk. This is similar to\n"
+	              "sending SIGHUP to NetworkManager but it allows for more fine-grained\n"
+	              "control over what to reload through the flags argument. It also allows\n"
+	              "non-root access via PolicyKit and contrary to signals it is synchronous.\n"
+	              "\n"
+	              "Available flags are:\n"
+	              "\n"
+	              "  'conf'        Reload the NetworkManager.conf configuration from\n"
+	              "                disk. Note that this does not include connections, which\n"
+	              "                can be reloaded through 'nmcli connection reload' instead.\n"
+	              "\n"
+	              "  'dns-rc'      Update DNS configuration, which usually involves writing\n"
+	              "                /etc/resolv.conf anew.\n"
+	              "\n"
+	              "  'dns-full'    Restart the DNS plugin. This is for example useful when\n"
+	              "                using dnsmasq plugin, which uses additional configuration\n"
+	              "                in /etc/NetworkManager/dnsmasq.d. If you edit those files,\n"
+	              "                you can restart the DNS plugin. This action shortly\n"
+	              "                interrupts name resolution.\n"
+	              "\n"
+	              "With no flags, everything that is supported is reloaded, which is\n"
+	              "identical to sending a SIGHUP.\n"));
+}
+
+static void
 usage_general_logging (void)
 {
 	g_printerr (_("Usage: nmcli general logging { ARGUMENTS | help }\n"
@@ -582,6 +600,9 @@ permission_changed (NMClient *client,
 	if (got_permissions (nmc)) {
 		/* Defer the printing, so that we have a chance to process the other
 		 * permission-changed signals. */
+		g_signal_handlers_disconnect_by_func (nmc->client,
+		                                      G_CALLBACK (permission_changed),
+		                                      nmc);
 		g_idle_remove_by_data (nmc);
 		g_idle_add (print_permissions, nmc);
 	}
@@ -598,7 +619,7 @@ show_nm_permissions (NmCli *nmc)
 
 	/* The client didn't get the permissions reply yet. Subscribe to changes. */
 	g_signal_connect (nmc->client, NM_CLIENT_PERMISSION_CHANGED,
-                          G_CALLBACK (permission_changed), nmc);
+	                  G_CALLBACK (permission_changed), nmc);
 
 	if (nmc->timeout == -1)
 		nmc->timeout = 10;
@@ -609,6 +630,70 @@ show_nm_permissions (NmCli *nmc)
 }
 
 static NMCResultCode
+do_general_reload (NmCli *nmc, int argc, char **argv)
+{
+	gs_unref_variant GVariant *result = NULL;
+	gs_free_error GError *error = NULL;
+	gs_free const char **values = NULL;
+	gs_free char *err_token = NULL;
+	gs_free char *joined = NULL;
+	int flags = 0;
+
+	next_arg (nmc, &argc, &argv, NULL);
+
+	if (nmc->complete) {
+		if (argc == 0)
+			return nmc->return_value;
+
+		if (argc == 1) {
+			values = nm_utils_enum_get_values (nm_manager_reload_flags_get_type (),
+			                                   NM_MANAGER_RELOAD_FLAG_CONF,
+			                                   NM_MANAGER_RELOAD_FLAG_ALL);
+			nmc_complete_strv (*argv, -1, values);
+		}
+		return nmc->return_value;
+	}
+
+	if (argc > 0) {
+		if (!nm_utils_enum_from_str (nm_manager_reload_flags_get_type (), *argv, &flags, &err_token)) {
+			values = nm_utils_enum_get_values (nm_manager_reload_flags_get_type (),
+			                                   NM_MANAGER_RELOAD_FLAG_CONF,
+			                                   NM_MANAGER_RELOAD_FLAG_ALL);
+			joined = g_strjoinv (",", (char **) values);
+			g_string_printf (nmc->return_text,
+			                 _("Error: invalid reload flag '%s'. Allowed flags are: %s"),
+			                 err_token,
+			                 joined);
+			return NMC_RESULT_ERROR_USER_INPUT;
+		}
+		argc--;
+		argv++;
+	}
+
+	if (argc > 0) {
+		g_string_printf (nmc->return_text, _("Error: extra argument '%s'"), *argv);
+		return NMC_RESULT_ERROR_USER_INPUT;
+	}
+
+	result = nmc_dbus_call_sync (nmc,
+	                             "/org/freedesktop/NetworkManager",
+	                             "org.freedesktop.NetworkManager",
+	                             "Reload",
+	                             g_variant_new ("(u)", flags),
+	                             G_VARIANT_TYPE("()"),
+	                             &error);
+
+	if (error) {
+		g_string_printf (nmc->return_text,
+		                 _("Error: failed to reload: %s"),
+		                 nmc_error_get_simple_message (error));
+		return NMC_RESULT_ERROR_UNKNOWN;
+	}
+
+	return nmc->return_value;
+}
+
+static NMCResultCode
 do_general_permissions (NmCli *nmc, int argc, char **argv)
 {
 	next_arg (nmc, &argc, &argv, NULL);
@@ -785,6 +870,7 @@ static const NMCCommand general_cmds[] = {
 	{ "hostname",     do_general_hostname,     usage_general_hostname,     TRUE,   TRUE },
 	{ "permissions",  do_general_permissions,  usage_general_permissions,  TRUE,   TRUE },
 	{ "logging",      do_general_logging,      usage_general_logging,      TRUE,   TRUE },
+	{ "reload",       do_general_reload,       usage_general_reload,       FALSE,  FALSE },
 	{ NULL,           do_general_status,       usage_general,              TRUE,   TRUE },
 };
 
@@ -1158,6 +1244,41 @@ device_overview (NmCli *nmc, NMDevice *device)
 		g_string_append_printf (outbuf, "%s, ", tmp);
 		g_free (tmp);
 	}
+
+	switch (nm_device_get_device_type (device)) {
+	case NM_DEVICE_TYPE_WIFI:
+	case NM_DEVICE_TYPE_OLPC_MESH:
+	case NM_DEVICE_TYPE_WIFI_P2P:
+		if (!nm_client_wireless_get_enabled (nmc->client)) {
+			tmp = nmc_colorize (&nmc->nmc_config, NM_META_COLOR_DEVICE_DISABLED, _("sw disabled"));
+			g_string_append_printf (outbuf, "%s, ", tmp);
+			g_free (tmp);
+		}
+		if (!nm_client_wireless_hardware_get_enabled (nmc->client)) {
+			tmp = nmc_colorize (&nmc->nmc_config, NM_META_COLOR_DEVICE_DISABLED, _("hw disabled"));
+			g_string_append_printf (outbuf, "%s, ", tmp);
+			g_free (tmp);
+		}
+		break;
+	case NM_DEVICE_TYPE_MODEM:
+		if (  nm_device_modem_get_current_capabilities (NM_DEVICE_MODEM (device))
+		    & (NM_DEVICE_MODEM_CAPABILITY_GSM_UMTS | NM_DEVICE_MODEM_CAPABILITY_CDMA_EVDO)) {
+			if (!nm_client_wwan_get_enabled (nmc->client)) {
+				tmp = nmc_colorize (&nmc->nmc_config, NM_META_COLOR_DEVICE_DISABLED, _("sw disabled"));
+				g_string_append_printf (outbuf, "%s, ", tmp);
+				g_free (tmp);
+			}
+			if (!nm_client_wwan_hardware_get_enabled (nmc->client)) {
+				tmp = nmc_colorize (&nmc->nmc_config, NM_META_COLOR_DEVICE_DISABLED, _("hw disabled"));
+				g_string_append_printf (outbuf, "%s, ", tmp);
+				g_free (tmp);
+			}
+		}
+		break;
+	default:
+		break;
+	}
+
 	if (nm_device_is_software (device))
 		g_string_append_printf (outbuf, "%s, ", _("sw"));
 	else
@@ -1296,11 +1417,20 @@ do_overview (NmCli *nmc, int argc, char **argv)
 
 		state = nm_device_get_state (devices[i]);
 		color = nmc_device_state_to_color (state);
-		tmp = nmc_colorize (&nmc->nmc_config, color, "%s: %s%s%s",
-		                    nm_device_get_iface (devices[i]),
-		                    gettext (nmc_device_state_to_string (state)),
-		                    ac ? " to " : "",
-		                    ac ? nm_active_connection_get_id (ac) : "");
+		if (ac) {
+			/* TRANSLATORS: prints header line for activated device in plain `nmcli` overview output as
+			 * "<interface-name>: <device-state> to <connection-id>" */
+			tmp = nmc_colorize (&nmc->nmc_config, color, C_("nmcli-overview", "%s: %s to %s"),
+			                    nm_device_get_iface (devices[i]),
+			                    gettext (nmc_device_state_to_string (state)),
+			                    nm_active_connection_get_id (ac));
+		} else {
+			/* TRANSLATORS: prints header line for not active device in plain `nmcli` overview output as
+			 * "<interface-name>: <device-state>" */
+			tmp = nmc_colorize (&nmc->nmc_config, color, C_("nmcli-overview", "%s: %s"),
+			                    nm_device_get_iface (devices[i]),
+			                    gettext (nmc_device_state_to_string (state)));
+		}
 		g_print ("%s\n", tmp);
 		g_free (tmp);
 
diff --git a/clients/cli/general.h b/clients/cli/general.h
index 05caffea..dd63e43f 100644
--- a/clients/cli/general.h
+++ b/clients/cli/general.h
@@ -1,20 +1,6 @@
-/* nmcli - command-line tool to control NetworkManager
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License along
- * with this program; if not, write to the Free Software Foundation, Inc.,
- * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
- *
- * Copyright 2010 - 2014 Red Hat, Inc.
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * Copyright (C) 2010 - 2014 Red Hat, Inc.
  */
 
 #ifndef NMC_GENERAL_H
diff --git a/clients/cli/meson.build b/clients/cli/meson.build
index 396466a2..56202063 100644
--- a/clients/cli/meson.build
+++ b/clients/cli/meson.build
@@ -19,17 +19,11 @@ sources = files(
 )
 
 deps = [
-  libnm_dep,
   libnmc_base_dep,
   libnmc_dep,
-  libnm_core_dep,
   readline_dep,
 ]
 
-cflags = clients_cflags + [
-  '-DG_LOG_DOMAIN="@0@"'.format(name),
-]
-
 if enable_polkit_agent
   sources += nm_polkit_listener
 
@@ -40,7 +34,7 @@ executable(
   name,
   sources,
   dependencies: deps,
-  c_args: cflags,
+  c_args: clients_c_flags + ['-DG_LOG_DOMAIN="@0@"'.format(name)],
   link_args: ldflags_linker_script_binary,
   link_depends: linker_script_binary,
   install: true,
diff --git a/clients/cli/nmcli.c b/clients/cli/nmcli.c
index ad45f179..5fbd6d72 100644
--- a/clients/cli/nmcli.c
+++ b/clients/cli/nmcli.c
@@ -1,22 +1,7 @@
-/* nmcli - command-line tool to control NetworkManager
- *
+// SPDX-License-Identifier: GPL-2.0+
+/*
  * Jiri Klimes <jklimes@redhat.com>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License along
- * with this program; if not, write to the Free Software Foundation, Inc.,
- * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
- *
- * Copyright 2010 - 2018 Red Hat, Inc.
+ * Copyright (C) 2010 - 2018 Red Hat, Inc.
  */
 
 #include "nm-default.h"
@@ -65,6 +50,7 @@
 	[NM_META_COLOR_DEVICE_FIRMWARE_MISSING]  = "31", \
 	[NM_META_COLOR_DEVICE_PLUGIN_MISSING]    = "31", \
 	[NM_META_COLOR_DEVICE_UNAVAILABLE]       =  "2", \
+	[NM_META_COLOR_DEVICE_DISABLED]          = "31", \
 	[NM_META_COLOR_MANAGER_RUNNING]          = "32", \
 	[NM_META_COLOR_MANAGER_STARTING]         = "33", \
 	[NM_META_COLOR_MANAGER_STOPPED]          = "31", \
@@ -470,6 +456,12 @@ check_colors (NmcColorOption color_option,
 		return FALSE;
 	}
 
+	if (   color_option == NMC_USE_COLOR_AUTO
+	    && g_getenv ("NO_COLOR")) {
+		/* https://no-color.org/ */
+		return FALSE;
+	}
+
 	term = g_getenv ("TERM");
 
 	if (color_option == NMC_USE_COLOR_AUTO) {
@@ -571,6 +563,7 @@ parse_color_scheme (char *palette_buffer,
 		[NM_META_COLOR_DEVICE_FIRMWARE_MISSING]  = "device-firmware-missing",
 		[NM_META_COLOR_DEVICE_PLUGIN_MISSING]    = "device-plugin-missing",
 		[NM_META_COLOR_DEVICE_UNAVAILABLE]       = "device-unavailable",
+		[NM_META_COLOR_DEVICE_DISABLED]          = "device-disabled",
 		[NM_META_COLOR_DEVICE_UNKNOWN]           = "device-unknown",
 		[NM_META_COLOR_MANAGER_RUNNING]          = "manager-running",
 		[NM_META_COLOR_MANAGER_STARTING]         = "manager-starting",
diff --git a/clients/cli/nmcli.h b/clients/cli/nmcli.h
index cd50333a..4615b046 100644
--- a/clients/cli/nmcli.h
+++ b/clients/cli/nmcli.h
@@ -1,20 +1,6 @@
-/* nmcli - command-line tool to control NetworkManager
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License along
- * with this program; if not, write to the Free Software Foundation, Inc.,
- * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
- *
- * Copyright 2010 - 2018 Red Hat, Inc.
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * Copyright (C) 2010 - 2018 Red Hat, Inc.
  */
 
 #ifndef NMC_NMCLI_H
@@ -149,11 +135,6 @@ typedef struct _NmCli {
 	char *palette_buffer;                             /* Buffer with sequences for terminal-colors.d(5)-based coloring. */
 } NmCli;
 
-#define NMC_RETURN(nmc, rvalue) \
-	G_STMT_START { \
-		return ((nmc)->return_value = (rvalue)); \
-	} G_STMT_END
-
 extern NmCli nm_cli;
 
 /* Error quark for GError domain */
diff --git a/clients/cli/polkit-agent.c b/clients/cli/polkit-agent.c
index accb567f..69bfb68d 100644
--- a/clients/cli/polkit-agent.c
+++ b/clients/cli/polkit-agent.c
@@ -1,20 +1,6 @@
-/* nmcli - command-line tool to control NetworkManager
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License along
- * with this program; if not, write to the Free Software Foundation, Inc.,
- * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
- *
- * Copyright 2014 Red Hat, Inc.
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * Copyright (C) 2014 Red Hat, Inc.
  */
 
 #include "nm-default.h"
diff --git a/clients/cli/polkit-agent.h b/clients/cli/polkit-agent.h
index e2902dc0..722d6d33 100644
--- a/clients/cli/polkit-agent.h
+++ b/clients/cli/polkit-agent.h
@@ -1,20 +1,6 @@
-/* nmcli - command-line tool to control NetworkManager
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License along
- * with this program; if not, write to the Free Software Foundation, Inc.,
- * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
- *
- * Copyright 2014 Red Hat, Inc.
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * Copyright (C) 2014 Red Hat, Inc.
  */
 
 #ifndef __NMC_POLKIT_AGENT_H__
diff --git a/clients/cli/settings.c b/clients/cli/settings.c
index 2446cb08..698471d7 100644
--- a/clients/cli/settings.c
+++ b/clients/cli/settings.c
@@ -1,20 +1,6 @@
-/* nmcli - command-line tool to control NetworkManager
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License along
- * with this program; if not, write to the Free Software Foundation, Inc.,
- * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
- *
- * Copyright 2010 - 2015 Red Hat, Inc.
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * Copyright (C) 2010 - 2015 Red Hat, Inc.
  */
 
 #include "nm-default.h"
@@ -532,7 +518,7 @@ gboolean
 nmc_setting_set_property (NMClient *client,
                           NMSetting *setting,
                           const char *prop,
-                          char modifier,
+                          NMMetaAccessorModifier modifier,
                           const char *value,
                           GError **error)
 {
@@ -542,20 +528,14 @@ nmc_setting_set_property (NMClient *client,
 
 	g_return_val_if_fail (NM_IS_SETTING (setting), FALSE);
 	g_return_val_if_fail (error == NULL || *error == NULL, FALSE);
-	g_return_val_if_fail (NM_IN_SET (modifier, '\0', '-', '+'), FALSE);
+	g_return_val_if_fail (NM_IN_SET (modifier, NM_META_ACCESSOR_MODIFIER_SET, NM_META_ACCESSOR_MODIFIER_DEL, NM_META_ACCESSOR_MODIFIER_ADD), FALSE);
 
 	if (!(property_info = nm_meta_property_info_find_by_setting (setting, prop)))
 		goto out_fail_read_only;
 	if (!property_info->property_type->set_fcn)
 		goto out_fail_read_only;
 
-	if (   NM_IN_SET (modifier, '+', '-')
-	    && !value) {
-		/* nothing to do. */
-		return TRUE;
-	}
-
-	if (   modifier == '-'
+	if (   modifier == NM_META_ACCESSOR_MODIFIER_DEL
 	    && !property_info->property_type->set_supports_remove) {
 		/* The property is a plain property. It does not support '-'.
 		 *
@@ -578,6 +558,13 @@ nmc_setting_set_property (NMClient *client,
 		}
 	}
 
+	if (   NM_IN_SET (modifier, NM_META_ACCESSOR_MODIFIER_ADD, NM_META_ACCESSOR_MODIFIER_DEL)
+	    && (   !value
+	        || !value[0])) {
+		/* nothing to do. */
+		return TRUE;
+	}
+
 	g_object_freeze_notify (G_OBJECT (setting));
 	success = property_info->property_type->set_fcn (property_info,
 	                                                 nmc_meta_environment,
diff --git a/clients/cli/settings.h b/clients/cli/settings.h
index 1ff93685..59ad5e87 100644
--- a/clients/cli/settings.h
+++ b/clients/cli/settings.h
@@ -1,20 +1,6 @@
-/* nmcli - command-line tool to control NetworkManager
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License along
- * with this program; if not, write to the Free Software Foundation, Inc.,
- * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
- *
- * Copyright 2010 - 2014 Red Hat, Inc.
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * Copyright (C) 2010 - 2014 Red Hat, Inc.
  */
 
 #ifndef NMC_SETTINGS_H
@@ -45,7 +31,7 @@ char       *nmc_setting_get_property_parsable (NMSetting *setting,
 gboolean    nmc_setting_set_property (NMClient *client,
                                       NMSetting *setting,
                                       const char *prop,
-                                      char modifier,
+                                      NMMetaAccessorModifier modifier,
                                       const char *val,
                                       GError **error);
 
diff --git a/clients/cli/utils.c b/clients/cli/utils.c
index a822dd89..2e3a38f7 100644
--- a/clients/cli/utils.c
+++ b/clients/cli/utils.c
@@ -1,21 +1,7 @@
-/* nmcli - command-line tool to control NetworkManager
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License along
- * with this program; if not, write to the Free Software Foundation, Inc.,
- * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
- *
- * Copyright 2010 Lennart Poettering
- * Copyright 2010 - 2018 Red Hat, Inc.
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * Copyright (C) 2010 Lennart Poettering
+ * Copyright (C) 2010 - 2018 Red Hat, Inc.
  */
 
 #include "nm-default.h"
diff --git a/clients/cli/utils.h b/clients/cli/utils.h
index 82b186b7..e699a641 100644
--- a/clients/cli/utils.h
+++ b/clients/cli/utils.h
@@ -1,20 +1,6 @@
-/* nmcli - command-line tool to control NetworkManager
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License along
- * with this program; if not, write to the Free Software Foundation, Inc.,
- * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
- *
- * Copyright 2010 - 2018 Red Hat, Inc.
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * Copyright (C) 2010 - 2018 Red Hat, Inc.
  */
 
 #ifndef NMC_UTILS_H
@@ -144,6 +130,7 @@ typedef enum {
 	NMC_GENERIC_INFO_TYPE_CON_ACTIVE_GENERAL_NAME = 0,
 	NMC_GENERIC_INFO_TYPE_CON_ACTIVE_GENERAL_UUID,
 	NMC_GENERIC_INFO_TYPE_CON_ACTIVE_GENERAL_DEVICES,
+	NMC_GENERIC_INFO_TYPE_CON_ACTIVE_GENERAL_IP_IFACE,
 	NMC_GENERIC_INFO_TYPE_CON_ACTIVE_GENERAL_STATE,
 	NMC_GENERIC_INFO_TYPE_CON_ACTIVE_GENERAL_DEFAULT,
 	NMC_GENERIC_INFO_TYPE_CON_ACTIVE_GENERAL_DEFAULT6,
@@ -177,6 +164,7 @@ typedef enum {
 	NMC_GENERIC_INFO_TYPE_DEVICE_DETAIL_GENERAL_DEVICE = 0,
 	NMC_GENERIC_INFO_TYPE_DEVICE_DETAIL_GENERAL_TYPE,
 	NMC_GENERIC_INFO_TYPE_DEVICE_DETAIL_GENERAL_NM_TYPE,
+	NMC_GENERIC_INFO_TYPE_DEVICE_DETAIL_GENERAL_DBUS_PATH,
 	NMC_GENERIC_INFO_TYPE_DEVICE_DETAIL_GENERAL_VENDOR,
 	NMC_GENERIC_INFO_TYPE_DEVICE_DETAIL_GENERAL_PRODUCT,
 	NMC_GENERIC_INFO_TYPE_DEVICE_DETAIL_GENERAL_DRIVER,
@@ -226,8 +214,14 @@ typedef enum {
 	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_IBSS_RSN,
 	_NMC_GENERIC_INFO_TYPE_DEVICE_DETAIL_WIFI_PROPERTIES_NUM,
 
+	NMC_GENERIC_INFO_TYPE_DEVICE_DETAIL_INTERFACE_FLAGS_UP = 0,
+	NMC_GENERIC_INFO_TYPE_DEVICE_DETAIL_INTERFACE_FLAGS_LOWER_UP,
+	NMC_GENERIC_INFO_TYPE_DEVICE_DETAIL_INTERFACE_FLAGS_CARRIER,
+	_NMC_GENERIC_INFO_TYPE_DEVICE_DETAIL_INTERFACE_FLAGS_NUM,
+
 } NmcGenericInfoType;
 
 #define NMC_HANDLE_COLOR(color) \