summary refs log tree commit diff
path: root/clients/cli/devices.c
diff options
context:
space:
mode:
Diffstat (limited to 'clients/cli/devices.c')
-rw-r--r--clients/cli/devices.c918
1 files changed, 639 insertions, 279 deletions
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