summary refs log tree commit diff
path: root/clients/cli/connections.c
diff options
context:
space:
mode:
authorMichael Biebl <biebl@debian.org>2016-03-30 00:56:30 +0200
committerMichael Biebl <biebl@debian.org>2016-03-30 00:56:30 +0200
commitd9c99a29a0d3384c9c3d2adce430f5cb1134ab6a (patch)
treefa41baf72753961e71dd8d5bdbe2b89c9109e4f1 /clients/cli/connections.c
parentc2de0d98ba39e0a1a970d066fd19be786092f376 (diff)
Imported Upstream version 1.1.92 upstream/1.1.92
Diffstat (limited to 'clients/cli/connections.c')
-rw-r--r--clients/cli/connections.c688
1 files changed, 389 insertions, 299 deletions
diff --git a/clients/cli/connections.c b/clients/cli/connections.c
index d263154d..129a5298 100644
--- a/clients/cli/connections.c
+++ b/clients/cli/connections.c
@@ -1641,13 +1641,13 @@ do_connections_show (NmCli *nmc, gboolean active_only, gboolean show_secrets,
 		invisibles = get_invisible_active_connections (nmc);
 		for (i = 0; i < invisibles->len; i++)
 			fill_output_connection_for_invisible (invisibles->pdata[i], nmc);
-		g_ptr_array_free (invisibles, FALSE);
+		g_ptr_array_free (invisibles, TRUE);
 
 		/* Sort the connections and fill the output data */
 		sorted_cons = sort_connections (nmc->connections, nmc, order);
 		for (i = 0; i < sorted_cons->len; i++)
 			fill_output_connection (sorted_cons->pdata[i], nmc, active_only);
-		g_ptr_array_free (sorted_cons, FALSE);
+		g_ptr_array_free (sorted_cons, TRUE);
 
 		print_data (nmc);  /* Print all data */
 	} else {
@@ -2302,7 +2302,7 @@ nmc_activate_connection (NmCli *nmc,
 		/* Virtual connection may not have their interfaces created yet */
 		if (!device_found && !nm_connection_is_virtual (connection)) {
 			g_set_error (error, NMCLI_ERROR, NMC_RESULT_ERROR_CON_ACTIVATION,
-				     "%s", local && local->message ? local->message : _("unknown error"));
+			             "%s", local->message);
 			g_clear_error (&local);
 			return FALSE;
 		}
@@ -2450,8 +2450,8 @@ do_connection_up (NmCli *nmc, int argc, char **argv)
 
 	if (!nmc_activate_connection (nmc, connection, ifname, ap, nsp, pwds, activate_connection_cb, &error)) {
 		g_string_printf (nmc->return_text, _("Error: %s."),
-		                 error ? error->message : _("unknown error"));
-		nmc->return_value = error ? error->code : NMC_RESULT_ERROR_CON_ACTIVATION;
+		                 error->message);
+		nmc->return_value = error->code;
 		g_clear_error (&error);
 		nmc->should_wait--;
 		goto error;
@@ -2653,8 +2653,6 @@ typedef struct NameItem {
 
 static const NameItem nmc_generic_settings [] = {
 	{ NM_SETTING_CONNECTION_SETTING_NAME, NULL,       NULL, TRUE  },
-	{ NM_SETTING_IP4_CONFIG_SETTING_NAME, NULL,       NULL, FALSE },
-	{ NM_SETTING_IP6_CONFIG_SETTING_NAME, NULL,       NULL, FALSE },
 	{ NULL, NULL, NULL, FALSE }
 };
 
@@ -2662,8 +2660,6 @@ static const NameItem nmc_ethernet_settings [] = {
 	{ NM_SETTING_CONNECTION_SETTING_NAME, NULL,       NULL, TRUE  },
 	{ NM_SETTING_WIRED_SETTING_NAME,      "ethernet", NULL, TRUE  },
 	{ NM_SETTING_802_1X_SETTING_NAME,     NULL,       NULL, FALSE },
-	{ NM_SETTING_IP4_CONFIG_SETTING_NAME, NULL,       NULL, FALSE },
-	{ NM_SETTING_IP6_CONFIG_SETTING_NAME, NULL,       NULL, FALSE },
 	{ NM_SETTING_DCB_SETTING_NAME,        NULL,       NULL, FALSE },
 	{ NULL, NULL, NULL, FALSE }
 };
@@ -2671,8 +2667,6 @@ static const NameItem nmc_ethernet_settings [] = {
 static const NameItem nmc_infiniband_settings [] = {
 	{ NM_SETTING_CONNECTION_SETTING_NAME, NULL, NULL, TRUE  },
 	{ NM_SETTING_INFINIBAND_SETTING_NAME, NULL, NULL, TRUE  },
-	{ NM_SETTING_IP4_CONFIG_SETTING_NAME, NULL, NULL, FALSE },
-	{ NM_SETTING_IP6_CONFIG_SETTING_NAME, NULL, NULL, FALSE },
 	{ NULL, NULL, NULL, FALSE }
 };
 
@@ -2681,16 +2675,12 @@ static const NameItem nmc_wifi_settings [] = {
 	{ NM_SETTING_WIRELESS_SETTING_NAME,          "wifi",     NULL, TRUE  },
 	{ NM_SETTING_WIRELESS_SECURITY_SETTING_NAME, "wifi-sec", NULL, FALSE },
 	{ NM_SETTING_802_1X_SETTING_NAME,            NULL,       NULL, FALSE },
-	{ NM_SETTING_IP4_CONFIG_SETTING_NAME,        NULL,       NULL, FALSE },
-	{ NM_SETTING_IP6_CONFIG_SETTING_NAME,        NULL,       NULL, FALSE },
 	{ NULL, NULL, NULL, FALSE }
 };
 
 static const NameItem nmc_wimax_settings [] = {
 	{ NM_SETTING_CONNECTION_SETTING_NAME, NULL,   NULL, TRUE  },
 	{ NM_SETTING_WIMAX_SETTING_NAME,      NULL,   NULL, TRUE  },
-	{ NM_SETTING_IP4_CONFIG_SETTING_NAME, NULL,   NULL, FALSE },
-	{ NM_SETTING_IP6_CONFIG_SETTING_NAME, NULL,   NULL, FALSE },
 	{ NULL, NULL, NULL, FALSE }
 };
 
@@ -2699,8 +2689,6 @@ static const NameItem nmc_gsm_settings [] = {
 	{ NM_SETTING_GSM_SETTING_NAME,        NULL,       NULL, TRUE  },
 	{ NM_SETTING_SERIAL_SETTING_NAME,     NULL,       NULL, FALSE },
 	{ NM_SETTING_PPP_SETTING_NAME,        NULL,       NULL, FALSE },
-	{ NM_SETTING_IP4_CONFIG_SETTING_NAME, NULL,       NULL, FALSE },
-	{ NM_SETTING_IP6_CONFIG_SETTING_NAME, NULL,       NULL, FALSE },
 	{ NULL, NULL, NULL, FALSE }
 };
 
@@ -2709,24 +2697,18 @@ static const NameItem nmc_cdma_settings [] = {
 	{ NM_SETTING_CDMA_SETTING_NAME,       NULL,       NULL, TRUE  },
 	{ NM_SETTING_SERIAL_SETTING_NAME,     NULL,       NULL, FALSE },
 	{ NM_SETTING_PPP_SETTING_NAME,        NULL,       NULL, FALSE },
-	{ NM_SETTING_IP4_CONFIG_SETTING_NAME, NULL,       NULL, FALSE },
-	{ NM_SETTING_IP6_CONFIG_SETTING_NAME, NULL,       NULL, FALSE },
 	{ NULL, NULL, NULL, FALSE }
 };
 
 static const NameItem nmc_bluetooth_settings [] = {
 	{ NM_SETTING_CONNECTION_SETTING_NAME, NULL,   NULL, TRUE  },
 	{ NM_SETTING_BLUETOOTH_SETTING_NAME,  NULL,   NULL, TRUE  },
-	{ NM_SETTING_IP4_CONFIG_SETTING_NAME, NULL,   NULL, FALSE },
-	{ NM_SETTING_IP6_CONFIG_SETTING_NAME, NULL,   NULL, FALSE },
 	{ NULL, NULL, NULL, FALSE }
 };
 
 static const NameItem nmc_adsl_settings [] = {
 	{ NM_SETTING_CONNECTION_SETTING_NAME, NULL,   NULL, TRUE  },
 	{ NM_SETTING_ADSL_SETTING_NAME,       NULL,   NULL, TRUE  },
-	{ NM_SETTING_IP4_CONFIG_SETTING_NAME, NULL,   NULL, FALSE },
-	{ NM_SETTING_IP6_CONFIG_SETTING_NAME, NULL,   NULL, FALSE },
 	{ NULL, NULL, NULL, FALSE }
 };
 
@@ -2739,24 +2721,18 @@ static const NameItem nmc_pppoe_settings [] = {
 	{ NM_SETTING_PPPOE_SETTING_NAME,      NULL,       NULL, TRUE  },
 	{ NM_SETTING_PPP_SETTING_NAME,        NULL,       NULL, FALSE },
 	{ NM_SETTING_802_1X_SETTING_NAME,     NULL,       NULL, FALSE },
-	{ NM_SETTING_IP4_CONFIG_SETTING_NAME, NULL,       NULL, FALSE },
-	{ NM_SETTING_IP6_CONFIG_SETTING_NAME, NULL,       NULL, FALSE },
 	{ NULL, NULL, NULL, FALSE }
 };
 
 static const NameItem nmc_olpc_mesh_settings [] = {
 	{ NM_SETTING_CONNECTION_SETTING_NAME, NULL,        NULL, TRUE  },
 	{ NM_SETTING_OLPC_MESH_SETTING_NAME,  "olpc-mesh", NULL, TRUE  },
-	{ NM_SETTING_IP4_CONFIG_SETTING_NAME, NULL,        NULL, FALSE },
-	{ NM_SETTING_IP6_CONFIG_SETTING_NAME, NULL,        NULL, FALSE },
 	{ NULL, NULL, NULL, FALSE }
 };
 
 static const NameItem nmc_vpn_settings [] = {
 	{ NM_SETTING_CONNECTION_SETTING_NAME, NULL,   NULL, TRUE  },
 	{ NM_SETTING_VPN_SETTING_NAME,        NULL,   NULL, TRUE  },
-	{ NM_SETTING_IP4_CONFIG_SETTING_NAME, NULL,   NULL, FALSE },
-	{ NM_SETTING_IP6_CONFIG_SETTING_NAME, NULL,   NULL, FALSE },
 	{ NULL, NULL, NULL, FALSE }
 };
 
@@ -2764,8 +2740,6 @@ static const NameItem nmc_vlan_settings [] = {
 	{ NM_SETTING_CONNECTION_SETTING_NAME, NULL,       NULL, TRUE  },
 	{ NM_SETTING_WIRED_SETTING_NAME,      "ethernet", NULL, FALSE },
 	{ NM_SETTING_VLAN_SETTING_NAME,       NULL,       NULL, TRUE  },
-	{ NM_SETTING_IP4_CONFIG_SETTING_NAME, NULL,       NULL, FALSE },
-	{ NM_SETTING_IP6_CONFIG_SETTING_NAME, NULL,       NULL, FALSE },
 	{ NULL, NULL, NULL, FALSE }
 };
 
@@ -2773,8 +2747,6 @@ static const NameItem nmc_bond_settings [] = {
 	{ NM_SETTING_CONNECTION_SETTING_NAME, NULL,       NULL, TRUE  },
 	{ NM_SETTING_BOND_SETTING_NAME,       NULL,       NULL, TRUE  },
 	{ NM_SETTING_WIRED_SETTING_NAME,      "ethernet", NULL, FALSE },
-	{ NM_SETTING_IP4_CONFIG_SETTING_NAME, NULL,       NULL, FALSE },
-	{ NM_SETTING_IP6_CONFIG_SETTING_NAME, NULL,       NULL, FALSE },
 	{ NULL, NULL, NULL, FALSE }
 };
 
@@ -2782,8 +2754,6 @@ static const NameItem nmc_team_settings [] = {
 	{ NM_SETTING_CONNECTION_SETTING_NAME, NULL,       NULL, TRUE  },
 	{ NM_SETTING_TEAM_SETTING_NAME,       NULL,       NULL, TRUE  },
 	{ NM_SETTING_WIRED_SETTING_NAME,      "ethernet", NULL, FALSE },
-	{ NM_SETTING_IP4_CONFIG_SETTING_NAME, NULL,       NULL, FALSE },
-	{ NM_SETTING_IP6_CONFIG_SETTING_NAME, NULL,       NULL, FALSE },
 	{ NULL, NULL, NULL, FALSE }
 };
 
@@ -2791,31 +2761,26 @@ static const NameItem nmc_bridge_settings [] = {
 	{ NM_SETTING_CONNECTION_SETTING_NAME, NULL,       NULL, TRUE  },
 	{ NM_SETTING_BRIDGE_SETTING_NAME,     NULL,       NULL, TRUE  },
 	{ NM_SETTING_WIRED_SETTING_NAME,      "ethernet", NULL, FALSE },
-	{ NM_SETTING_IP4_CONFIG_SETTING_NAME, NULL,       NULL, FALSE },
-	{ NM_SETTING_IP6_CONFIG_SETTING_NAME, NULL,       NULL, FALSE },
 	{ NULL, NULL, NULL, FALSE }
 };
 
 static const NameItem nmc_bond_slave_settings [] = {
-	{ NM_SETTING_CONNECTION_SETTING_NAME, NULL,       NULL, TRUE  },
-	{ NM_SETTING_WIRED_SETTING_NAME,      "ethernet", NULL, TRUE  },
-	{ NM_SETTING_802_1X_SETTING_NAME,     NULL,       NULL, FALSE },
 	{ NULL, NULL, NULL, FALSE }
 };
 
 static const NameItem nmc_team_slave_settings [] = {
-	{ NM_SETTING_CONNECTION_SETTING_NAME, NULL,       NULL, TRUE  },
-	{ NM_SETTING_WIRED_SETTING_NAME,      "ethernet", NULL, TRUE  },
 	{ NM_SETTING_TEAM_PORT_SETTING_NAME,  NULL,       NULL, TRUE  },
-	{ NM_SETTING_802_1X_SETTING_NAME,     NULL,       NULL, FALSE },
 	{ NULL, NULL, NULL, FALSE }
 };
 
 static const NameItem nmc_bridge_slave_settings [] = {
-	{ NM_SETTING_CONNECTION_SETTING_NAME,  NULL,       NULL, TRUE  },
 	{ NM_SETTING_BRIDGE_PORT_SETTING_NAME, NULL,       NULL, TRUE  },
-	{ NM_SETTING_WIRED_SETTING_NAME,       "ethernet", NULL, TRUE  },
-	{ NM_SETTING_802_1X_SETTING_NAME,      NULL,       NULL, FALSE },
+	{ NULL, NULL, NULL, FALSE }
+};
+
+static const NameItem nmc_no_slave_settings [] = {
+	{ NM_SETTING_IP4_CONFIG_SETTING_NAME, NULL,   NULL, FALSE },
+	{ NM_SETTING_IP6_CONFIG_SETTING_NAME, NULL,   NULL, FALSE },
 	{ NULL, NULL, NULL, FALSE }
 };
 
@@ -2823,16 +2788,12 @@ static const NameItem nmc_tun_settings [] = {
 	{ NM_SETTING_CONNECTION_SETTING_NAME, NULL,       NULL, TRUE  },
 	{ NM_SETTING_TUN_SETTING_NAME,        NULL,       NULL, TRUE  },
 	{ NM_SETTING_WIRED_SETTING_NAME,      "ethernet", NULL, FALSE },
-	{ NM_SETTING_IP4_CONFIG_SETTING_NAME, NULL,       NULL, FALSE },
-	{ NM_SETTING_IP6_CONFIG_SETTING_NAME, NULL,       NULL, FALSE },
 	{ NULL, NULL, NULL, FALSE }
 };
 
 static const NameItem nmc_ip_tunnel_settings [] = {
 	{ NM_SETTING_CONNECTION_SETTING_NAME, NULL,       NULL, TRUE  },
 	{ NM_SETTING_IP_TUNNEL_SETTING_NAME,  NULL,       NULL, TRUE  },
-	{ NM_SETTING_IP4_CONFIG_SETTING_NAME, NULL,       NULL, FALSE },
-	{ NM_SETTING_IP6_CONFIG_SETTING_NAME, NULL,       NULL, FALSE },
 	{ NULL, NULL, NULL, FALSE }
 };
 
@@ -2840,8 +2801,6 @@ static const NameItem nmc_macvlan_settings [] = {
 	{ NM_SETTING_CONNECTION_SETTING_NAME, NULL,       NULL, TRUE  },
 	{ NM_SETTING_WIRED_SETTING_NAME,      "ethernet", NULL, FALSE },
 	{ NM_SETTING_MACVLAN_SETTING_NAME,    NULL,       NULL, TRUE  },
-	{ NM_SETTING_IP4_CONFIG_SETTING_NAME, NULL,       NULL, FALSE },
-	{ NM_SETTING_IP6_CONFIG_SETTING_NAME, NULL,       NULL, FALSE },
 	{ NULL, NULL, NULL, FALSE }
 };
 
@@ -2849,8 +2808,6 @@ static const NameItem nmc_vxlan_settings [] = {
 	{ NM_SETTING_CONNECTION_SETTING_NAME,  NULL,       NULL, TRUE  },
 	{ NM_SETTING_VXLAN_SETTING_NAME,       NULL,       NULL, TRUE  },
 	{ NM_SETTING_WIRED_SETTING_NAME,       "ethernet", NULL, FALSE },
-	{ NM_SETTING_IP4_CONFIG_SETTING_NAME,  NULL,       NULL, FALSE },
-	{ NM_SETTING_IP6_CONFIG_SETTING_NAME,  NULL,       NULL, FALSE },
 	{ NULL, NULL, NULL, FALSE }
 };
 
@@ -2875,6 +2832,7 @@ static const NameItem nmc_valid_connection_types[] = {
 	{ "bond-slave",                       NULL,        nmc_bond_slave_settings   },
 	{ "team-slave",                       NULL,        nmc_team_slave_settings   },
 	{ "bridge-slave",                     NULL,        nmc_bridge_slave_settings },
+	{ "no-slave",                         NULL,        nmc_no_slave_settings     },
 	{ NM_SETTING_TUN_SETTING_NAME,        NULL,        nmc_tun_settings          },
 	{ NM_SETTING_IP_TUNNEL_SETTING_NAME,  NULL,        nmc_ip_tunnel_settings    },
 	{ NM_SETTING_MACVLAN_SETTING_NAME,    NULL,        nmc_macvlan_settings      },
@@ -2907,32 +2865,53 @@ get_name_alias (const char *name, const NameItem array[])
 }
 
 /*
- * Construct a string with names and aliases from the array formatted as:
+ * Construct a string with names and aliases from the arrays formatted as:
  * "name (alias), name, name (alias), name, name"
  *
  * Returns: string; the caller is responsible for freeing it.
  */
 static char *
-get_valid_options_string (const NameItem array[])
+get_valid_options_string (const NameItem *array, const NameItem *array_slv)
 {
-	const NameItem *iter = &array[0];
+	const NameItem *iter = array;
 	GString *str;
+	int i;
 
 	str = g_string_sized_new (150);
-	while (iter && iter->name) {
-		if (str->len)
-			g_string_append (str, ", ");
-		if (iter->alias)
-			g_string_append_printf (str, "%s (%s)", iter->name, iter->alias);
-		else
-			g_string_append (str, iter->name);
-		iter++;
+
+	for (i = 0; i < 2; i++, iter = array_slv) {
+		while (iter && iter->name) {
+			if (str->len)
+				g_string_append (str, ", ");
+			if (iter->alias)
+				g_string_append_printf (str, "%s (%s)", iter->name, iter->alias);
+			else
+				g_string_append (str, iter->name);
+			iter++;
+		}
 	}
 	return g_string_free (str, FALSE);
 }
 
+static const NameItem *
+get_valid_settings_array (const char *con_type)
+{
+	guint i, num;
+
+	if (!con_type)
+		return NULL;
+
+	num = G_N_ELEMENTS (nmc_valid_connection_types);
+	for (i = 0; i < num; i++) {
+		if (nm_streq0 (con_type, nmc_valid_connection_types[i].name))
+			return nmc_valid_connection_types[i].settings;
+	}
+	return NULL;
+}
+
 /*
- * Check if 'val' is valid string in either array->name or array->alias.
+ * Check if 'val' is valid string in either array->name or array->alias for
+ * both array parameters (array & array_slv).
  * It accepts shorter string provided they are not ambiguous.
  * 'val' == NULL doesn't hurt.
  *
@@ -2940,21 +2919,27 @@ get_valid_options_string (const NameItem array[])
  * The returned string must not be freed.
  */
 static const char *
-check_valid_name (const char *val, const NameItem array[], GError **error)
+check_valid_name (const char *val, const NameItem *array, const NameItem *array_slv, GError **error)
 {
 	const NameItem *iter;
-	GPtrArray *tmp_arr;
+	gs_unref_ptrarray GPtrArray *tmp_arr = NULL;
 	const char *str;
 	GError *tmp_err = NULL;
+	int i;
+
+	g_return_val_if_fail (val, NULL);
+	g_return_val_if_fail (array, NULL);
 
 	/* Create a temporary array that can be used in nmc_string_is_valid() */
-	tmp_arr = g_ptr_array_sized_new (30);
-	iter = &array[0];
-	while (iter && iter->name) {
-		g_ptr_array_add (tmp_arr, (gpointer) iter->name);
-		if (iter->alias)
-			g_ptr_array_add (tmp_arr, (gpointer) iter->alias);
-		iter++;
+	tmp_arr = g_ptr_array_sized_new (32);
+	iter = array;
+	for (i = 0; i < 2; i++, iter = array_slv) {
+		while (iter && iter->name) {
+			g_ptr_array_add (tmp_arr, (gpointer) iter->name);
+			if (iter->alias)
+				g_ptr_array_add (tmp_arr, (gpointer) iter->alias);
+			iter++;
+		}
 	}
 	g_ptr_array_add (tmp_arr, (gpointer) NULL);
 
@@ -2965,48 +2950,33 @@ check_valid_name (const char *val, const NameItem array[], GError **error)
 			g_propagate_error (error, tmp_err);
 		else {
 			/* We want to handle aliases, so construct own error message */
-			char *err_str = get_valid_options_string (array);
+			char *err_str = get_valid_options_string (array, array_slv);
+
 			g_set_error (error, 1, 0, _("'%s' not among [%s]"),
-			             val ? val : "", err_str);
+			             val, err_str);
 			g_free (err_str);
 			g_clear_error (&tmp_err);
 		}
-		g_ptr_array_free (tmp_arr, TRUE);
 		return NULL;
 	}
 
 	/* Return a pointer to the found string in passed 'array' */
-	iter = &array[0];
-	while (iter && iter->name) {
-		if (   (iter->name && g_strcmp0 (iter->name, str) == 0)
-		    || (iter->alias && g_strcmp0 (iter->alias, str) == 0)) {
-			g_ptr_array_free (tmp_arr, TRUE);
-			return iter->name;
+	iter = array;
+	for (i = 0; i < 2; i++, iter = array_slv) {
+		while (iter && iter->name) {
+			if (   nm_streq (iter->name, str)
+			    || nm_streq0 (iter->alias, str)) {
+				return iter->name;
+			}
+			iter++;
 		}
-		iter++;
 	}
+
 	/* We should not really come here */
-	g_ptr_array_free (tmp_arr, TRUE);
 	g_set_error (error, 1, 0, _("Unknown error"));
 	return NULL;
 }
 
-static const NameItem *
-get_valid_settings_array (const char *con_type)
-{
-	guint i, num;
-
-	if (!con_type)
-		return NULL;
-
-	num = G_N_ELEMENTS (nmc_valid_connection_types);
-        for (i = 0; i < num; i++) {
-		if (!g_strcmp0 (con_type, nmc_valid_connection_types[i].name))
-			return nmc_valid_connection_types[i].settings;
-	}
-	return NULL;
-}
-
 static gboolean
 is_setting_mandatory (NMConnection *connection, NMSetting *setting)
 {
@@ -3014,6 +2984,8 @@ is_setting_mandatory (NMConnection *connection, NMSetting *setting)
 	const char *c_type;
 	const NameItem *item;
 	const char *name;
+	const char *s_type;
+	char *slv_type;
 
 	s_con = nm_connection_get_setting_connection (connection);
 	g_assert (s_con);
@@ -3027,6 +2999,18 @@ is_setting_mandatory (NMConnection *connection, NMSetting *setting)
 			return item->mandatory;
 		item++;
 	}
+
+	/* Let's give a try to parameters related to slave type */
+	s_type = nm_setting_connection_get_slave_type (s_con);
+	slv_type = g_strdup_printf ("%s-slave", s_type ? s_type : "no");
+	item = get_valid_settings_array (slv_type);
+	g_free (slv_type);
+	while (item && item->name) {
+		if (!strcmp (name, item->name))
+			return item->mandatory;
+		item++;
+	}
+
 	return FALSE;
 }
 
@@ -4482,11 +4466,11 @@ do_questionnaire_ip (NMConnection *connection)
 }
 
 static NMSetting *
-is_setting_valid (NMConnection *connection, const NameItem *valid_settings, char *setting)
+is_setting_valid (NMConnection *connection, const NameItem *valid_settings_main, const NameItem *valid_settings_slave, char *setting)
 {
 	const char *setting_name;
 
-	if (!(setting_name = check_valid_name (setting, valid_settings, NULL)))
+	if (!(setting_name = check_valid_name (setting, valid_settings_main, valid_settings_slave, NULL)))
 		return NULL;
 	return nm_connection_get_setting_by_name (connection, setting_name);
 }
@@ -4639,6 +4623,7 @@ read_connection_properties (NMConnection *connection,
 	const char *s_dot_p;
 	const char *value;
 	char **strv = NULL;
+	char *slv_type = NULL;
 	const char *setting_name;
 	gboolean append = FALSE;
 	gboolean remove = FALSE;
@@ -4647,6 +4632,16 @@ read_connection_properties (NMConnection *connection,
 
 	s_con = nm_connection_get_setting_connection (connection);
 	g_assert (s_con);
+
+	/* First check if we have a slave-type, as this would mean we will not
+	 * have ip properties but possibly others, slave-type specific.
+	 */
+	con_type = nm_setting_connection_get_slave_type (s_con);
+	if (!con_type)
+		con_type = "no";
+
+	slv_type = g_strdup_printf ("%s-slave", con_type);
+
 	con_type = nm_setting_connection_get_connection_type (s_con);
 
 	/* Go through arguments and set properties */
@@ -4687,7 +4682,8 @@ read_connection_properties (NMConnection *connection,
 			goto finish;
 		}
 
-		setting_name = check_valid_name (strv[0], get_valid_settings_array (con_type), &local);
+		setting_name = check_valid_name (strv[0], get_valid_settings_array (con_type),
+		                                 get_valid_settings_array (slv_type), &local);
 		if (!setting_name) {
 			g_set_error (error, NMCLI_ERROR, NMC_RESULT_ERROR_USER_INPUT,
 			             _("Error: invalid or not allowed setting '%s': %s."),
@@ -4759,6 +4755,7 @@ read_connection_properties (NMConnection *connection,
 finish:
 	if (strv)
 		g_strfreev (strv);
+	g_free (slv_type);
 	return success;
 }
 
@@ -4802,6 +4799,7 @@ complete_slave (NMSettingConnection *s_con,
 		/* Change properties in 'connection' setting */
 		g_object_set (s_con,
 		              NM_SETTING_CONNECTION_MASTER, checked_master,
+		              NM_SETTING_CONNECTION_SLAVE_TYPE, slave_type,
 		              NULL);
 
 		g_free (master_ask);
@@ -4842,7 +4840,6 @@ complete_connection_by_type (NMConnection *connection,
 	NMSettingIPTunnel *s_ip_tunnel;
 	NMSettingMacvlan *s_macvlan;
 	NMSettingVxlan *s_vxlan;
-	const char *slave_type;
 
 	g_return_val_if_fail (error == NULL || *error == NULL, FALSE);
 
@@ -5545,12 +5542,24 @@ cleanup_bond:
 			return FALSE;
 
 	} else if (!strcmp (con_type, "bond-slave")) {
+		/* Slave types without any specific settings ('bond-slave') */
+		const char *master = NULL;
+		const char *type = NULL;
+		nmc_arg_t exp_args[] = { {"master", TRUE, &master, FALSE},
+		                         {"type",   TRUE, &type,   FALSE},
+		                         {NULL} };
+
+		/* Set global variables for use in TAB completion */
+		nmc_tab_completion.con_type = NM_SETTING_BOND_SETTING_NAME;
+
+		if (!nmc_parse_args (exp_args, FALSE, &argc, &argv, error))
+			return FALSE;
+
+		if (!complete_slave (s_con, all_connections, NM_SETTING_BOND_SETTING_NAME, master, type, ask, error))
+			return FALSE;
 
 		/* Change properties in 'connection' setting */
-		g_object_set (s_con,
-		              NM_SETTING_CONNECTION_TYPE, NM_SETTING_WIRED_SETTING_NAME,
-		              NM_SETTING_CONNECTION_SLAVE_TYPE, NM_SETTING_BOND_SETTING_NAME,
-		              NULL);
+		g_object_set (s_con, NM_SETTING_CONNECTION_TYPE, NM_SETTING_WIRED_SETTING_NAME, NULL);
 
 		/* Add ethernet setting */
 		s_wired = (NMSettingWired *) nm_setting_wired_new ();
@@ -5605,12 +5614,55 @@ cleanup_team:
 			return FALSE;
 
 	} else if (!strcmp (con_type, "team-slave")) {
+		/* Build up the settings required for 'team-slave' */
+		gboolean success = FALSE;
+		const char *master = NULL;
+		char *master_ask = NULL;
+		const char *type = NULL;
+		const char *config_c = NULL;
+		char *config = NULL;
+		char *json = NULL;
+		nmc_arg_t exp_args[] = { {"master", TRUE, &master,   FALSE},
+		                         {"type",   TRUE, &type,     FALSE},
+		                         {"config", TRUE, &config_c, FALSE},
+		                         {NULL} };
+
+		/* Set global variables for use in TAB completion */
+		nmc_tab_completion.con_type = NM_SETTING_TEAM_SETTING_NAME;
+
+		if (!nmc_parse_args (exp_args, FALSE, &argc, &argv, error))
+			return FALSE;
+
+		if (!complete_slave (s_con, all_connections, NM_SETTING_TEAM_SETTING_NAME, master, type, ask, error))
+			return FALSE;
+
+		/* Also ask for all optional arguments if '--ask' is specified. */
+		config = g_strdup (config_c);
+		if (ask)
+			do_questionnaire_team_slave (&config);
+
+		/* Add 'team-port' setting */
+		s_team_port = (NMSettingTeamPort *) nm_setting_team_port_new ();
+		nm_connection_add_setting (connection, NM_SETTING (s_team_port));
+
+		if (!nmc_team_check_config (config, &json, error)) {
+			g_prefix_error (error, _("Error: "));
+			goto cleanup_team_slave;
+		}
+
+		/* Set team-port options */
+		g_object_set (s_team_port, NM_SETTING_TEAM_PORT_CONFIG, json, NULL);
+
+		success = TRUE;
+cleanup_team_slave:
+		g_free (master_ask);
+		g_free (config);
+		g_free (json);
+		if (!success)
+			return FALSE;
 
 		/* Change properties in 'connection' setting */
-		g_object_set (s_con,
-		              NM_SETTING_CONNECTION_TYPE, NM_SETTING_WIRED_SETTING_NAME,
-		              NM_SETTING_CONNECTION_SLAVE_TYPE, NM_SETTING_TEAM_SETTING_NAME,
-		              NULL);
+		g_object_set (s_con, NM_SETTING_CONNECTION_TYPE, NM_SETTING_WIRED_SETTING_NAME, NULL);
 
 		/* Add ethernet setting */
 		s_wired = (NMSettingWired *) nm_setting_wired_new ();
@@ -5755,12 +5807,83 @@ cleanup_bridge:
 			return FALSE;
 
 	} else if (!strcmp (con_type, "bridge-slave")) {
+		/* Build up the settings required for 'bridge-slave' */
+		gboolean success = FALSE;
+		const char *master = NULL;
+		char *master_ask = NULL;
+		const char *type = NULL;
+		const char *priority_c = NULL;
+		char *priority = NULL;
+		const char *path_cost_c = NULL;
+		char *path_cost = NULL;
+		const char *hairpin_c = NULL;
+		char *hairpin = NULL;
+		unsigned long prio_int, path_cost_int;
+		gboolean hairpin_bool;
+		nmc_arg_t exp_args[] = { {"master",    TRUE, &master,      FALSE},
+		                         {"type",      TRUE, &type,        FALSE},
+		                         {"priority",  TRUE, &priority_c,  FALSE},
+		                         {"path-cost", TRUE, &path_cost_c, FALSE},
+		                         {"hairpin",   TRUE, &hairpin_c,   FALSE},
+		                         {NULL} };
+
+		/* Set global variables for use in TAB completion */
+		nmc_tab_completion.con_type = NM_SETTING_BRIDGE_SETTING_NAME;
+
+		if (!nmc_parse_args (exp_args, FALSE, &argc, &argv, error))
+			return FALSE;
+
+		if (!complete_slave (s_con, all_connections, NM_SETTING_BRIDGE_SETTING_NAME, master, type, ask, error))
+			return FALSE;
+
+		/* Add 'bridge-port' setting */
+		/* Must be done *before* bridge_prop_string_to_uint() so that the type is known */
+		s_bridge_port = (NMSettingBridgePort *) nm_setting_bridge_port_new ();
+		nm_connection_add_setting (connection, NM_SETTING (s_bridge_port));
+
+		/* Also ask for all optional arguments if '--ask' is specified. */
+		priority = g_strdup (priority_c);
+		path_cost = g_strdup (path_cost_c);
+		hairpin = g_strdup (hairpin_c);
+		if (ask)
+			do_questionnaire_bridge_slave (&priority, &path_cost, &hairpin);
+
+		if (priority)
+			if (!bridge_prop_string_to_uint (priority, "priority", NM_TYPE_SETTING_BRIDGE_PORT,
+							 NM_SETTING_BRIDGE_PORT_PRIORITY, &prio_int, error))
+				goto cleanup_bridge_slave;
+		if (path_cost)
+			if (!bridge_prop_string_to_uint (path_cost, "path-cost", NM_TYPE_SETTING_BRIDGE_PORT,
+							 NM_SETTING_BRIDGE_PORT_PATH_COST, &path_cost_int, error))
+				goto cleanup_bridge_slave;
+		if (hairpin) {
+			GError *tmp_err = NULL;
+			if (!nmc_string_to_bool (hairpin, &hairpin_bool, &tmp_err)) {
+				g_set_error (error, NMCLI_ERROR, NMC_RESULT_ERROR_USER_INPUT,
+					     _("Error: 'hairpin': %s."), tmp_err->message);
+				g_clear_error (&tmp_err);
+				goto cleanup_bridge_slave;
+			}
+		}
+
+		if (priority)
+			g_object_set (s_bridge_port, NM_SETTING_BRIDGE_PORT_PRIORITY, prio_int, NULL);
+		if (path_cost)
+			g_object_set (s_bridge_port, NM_SETTING_BRIDGE_PORT_PATH_COST, path_cost_int, NULL);
+		if (hairpin)
+			g_object_set (s_bridge_port, NM_SETTING_BRIDGE_PORT_HAIRPIN_MODE, hairpin_bool, NULL);
+
+		success = TRUE;
+cleanup_bridge_slave:
+		g_free (master_ask);
+		g_free (priority);
+		g_free (path_cost);
+		g_free (hairpin);
+		if (!success)
+			return FALSE;
 
 		/* Change properties in 'connection' setting */
-		g_object_set (s_con,
-		              NM_SETTING_CONNECTION_TYPE, NM_SETTING_WIRED_SETTING_NAME,
-		              NM_SETTING_CONNECTION_SLAVE_TYPE, NM_SETTING_BRIDGE_SETTING_NAME,
-		              NULL);
+		g_object_set (s_con, NM_SETTING_CONNECTION_TYPE, NM_SETTING_WIRED_SETTING_NAME, NULL);
 
 		/* Add ethernet setting */
 		s_wired = (NMSettingWired *) nm_setting_wired_new ();
@@ -6064,7 +6187,7 @@ cleanup_macvlan:
 		                         {"pi",          TRUE,  &pi_c,          FALSE},
 		                         {"vnet-hdr",    TRUE,  &vnet_hdr_c,    FALSE},
 		                         {"multi-queue", TRUE,  &multi_queue_c, FALSE},
-                                         {NULL} };
+		                         {NULL} };
 
 		if (!nmc_parse_args (exp_args, FALSE, &argc, &argv, error))
 			return FALSE;
@@ -6416,145 +6539,7 @@ cleanup_vxlan:
 		return FALSE;
 	}
 
-	slave_type = nm_setting_connection_get_slave_type (s_con);
-	if (slave_type) {
-
-		/* Set global variables for use in TAB completion */
-		nmc_tab_completion.con_type = (char *)slave_type;
-
-		if (!strcmp (slave_type, NM_SETTING_TEAM_SETTING_NAME)) {
-			/* Build up the settings required for 'team-slave' */
-			gboolean success = FALSE;
-			const char *master = NULL;
-			char *master_ask = NULL;
-			const char *type = NULL;
-			const char *config_c = NULL;
-			char *config = NULL;
-			char *json = NULL;
-			nmc_arg_t exp_args[] = { {"master", TRUE, &master,   FALSE},
-						 {"type",   TRUE, &type,     FALSE},
-						 {"config", TRUE, &config_c, FALSE},
-						 {NULL} };
-
-			if (!nmc_parse_args (exp_args, FALSE, &argc, &argv, error))
-				return FALSE;
-
-			if (!complete_slave (s_con, all_connections, slave_type, master, type, ask, error))
-				return FALSE;
-
-			/* Also ask for all optional arguments if '--ask' is specified. */
-			config = g_strdup (config_c);
-			if (ask)
-				do_questionnaire_team_slave (&config);
-
-			/* Add 'team-port' setting */
-			s_team_port = (NMSettingTeamPort *) nm_setting_team_port_new ();
-			nm_connection_add_setting (connection, NM_SETTING (s_team_port));
-
-			if (!nmc_team_check_config (config, &json, error)) {
-				g_prefix_error (error, _("Error: "));
-				goto cleanup_team_slave;
-			}
-
-			/* Set team-port options */
-			g_object_set (s_team_port, NM_SETTING_TEAM_PORT_CONFIG, json, NULL);
-
-			success = TRUE;
-cleanup_team_slave:
-			g_free (master_ask);
-			g_free (config);
-			g_free (json);
-			if (!success)
-				return FALSE;
-
-		} else if (!strcmp (slave_type, NM_SETTING_BRIDGE_SETTING_NAME)) {
-			/* Build up the settings required for 'bridge-slave' */
-			gboolean success = FALSE;
-			const char *master = NULL;
-			char *master_ask = NULL;
-			const char *type = NULL;
-			const char *priority_c = NULL;
-			char *priority = NULL;
-			const char *path_cost_c = NULL;
-			char *path_cost = NULL;
-			const char *hairpin_c = NULL;
-			char *hairpin = NULL;
-			unsigned long prio_int, path_cost_int;
-			gboolean hairpin_bool;
-			nmc_arg_t exp_args[] = { {"master",    TRUE, &master,      FALSE},
-						 {"type",      TRUE, &type,        FALSE},
-						 {"priority",  TRUE, &priority_c,  FALSE},
-						 {"path-cost", TRUE, &path_cost_c, FALSE},
-						 {"hairpin",   TRUE, &hairpin_c,   FALSE},
-						 {NULL} };
-
-			if (!nmc_parse_args (exp_args, FALSE, &argc, &argv, error))
-				return FALSE;
-
-			if (!complete_slave (s_con, all_connections, slave_type, master, type, ask, error))
-				return FALSE;
-
-			/* Add 'bridge-port' setting */
-			/* Must be done *before* bridge_prop_string_to_uint() so that the type is known */
-			s_bridge_port = (NMSettingBridgePort *) nm_setting_bridge_port_new ();
-			nm_connection_add_setting (connection, NM_SETTING (s_bridge_port));
-
-			/* Also ask for all optional arguments if '--ask' is specified. */
-			priority = g_strdup (priority_c);
-			path_cost = g_strdup (path_cost_c);
-			hairpin = g_strdup (hairpin_c);
-			if (ask)
-				do_questionnaire_bridge_slave (&priority, &path_cost, &hairpin);
-
-			if (priority)
-				if (!bridge_prop_string_to_uint (priority, "priority", NM_TYPE_SETTING_BRIDGE_PORT,
-								 NM_SETTING_BRIDGE_PORT_PRIORITY, &prio_int, error))
-					goto cleanup_bridge_slave;
-			if (path_cost)
-				if (!bridge_prop_string_to_uint (path_cost, "path-cost", NM_TYPE_SETTING_BRIDGE_PORT,
-								 NM_SETTING_BRIDGE_PORT_PATH_COST, &path_cost_int, error))
-					goto cleanup_bridge_slave;
-			if (hairpin) {
-				GError *tmp_err = NULL;
-				if (!nmc_string_to_bool (hairpin, &hairpin_bool, &tmp_err)) {
-					g_set_error (error, NMCLI_ERROR, NMC_RESULT_ERROR_USER_INPUT,
-						     _("Error: 'hairpin': %s."), tmp_err->message);
-					g_clear_error (&tmp_err);
-					goto cleanup_bridge_slave;
-				}
-			}
-
-			if (priority)
-				g_object_set (s_bridge_port, NM_SETTING_BRIDGE_PORT_PRIORITY, prio_int, NULL);
-			if (path_cost)
-				g_object_set (s_bridge_port, NM_SETTING_BRIDGE_PORT_PATH_COST, path_cost_int, NULL);
-			if (hairpin)
-				g_object_set (s_bridge_port, NM_SETTING_BRIDGE_PORT_HAIRPIN_MODE, hairpin_bool, NULL);
-
-			success = TRUE;
-cleanup_bridge_slave:
-			g_free (master_ask);
-			g_free (priority);
-			g_free (path_cost);
-			g_free (hairpin);
-			if (!success)
-				return FALSE;
-		} else {
-			/* Slave types without any specific settings ('bond-slave') */
-			const char *master = NULL;
-			const char *type = NULL;
-			nmc_arg_t exp_args[] = { {"master", TRUE, &master, FALSE},
-						 {"type",   TRUE, &type,   FALSE},
-						 {NULL} };
-
-			if (!nmc_parse_args (exp_args, FALSE, &argc, &argv, error))
-				return FALSE;
-
-			if (!complete_slave (s_con, all_connections, slave_type, master, type, ask, error))
-				return FALSE;
-		}
-
-	} else {
+	if (!nm_setting_connection_get_slave_type (s_con)) {
 		/* Read and add IP configuration */
 		NMIPAddress *ip4addr = NULL, *ip6addr = NULL;
 		const char *ip4 = NULL, *gw4 = NULL, *ip6 = NULL, *gw6 = NULL;
@@ -6649,7 +6634,7 @@ cleanup_bridge_slave:
 	if (argc) {
 		/* Set extra connection properties. */
 		nmc_arg_t exp_args[] = { {"--", FALSE, NULL, TRUE},
-					 {NULL} };
+		                         {NULL} };
 
 		if (!nmc_parse_args (exp_args, FALSE, &argc, &argv, error))
 			return FALSE;
@@ -6954,7 +6939,7 @@ do_connection_add (NmCli *nmc, int argc, char **argv)
 	}
 
 	if (!type && nmc->ask) {
-		char *types_tmp = get_valid_options_string (nmc_valid_connection_types);
+		char *types_tmp = get_valid_options_string (nmc_valid_connection_types, NULL);
 		g_print ("Valid types: [%s]\n", types_tmp);
 		type = type_ask = nmc_readline (PROMPT_CON_TYPE);
 		g_free (types_tmp);
@@ -6967,7 +6952,7 @@ do_connection_add (NmCli *nmc, int argc, char **argv)
 	if (type_ask)
 		type = g_strstrip (type_ask);
 
-	if (!(setting_name = check_valid_name (type, nmc_valid_connection_types, &error))) {
+	if (!(setting_name = check_valid_name (type, nmc_valid_connection_types, NULL, &error))) {
 		g_string_printf (nmc->return_text, _("Error: invalid connection type; %s."),
 		                 error->message);
 		nmc->return_value = NMC_RESULT_ERROR_USER_INPUT;
@@ -7250,18 +7235,48 @@ gen_connection_types (const char *text, int state)
 static char *
 gen_setting_names (const char *text, int state)
 {
-	static int list_idx, len;
+	static int list_idx, len, is_slv;
 	const char *s_name, *a_name;
 	const NameItem *valid_settings_arr;
+	NMSettingConnection *s_con;
+	const char *s_type = NULL;
+	char *slv_type;
 
 	if (!state) {
 		list_idx = 0;
 		len = strlen (text);
+		is_slv = 0;
 	}
 
-	valid_settings_arr = get_valid_settings_array (nmc_tab_completion.con_type);
-	if (!valid_settings_arr)
-		return NULL;
+	if (!is_slv) {
+		valid_settings_arr = get_valid_settings_array (nmc_tab_completion.con_type);
+		if (!valid_settings_arr)
+			return NULL;
+		while (valid_settings_arr[list_idx].name) {
+			a_name = valid_settings_arr[list_idx].alias;
+			s_name = valid_settings_arr[list_idx].name;
+			list_idx++;
+			if (len == 0 && a_name)
+				return g_strdup_printf ("%s (%s)", s_name, a_name);
+			if (a_name && !strncmp (text, a_name, len))
+				return g_strdup (a_name);
+			if (s_name && !strncmp (text, s_name, len))
+				return g_strdup (s_name);
+		}
+
+		/* Let's give a try to parameters related to slave type */
+		list_idx = 0;
+		is_slv = 1;
+	}
+
+	/* is_slv */
+	s_con = nm_connection_get_setting_connection (nmc_tab_completion.connection);
+	if (s_con)
+		s_type = nm_setting_connection_get_slave_type (s_con);
+	slv_type = g_strdup_printf ("%s-slave", s_type ? s_type : "no");
+	valid_settings_arr = get_valid_settings_array (slv_type);
+	g_free (slv_type);
+
 	while (valid_settings_arr[list_idx].name) {
 		a_name = valid_settings_arr[list_idx].alias;
 		s_name = valid_settings_arr[list_idx].name;
@@ -7273,6 +7288,7 @@ gen_setting_names (const char *text, int state)
 		if (s_name && !strncmp (text, s_name, len))
 			return g_strdup (s_name);
 	}
+
 	return NULL;
 }
 
@@ -7285,8 +7301,10 @@ gen_property_names (const char *text, int state)
 	const char *line = rl_line_buffer;
 	const char *setting_name;
 	char **strv = NULL;
-	const NameItem *valid_settings_arr;
+	const NameItem *valid_settings_main;
+	const NameItem *valid_settings_slave;
 	const char *p1;
+	const char *slv_type;
 
 	/* Try to get the setting from 'line' - setting_name.property */
 	p1 = strchr (line, '.');
@@ -7296,8 +7314,23 @@ gen_property_names (const char *text, int state)
 
 		strv = g_strsplit (p1+1, ".", 2);
 
-		valid_settings_arr = get_valid_settings_array (nmc_tab_completion.con_type);
-		setting_name = check_valid_name (strv[0], valid_settings_arr, NULL);
+		valid_settings_main = get_valid_settings_array (nmc_tab_completion.con_type);
+
+		/* Support autocompletion of slave-connection parameters
+		 * guessing the slave type from the setting name already
+		 * typed (or autocompleted) */
+		if (nm_streq0 (strv[0], NM_SETTING_TEAM_PORT_SETTING_NAME))
+			slv_type = "team-slave";
+		else if (nm_streq0 (strv[0], NM_SETTING_BRIDGE_PORT_SETTING_NAME))
+			slv_type = "bridge-slave";
+		else
+			slv_type = "no-slave";
+		valid_settings_slave = get_valid_settings_array (slv_type);
+
+		setting_name = check_valid_name (strv[0],
+		                                 valid_settings_main,
+		                                 valid_settings_slave,
+		                                 NULL);
 		setting = nmc_setting_new_for_name (setting_name);
 	} else {
 		/* Else take the current setting, if any */
@@ -7575,16 +7608,30 @@ static void
 get_setting_and_property (const char *prompt, const char *line,
                           NMSetting **setting_out, char**property_out)
 {
-	const NameItem *valid_settings_arr;
+	const NameItem *valid_settings_main;
+	const NameItem *valid_settings_slave;
 	const char *setting_name;
 	NMSetting *setting = NULL;
 	char *property = NULL;
 	char *sett = NULL, *prop = NULL;
+	NMSettingConnection *s_con;
+	const char *s_type = NULL;
+	char *slv_type;
 
 	extract_setting_and_property (prompt, line, &sett, &prop);
 	if (sett) {
-		valid_settings_arr = get_valid_settings_array (nmc_tab_completion.con_type);
-		setting_name = check_valid_name (sett, valid_settings_arr, NULL);
+		/* Is this too much (and useless?) effort for an unlikely case? */
+		s_con = nm_connection_get_setting_connection (nmc_tab_completion.connection);
+		if (s_con)
+			s_type = nm_setting_connection_get_slave_type (s_con);
+		slv_type = g_strdup_printf ("%s-slave", s_type ? s_type : "no");
+
+		valid_settings_main = get_valid_settings_array (nmc_tab_completion.con_type);
+		valid_settings_slave = get_valid_settings_array (slv_type);
+		g_free (slv_type);
+
+		setting_name = check_valid_name (sett, valid_settings_main,
+		                                 valid_settings_slave,  NULL);
 		setting = nmc_setting_new_for_name (setting_name);
 	} else
 		setting = nmc_tab_completion.setting ? g_object_ref (nmc_tab_completion.setting) : NULL;
@@ -7898,7 +7945,7 @@ load_history_cmds (const char *uuid)
 	filename = g_build_filename (g_get_home_dir (), NMCLI_EDITOR_HISTORY, NULL);
 	kf = g_key_file_new ();
 	if (!g_key_file_load_from_file (kf, filename, G_KEY_FILE_KEEP_COMMENTS, &err)) {
-		if (err->code == G_KEY_FILE_ERROR_PARSE)
+		if (g_error_matches (err, G_KEY_FILE_ERROR, G_KEY_FILE_ERROR_PARSE))
 			g_print ("Warning: %s parse error: %s\n", filename, err->message);
 		g_key_file_free (kf);
 		g_free (filename);
@@ -7933,8 +7980,8 @@ save_history_cmds (const char *uuid)
 		filename = g_build_filename (g_get_home_dir (), NMCLI_EDITOR_HISTORY, NULL);
 		kf = g_key_file_new ();
 		if (!g_key_file_load_from_file (kf, filename, G_KEY_FILE_KEEP_COMMENTS, &err)) {
-			if (   err->code != G_FILE_ERROR_NOENT
-			    && err->code != G_KEY_FILE_ERROR_NOT_FOUND) {
+			if (   !g_error_matches (err, G_FILE_ERROR, G_FILE_ERROR_NOENT)
+			    && !g_error_matches (err, G_KEY_FILE_ERROR, G_KEY_FILE_ERROR_NOT_FOUND)) {
 				g_print ("Warning: %s parse error: %s\n", filename, err->message);
 				g_key_file_free (kf);
 				g_free (filename);
@@ -8786,13 +8833,13 @@ split_editor_main_cmd_args (const char *str, char **setting, char **property, ch
 }
 
 static NMSetting *
-create_setting_by_name (const char *name, const NameItem *valid_settings)
+create_setting_by_name (const char *name, const NameItem *valid_settings_main, const NameItem *valid_settings_slave)
 {
 	const char *setting_name;
 	NMSetting *setting = NULL;
 
 	/* Get a valid setting name */
-	setting_name = check_valid_name (name, valid_settings, NULL);
+	setting_name = check_valid_name (name, valid_settings_main, valid_settings_slave, NULL);
 
 	if (setting_name) {
 		setting = nmc_setting_new_for_name (setting_name);
@@ -8805,7 +8852,8 @@ create_setting_by_name (const char *name, const NameItem *valid_settings)
 
 static const char *
 ask_check_setting (const char *arg,
-                   const NameItem *valid_settings_arr,
+                   const NameItem *valid_settings_main,
+                   const NameItem *valid_settings_slave,
                    const char *valid_settings_str)
 {
 	char *setting_name_user;
@@ -8821,7 +8869,10 @@ ask_check_setting (const char *arg,
 	if (setting_name_user)
 		g_strstrip (setting_name_user);
 
-	if (!(setting_name = check_valid_name (setting_name_user, valid_settings_arr, &err))) {
+	if (!(setting_name = check_valid_name (setting_name_user,
+	                                       valid_settings_main,
+	                                       valid_settings_slave,
+	                                       &err))) {
 		g_print (_("Error: invalid setting name; %s\n"), err->message);
 		g_clear_error (&err);
 	}
@@ -8946,6 +8997,7 @@ menu_switch_to_level1 (NmCli *nmc,
 static gboolean
 editor_menu_main (NmCli *nmc, NMConnection *connection, const char *connection_type)
 {
+	NMSettingConnection *s_con;
 	NMRemoteConnection *rem_con;
 	NMRemoteConnection *con_tmp;
 	GWeakRef weak = { { NULL } };
@@ -8956,16 +9008,27 @@ editor_menu_main (NmCli *nmc, NMConnection *connection, const char *connection_t
 	char *cmd_arg = NULL;
 	char *cmd_arg_s, *cmd_arg_p, *cmd_arg_v;
 	const char *BASE_PROMPT = "nmcli> ";
-	const NameItem *valid_settings_arr = NULL;
+	const NameItem *valid_settings_main = NULL;
+	const NameItem *valid_settings_slave = NULL;
 	char *valid_settings_str = NULL;
+	const char *s_type = NULL;
+	char *slv_type;
 	AddConnectionInfo *info = NULL;
 	gboolean dirty;
 	gboolean temp_changes;
 	GError *err1 = NULL;
 	NmcEditorMenuContext menu_ctx;
 
-	valid_settings_arr = get_valid_settings_array (connection_type);
-	valid_settings_str = get_valid_options_string (valid_settings_arr);
+	s_con = nm_connection_get_setting_connection (connection);
+	if (s_con)
+		s_type = nm_setting_connection_get_slave_type (s_con);
+	slv_type = g_strdup_printf ("%s-slave", s_type ? s_type : "no");
+
+	valid_settings_main = get_valid_settings_array (connection_type);
+	valid_settings_slave = get_valid_settings_array (slv_type);
+	g_free (slv_type);
+
+	valid_settings_str = get_valid_options_string (valid_settings_main, valid_settings_slave);
 	g_print (_("You may edit the following settings: %s\n"), valid_settings_str);
 
 	menu_ctx.level = 0;
@@ -9047,9 +9110,9 @@ editor_menu_main (NmCli *nmc, NMConnection *connection, const char *connection_t
 
 				if (cmd_arg_s) {
 					/* setting provided as "setting.property" */
-					ss = is_setting_valid (connection, valid_settings_arr, cmd_arg_s);
+					ss = is_setting_valid (connection, valid_settings_main, valid_settings_slave, cmd_arg_s);
 					if (!ss) {
-						ss = create_setting_by_name (cmd_arg_s, valid_settings_arr);
+						ss = create_setting_by_name (cmd_arg_s, valid_settings_main, valid_settings_slave);
 						if (!ss) {
 							g_print (_("Error: invalid setting argument '%s'; valid are [%s]\n"),
 							         cmd_arg_s, valid_settings_str);
@@ -9110,7 +9173,10 @@ editor_menu_main (NmCli *nmc, NMConnection *connection, const char *connection_t
 				NMSetting *setting;
 				const char *user_arg = cmd_arg_s ? cmd_arg_s : cmd_arg_p;
 
-				setting_name = ask_check_setting (user_arg, valid_settings_arr, valid_settings_str);
+				setting_name = ask_check_setting (user_arg,
+								  valid_settings_main,
+								  valid_settings_slave,
+								  valid_settings_str);
 				if (!setting_name)
 					break;
 
@@ -9185,10 +9251,17 @@ editor_menu_main (NmCli *nmc, NMConnection *connection, const char *connection_t
 				descr_all = !cmd_arg_s && !menu_ctx.curr_setting;
 				user_s = descr_all ? cmd_arg_p : cmd_arg_s ? cmd_arg_s : NULL;
 				if (user_s) {
-					ss = is_setting_valid (connection, valid_settings_arr, user_s);
+					ss = is_setting_valid (connection,
+							       valid_settings_main,
+							       valid_settings_slave,
+							       user_s);
 					if (!ss) {
-						if (check_valid_name (user_s, valid_settings_arr, NULL))
-							g_print (_("Setting '%s' is not present in the connection.\n"), user_s);
+						if (check_valid_name (user_s,
+						                      valid_settings_main,
+						                      valid_settings_slave,
+						                      NULL))
+							g_print (_("Setting '%s' is not present in the connection.\n"),
+								 user_s);
 						else
 							g_print (_("Error: invalid setting argument '%s'; valid are [%s]\n"),
 							         user_s, valid_settings_str);
@@ -9218,7 +9291,10 @@ editor_menu_main (NmCli *nmc, NMConnection *connection, const char *connection_t
 					} else {
 						/* If the string is not a property, try it as a setting */
 						NMSetting *s_tmp;
-						s_tmp = is_setting_valid (connection, valid_settings_arr, cmd_arg_p);
+						s_tmp = is_setting_valid (connection,
+									  valid_settings_main,
+									  valid_settings_slave,
+									  cmd_arg_p);
 						if (s_tmp) {
 							/* Remove setting from the connection */
 							connection_remove_setting (connection, s_tmp);
@@ -9266,9 +9342,14 @@ editor_menu_main (NmCli *nmc, NMConnection *connection, const char *connection_t
 				descr_all = !cmd_arg_s && !menu_ctx.curr_setting;
 				user_s = descr_all ? cmd_arg_p : cmd_arg_s ? cmd_arg_s : NULL;
 				if (user_s) {
-					ss = is_setting_valid (connection, valid_settings_arr, user_s);
+					ss = is_setting_valid (connection,
+							       valid_settings_main,
+							       valid_settings_slave,
+							       user_s);
 					if (!ss) {
-						ss = create_setting_by_name (user_s, valid_settings_arr);
+						ss = create_setting_by_name (user_s,
+									     valid_settings_main,
+									     valid_settings_slave);
 						if (!ss) {
 							g_print (_("Error: invalid setting argument '%s'; valid are [%s]\n"),
 							         user_s, valid_settings_str);
@@ -9291,7 +9372,10 @@ editor_menu_main (NmCli *nmc, NMConnection *connection, const char *connection_t
 					} else {
 						/* If the string is not a property, try it as a setting */
 						NMSetting *s_tmp;
-						s_tmp = is_setting_valid (connection, valid_settings_arr, cmd_arg_p);
+						s_tmp = is_setting_valid (connection,
+									  valid_settings_main,
+									  valid_settings_slave,
+									  cmd_arg_p);
 						if (s_tmp)
 							print_setting_description (s_tmp);
 						else
@@ -9322,7 +9406,10 @@ editor_menu_main (NmCli *nmc, NMConnection *connection, const char *connection_t
 					user_s = whole_setting ? cmd_arg_p : cmd_arg_s ? cmd_arg_s : NULL;
 					if (user_s) {
 						const char *s_name;
-						s_name = check_valid_name (user_s, valid_settings_arr, NULL);
+						s_name = check_valid_name (user_s,
+						                           valid_settings_main,
+						                           valid_settings_slave,
+						                           NULL);
 						if (!s_name) {
 							g_print (_("Error: unknown setting: '%s'\n"), user_s);
 							break;
@@ -9349,7 +9436,10 @@ editor_menu_main (NmCli *nmc, NMConnection *connection, const char *connection_t
 						} else {
 							/* If the string is not a property, try it as a setting */
 							NMSetting *s_tmp;
-							s_tmp = is_setting_valid (connection, valid_settings_arr, cmd_arg_p);
+							s_tmp = is_setting_valid (connection,
+										  valid_settings_main,
+										  valid_settings_slave,
+										  cmd_arg_p);
 							if (s_tmp) {
 								/* Print the whole setting */
 								editor_show_setting (s_tmp, nmc);
@@ -9928,8 +10018,8 @@ do_connection_edit (NmCli *nmc, int argc, char **argv)
 		editor_init_existing_connection (connection);
 	} else {
 		/* New connection */
-		connection_type = check_valid_name (type, nmc_valid_connection_types, &err1);
-		tmp_str = get_valid_options_string (nmc_valid_connection_types);
+		connection_type = check_valid_name (type, nmc_valid_connection_types, NULL, &err1);
+		tmp_str = get_valid_options_string (nmc_valid_connection_types, NULL);
 
 		while (!connection_type) {
 			if (!type)
@@ -9940,7 +10030,7 @@ do_connection_edit (NmCli *nmc, int argc, char **argv)
 
 			type_ask = nmc_readline (EDITOR_PROMPT_CON_TYPE);
 			type = type_ask = type_ask ? g_strstrip (type_ask) : NULL;
-			connection_type = check_valid_name (type_ask, nmc_valid_connection_types, &err1);
+			connection_type = check_valid_name (type_ask, nmc_valid_connection_types, NULL, &err1);
 			g_free (type_ask);
 		}
 		g_free (tmp_str);
@@ -10724,7 +10814,7 @@ do_connection_export (NmCli *nmc, int argc, char **argv)
 
 	if (!nm_vpn_editor_plugin_export (plugin, path, connection, &error)) {
 		g_string_printf (nmc->return_text, _("Error: failed to export '%s': %s."),
-		                 nm_connection_get_id (connection), error ? error->message : "(unknown)");
+		                 nm_connection_get_id (connection), error->message);
 		nmc->return_value = NMC_RESULT_ERROR_UNKNOWN;
 		goto finish;
 	}
@@ -11021,8 +11111,6 @@ do_connections (NmCli *nmc, int argc, char **argv)
 			g_thread_unref (editor_thread);
 		} else if (matches(*argv, "delete") == 0) {
 			nmc->return_value = do_connection_delete (nmc, argc-1, argv+1);
-		} else if (matches(*argv, "monitor") == 0) {
-			nmc->return_value = do_connection_monitor (nmc, argc-1, argv+1);
 		} else if (matches(*argv, "reload") == 0) {
 			nmc->return_value = do_connection_reload (nmc, argc-1, argv+1);
 		} else if (matches(*argv, "load") == 0) {
@@ -11056,6 +11144,8 @@ do_connections (NmCli *nmc, int argc, char **argv)
 			nmc->return_value = do_connection_import (nmc, temporary, argc, argv);
 		} else if (matches(*argv, "export") == 0) {
 			nmc->return_value = do_connection_export (nmc, argc-1, argv+1);
+		} else if (matches(*argv, "monitor") == 0) {
+			nmc->return_value = do_connection_monitor (nmc, argc-1, argv+1);
 		} else {
 			usage ();
 			g_string_printf (nmc->return_text, _("Error: '%s' is not valid 'connection' command."), *argv);