about summary refs log tree commit diff
path: root/cli
diff options
context:
space:
mode:
Diffstat (limited to 'cli')
-rw-r--r--cli/Makefile.in9
-rw-r--r--cli/src/Makefile.am4
-rw-r--r--cli/src/Makefile.in37
-rw-r--r--cli/src/common.c360
-rw-r--r--cli/src/common.h39
-rw-r--r--cli/src/connections.c1053
-rw-r--r--cli/src/devices.c466
-rw-r--r--cli/src/nmcli.h30
-rw-r--r--cli/src/settings.c416
-rw-r--r--cli/src/settings.h40
-rw-r--r--cli/src/utils.c132
-rw-r--r--cli/src/utils.h6
12 files changed, 1744 insertions, 848 deletions
diff --git a/cli/Makefile.in b/cli/Makefile.in
index c3de35f3..46ab6733 100644
--- a/cli/Makefile.in
+++ b/cli/Makefile.in
@@ -147,6 +147,8 @@ GIO_LIBS = @GIO_LIBS@
 GLIB_CFLAGS = @GLIB_CFLAGS@
 GLIB_GENMARSHAL = @GLIB_GENMARSHAL@
 GLIB_LIBS = @GLIB_LIBS@
+GLIB_MAKEFILE = @GLIB_MAKEFILE@
+GLIB_MKENUMS = @GLIB_MKENUMS@
 GMODULE_CFLAGS = @GMODULE_CFLAGS@
 GMODULE_LIBS = @GMODULE_LIBS@
 GMSGFMT = @GMSGFMT@
@@ -201,11 +203,15 @@ LIBNL2_LIBS = @LIBNL2_LIBS@
 LIBNL3_CFLAGS = @LIBNL3_CFLAGS@
 LIBNL3_LIBS = @LIBNL3_LIBS@
 LIBNL_CFLAGS = @LIBNL_CFLAGS@
+LIBNL_GENL3_CFLAGS = @LIBNL_GENL3_CFLAGS@
+LIBNL_GENL3_LIBS = @LIBNL_GENL3_LIBS@
 LIBNL_LIBS = @LIBNL_LIBS@
 LIBNL_ROUTE3_CFLAGS = @LIBNL_ROUTE3_CFLAGS@
 LIBNL_ROUTE3_LIBS = @LIBNL_ROUTE3_LIBS@
 LIBOBJS = @LIBOBJS@
 LIBS = @LIBS@
+LIBSOUP_CFLAGS = @LIBSOUP_CFLAGS@
+LIBSOUP_LIBS = @LIBSOUP_LIBS@
 LIBTOOL = @LIBTOOL@
 LIPO = @LIPO@
 LN_S = @LN_S@
@@ -216,6 +222,7 @@ MAINT = @MAINT@
 MAKEINFO = @MAKEINFO@
 MANIFEST_TOOL = @MANIFEST_TOOL@
 MKDIR_P = @MKDIR_P@
+MOC = @MOC@
 MSGFMT = @MSGFMT@
 MSGFMT_015 = @MSGFMT_015@
 MSGMERGE = @MSGMERGE@
@@ -255,6 +262,8 @@ SED = @SED@
 SET_MAKE = @SET_MAKE@
 SHELL = @SHELL@
 STRIP = @STRIP@
+SYSTEMD_CFLAGS = @SYSTEMD_CFLAGS@
+SYSTEMD_LIBS = @SYSTEMD_LIBS@
 SYSTEM_CA_PATH = @SYSTEM_CA_PATH@
 UDEV_BASE_DIR = @UDEV_BASE_DIR@
 USE_NLS = @USE_NLS@
diff --git a/cli/src/Makefile.am b/cli/src/Makefile.am
index f49d0127..ec62bfea 100644
--- a/cli/src/Makefile.am
+++ b/cli/src/Makefile.am
@@ -4,10 +4,14 @@ bin_PROGRAMS = \
 INCLUDES = \
 	-I${top_srcdir} \
 	-I${top_srcdir}/include \
+	-I${top_builddir}/include \
 	-I${top_srcdir}/libnm-util \
+	-I${top_builddir}/libnm-util \
 	-I${top_srcdir}/libnm-glib
 
 nmcli_SOURCES = \
+	common.c \
+	common.h \
 	connections.c \
 	connections.h \
 	devices.c \
diff --git a/cli/src/Makefile.in b/cli/src/Makefile.in
index def0b286..ea5214e5 100644
--- a/cli/src/Makefile.in
+++ b/cli/src/Makefile.in
@@ -57,9 +57,10 @@ CONFIG_CLEAN_FILES =
 CONFIG_CLEAN_VPATH_FILES =
 am__installdirs = "$(DESTDIR)$(bindir)"
 PROGRAMS = $(bin_PROGRAMS)
-am_nmcli_OBJECTS = nmcli-connections.$(OBJEXT) nmcli-devices.$(OBJEXT) \
-	nmcli-network-manager.$(OBJEXT) nmcli-settings.$(OBJEXT) \
-	nmcli-nmcli.$(OBJEXT) nmcli-utils.$(OBJEXT)
+am_nmcli_OBJECTS = nmcli-common.$(OBJEXT) nmcli-connections.$(OBJEXT) \
+	nmcli-devices.$(OBJEXT) nmcli-network-manager.$(OBJEXT) \
+	nmcli-settings.$(OBJEXT) nmcli-nmcli.$(OBJEXT) \
+	nmcli-utils.$(OBJEXT)
 nmcli_OBJECTS = $(am_nmcli_OBJECTS)
 am__DEPENDENCIES_1 =
 nmcli_DEPENDENCIES = $(am__DEPENDENCIES_1) $(am__DEPENDENCIES_1) \
@@ -144,6 +145,8 @@ GIO_LIBS = @GIO_LIBS@
 GLIB_CFLAGS = @GLIB_CFLAGS@
 GLIB_GENMARSHAL = @GLIB_GENMARSHAL@
 GLIB_LIBS = @GLIB_LIBS@
+GLIB_MAKEFILE = @GLIB_MAKEFILE@
+GLIB_MKENUMS = @GLIB_MKENUMS@
 GMODULE_CFLAGS = @GMODULE_CFLAGS@
 GMODULE_LIBS = @GMODULE_LIBS@
 GMSGFMT = @GMSGFMT@
@@ -198,11 +201,15 @@ LIBNL2_LIBS = @LIBNL2_LIBS@
 LIBNL3_CFLAGS = @LIBNL3_CFLAGS@
 LIBNL3_LIBS = @LIBNL3_LIBS@
 LIBNL_CFLAGS = @LIBNL_CFLAGS@
+LIBNL_GENL3_CFLAGS = @LIBNL_GENL3_CFLAGS@
+LIBNL_GENL3_LIBS = @LIBNL_GENL3_LIBS@
 LIBNL_LIBS = @LIBNL_LIBS@
 LIBNL_ROUTE3_CFLAGS = @LIBNL_ROUTE3_CFLAGS@
 LIBNL_ROUTE3_LIBS = @LIBNL_ROUTE3_LIBS@
 LIBOBJS = @LIBOBJS@
 LIBS = @LIBS@
+LIBSOUP_CFLAGS = @LIBSOUP_CFLAGS@
+LIBSOUP_LIBS = @LIBSOUP_LIBS@
 LIBTOOL = @LIBTOOL@
 LIPO = @LIPO@
 LN_S = @LN_S@
@@ -213,6 +220,7 @@ MAINT = @MAINT@
 MAKEINFO = @MAKEINFO@
 MANIFEST_TOOL = @MANIFEST_TOOL@
 MKDIR_P = @MKDIR_P@
+MOC = @MOC@
 MSGFMT = @MSGFMT@
 MSGFMT_015 = @MSGFMT_015@
 MSGMERGE = @MSGMERGE@
@@ -252,6 +260,8 @@ SED = @SED@
 SET_MAKE = @SET_MAKE@
 SHELL = @SHELL@
 STRIP = @STRIP@
+SYSTEMD_CFLAGS = @SYSTEMD_CFLAGS@
+SYSTEMD_LIBS = @SYSTEMD_LIBS@
 SYSTEM_CA_PATH = @SYSTEM_CA_PATH@
 UDEV_BASE_DIR = @UDEV_BASE_DIR@
 USE_NLS = @USE_NLS@
@@ -318,10 +328,14 @@ top_srcdir = @top_srcdir@
 INCLUDES = \
 	-I${top_srcdir} \
 	-I${top_srcdir}/include \
+	-I${top_builddir}/include \
 	-I${top_srcdir}/libnm-util \
+	-I${top_builddir}/libnm-util \
 	-I${top_srcdir}/libnm-glib
 
 nmcli_SOURCES = \
+	common.c \
+	common.h \
 	connections.c \
 	connections.h \
 	devices.c \
@@ -434,6 +448,7 @@ mostlyclean-compile:
 distclean-compile:
 	-rm -f *.tab.c
 
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/nmcli-common.Po@am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/nmcli-connections.Po@am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/nmcli-devices.Po@am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/nmcli-network-manager.Po@am__quote@
@@ -468,6 +483,22 @@ distclean-compile:
 @AMDEP_TRUE@@am__fastdepCC_FALSE@	DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
 @am__fastdepCC_FALSE@	$(LTCOMPILE) -c -o $@ $<
 
+nmcli-common.o: common.c
+@am__fastdepCC_TRUE@	$(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(nmcli_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT nmcli-common.o -MD -MP -MF $(DEPDIR)/nmcli-common.Tpo -c -o nmcli-common.o `test -f 'common.c' || echo '$(srcdir)/'`common.c
+@am__fastdepCC_TRUE@	$(AM_V_at)$(am__mv) $(DEPDIR)/nmcli-common.Tpo $(DEPDIR)/nmcli-common.Po
+@am__fastdepCC_FALSE@	$(AM_V_CC) @AM_BACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@	source='common.c' object='nmcli-common.o' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@	DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@	$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(nmcli_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o nmcli-common.o `test -f 'common.c' || echo '$(srcdir)/'`common.c
+
+nmcli-common.obj: common.c
+@am__fastdepCC_TRUE@	$(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(nmcli_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT nmcli-common.obj -MD -MP -MF $(DEPDIR)/nmcli-common.Tpo -c -o nmcli-common.obj `if test -f 'common.c'; then $(CYGPATH_W) 'common.c'; else $(CYGPATH_W) '$(srcdir)/common.c'; fi`
+@am__fastdepCC_TRUE@	$(AM_V_at)$(am__mv) $(DEPDIR)/nmcli-common.Tpo $(DEPDIR)/nmcli-common.Po
+@am__fastdepCC_FALSE@	$(AM_V_CC) @AM_BACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@	source='common.c' object='nmcli-common.obj' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@	DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@	$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(nmcli_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o nmcli-common.obj `if test -f 'common.c'; then $(CYGPATH_W) 'common.c'; else $(CYGPATH_W) '$(srcdir)/common.c'; fi`
+
 nmcli-connections.o: connections.c
 @am__fastdepCC_TRUE@	$(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(nmcli_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT nmcli-connections.o -MD -MP -MF $(DEPDIR)/nmcli-connections.Tpo -c -o nmcli-connections.o `test -f 'connections.c' || echo '$(srcdir)/'`connections.c
 @am__fastdepCC_TRUE@	$(AM_V_at)$(am__mv) $(DEPDIR)/nmcli-connections.Tpo $(DEPDIR)/nmcli-connections.Po
diff --git a/cli/src/common.c b/cli/src/common.c
new file mode 100644
index 00000000..e9a5d760
--- /dev/null
+++ b/cli/src/common.c
@@ -0,0 +1,360 @@
+/*
+ *  nmcli - command-line tool for controlling NetworkManager
+ *  Common functions and data shared between files.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * (C) Copyright 2012 Red Hat, Inc.
+ */
+
+#include "config.h"
+
+#include <glib.h>
+#include <glib/gi18n.h>
+
+#include "common.h"
+#include "utils.h"
+
+/* Available fields for IPv4 group */
+static NmcOutputField nmc_fields_ip4_config[] = {
+	{"GROUP",      N_("GROUP"),       15, NULL, 0},  /* 0 */
+	{"ADDRESS",    N_("ADDRESS"),     68, NULL, 0},  /* 1 */
+	{"ROUTE",      N_("ROUTE"),       68, NULL, 0},  /* 2 */
+	{"DNS",        N_("DNS"),         35, NULL, 0},  /* 3 */
+	{"DOMAIN",     N_("DOMAIN"),      35, NULL, 0},  /* 4 */
+	{"WINS",       N_("WINS"),        20, NULL, 0},  /* 5 */
+	{NULL,         NULL,               0, NULL, 0}
+};
+#define NMC_FIELDS_IP4_CONFIG_ALL     "GROUP,ADDRESS,ROUTE,DNS,DOMAIN,WINS"
+
+/* Available fields for DHCPv4 group */
+static NmcOutputField nmc_fields_dhcp4_config[] = {
+	{"GROUP",      N_("GROUP"),       15, NULL, 0},  /* 0 */
+	{"OPTION",     N_("OPTION"),      80, NULL, 0},  /* 1 */
+	{NULL,         NULL,               0, NULL, 0}
+};
+#define NMC_FIELDS_DHCP4_CONFIG_ALL     "GROUP,OPTION"
+
+/* Available fields for IPv6 group */
+static NmcOutputField nmc_fields_ip6_config[] = {
+	{"GROUP",      N_("GROUP"),       15, NULL, 0},  /* 0 */
+	{"ADDRESS",    N_("ADDRESS"),     95, NULL, 0},  /* 1 */
+	{"ROUTE",      N_("ROUTE"),       95, NULL, 0},  /* 2 */
+	{"DNS",        N_("DNS"),         60, NULL, 0},  /* 3 */
+	{"DOMAIN",     N_("DOMAIN"),      35, NULL, 0},  /* 4 */
+	{NULL,         NULL,               0, NULL, 0}
+};
+#define NMC_FIELDS_IP6_CONFIG_ALL     "GROUP,ADDRESS,ROUTE,DNS,DOMAIN"
+
+/* Available fields for DHCPv6 group */
+static NmcOutputField nmc_fields_dhcp6_config[] = {
+	{"GROUP",      N_("GROUP"),       15, NULL, 0},  /* 0 */
+	{"OPTION",     N_("OPTION"),      80, NULL, 0},  /* 1 */
+	{NULL,         NULL,               0, NULL, 0}
+};
+#define NMC_FIELDS_DHCP6_CONFIG_ALL     "GROUP,OPTION"
+
+
+gboolean
+print_ip4_config (NMIP4Config *cfg4, NmCli *nmc, const char *group_prefix)
+{
+	GSList *list, *iter;
+	const GArray *array;
+	const GPtrArray *ptr_array;
+	char **addr_arr = NULL;
+	char **route_arr = NULL;
+	char **dns_arr = NULL;
+	char **domain_arr = NULL;
+	char **wins_arr = NULL;
+	int i = 0;
+	guint32 mode_flag = (nmc->print_output == NMC_PRINT_PRETTY) ? NMC_PF_FLAG_PRETTY : (nmc->print_output == NMC_PRINT_TERSE) ? NMC_PF_FLAG_TERSE : 0;
+	guint32 multiline_flag = nmc->multiline_output ? NMC_PF_FLAG_MULTILINE : 0;
+	guint32 escape_flag = nmc->escape_values ? NMC_PF_FLAG_ESCAPE : 0;
+
+	if (cfg4 == NULL)
+		return FALSE;
+
+	nmc->allowed_fields = nmc_fields_ip4_config;
+	nmc->print_fields.flags = multiline_flag | mode_flag | escape_flag | NMC_PF_FLAG_FIELD_NAMES;
+	nmc->print_fields.indices = parse_output_fields (NMC_FIELDS_IP4_CONFIG_ALL, nmc->allowed_fields, NULL);
+	print_fields (nmc->print_fields, nmc->allowed_fields); /* Print header */
+
+	/* addresses */
+	list = (GSList *) nm_ip4_config_get_addresses (cfg4);
+	addr_arr = g_new (char *, g_slist_length (list) + 1);
+	for (iter = list; iter; iter = g_slist_next (iter)) {
+		NMIP4Address *addr = (NMIP4Address *) iter->data;
+		guint32 prefix;
+		char *ip_str, *gw_str;
+
+		ip_str = nmc_ip4_address_as_string (nm_ip4_address_get_address (addr), NULL);
+		prefix = nm_ip4_address_get_prefix (addr);
+		gw_str = nmc_ip4_address_as_string (nm_ip4_address_get_gateway (addr), NULL);
+
+		addr_arr[i++] = g_strdup_printf ("ip = %s/%u, gw = %s", ip_str, prefix, gw_str);
+		g_free (ip_str);
+		g_free (gw_str);
+	}
+	addr_arr[i] = NULL;
+
+	/* routes */
+	list = (GSList *) nm_ip4_config_get_routes (cfg4);
+	route_arr = g_new (char *, g_slist_length (list) + 1);
+	i = 0;
+	for (iter = list; iter; iter = g_slist_next (iter)) {
+		NMIP4Route *route = (NMIP4Route *) iter->data;
+		guint32 prefix, metric;
+		char *dest_str, *nexthop_str;
+
+		dest_str = nmc_ip4_address_as_string (nm_ip4_route_get_dest (route), NULL);
+		nexthop_str = nmc_ip4_address_as_string (nm_ip4_route_get_next_hop (route), NULL);
+		prefix = nm_ip4_route_get_prefix (route);
+		metric = nm_ip4_route_get_metric (route);
+
+		route_arr[i++] = g_strdup_printf ("dst = %s/%u, nh = %s, mt = %u", dest_str, prefix, nexthop_str, metric);
+		g_free (dest_str);
+		g_free (nexthop_str);
+	}
+	route_arr[i] = NULL;
+
+	/* DNS */
+	array = nm_ip4_config_get_nameservers (cfg4);
+	if (array) {
+		dns_arr = g_new (char *, array->len + 1);
+		for (i = 0; i < array->len; i++)
+			dns_arr[i] = nmc_ip4_address_as_string (g_array_index (array, guint32, i), NULL);
+
+		dns_arr[i] = NULL;
+	}
+
+	/* domains */
+	ptr_array = nm_ip4_config_get_domains (cfg4);
+	if (ptr_array) {
+		domain_arr = g_new (char *, ptr_array->len + 1);
+		for (i = 0; i < ptr_array->len; i++)
+			domain_arr[i] = g_ptr_array_index (ptr_array, i);
+
+		domain_arr[i] = NULL;
+	}
+
+	/* WINS */
+	array = nm_ip4_config_get_wins_servers (cfg4);
+	if (array) {
+		wins_arr = g_new (char *, array->len + 1);
+		for (i = 0; i < array->len; i++)
+			wins_arr[i] = nmc_ip4_address_as_string (g_array_index (array, guint32, i), NULL);
+
+		wins_arr[i] = NULL;
+	}
+
+	set_val_str (nmc->allowed_fields, 0, group_prefix);
+	set_val_arr (nmc->allowed_fields, 1, (const char **) addr_arr);
+	set_val_arr (nmc->allowed_fields, 2, (const char **) route_arr);
+	set_val_arr (nmc->allowed_fields, 3, (const char **) dns_arr);
+	set_val_arr (nmc->allowed_fields, 4, (const char **) domain_arr);
+	set_val_arr (nmc->allowed_fields, 5, (const char **) wins_arr);
+
+	nmc->print_fields.flags = multiline_flag | mode_flag | escape_flag | NMC_PF_FLAG_SECTION_PREFIX;
+	print_fields (nmc->print_fields, nmc->allowed_fields); /* Print values */
+
+	g_strfreev (addr_arr);
+	g_strfreev (route_arr);
+	g_strfreev (dns_arr);
+	g_free (domain_arr);
+	g_strfreev (wins_arr);
+
+	return TRUE;
+}
+
+gboolean
+print_ip6_config (NMIP6Config *cfg6, NmCli *nmc, const char *group_prefix)
+{
+	GSList *list, *iter;
+	const GPtrArray *ptr_array;
+	char **addr_arr = NULL;
+	char **route_arr = NULL;
+	char **dns_arr = NULL;
+	char **domain_arr = NULL;
+	int i = 0;
+	guint32 mode_flag = (nmc->print_output == NMC_PRINT_PRETTY) ? NMC_PF_FLAG_PRETTY : (nmc->print_output == NMC_PRINT_TERSE) ? NMC_PF_FLAG_TERSE : 0;
+	guint32 multiline_flag = nmc->multiline_output ? NMC_PF_FLAG_MULTILINE : 0;
+	guint32 escape_flag = nmc->escape_values ? NMC_PF_FLAG_ESCAPE : 0;
+
+	if (cfg6 == NULL)
+		return FALSE;
+
+	nmc->allowed_fields = nmc_fields_ip6_config;
+	nmc->print_fields.flags = multiline_flag | mode_flag | escape_flag | NMC_PF_FLAG_FIELD_NAMES;
+	nmc->print_fields.indices = parse_output_fields (NMC_FIELDS_IP6_CONFIG_ALL, nmc->allowed_fields, NULL);
+	print_fields (nmc->print_fields, nmc->allowed_fields); /* Print header */
+
+	/* addresses */
+	list = (GSList *) nm_ip6_config_get_addresses (cfg6);
+	addr_arr = g_new (char *, g_slist_length (list) + 1);
+	for (iter = list; iter; iter = g_slist_next (iter)) {
+		NMIP6Address *addr = (NMIP6Address *) iter->data;
+		guint32 prefix;
+		char *ip_str, *gw_str;
+
+		ip_str = nmc_ip6_address_as_string (nm_ip6_address_get_address (addr), NULL);
+		prefix = nm_ip6_address_get_prefix (addr);
+		gw_str = nmc_ip6_address_as_string (nm_ip6_address_get_gateway (addr), NULL);
+
+		addr_arr[i++] = g_strdup_printf ("ip = %s/%u, gw = %s", ip_str, prefix, gw_str);
+		g_free (ip_str);
+		g_free (gw_str);
+	}
+	addr_arr[i] = NULL;
+
+	/* routes */
+	list = (GSList *) nm_ip6_config_get_routes (cfg6);
+	route_arr = g_new (char *, g_slist_length (list) + 1);
+	i = 0;
+	for (iter = list; iter; iter = g_slist_next (iter)) {
+		NMIP6Route *route = (NMIP6Route *) iter->data;
+		guint32 prefix, metric;
+		char *dest_str, *nexthop_str;
+
+		dest_str = nmc_ip6_address_as_string (nm_ip6_route_get_dest (route), NULL);
+		nexthop_str = nmc_ip6_address_as_string (nm_ip6_route_get_next_hop (route), NULL);
+		prefix = nm_ip6_route_get_prefix (route);
+		metric = nm_ip6_route_get_metric (route);
+
+		route_arr[i++] = g_strdup_printf ("dst = %s/%u, nh = %s, mt = %u", dest_str, prefix, nexthop_str, metric);
+		g_free (dest_str);
+		g_free (nexthop_str);
+	}
+	route_arr[i] = NULL;
+
+	/* DNS */
+	list = (GSList *) nm_ip6_config_get_nameservers (cfg6);
+	dns_arr = g_new (char *, g_slist_length (list) + 1);
+	i = 0;
+	for (iter = list; iter; iter = g_slist_next (iter))
+		dns_arr[i++] = nmc_ip6_address_as_string (iter->data, NULL);
+
+	dns_arr[i] = NULL;
+
+	/* domains */
+	ptr_array = nm_ip6_config_get_domains (cfg6);
+	if (ptr_array) {
+		domain_arr = g_new (char *, ptr_array->len + 1);
+		for (i = 0; i < ptr_array->len; i++)
+			domain_arr[i] = g_ptr_array_index (ptr_array, i);
+
+		domain_arr[i] = NULL;
+	}
+
+	set_val_str (nmc->allowed_fields, 0, group_prefix);
+	set_val_arr (nmc->allowed_fields, 1, (const char **) addr_arr);
+	set_val_arr (nmc->allowed_fields, 2, (const char **) route_arr);
+	set_val_arr (nmc->allowed_fields, 3, (const char **) dns_arr);
+	set_val_arr (nmc->allowed_fields, 4, (const char **) domain_arr);
+
+	nmc->print_fields.flags = multiline_flag | mode_flag | escape_flag | NMC_PF_FLAG_SECTION_PREFIX;
+	print_fields (nmc->print_fields, nmc->allowed_fields); /* Print values */
+
+	g_strfreev (addr_arr);
+	g_strfreev (route_arr);
+	g_strfreev (dns_arr);
+	g_free (domain_arr);
+
+	return TRUE;
+}
+
+gboolean
+print_dhcp4_config (NMDHCP4Config *dhcp4, NmCli *nmc, const char *group_prefix)
+{
+	GHashTable *table;
+	guint32 mode_flag = (nmc->print_output == NMC_PRINT_PRETTY) ? NMC_PF_FLAG_PRETTY : (nmc->print_output == NMC_PRINT_TERSE) ? NMC_PF_FLAG_TERSE : 0;
+	guint32 multiline_flag = nmc->multiline_output ? NMC_PF_FLAG_MULTILINE : 0;
+	guint32 escape_flag = nmc->escape_values ? NMC_PF_FLAG_ESCAPE : 0;
+
+	if (dhcp4 == NULL)
+		return FALSE;
+
+	table = nm_dhcp4_config_get_options (dhcp4);
+	if (table) {
+		GHashTableIter table_iter;
+		gpointer key, value;
+		char **options_arr = NULL;
+		int i = 0;
+
+		nmc->allowed_fields = nmc_fields_dhcp4_config;
+		nmc->print_fields.flags = multiline_flag | mode_flag | escape_flag | NMC_PF_FLAG_FIELD_NAMES;
+		nmc->print_fields.indices = parse_output_fields (NMC_FIELDS_DHCP4_CONFIG_ALL, nmc->allowed_fields, NULL);
+		print_fields (nmc->print_fields, nmc->allowed_fields); /* Print header */
+
+		options_arr = g_new (char *, g_hash_table_size (table) + 1);
+		g_hash_table_iter_init (&table_iter, table);
+		while (g_hash_table_iter_next (&table_iter, &key, &value))
+			options_arr[i++] = g_strdup_printf ("%s = %s", (char *) key, (char *) value);
+		options_arr[i] = NULL;
+
+		set_val_str (nmc->allowed_fields, 0, group_prefix);
+		set_val_arr (nmc->allowed_fields, 1, (const char **) options_arr);
+
+		nmc->print_fields.flags = multiline_flag | mode_flag | escape_flag | NMC_PF_FLAG_SECTION_PREFIX;
+		print_fields (nmc->print_fields, nmc->allowed_fields); /* Print values */
+
+		g_strfreev (options_arr);
+
+		return TRUE;
+	}
+	return FALSE;
+}
+
+gboolean
+print_dhcp6_config (NMDHCP6Config *dhcp6, NmCli *nmc, const char *group_prefix)
+{
+	GHashTable *table;
+	guint32 mode_flag = (nmc->print_output == NMC_PRINT_PRETTY) ? NMC_PF_FLAG_PRETTY : (nmc->print_output == NMC_PRINT_TERSE) ? NMC_PF_FLAG_TERSE : 0;
+	guint32 multiline_flag = nmc->multiline_output ? NMC_PF_FLAG_MULTILINE : 0;
+	guint32 escape_flag = nmc->escape_values ? NMC_PF_FLAG_ESCAPE : 0;
+
+	if (dhcp6 == NULL)
+		return FALSE;
+
+	table = nm_dhcp6_config_get_options (dhcp6);
+	if (table) {
+		GHashTableIter table_iter;
+		gpointer key, value;
+		char **options_arr = NULL;
+		int i = 0;
+
+		nmc->allowed_fields = nmc_fields_dhcp6_config;
+		nmc->print_fields.flags = multiline_flag | mode_flag | escape_flag | NMC_PF_FLAG_FIELD_NAMES;
+		nmc->print_fields.indices = parse_output_fields (NMC_FIELDS_DHCP6_CONFIG_ALL, nmc->allowed_fields, NULL);
+		print_fields (nmc->print_fields, nmc->allowed_fields); /* Print header */
+
+		options_arr = g_new (char *, g_hash_table_size (table) + 1);
+		g_hash_table_iter_init (&table_iter, table);
+		while (g_hash_table_iter_next (&table_iter, &key, &value))
+			options_arr[i++] = g_strdup_printf ("%s = %s", (char *) key, (char *) value);
+		options_arr[i] = NULL;
+
+		set_val_str (nmc->allowed_fields, 0, group_prefix);
+		set_val_arr (nmc->allowed_fields, 1, (const char **) options_arr);
+
+		nmc->print_fields.flags = multiline_flag | mode_flag | escape_flag | NMC_PF_FLAG_SECTION_PREFIX;
+		print_fields (nmc->print_fields, nmc->allowed_fields); /* Print values */
+
+		g_strfreev (options_arr);
+
+		return TRUE;
+	}
+	return FALSE;
+}
+
diff --git a/cli/src/common.h b/cli/src/common.h
new file mode 100644
index 00000000..85015a9f
--- /dev/null
+++ b/cli/src/common.h
@@ -0,0 +1,39 @@
+/*
+ *  nmcli - command-line tool for controlling NetworkManager
+ *  Common functions and data shared between files.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * (C) Copyright 2012 Red Hat, Inc.
+ */
+
+#ifndef NMC_COMMON_H
+#define NMC_COMMON_H
+
+#include <glib.h>
+
+#include <nm-ip4-config.h>
+#include <nm-ip6-config.h>
+#include <nm-dhcp4-config.h>
+#include <nm-dhcp6-config.h>
+
+#include "nmcli.h"
+
+gboolean print_ip4_config (NMIP4Config *cfg4, NmCli *nmc, const char *group_prefix);
+gboolean print_ip6_config (NMIP6Config *cfg6, NmCli *nmc, const char *group_prefix);
+gboolean print_dhcp4_config (NMDHCP4Config *dhcp4, NmCli *nmc, const char *group_prefix);
+gboolean print_dhcp6_config (NMDHCP6Config *dhcp6, NmCli *nmc, const char *group_prefix);
+
+#endif /* NMC_COMMON_H */
diff --git a/cli/src/connections.c b/cli/src/connections.c
index 7d4fffc0..ea5211f5 100644
--- a/cli/src/connections.c
+++ b/cli/src/connections.c
@@ -14,7 +14,7 @@
  * with this program; if not, write to the Free Software Foundation, Inc.,
  * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
  *
- * (C) Copyright 2010 - 2011 Red Hat, Inc.
+ * (C) Copyright 2010 - 2012 Red Hat, Inc.
  */
 
 #include "config.h"
@@ -32,17 +32,6 @@
 #include <netinet/ether.h>
 
 #include <nm-client.h>
-#include <nm-setting-connection.h>
-#include <nm-setting-wired.h>
-#include <nm-setting-pppoe.h>
-#include <nm-setting-wireless.h>
-#include <nm-setting-gsm.h>
-#include <nm-setting-cdma.h>
-#include <nm-setting-bluetooth.h>
-#include <nm-setting-olpc-mesh.h>
-#if WITH_WIMAX
-#include <nm-setting-wimax.h>
-#endif
 #include <nm-device-ethernet.h>
 #include <nm-device-wifi.h>
 #if WITH_WIMAX
@@ -50,29 +39,20 @@
 #endif
 #include <nm-device-modem.h>
 #include <nm-device-bt.h>
-//#include <nm-device-olpc-mesh.h>
+#include <nm-device-olpc-mesh.h>
+#include <nm-device-infiniband.h>
+#include <nm-device-bond.h>
+#include <nm-device-vlan.h>
 #include <nm-remote-settings.h>
 #include <nm-vpn-connection.h>
+#include <nm-utils.h>
 
 #include "utils.h"
+#include "common.h"
 #include "settings.h"
 #include "connections.h"
 
 
-/* Available fields for 'con status' */
-static NmcOutputField nmc_fields_con_status[] = {
-	{"NAME",          N_("NAME"),         25, NULL, 0},  /* 0 */
-	{"UUID",          N_("UUID"),         38, NULL, 0},  /* 1 */
-	{"DEVICES",       N_("DEVICES"),      10, NULL, 0},  /* 2 */
-	{"DEFAULT",       N_("DEFAULT"),       8, NULL, 0},  /* 3 */
-	{"SPEC-OBJECT",   N_("SPEC-OBJECT"),  10, NULL, 0},  /* 4 */
-	{"VPN",           N_("VPN"),           5, NULL, 0},  /* 5 */
-	{"DBUS-PATH",     N_("DBUS-PATH"),    51, NULL, 0},  /* 6 */
-	{NULL,            NULL,                0, NULL, 0}
-};
-#define NMC_FIELDS_CON_STATUS_ALL     "NAME,UUID,DEVICES,DEFAULT,VPN,DBUS-PATH,SPEC-OBJECT"
-#define NMC_FIELDS_CON_STATUS_COMMON  "NAME,UUID,DEVICES,DEFAULT,VPN"
-
 /* Available fields for 'con list' */
 static NmcOutputField nmc_fields_con_list[] = {
 	{"NAME",            N_("NAME"),           25, NULL, 0},  /* 0 */
@@ -88,7 +68,6 @@ static NmcOutputField nmc_fields_con_list[] = {
 #define NMC_FIELDS_CON_LIST_ALL     "NAME,UUID,TYPE,TIMESTAMP,TIMESTAMP-REAL,AUTOCONNECT,READONLY,DBUS-PATH"
 #define NMC_FIELDS_CON_LIST_COMMON  "NAME,UUID,TYPE,TIMESTAMP-REAL"
 
-
 /* Helper macro to define fields */
 #define SETTING_FIELD(setting, width) { setting, N_(setting), width, NULL, 0 }
 
@@ -110,6 +89,9 @@ static NmcOutputField nmc_fields_settings_names[] = {
 	SETTING_FIELD (NM_SETTING_OLPC_MESH_SETTING_NAME, 0),             /* 13 */
 	SETTING_FIELD (NM_SETTING_VPN_SETTING_NAME, 0),                   /* 14 */
 	SETTING_FIELD (NM_SETTING_WIMAX_SETTING_NAME, 0),                 /* 15 */
+	SETTING_FIELD (NM_SETTING_INFINIBAND_SETTING_NAME, 0),            /* 16 */
+	SETTING_FIELD (NM_SETTING_BOND_SETTING_NAME, 0),                  /* 17 */
+	SETTING_FIELD (NM_SETTING_VLAN_SETTING_NAME, 0),                  /* 18 */
 	{NULL, NULL, 0, NULL, 0}
 };
 #define NMC_FIELDS_SETTINGS_NAMES_ALL_X  NM_SETTING_CONNECTION_SETTING_NAME","\
@@ -126,7 +108,10 @@ static NmcOutputField nmc_fields_settings_names[] = {
                                          NM_SETTING_CDMA_SETTING_NAME","\
                                          NM_SETTING_BLUETOOTH_SETTING_NAME","\
                                          NM_SETTING_OLPC_MESH_SETTING_NAME","\
-                                         NM_SETTING_VPN_SETTING_NAME
+                                         NM_SETTING_VPN_SETTING_NAME","\
+                                         NM_SETTING_INFINIBAND_SETTING_NAME","\
+                                         NM_SETTING_BOND_SETTING_NAME","\
+                                         NM_SETTING_VLAN_SETTING_NAME
 #if WITH_WIMAX
 #define NMC_FIELDS_SETTINGS_NAMES_ALL    NMC_FIELDS_SETTINGS_NAMES_ALL_X","\
                                          NM_SETTING_WIMAX_SETTING_NAME
@@ -135,6 +120,54 @@ static NmcOutputField nmc_fields_settings_names[] = {
 #endif
 
 
+/* Available fields for 'con status' */
+static NmcOutputField nmc_fields_con_status[] = {
+	{"GROUP",         N_("GROUP"),         9, NULL, 0},  /* 0 */  /* used only for 'GENERAL' group listing */
+	{"NAME",          N_("NAME"),         25, NULL, 0},  /* 1 */
+	{"UUID",          N_("UUID"),         38, NULL, 0},  /* 2 */
+	{"DEVICES",       N_("DEVICES"),      10, NULL, 0},  /* 3 */
+	{"STATE",         N_("STATE"),        12, NULL, 0},  /* 4 */
+	{"DEFAULT",       N_("DEFAULT"),       8, NULL, 0},  /* 5 */
+	{"DEFAULT6",      N_("DEFAULT6"),      9, NULL, 0},  /* 6 */
+	{"SPEC-OBJECT",   N_("SPEC-OBJECT"),  10, NULL, 0},  /* 7 */
+	{"VPN",           N_("VPN"),           5, NULL, 0},  /* 8 */
+	{"DBUS-PATH",     N_("DBUS-PATH"),    51, NULL, 0},  /* 9 */
+	{"CON-PATH",      N_("CON-PATH"),     44, NULL, 0},  /* 10 */
+	{"ZONE",          N_("ZONE"),         15, NULL, 0},  /* 11 */
+	{"MASTER-PATH",   N_("MASTER-PATH"),  44, NULL, 0},  /* 12 */
+	{NULL,            NULL,                0, NULL, 0}
+};
+#define NMC_FIELDS_CON_STATUS_ALL     "NAME,UUID,DEVICES,STATE,DEFAULT,DEFAULT6,VPN,ZONE,DBUS-PATH,CON-PATH,SPEC-OBJECT,MASTER-PATH"
+#define NMC_FIELDS_CON_STATUS_COMMON  "NAME,UUID,DEVICES,DEFAULT,VPN,MASTER-PATH"
+
+/* Available fields for 'con status id/uuid/path <con>' */
+static NmcOutputField nmc_fields_status_details_groups[] = {
+	{"GENERAL",  N_("GENERAL"), 9, NULL, 0},  /* 0 */
+	{"IP",       N_("IP"),      5, NULL, 0},  /* 1 */
+	{"VPN",      N_("VPN"),     5, NULL, 0},  /* 2 */
+	{NULL, NULL, 0, NULL, 0}
+};
+#define NMC_FIELDS_CON_STATUS_DETAILS_ALL  "GENERAL,IP,VPN"
+
+/* GENERAL group is the same as nmc_fields_con_status */
+#define NMC_FIELDS_CON_STATUS_DETAILS_GENERAL_ALL  "GROUP,"NMC_FIELDS_CON_STATUS_ALL
+
+/* IP group is handled by common.c */
+
+/* Available fields for VPN group */
+static NmcOutputField nmc_fields_status_details_vpn[] = {
+	{"GROUP",     N_("GROUP"),       9, NULL, 0},  /* 0 */
+	{"TYPE",      N_("TYPE"),       15, NULL, 0},  /* 1 */
+	{"USERNAME",  N_("USERNAME"),   15, NULL, 0},  /* 2 */
+	{"GATEWAY",   N_("GATEWAY"),    25, NULL, 0},  /* 3 */
+	{"BANNER",    N_("BANNER"),    120, NULL, 0},  /* 4 */
+	{"VPN-STATE", N_("VPN-STATE"),  40, NULL, 0},  /* 5 */
+	{"CFG",       N_("CFG"),       120, NULL, 0},  /* 6 */
+	{NULL, NULL, 0, NULL, 0}
+};
+#define NMC_FIELDS_CON_STATUS_DETAILS_VPN_ALL  "GROUP,TYPE,USERNAME,GATEWAY,BANNER,VPN-STATE,CFG"
+
+
 typedef struct {
 	NmCli *nmc;
 	int argc;
@@ -153,7 +186,7 @@ usage (void)
 	         _("Usage: nmcli con { COMMAND | help }\n"
 	         "  COMMAND := { list | status | up | down | delete }\n\n"
 	         "  list [id <id> | uuid <id>]\n"
-	         "  status\n"
+	         "  status [id <id> | uuid <id> | path <path>]\n"
 #if WITH_WIMAX
 	         "  up id <id> | uuid <id> [iface <iface>] [ap <BSSID>] [nsp <name>] [--nowait] [--timeout <timeout>]\n"
 #else
@@ -183,7 +216,6 @@ quit (void)
 static gboolean
 nmc_connection_detail (NMConnection *connection, NmCli *nmc)
 {
-	NMSetting *setting;
 	GError *error = NULL;
 	GArray *print_settings_array;
 	int i;
@@ -229,135 +261,135 @@ nmc_connection_detail (NMConnection *connection, NmCli *nmc)
 		was_output = FALSE;
 
 		if (!strcasecmp (nmc_fields_settings_names[section_idx].name, nmc_fields_settings_names[0].name)) {
-			setting = nm_connection_get_setting (connection, NM_TYPE_SETTING_CONNECTION);
-			if (setting) {
-				setting_connection_details (setting, nmc);
+			NMSettingConnection *s_con = nm_connection_get_setting_connection (connection);
+			if (s_con) {
+				setting_connection_details (s_con, nmc);
 				was_output = TRUE;
 				continue;
 			}
 		}
 
 		if (!strcasecmp (nmc_fields_settings_names[section_idx].name, nmc_fields_settings_names[1].name)) {
-			setting = nm_connection_get_setting (connection, NM_TYPE_SETTING_WIRED);
-			if (setting) {
-				setting_wired_details (setting, nmc);
+			NMSettingWired *s_wired = nm_connection_get_setting_wired (connection);
+			if (s_wired) {
+				setting_wired_details (s_wired, nmc);
 				was_output = TRUE;
 				continue;
 			}
 		}
 
 		if (!strcasecmp (nmc_fields_settings_names[section_idx].name, nmc_fields_settings_names[2].name)) {
-			setting = nm_connection_get_setting (connection, NM_TYPE_SETTING_802_1X);
-			if (setting) {
-				setting_802_1X_details (setting, nmc);
+			NMSetting8021x *s_8021X = nm_connection_get_setting_802_1x (connection);
+			if (s_8021X) {
+				setting_802_1X_details (s_8021X, nmc);
 				was_output = TRUE;
 				continue;
 			}
 		}
 
 		if (!strcasecmp (nmc_fields_settings_names[section_idx].name, nmc_fields_settings_names[3].name)) {
-			setting = nm_connection_get_setting (connection, NM_TYPE_SETTING_WIRELESS);
-			if (setting) {
-				setting_wireless_details (setting, nmc);
+			NMSettingWireless *s_wireless = nm_connection_get_setting_wireless (connection);
+			if (s_wireless) {
+				setting_wireless_details (s_wireless, nmc);
 				was_output = TRUE;
 				continue;
 			}
 		}
 
 		if (!strcasecmp (nmc_fields_settings_names[section_idx].name, nmc_fields_settings_names[4].name)) {
-			setting = nm_connection_get_setting (connection, NM_TYPE_SETTING_WIRELESS_SECURITY);
-			if (setting) {
-				setting_wireless_security_details (setting, nmc);
+			NMSettingWirelessSecurity *s_wsec = nm_connection_get_setting_wireless_security (connection);
+			if (s_wsec) {
+				setting_wireless_security_details (s_wsec, nmc);
 				was_output = TRUE;
 				continue;
 			}
 		}
 
 		if (!strcasecmp (nmc_fields_settings_names[section_idx].name, nmc_fields_settings_names[5].name)) {
-			setting = nm_connection_get_setting (connection, NM_TYPE_SETTING_IP4_CONFIG);
-			if (setting) {
-				setting_ip4_config_details (setting, nmc);
+			NMSettingIP4Config *s_ip4 = nm_connection_get_setting_ip4_config (connection);
+			if (s_ip4) {
+				setting_ip4_config_details (s_ip4, nmc);
 				was_output = TRUE;
 				continue;
 			}
 		}
 
 		if (!strcasecmp (nmc_fields_settings_names[section_idx].name, nmc_fields_settings_names[6].name)) {
-			setting = nm_connection_get_setting (connection, NM_TYPE_SETTING_IP6_CONFIG);
-			if (setting) {
-				setting_ip6_config_details (setting, nmc);
+			NMSettingIP6Config *s_ip6 = nm_connection_get_setting_ip6_config (connection);
+			if (s_ip6) {
+				setting_ip6_config_details (s_ip6, nmc);
 				was_output = TRUE;
 				continue;
 			}
 		}
 
 		if (!strcasecmp (nmc_fields_settings_names[section_idx].name, nmc_fields_settings_names[7].name)) {
-			setting = nm_connection_get_setting (connection, NM_TYPE_SETTING_SERIAL);
-			if (setting) {
-				setting_serial_details (setting, nmc);
+			NMSettingSerial *s_serial = nm_connection_get_setting_serial (connection);
+			if (s_serial) {
+				setting_serial_details (s_serial, nmc);
 				was_output = TRUE;
 				continue;
 			}
 		}
 
 		if (!strcasecmp (nmc_fields_settings_names[section_idx].name, nmc_fields_settings_names[8].name)) {
-			setting = nm_connection_get_setting (connection, NM_TYPE_SETTING_PPP);
-			if (setting) {
-				setting_ppp_details (setting, nmc);
+			NMSettingPPP *s_ppp = nm_connection_get_setting_ppp (connection);
+			if (s_ppp) {
+				setting_ppp_details (s_ppp, nmc);
 				was_output = TRUE;
 				continue;
 			}
 		}
 
 		if (!strcasecmp (nmc_fields_settings_names[section_idx].name, nmc_fields_settings_names[9].name)) {
-			setting = nm_connection_get_setting (connection, NM_TYPE_SETTING_PPPOE);
-			if (setting) {
-				setting_pppoe_details (setting, nmc);
+			NMSettingPPPOE *s_pppoe = nm_connection_get_setting_pppoe (connection);
+			if (s_pppoe) {
+				setting_pppoe_details (s_pppoe, nmc);
 				was_output = TRUE;
 				continue;
 			}
 		}
 
 		if (!strcasecmp (nmc_fields_settings_names[section_idx].name, nmc_fields_settings_names[10].name)) {
-			setting = nm_connection_get_setting (connection, NM_TYPE_SETTING_GSM);
-			if (setting) {
-				setting_gsm_details (setting, nmc);
+			NMSettingGsm *s_gsm = nm_connection_get_setting_gsm (connection);
+			if (s_gsm) {
+				setting_gsm_details (s_gsm, nmc);
 				was_output = TRUE;
 				continue;
 			}
 		}
 
 		if (!strcasecmp (nmc_fields_settings_names[section_idx].name, nmc_fields_settings_names[11].name)) {
-			setting = nm_connection_get_setting (connection, NM_TYPE_SETTING_CDMA);
-			if (setting) {
-				setting_cdma_details (setting, nmc);
+			NMSettingCdma *s_cdma = nm_connection_get_setting_cdma (connection);
+			if (s_cdma) {
+				setting_cdma_details (s_cdma, nmc);
 				was_output = TRUE;
 				continue;
 			}
 		}
 
 		if (!strcasecmp (nmc_fields_settings_names[section_idx].name, nmc_fields_settings_names[12].name)) {
-			setting = nm_connection_get_setting (connection, NM_TYPE_SETTING_BLUETOOTH);
-			if (setting) {
-				setting_bluetooth_details (setting, nmc);
+			NMSettingBluetooth *s_bluetooth = nm_connection_get_setting_bluetooth (connection);
+			if (s_bluetooth) {
+				setting_bluetooth_details (s_bluetooth, nmc);
 				was_output = TRUE;
 				continue;
 			}
 		}
 
 		if (!strcasecmp (nmc_fields_settings_names[section_idx].name, nmc_fields_settings_names[13].name)) {
-			setting = nm_connection_get_setting (connection, NM_TYPE_SETTING_OLPC_MESH);
-			if (setting) {
-				setting_olpc_mesh_details (setting, nmc);
+			NMSettingOlpcMesh *s_olpc_mesh = nm_connection_get_setting_olpc_mesh (connection);
+			if (s_olpc_mesh) {
+				setting_olpc_mesh_details (s_olpc_mesh, nmc);
 				was_output = TRUE;
 				continue;
 			}
 		}
 
 		if (!strcasecmp (nmc_fields_settings_names[section_idx].name, nmc_fields_settings_names[14].name)) {
-			setting = nm_connection_get_setting (connection, NM_TYPE_SETTING_VPN);
-			if (setting) {
-				setting_vpn_details (setting, nmc);
+			NMSettingVPN *s_vpn = nm_connection_get_setting_vpn (connection);
+			if (s_vpn) {
+				setting_vpn_details (s_vpn, nmc);
 				was_output = TRUE;
 				continue;
 			}
@@ -365,14 +397,41 @@ nmc_connection_detail (NMConnection *connection, NmCli *nmc)
 
 #if WITH_WIMAX
 		if (!strcasecmp (nmc_fields_settings_names[section_idx].name, nmc_fields_settings_names[15].name)) {
-			setting = nm_connection_get_setting (connection, NM_TYPE_SETTING_WIMAX);
-			if (setting) {
-				setting_wimax_details (setting, nmc);
+			NMSettingWimax *s_wimax = nm_connection_get_setting_wimax (connection);
+			if (s_wimax) {
+				setting_wimax_details (s_wimax, nmc);
 				was_output = TRUE;
 				continue;
 			}
 		}
 #endif
+
+		if (!strcasecmp (nmc_fields_settings_names[section_idx].name, nmc_fields_settings_names[16].name)) {
+			NMSettingInfiniband *s_infiniband = nm_connection_get_setting_infiniband (connection);
+			if (s_infiniband) {
+				setting_infiniband_details (s_infiniband, nmc);
+				was_output = TRUE;
+				continue;
+			}
+		}
+
+		if (!strcasecmp (nmc_fields_settings_names[section_idx].name, nmc_fields_settings_names[17].name)) {
+			NMSettingBond *s_bond = nm_connection_get_setting_bond (connection);
+			if (s_bond) {
+				setting_bond_details (s_bond, nmc);
+				was_output = TRUE;
+				continue;
+			}
+		}
+
+		if (!strcasecmp (nmc_fields_settings_names[section_idx].name, nmc_fields_settings_names[18].name)) {
+			NMSettingVlan *s_vlan = nm_connection_get_setting_vlan (connection);
+			if (s_vlan) {
+				setting_vlan_details (s_vlan, nmc);
+				was_output = TRUE;
+				continue;
+			}
+		}
 	}
 
 	if (print_settings_array)
@@ -544,19 +603,77 @@ error:
 	return nmc->return_value;
 }
 
-static void
-show_active_connection (gpointer data, gpointer user_data)
+static const char *
+active_connection_state_to_string (NMActiveConnectionState state)
 {
-	NMActiveConnection *active = NM_ACTIVE_CONNECTION (data);
-	NmCli *nmc = (NmCli *) user_data;
-	GSList *con_list, *iter;
+	switch (state) {
+	case NM_ACTIVE_CONNECTION_STATE_ACTIVATING:
+		return _("activating");
+	case NM_ACTIVE_CONNECTION_STATE_ACTIVATED:
+		return _("activated");
+	case NM_ACTIVE_CONNECTION_STATE_DEACTIVATING:
+		return _("deactivating");
+	case NM_ACTIVE_CONNECTION_STATE_UNKNOWN:
+	default:
+		return _("unknown");
+	}
+}
+
+static const char *
+vpn_connection_state_to_string (NMVPNConnectionState state)
+{
+	switch (state) {
+	case NM_VPN_CONNECTION_STATE_PREPARE:
+		return _("VPN connecting (prepare)");
+	case NM_VPN_CONNECTION_STATE_NEED_AUTH:
+		return _("VPN connecting (need authentication)");
+	case NM_VPN_CONNECTION_STATE_CONNECT:
+		return _("VPN connecting");
+	case NM_VPN_CONNECTION_STATE_IP_CONFIG_GET:
+		return _("VPN connecting (getting IP configuration)");
+	case NM_VPN_CONNECTION_STATE_ACTIVATED:
+		return _("VPN connected");
+	case NM_VPN_CONNECTION_STATE_FAILED:
+		return _("VPN connection failed");
+	case NM_VPN_CONNECTION_STATE_DISCONNECTED:
+		return _("VPN disconnected");
+	default:
+		return _("unknown");
+	}
+}
+
+static NMConnection *
+get_connection_for_active (const GSList *con_list, NMActiveConnection *active)
+{
+	const GSList *iter;
+	const char *path;
+
+	path = nm_active_connection_get_connection (active);
+	g_return_val_if_fail (path != NULL, NULL);
+
+	for (iter = con_list; iter; iter = g_slist_next (iter)) {
+		NMConnection *candidate = NM_CONNECTION (iter->data);
+
+		if (strcmp (nm_connection_get_path (candidate), path) == 0)
+			return candidate;
+	}
+	return NULL;
+}
+
+static gboolean
+fill_in_fields_con_status (NMActiveConnection *active, GSList *con_list)
+{
+	GSList *iter;
 	const char *active_path;
 	NMSettingConnection *s_con;
 	const GPtrArray *devices;
 	GString *dev_str;
+	NMActiveConnectionState state;
 	int i;
+	gboolean success = FALSE;
 
 	active_path = nm_active_connection_get_connection (active);
+	state = nm_active_connection_get_state (active);
 
 	/* Get devices of the active connection */
 	dev_str = g_string_new (NULL);
@@ -570,7 +687,6 @@ show_active_connection (gpointer data, gpointer user_data)
 	if (dev_str->len > 0)
 		g_string_truncate (dev_str, dev_str->len - 1);  /* Cut off last ',' */
 
-	con_list = nmc->system_connections; 
 	for (iter = con_list; iter; iter = g_slist_next (iter)) {
 		NMConnection *connection = (NMConnection *) iter->data;
 		const char *con_path = nm_connection_get_path (connection);
@@ -580,410 +696,432 @@ show_active_connection (gpointer data, gpointer user_data)
 			s_con = nm_connection_get_setting_connection (connection);
 			g_assert (s_con != NULL);
 
-			/* Obtain field values */
-			nmc->allowed_fields[0].value = nm_setting_connection_get_id (s_con);
-			nmc->allowed_fields[1].value = nm_setting_connection_get_uuid (s_con);
-			nmc->allowed_fields[2].value = dev_str->str;
-			nmc->allowed_fields[3].value = nm_active_connection_get_default (active) ? _("yes") : _("no");
-			nmc->allowed_fields[4].value = nm_active_connection_get_specific_object (active);
-			nmc->allowed_fields[5].value = NM_IS_VPN_CONNECTION (active) ? _("yes") : _("no");
-			nmc->allowed_fields[6].value = nm_object_get_path (NM_OBJECT (active));
-
-			nmc->print_fields.flags &= ~NMC_PF_FLAG_MAIN_HEADER_ADD & ~NMC_PF_FLAG_MAIN_HEADER_ONLY & ~NMC_PF_FLAG_FIELD_NAMES; /* Clear header flags */
-			print_fields (nmc->print_fields, nmc->allowed_fields);
+			/* Fill field values */
+			nmc_fields_con_status[0].value = nmc_fields_status_details_groups[0].name;
+			nmc_fields_con_status[1].value = nm_setting_connection_get_id (s_con);
+			nmc_fields_con_status[2].value = nm_setting_connection_get_uuid (s_con);
+			nmc_fields_con_status[3].value = dev_str->str;
+			nmc_fields_con_status[4].value = active_connection_state_to_string (state);
+			nmc_fields_con_status[5].value = nm_active_connection_get_default (active) ? _("yes") : _("no");
+			nmc_fields_con_status[6].value = nm_active_connection_get_default6 (active) ? _("yes") : _("no");
+			nmc_fields_con_status[7].value = nm_active_connection_get_specific_object (active);
+			nmc_fields_con_status[8].value = NM_IS_VPN_CONNECTION (active) ? _("yes") : _("no");
+			nmc_fields_con_status[9].value = nm_object_get_path (NM_OBJECT (active));
+			nmc_fields_con_status[10].value = nm_active_connection_get_connection (active);
+			nmc_fields_con_status[11].value = nm_setting_connection_get_zone (s_con);
+			nmc_fields_con_status[12].value = nm_active_connection_get_master (active);
+
+			success = TRUE;
 			break;
 		}
 	}
 
-	g_string_free (dev_str, TRUE);
+	/* Just free GString here, the char array has to be freed after printing
+	 * (by free_fields_con_status()) */
+	g_string_free (dev_str, FALSE);
+	return success;
 }
 
-static NMCResultCode
-do_connections_status (NmCli *nmc, int argc, char **argv)
+static void
+free_fields_con_status (void)
 {
-	const GPtrArray *active_cons;
-	GError *error = NULL;
-	char *fields_str;
-	char *fields_all =    NMC_FIELDS_CON_STATUS_ALL;
-	char *fields_common = NMC_FIELDS_CON_STATUS_COMMON;
-	guint32 mode_flag = (nmc->print_output == NMC_PRINT_PRETTY) ? NMC_PF_FLAG_PRETTY : (nmc->print_output == NMC_PRINT_TERSE) ? NMC_PF_FLAG_TERSE : 0;
-	guint32 multiline_flag = nmc->multiline_output ? NMC_PF_FLAG_MULTILINE : 0;
-	guint32 escape_flag = nmc->escape_values ? NMC_PF_FLAG_ESCAPE : 0;
-
-	nmc->should_wait = FALSE;
-
-	if (!nmc->required_fields || strcasecmp (nmc->required_fields, "common") == 0)
-		fields_str = fields_common;
-	else if (!nmc->required_fields || strcasecmp (nmc->required_fields, "all") == 0)
-		fields_str = fields_all;
-	else
-		fields_str = nmc->required_fields;
+	/* Just DEVICES string was dynamically allocated */
+	g_free ((char *) nmc_fields_con_status[3].value);
+	nmc_fields_con_status[3].value = NULL;
+}
 
-	nmc->allowed_fields = nmc_fields_con_status;
-	nmc->print_fields.indices = parse_output_fields (fields_str, nmc->allowed_fields, &error);
+static void
+show_active_connection (gpointer data, gpointer user_data)
+{
+	NMActiveConnection *active = NM_ACTIVE_CONNECTION (data);
+	NmCli *nmc = (NmCli *) user_data;
 
-	if (error) {
-		if (error->code == 0)
-			g_string_printf (nmc->return_text, _("Error: 'con status': %s"), error->message);
-		else
-			g_string_printf (nmc->return_text, _("Error: 'con status': %s; allowed fields: %s"), error->message, NMC_FIELDS_CON_STATUS_ALL);
-		g_error_free (error);
-		nmc->return_value = NMC_RESULT_ERROR_USER_INPUT;
-		goto error;
-	}
+	fill_in_fields_con_status (active, nmc->system_connections);
 
-	if (!nmc_is_nm_running (nmc, &error)) {
-		if (error) {
-			g_string_printf (nmc->return_text, _("Error: Can't find out if NetworkManager is running: %s."), error->message);
-			nmc->return_value = NMC_RESULT_ERROR_UNKNOWN;
-			g_error_free (error);
-		} else {
-			g_string_printf (nmc->return_text, _("Error: NetworkManager is not running."));
-			nmc->return_value = NMC_RESULT_ERROR_NM_NOT_RUNNING;
-		}
-		goto error;
-	}
-
-	/* Print headers */
-	nmc->print_fields.flags = multiline_flag | mode_flag | escape_flag | NMC_PF_FLAG_MAIN_HEADER_ADD | NMC_PF_FLAG_FIELD_NAMES;
-	nmc->print_fields.header_name = _("Active connections");
+	nmc->print_fields.flags &= ~NMC_PF_FLAG_MAIN_HEADER_ADD & ~NMC_PF_FLAG_MAIN_HEADER_ONLY & ~NMC_PF_FLAG_FIELD_NAMES; /* Clear header flags */
 	print_fields (nmc->print_fields, nmc->allowed_fields);
 
-	nmc->get_client (nmc);
-	active_cons = nm_client_get_active_connections (nmc->client);
-	if (active_cons && active_cons->len)
-		g_ptr_array_foreach ((GPtrArray *) active_cons, show_active_connection, (gpointer) nmc);
-
-error:
-	return nmc->return_value;
+	free_fields_con_status ();
 }
 
-/* --------------------
- * These function should be moved to libnm-glib in the end.
- */
-static gboolean
-check_ethernet_compatible (NMDeviceEthernet *device, NMConnection *connection, GError **error)
+static NMActiveConnection *
+find_active_connection (const GPtrArray *active_cons, const GSList *cons,
+                        const char *filter_type, const char *filter_val)
 {
+	int i;
+	const char *s_path, *a_path;
+	const char *id;
+	const char *uuid;
+	NMConnection *con;
 	NMSettingConnection *s_con;
-	NMSettingWired *s_wired;
-	const char *connection_type;
-	gboolean is_pppoe = FALSE;
-
-	g_return_val_if_fail (error == NULL || *error == NULL, FALSE);
-
-	s_con = nm_connection_get_setting_connection (connection);
-	g_assert (s_con);
-
-	connection_type = nm_setting_connection_get_connection_type (s_con);
-	if (   strcmp (connection_type, NM_SETTING_WIRED_SETTING_NAME)
-	    && strcmp (connection_type, NM_SETTING_PPPOE_SETTING_NAME)) {
-		g_set_error (error, 0, 0,
-		             "The connection was not a wired or PPPoE connection.");
-		return FALSE;
-	}
 
-	if (!strcmp (connection_type, NM_SETTING_PPPOE_SETTING_NAME))
-		is_pppoe = TRUE;
-
-	s_wired = nm_connection_get_setting_wired (connection);
-	/* Wired setting is optional for PPPoE */
-	if (!is_pppoe && !s_wired) {
-		g_set_error (error, 0, 0,
-		             "The connection was not a valid wired connection.");
-		return FALSE;
-	}
-
-	if (s_wired) {
-		const GByteArray *mac;
-		const char *device_mac_str;
-		struct ether_addr *device_mac = NULL;
-
-		device_mac_str = nm_device_ethernet_get_permanent_hw_address (device);
-		if (device_mac_str)
-			device_mac = ether_aton (device_mac_str);
-		if (!device_mac) {
-			g_set_error (error, 0, 0, "Invalid device MAC address.");
-			return FALSE;
-		}
+	for (i = 0; active_cons && (i < active_cons->len); i++) {
+		NMActiveConnection *candidate = g_ptr_array_index (active_cons, i);
 
-		mac = nm_setting_wired_get_mac_address (s_wired);
-		if (mac && memcmp (mac->data, device_mac->ether_addr_octet, ETH_ALEN)) {
-			g_set_error (error, 0, 0,
-			             "The connection's MAC address did not match this device.");
-			return FALSE;
+		s_path = nm_active_connection_get_connection (candidate);
+		a_path = nm_object_get_path (NM_OBJECT (candidate));
+		uuid = nm_active_connection_get_uuid (candidate);
+
+		con = get_connection_for_active (cons, candidate);
+		s_con = nm_connection_get_setting_connection (con);
+		g_assert (s_con != NULL);
+		id = nm_setting_connection_get_id (s_con);
+
+		if (filter_type) {
+			if (   (strcmp (filter_type, "id") == 0 && strcmp (filter_val, id) == 0)
+			    || (strcmp (filter_type, "uuid") == 0 && strcmp (filter_val, uuid) == 0)
+			    || (strcmp (filter_type, "path") == 0 && strcmp (filter_val, s_path) == 0)
+			    || (strcmp (filter_type, "path") == 0 && strcmp (filter_val, a_path) == 0)) {
+				return candidate;
+			}
 		}
 	}
+	return NULL;
+}
 
-	// FIXME: check bitrate against device capabilities
+typedef struct {
+	char **array;
+	guint32 idx;
+} FillVPNDataInfo;
 
-	return TRUE;
+static void
+fill_vpn_data_item (const char *key, const char *value, gpointer user_data)
+{
+        FillVPNDataInfo *info = (FillVPNDataInfo *) user_data;
+
+	info->array[info->idx++] = g_strdup_printf ("%s = %s", key, value);
 }
 
-static gboolean
-check_wifi_compatible (NMDeviceWifi *device, NMConnection *connection, GError **error)
+// FIXME: The same or similar code for VPN info appears also in nm-applet (applet-dialogs.c),
+// and in gnome-control-center as well. It could probably be shared somehow.
+static char *
+get_vpn_connection_type (NMConnection *connection)
 {
-	NMSettingConnection *s_con;
-	NMSettingWireless *s_wireless;
+	const char *type, *p;
 
-	g_return_val_if_fail (error == NULL || *error == NULL, FALSE);
-
-	s_con = nm_connection_get_setting_connection (connection);
-	g_assert (s_con);
+	/* The service type is in form of "org.freedesktop.NetworkManager.vpnc".
+	 * Extract end part after last dot, e.g. "vpnc"
+	 */
+	type = nm_setting_vpn_get_service_type (nm_connection_get_setting_vpn (connection));
+	p = strrchr (type, '.');
+	return g_strdup (p ? p + 1 : type);
+}
 
-	if (strcmp (nm_setting_connection_get_connection_type (s_con), NM_SETTING_WIRELESS_SETTING_NAME)) {
-		g_set_error (error, 0, 0,
-		             "The connection was not a WiFi connection.");
-		return FALSE;
-	}
+/* VPN parameters can be found at:
+ * http://git.gnome.org/browse/network-manager-openvpn/tree/src/nm-openvpn-service.h
+ * http://git.gnome.org/browse/network-manager-vpnc/tree/src/nm-vpnc-service.h
+ * http://git.gnome.org/browse/network-manager-pptp/tree/src/nm-pptp-service.h
+ * http://git.gnome.org/browse/network-manager-openconnect/tree/src/nm-openconnect-service.h
+ * http://git.gnome.org/browse/network-manager-openswan/tree/src/nm-openswan-service.h
+ * See also 'properties' directory in these plugins.
+ */
+static const gchar *
+find_vpn_gateway_key (const char *vpn_type)
+{
+	if (g_strcmp0 (vpn_type, "openvpn") == 0)     return "remote";
+	if (g_strcmp0 (vpn_type, "vpnc") == 0)        return "IPSec gateway";
+	if (g_strcmp0 (vpn_type, "pptp") == 0)        return "gateway";
+	if (g_strcmp0 (vpn_type, "openconnect") == 0) return "gateway";
+	if (g_strcmp0 (vpn_type, "openswan") == 0)    return "right";
+	return "";
+}
 
-	s_wireless = nm_connection_get_setting_wireless (connection);
-	if (!s_wireless) {
-		g_set_error (error, 0, 0,
-		             "The connection was not a valid WiFi connection.");
-		return FALSE;
-	}
+static const gchar *
+find_vpn_username_key (const char *vpn_type)
+{
+	if (g_strcmp0 (vpn_type, "openvpn") == 0)     return "username";
+	if (g_strcmp0 (vpn_type, "vpnc") == 0)        return "Xauth username";
+	if (g_strcmp0 (vpn_type, "pptp") == 0)        return "user";
+	if (g_strcmp0 (vpn_type, "openconnect") == 0) return "username";
+	if (g_strcmp0 (vpn_type, "openswan") == 0)    return "leftxauthusername";
+	return "";
+}
 
-	if (s_wireless) {
-		const GByteArray *mac;
-		const char *device_mac_str;
-		struct ether_addr *device_mac = NULL;
+enum VpnDataItem {
+	VPN_DATA_ITEM_GATEWAY,
+	VPN_DATA_ITEM_USERNAME
+};
 
-		device_mac_str = nm_device_wifi_get_permanent_hw_address (device);
-		if (device_mac_str)
-			device_mac = ether_aton (device_mac_str);
-		if (!device_mac) {
-			g_set_error (error, 0, 0, "Invalid device MAC address.");
-			return FALSE;
-		}
+static const gchar *
+get_vpn_data_item (NMConnection *connection, enum VpnDataItem vpn_data_item)
+{
+	const char *key;
+	char *type = get_vpn_connection_type (connection);
 
-		mac = nm_setting_wireless_get_mac_address (s_wireless);
-		if (mac && memcmp (mac->data, device_mac->ether_addr_octet, ETH_ALEN)) {
-			g_set_error (error, 0, 0,
-		        	     "The connection's MAC address did not match this device.");
-			return FALSE;
-		}
+	switch (vpn_data_item) {
+	case VPN_DATA_ITEM_GATEWAY:
+		key = find_vpn_gateway_key (type);
+		break;
+	case VPN_DATA_ITEM_USERNAME:
+		key = find_vpn_username_key (type);
+		break;
+	default:
+		key = "";
+		break;
 	}
+	g_free (type);
 
-	// FIXME: check channel/freq/band against bands the hardware supports
-	// FIXME: check encryption against device capabilities
-	// FIXME: check bitrate against device capabilities
-
-	return TRUE;
+	return nm_setting_vpn_get_data_item (nm_connection_get_setting_vpn (connection), key);
 }
+/* FIXME end */
 
 static gboolean
-check_bt_compatible (NMDeviceBt *device, NMConnection *connection, GError **error)
+nmc_active_connection_detail (NMActiveConnection *acon, NmCli *nmc)
 {
-	NMSettingConnection *s_con;
-	NMSettingBluetooth *s_bt;
-	const GByteArray *array;
-	char *str;
-	const char *device_hw_str;
-	int addr_match = FALSE;
-	const char *bt_type_str;
-	guint32 bt_type, bt_capab;
-
-	g_return_val_if_fail (error == NULL || *error == NULL, FALSE);
+	GError *error = NULL;
+	GArray *print_groups;
+	int i;
+	char *fields_str;
+	char *fields_all =    NMC_FIELDS_CON_STATUS_DETAILS_ALL;
+	char *fields_common = NMC_FIELDS_CON_STATUS_DETAILS_ALL;
+	guint32 mode_flag = (nmc->print_output == NMC_PRINT_PRETTY) ? NMC_PF_FLAG_PRETTY : (nmc->print_output == NMC_PRINT_TERSE) ? NMC_PF_FLAG_TERSE : 0;
+	guint32 multiline_flag = nmc->multiline_output ? NMC_PF_FLAG_MULTILINE : 0;
+	guint32 escape_flag = nmc->escape_values ? NMC_PF_FLAG_ESCAPE : 0;
+	gboolean was_output = FALSE;
 
-	s_con = nm_connection_get_setting_connection (connection);
-	g_assert (s_con);
+	if (!nmc->required_fields || strcasecmp (nmc->required_fields, "common") == 0)
+		fields_str = fields_common;
+	else if (!nmc->required_fields || strcasecmp (nmc->required_fields, "all") == 0)
+		fields_str = fields_all;
+	else
+		fields_str = nmc->required_fields;
 
-	if (strcmp (nm_setting_connection_get_connection_type (s_con), NM_SETTING_BLUETOOTH_SETTING_NAME)) {
-		g_set_error (error, 0, 0,
-		             "The connection was not a Bluetooth connection.");
+	print_groups = parse_output_fields (fields_str, nmc_fields_status_details_groups, &error);
+	if (error) {
+		if (error->code == 0)
+			g_string_printf (nmc->return_text, _("Error: 'con status': %s"), error->message);
+		else
+			g_string_printf (nmc->return_text, _("Error: 'con status': %s; allowed fields: %s"), error->message, NMC_FIELDS_CON_STATUS_DETAILS_ALL);
+		g_error_free (error);
+		nmc->return_value = NMC_RESULT_ERROR_USER_INPUT;
 		return FALSE;
 	}
 
-	s_bt = nm_connection_get_setting_bluetooth (connection);
-	if (!s_bt) {
-		g_set_error (error, 0, 0,
-		             "The connection was not a valid Bluetooth connection.");
-		return FALSE;
-	}
+	nmc->allowed_fields = nmc_fields_status_details_groups;
+	nmc->print_fields.flags = multiline_flag | mode_flag | escape_flag | NMC_PF_FLAG_MAIN_HEADER_ONLY;
+	nmc->print_fields.header_name = _("Active connection details");
+	nmc->print_fields.indices = parse_output_fields (NMC_FIELDS_CON_STATUS_DETAILS_ALL, nmc->allowed_fields, NULL);
+	print_fields (nmc->print_fields, nmc->allowed_fields);
 
-	array = nm_setting_bluetooth_get_bdaddr (s_bt);
-	if (!array || (array->len != ETH_ALEN)) {
-		g_set_error (error, 0, 0,
-		             "The connection did not contain a valid Bluetooth address.");
-		return FALSE;
-	}
+	/* Loop through the groups and print them. */
+	for (i = 0; i < print_groups->len; i++) {
+		int group_idx = g_array_index (print_groups, int, i);
 
-	bt_type_str = nm_setting_bluetooth_get_connection_type (s_bt);
-	g_assert (bt_type_str);
+		if (nmc->print_output != NMC_PRINT_TERSE && !nmc->multiline_output && was_output)
+			printf ("\n"); /* Empty line */
 
-	bt_type = NM_BT_CAPABILITY_NONE;
-	if (!strcmp (bt_type_str, NM_SETTING_BLUETOOTH_TYPE_DUN))
-		bt_type = NM_BT_CAPABILITY_DUN;
-	else if (!strcmp (bt_type_str, NM_SETTING_BLUETOOTH_TYPE_PANU))
-		bt_type = NM_BT_CAPABILITY_NAP;
+		was_output = FALSE;
 
-	bt_capab = nm_device_bt_get_capabilities (device);
-	if (!(bt_type & bt_capab)) {
-		g_set_error (error, 0, 0,
-		             "The connection was not compatible with the device's capabilities.");
-		return FALSE;
-	}
+		/* GENERAL */
+		if (strcasecmp (nmc_fields_status_details_groups[group_idx].name, nmc_fields_status_details_groups[0].name) == 0) {
+			nmc->allowed_fields = nmc_fields_con_status;
+			nmc->print_fields.indices = parse_output_fields (NMC_FIELDS_CON_STATUS_DETAILS_GENERAL_ALL, nmc->allowed_fields, NULL);
 
-	device_hw_str = nm_device_bt_get_hw_address (device);
+			/* Print field names */
+			nmc->print_fields.flags = multiline_flag | mode_flag | escape_flag | NMC_PF_FLAG_FIELD_NAMES;
+			print_fields (nmc->print_fields, nmc->allowed_fields);
 
-	str = g_strdup_printf ("%02X:%02X:%02X:%02X:%02X:%02X",
-	                       array->data[0], array->data[1], array->data[2],
-	                       array->data[3], array->data[4], array->data[5]);
-	addr_match = !strcmp (device_hw_str, str);
-	g_free (str);
+			/* Fill in values */
+			fill_in_fields_con_status (acon, nmc->system_connections);
 
-	return addr_match;
-}
+			/* and print them */
+			nmc->print_fields.flags = multiline_flag | mode_flag | escape_flag | NMC_PF_FLAG_SECTION_PREFIX;
+			print_fields (nmc->print_fields, nmc->allowed_fields);
 
-#if 0
-static gboolean
-check_olpc_mesh_compatible (NMDeviceOlpcMesh *device, NMConnection *connection, GError **error)
-{
-	NMSettingConnection *s_con;
-	NMSettingOlpcMesh *s_mesh;
+			free_fields_con_status ();
+			was_output = TRUE;
+		}
 
-	g_return_val_if_fail (error == NULL || *error == NULL, FALSE);
+		/* IP */
+		if (strcasecmp (nmc_fields_status_details_groups[group_idx].name,  nmc_fields_status_details_groups[1].name) == 0) {
+			const GPtrArray *devices;
+			int j;
+
+			devices = nm_active_connection_get_devices (acon);
+			for (j = 0; devices && (j < devices->len); j++) {
+				gboolean b1 = FALSE, b2 = FALSE, b3 = FALSE, b4 = FALSE;
+				NMDevice *device = g_ptr_array_index (devices, j);
+				NMIP4Config *cfg4 = nm_device_get_ip4_config (device);
+				NMIP6Config *cfg6 = nm_device_get_ip6_config (device);
+				NMDHCP4Config *dhcp4 = nm_device_get_dhcp4_config (device);
+				NMDHCP6Config *dhcp6 = nm_device_get_dhcp6_config (device);
+
+				b1 = print_ip4_config (cfg4, nmc, "IP4");
+				b2 = print_dhcp4_config (dhcp4, nmc, "DHCP4");
+				b3 = print_ip6_config (cfg6, nmc, "IP6");
+				b4 = print_dhcp6_config (dhcp6, nmc, "DHCP6");
+				was_output = was_output || b1 || b2 || b3 || b4;
+			}
+		}
 
-	s_con = nm_connection_get_setting_connection (connection);
-	g_assert (s_con);
+		/* VPN */
+		if (NM_IS_VPN_CONNECTION (acon) &&
+		    strcasecmp (nmc_fields_status_details_groups[group_idx].name,  nmc_fields_status_details_groups[2].name) == 0) {
+			NMConnection *con;
+			NMSettingConnection *s_con;
+			NMSettingVPN *s_vpn;
+			NMVPNConnectionState vpn_state;
+			char *type_str, *banner_str, *vpn_state_str;
+			const char *username = NULL;
+			char **vpn_data_array = NULL;
+			guint32 items_num;
+
+			con = get_connection_for_active (nmc->system_connections, acon);
+
+			s_con = nm_connection_get_setting_connection (con);
+			g_assert (s_con != NULL);
 
-	if (strcmp (nm_setting_connection_get_connection_type (s_con), NM_SETTING_OLPC_MESH_SETTING_NAME)) {
-		g_set_error (error, 0, 0,
-		             "The connection was not a Mesh connection.");
-		return FALSE;
-	}
+			nmc->allowed_fields = nmc_fields_status_details_vpn;
+			nmc->print_fields.indices = parse_output_fields (NMC_FIELDS_CON_STATUS_DETAILS_VPN_ALL, nmc->allowed_fields, NULL);
 
-	s_mesh = nm_connection_get_setting_olpc_mesh (connection);
-	if (!s_mesh) {
-		g_set_error (error, 0, 0,
-		             "The connection was not a valid Mesh connection.");
-		return FALSE;
+			/* Print field names */
+			nmc->print_fields.flags = multiline_flag | mode_flag | escape_flag | NMC_PF_FLAG_FIELD_NAMES;
+			print_fields (nmc->print_fields, nmc->allowed_fields);
+
+			s_vpn = nm_connection_get_setting_vpn (con);
+			if (s_vpn) {
+				items_num = nm_setting_vpn_get_num_data_items (s_vpn);
+				if (items_num > 0) {
+					FillVPNDataInfo info;
+
+					vpn_data_array = g_new (char *, items_num + 1);
+					info.array = vpn_data_array;
+					info.idx = 0;
+					nm_setting_vpn_foreach_data_item (s_vpn, &fill_vpn_data_item, &info);
+					vpn_data_array[items_num] = NULL;
+				}
+				username = nm_setting_vpn_get_user_name (s_vpn);
+			}
+
+			type_str = get_vpn_connection_type (con);
+			banner_str = g_strescape (nm_vpn_connection_get_banner (NM_VPN_CONNECTION (acon)), "");
+			vpn_state = nm_vpn_connection_get_vpn_state (NM_VPN_CONNECTION (acon));
+			vpn_state_str = g_strdup_printf ("%d - %s", vpn_state, vpn_connection_state_to_string (vpn_state));
+
+			/* Print values */
+			set_val_str (nmc->allowed_fields, 0, nmc_fields_status_details_groups[2].name);
+			set_val_str (nmc->allowed_fields, 1, type_str);
+			set_val_str (nmc->allowed_fields, 2, username ? username : get_vpn_data_item (con, VPN_DATA_ITEM_USERNAME));
+			set_val_str (nmc->allowed_fields, 3, get_vpn_data_item (con, VPN_DATA_ITEM_GATEWAY));
+			set_val_str (nmc->allowed_fields, 4, banner_str);
+			set_val_str (nmc->allowed_fields, 5, vpn_state_str);
+			set_val_arr (nmc->allowed_fields, 6, (const char **) vpn_data_array);
+
+			nmc->print_fields.flags = multiline_flag | mode_flag | escape_flag | NMC_PF_FLAG_SECTION_PREFIX;
+			print_fields (nmc->print_fields, nmc->allowed_fields);
+
+			g_free (type_str);
+			g_free (banner_str);
+			g_free (vpn_state_str);
+			g_strfreev (vpn_data_array);
+			was_output = TRUE;
+		}
 	}
 
+	if (print_groups)
+		g_array_free (print_groups, FALSE);
+
 	return TRUE;
 }
-#endif
 
-#if WITH_WIMAX
-static gboolean
-check_wimax_compatible (NMDeviceWimax *device, NMConnection *connection, GError **error)
+static NMCResultCode
+do_connections_status (NmCli *nmc, int argc, char **argv)
 {
-	NMSettingConnection *s_con;
-	NMSettingWimax *s_wimax;
-	const GByteArray *mac;
-	const char *device_mac_str;
-	struct ether_addr *device_mac = NULL;
-
-	g_return_val_if_fail (error == NULL || *error == NULL, FALSE);
-
-	s_con = nm_connection_get_setting_connection (connection);
-	g_assert (s_con);
-
-	if (strcmp (nm_setting_connection_get_connection_type (s_con), NM_SETTING_WIMAX_SETTING_NAME)) {
-		g_set_error (error, 0, 0,
-		             "The connection was not a WiMAX connection.");
-		return FALSE;
-	}
+	const GPtrArray *active_cons;
+	GError *err = NULL;
+	GError *err1 = NULL;
 
-	s_wimax = nm_connection_get_setting_wimax (connection);
-	if (!s_wimax) {
-		g_set_error (error, 0, 0,
-		             "The connection was not a valid WiMAX connection.");
-		return FALSE;
-	}
+	nmc->should_wait = FALSE;
 
-	device_mac_str = nm_device_wimax_get_hw_address (device);
-	if (device_mac_str)
-		device_mac = ether_aton (device_mac_str);
-	if (!device_mac) {
-		g_set_error (error, 0, 0, "Invalid device MAC address.");
-		return FALSE;
+	if (!nmc_is_nm_running (nmc, &err)) {
+		if (err) {
+			g_string_printf (nmc->return_text, _("Error: Can't find out if NetworkManager is running: %s."), err->message);
+			nmc->return_value = NMC_RESULT_ERROR_UNKNOWN;
+			g_error_free (err);
+		} else {
+			g_string_printf (nmc->return_text, _("Error: NetworkManager is not running."));
+			nmc->return_value = NMC_RESULT_ERROR_NM_NOT_RUNNING;
+		}
+		goto error;
 	}
 
-	mac = nm_setting_wimax_get_mac_address (s_wimax);
-	if (mac && memcmp (mac->data, device_mac->ether_addr_octet, ETH_ALEN)) {
-		g_set_error (error, 0, 0,
-	        	     "The connection's MAC address did not match this device.");
-		return FALSE;
-	}
+	/* Get active connections */
+	nmc->get_client (nmc);
+	active_cons = nm_client_get_active_connections (nmc->client);
 
-	return TRUE;
-}
-#endif
+	if (argc == 0) {
+		char *fields_str;
+		char *fields_all =    NMC_FIELDS_CON_STATUS_ALL;
+		char *fields_common = NMC_FIELDS_CON_STATUS_COMMON;
+		guint32 mode_flag = (nmc->print_output == NMC_PRINT_PRETTY) ? NMC_PF_FLAG_PRETTY : (nmc->print_output == NMC_PRINT_TERSE) ? NMC_PF_FLAG_TERSE : 0;
+		guint32 multiline_flag = nmc->multiline_output ? NMC_PF_FLAG_MULTILINE : 0;
+		guint32 escape_flag = nmc->escape_values ? NMC_PF_FLAG_ESCAPE : 0;
+
+		if (!nmc->required_fields || strcasecmp (nmc->required_fields, "common") == 0)
+			fields_str = fields_common;
+		else if (!nmc->required_fields || strcasecmp (nmc->required_fields, "all") == 0)
+			fields_str = fields_all;
+		else
+			fields_str = nmc->required_fields;
 
-static gboolean
-check_modem_compatible (NMDeviceModem *device, NMConnection *connection, GError **error)
-{
-	NMSettingConnection *s_con;
-	NMSettingGsm *s_gsm;
-	NMSettingCdma *s_cdma;
-	NMDeviceModemCapabilities caps = NM_DEVICE_MODEM_CAPABILITY_NONE;
+		nmc->allowed_fields = nmc_fields_con_status + 1 ;
+		nmc->print_fields.indices = parse_output_fields (fields_str, nmc->allowed_fields, &err1);
+		if (err1)
+			goto error;
 
-	g_return_val_if_fail (error == NULL || *error == NULL, FALSE);
+		/* Print headers */
+		nmc->print_fields.flags = multiline_flag | mode_flag | escape_flag | NMC_PF_FLAG_MAIN_HEADER_ADD | NMC_PF_FLAG_FIELD_NAMES;
+		nmc->print_fields.header_name = _("Active connections");
+		print_fields (nmc->print_fields, nmc->allowed_fields);
 
-	s_con = nm_connection_get_setting_connection (connection);
-	g_assert (s_con);
+		if (active_cons && active_cons->len)
+			g_ptr_array_foreach ((GPtrArray *) active_cons, show_active_connection, (gpointer) nmc);
+	} else {
+		while (argc > 0) {
+			if (   strcmp (*argv, "id") == 0
+			    || strcmp (*argv, "uuid") == 0
+			    || strcmp (*argv, "path") == 0) {
+				const char *selector = *argv;
+				NMActiveConnection *acon;
 
-	/* Figure out what the modem supports */
-	caps = nm_device_modem_get_current_capabilities (device);
-	if (caps & NM_DEVICE_MODEM_CAPABILITY_GSM_UMTS) {
-		if (strcmp (nm_setting_connection_get_connection_type (s_con), NM_SETTING_GSM_SETTING_NAME)) {
-			g_set_error (error, 0, 0,
-				     "The connection was not a GSM connection.");
-			return FALSE;
-		}
+				if (next_arg (&argc, &argv) != 0) {
+					g_string_printf (nmc->return_text, _("Error: %s argument is missing."), *argv);
+					nmc->return_value = NMC_RESULT_ERROR_USER_INPUT;
+					return nmc->return_value;
+				}
+				if (!nmc->mode_specified)
+					nmc->multiline_output = TRUE;  /* multiline mode is default for 'con status id|uuid|path' */
 
-		s_gsm = nm_connection_get_setting_gsm (connection);
-		if (!s_gsm) {
-			g_set_error (error, 0, 0,
-				     "The connection was not a valid GSM connection.");
-			return FALSE;
-		}
-	} else if (caps & NM_DEVICE_MODEM_CAPABILITY_CDMA_EVDO) {
-		if (strcmp (nm_setting_connection_get_connection_type (s_con), NM_SETTING_CDMA_SETTING_NAME)) {
-			g_set_error (error, 0, 0,
-				     "The connection was not a CDMA connection.");
-			return FALSE;
-		}
+				acon = find_active_connection (active_cons, nmc->system_connections, selector, *argv);
+				if (acon) {
+					nmc_active_connection_detail (acon, nmc);
+				} else {
+					g_string_printf (nmc->return_text, _("Error: '%s' is not an active connection."), *argv);
+					nmc->return_value = NMC_RESULT_ERROR_UNKNOWN;
+				}
+				break;
+			} else {
+				g_string_printf (nmc->return_text, _("Error: unknown parameter: %s"), *argv);
+				nmc->return_value = NMC_RESULT_ERROR_USER_INPUT;
+			}
 
-		s_cdma = nm_connection_get_setting_cdma (connection);
-		if (!s_cdma) {
-			g_set_error (error, 0, 0,
-				     "The connection was not a valid CDMA connection.");
-			return FALSE;
+			argc--;
+			argv++;
 		}
 	}
 
-	return TRUE;
-}
-
-static gboolean
-nm_device_is_connection_compatible (NMDevice *device, NMConnection *connection, GError **error)
-{
-	g_return_val_if_fail (NM_IS_DEVICE (device), FALSE);
-	g_return_val_if_fail (NM_IS_CONNECTION (connection), FALSE);
-
-	if (NM_IS_DEVICE_ETHERNET (device))
-		return check_ethernet_compatible (NM_DEVICE_ETHERNET (device), connection, error);
-	else if (NM_IS_DEVICE_WIFI (device))
-		return check_wifi_compatible (NM_DEVICE_WIFI (device), connection, error);
-	else if (NM_IS_DEVICE_BT (device))
-		return check_bt_compatible (NM_DEVICE_BT (device), connection, error);
-//	else if (NM_IS_DEVICE_OLPC_MESH (device))
-//		return check_olpc_mesh_compatible (NM_DEVICE_OLPC_MESH (device), connection, error);
-#if WITH_WIMAX
-	else if (NM_IS_DEVICE_WIMAX (device))
-		return check_wimax_compatible (NM_DEVICE_WIMAX (device), connection, error);
-#endif
-	else if (NM_IS_DEVICE_MODEM (device))
-		return check_modem_compatible (NM_DEVICE_MODEM (device), connection, error);
-
-	g_set_error (error, 0, 0, "unhandled device type '%s'", G_OBJECT_TYPE_NAME (device));
-	return FALSE;
+error:
+	if (err1) {
+		if (err1->code == 0)
+			g_string_printf (nmc->return_text, _("Error: 'con status': %s"), err1->message);
+		else
+			g_string_printf (nmc->return_text, _("Error: 'con status': %s; allowed fields: %s"), err1->message, NMC_FIELDS_CON_STATUS_ALL);
+		g_error_free (err1);
+		nmc->return_value = NMC_RESULT_ERROR_USER_INPUT;
+	}
+	return nmc->return_value;
 }
 
-/* -------------------- */
-
 static NMActiveConnection *
 get_default_active_connection (NmCli *nmc, NMDevice **device)
 {
@@ -1095,11 +1233,11 @@ find_device_for_connection (NmCli *nmc,
 			if (iface) {
 				const char *dev_iface = nm_device_get_iface (dev);
 				if (   !strcmp (dev_iface, iface)
-				    && nm_device_is_connection_compatible (dev, connection, NULL)) {
+				    && nm_device_connection_compatible (dev, connection, NULL)) {
 					found_device = dev;
 				}
 			} else {
-				if (nm_device_is_connection_compatible (dev, connection, NULL)) {
+				if (nm_device_connection_compatible (dev, connection, NULL)) {
 					found_device = dev;
 				}
 			}
@@ -1158,45 +1296,6 @@ find_device_for_connection (NmCli *nmc,
 }
 
 static const char *
-active_connection_state_to_string (NMActiveConnectionState state)
-{
-	switch (state) {
-	case NM_ACTIVE_CONNECTION_STATE_ACTIVATING:
-		return _("activating");
-	case NM_ACTIVE_CONNECTION_STATE_ACTIVATED:
-		return _("activated");
-	case NM_ACTIVE_CONNECTION_STATE_DEACTIVATING:
-		return _("deactivating");
-	case NM_ACTIVE_CONNECTION_STATE_UNKNOWN:
-	default:
-		return _("unknown");
-	}
-}
-
-static const char *
-vpn_connection_state_to_string (NMVPNConnectionState state)
-{
-	switch (state) {
-	case NM_VPN_CONNECTION_STATE_PREPARE:
-		return _("VPN connecting (prepare)");
-	case NM_VPN_CONNECTION_STATE_NEED_AUTH:
-		return _("VPN connecting (need authentication)");
-	case NM_VPN_CONNECTION_STATE_CONNECT:
-		return _("VPN connecting");
-	case NM_VPN_CONNECTION_STATE_IP_CONFIG_GET:
-		return _("VPN connecting (getting IP configuration)");
-	case NM_VPN_CONNECTION_STATE_ACTIVATED:
-		return _("VPN connected");
-	case NM_VPN_CONNECTION_STATE_FAILED:
-		return _("VPN connection failed");
-	case NM_VPN_CONNECTION_STATE_DISCONNECTED:
-		return _("VPN disconnected");
-	default:
-		return _("unknown");
-	}
-}
-
-static const char *
 vpn_connection_state_reason_to_string (NMVPNConnectionStateReason reason)
 {
 	switch (reason) {
@@ -1341,6 +1440,7 @@ do_connection_up (NmCli *nmc, int argc, char **argv)
 	gboolean id_specified = FALSE;
 	gboolean wait = TRUE;
 	GError *error = NULL;
+	gboolean is_virtual = FALSE;
 
 	/* Set default timeout for connection activation. It can take quite a long time.
 	 * Using 90 seconds.
@@ -1444,9 +1544,13 @@ do_connection_up (NmCli *nmc, int argc, char **argv)
 	g_assert (s_con);
 	con_type = nm_setting_connection_get_connection_type (s_con);
 
-	device_found = find_device_for_connection (nmc, connection, iface, ap, nsp, &device, &spec_object, &error);
+	if (   nm_connection_is_type (connection, NM_SETTING_BOND_SETTING_NAME)
+	    || nm_connection_is_type (connection, NM_SETTING_VLAN_SETTING_NAME))
+		is_virtual = TRUE;
 
-	if (!device_found) {
+	device_found = find_device_for_connection (nmc, connection, iface, ap, nsp, &device, &spec_object, &error);
+	/* Virtual connection may not have their interfaces created yet */
+	if (!device_found && !is_virtual) {
 		if (error)
 			g_string_printf (nmc->return_text, _("Error: No suitable device found: %s."), error->message);
 		else
@@ -1563,6 +1667,27 @@ error:
 	return nmc->return_value;
 }
 
+static void
+delete_cb (NMRemoteConnection *con, GError *err, gpointer user_data)
+{
+	NmCli *nmc = (NmCli *) user_data;
+
+	if (err) {
+		g_string_printf (nmc->return_text, _("Error: Connection deletion failed: %s"), err->message);
+		nmc->return_value = NMC_RESULT_ERROR_CON_DEL;
+	}
+	quit ();
+}
+
+static void
+connection_removed_cb (NMRemoteConnection *con, gpointer user_data)
+{
+	NmCli *nmc = (NmCli *) user_data;
+
+	nmc->return_value = NMC_RESULT_SUCCESS;
+	quit ();
+}
+
 static NMCResultCode
 do_connection_delete (NmCli *nmc, int argc, char **argv)
 {
@@ -1571,8 +1696,6 @@ do_connection_delete (NmCli *nmc, int argc, char **argv)
 	const char *id = NULL;
 	GError *error = NULL;
 
-	nmc->should_wait = FALSE;
-
 	while (argc > 0) {
 		if (strcmp (*argv, "id") == 0 || strcmp (*argv, "uuid") == 0) {
 			selector = *argv;
@@ -1616,10 +1739,22 @@ do_connection_delete (NmCli *nmc, int argc, char **argv)
 		goto error;
 	}
 
+	/* We need to wait a bit so that nmcli's permissions can be queried.
+	 * We will exit either on "Removed" signal or when D-Bus return (error)
+	 * message is received.
+	 */
+	nmc->should_wait = TRUE;
+
+	/* Connect to "Removed" signal to be able to exit when connection was removed */
+	g_signal_connect (connection, NM_REMOTE_CONNECTION_REMOVED, G_CALLBACK (connection_removed_cb), nmc);
+
 	/* Delete the connection */
-	nm_remote_connection_delete (NM_REMOTE_CONNECTION (connection), NULL, NULL);
+	nm_remote_connection_delete (NM_REMOTE_CONNECTION (connection), delete_cb, nmc);
+
+	return nmc->return_value;
 
 error:
+	nmc->should_wait = FALSE;
 	return nmc->return_value;
 }
 
diff --git a/cli/src/devices.c b/cli/src/devices.c
index 500d2341..0b1b6d6e 100644
--- a/cli/src/devices.c
+++ b/cli/src/devices.c
@@ -14,7 +14,7 @@
  * with this program; if not, write to the Free Software Foundation, Inc.,
  * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
  *
- * (C) Copyright 2010 - 2011 Red Hat, Inc.
+ * (C) Copyright 2010 - 2012 Red Hat, Inc.
  */
 
 #include "config.h"
@@ -24,10 +24,6 @@
 #include <stdlib.h>
 #include <errno.h>
 
-#include <sys/socket.h>
-#include <netinet/in.h>
-#include <arpa/inet.h>
-
 #include <glib.h>
 #include <glib/gi18n.h>
 
@@ -37,10 +33,13 @@
 #include <nm-device-wifi.h>
 #include <nm-device-modem.h>
 #include <nm-device-bt.h>
-//#include <nm-device-olpc-mesh.h>
+#include <nm-device-olpc-mesh.h>
 #if WITH_WIMAX
 #include <nm-device-wimax.h>
 #endif
+#include <nm-device-infiniband.h>
+#include <nm-device-bond.h>
+#include <nm-device-vlan.h>
 #include <nm-utils.h>
 #include <nm-setting-ip4-config.h>
 #include <nm-setting-ip6-config.h>
@@ -56,8 +55,10 @@
 #if WITH_WIMAX
 #include <nm-setting-wimax.h>
 #endif
+#include <nm-setting-infiniband.h>
 
 #include "utils.h"
+#include "common.h"
 #include "devices.h"
 
 
@@ -82,32 +83,40 @@ static NmcOutputField nmc_fields_dev_list_sections[] = {
 	{"WIRED-PROPERTIES",  N_("WIRED-PROPERTIES"),  0, NULL, 0},  /* 4 */
 	{"WIMAX-PROPERTIES",  N_("WIMAX-PROPERTIES"),  0, NULL, 0},  /* 5 */
 	{"NSP",               N_("NSP"),               0, NULL, 0},  /* 6 */
-	{"IP4-SETTINGS",      N_("IP4-SETTINGS"),      0, NULL, 0},  /* 7 */
-	{"IP4-DNS",           N_("IP4-DNS"),           0, NULL, 0},  /* 8 */
-	{"IP6-SETTINGS",      N_("IP6-SETTINGS"),      0, NULL, 0},  /* 9 */
-	{"IP6-DNS",           N_("IP6-DNS"),           0, NULL, 0},  /* 10 */
+	{"IP4",               N_("IP4"),               0, NULL, 0},  /* 7 */
+	{"DHCP4",             N_("DHCP4"),             0, NULL, 0},  /* 8 */
+	{"IP6",               N_("IP6"),               0, NULL, 0},  /* 9 */
+	{"DHCP6",             N_("DHCP6"),             0, NULL, 0},  /* 10 */
 	{NULL,                NULL,                    0, NULL, 0}
 };
 #if WITH_WIMAX
-#define NMC_FIELDS_DEV_LIST_SECTIONS_ALL     "GENERAL,CAPABILITIES,WIFI-PROPERTIES,AP,WIRED-PROPERTIES,WIMAX-PROPERTIES,NSP,IP4-SETTINGS,IP4-DNS,IP6-SETTINGS,IP6-DNS"
-#define NMC_FIELDS_DEV_LIST_SECTIONS_COMMON  "GENERAL,CAPABILITIES,WIFI-PROPERTIES,AP,WIRED-PROPERTIES,WIMAX-PROPERTIES,NSP,IP4-SETTINGS,IP4-DNS,IP6-SETTINGS,IP6-DNS"
+#define NMC_FIELDS_DEV_LIST_SECTIONS_ALL     "GENERAL,CAPABILITIES,WIFI-PROPERTIES,AP,WIRED-PROPERTIES,WIMAX-PROPERTIES,NSP,IP4,DHCP4,IP6,DHCP6"
+#define NMC_FIELDS_DEV_LIST_SECTIONS_COMMON  "GENERAL,CAPABILITIES,WIFI-PROPERTIES,AP,WIRED-PROPERTIES,WIMAX-PROPERTIES,NSP,IP4,DHCP4,IP6,DHCP6"
 #else
-#define NMC_FIELDS_DEV_LIST_SECTIONS_ALL     "GENERAL,CAPABILITIES,WIFI-PROPERTIES,AP,WIRED-PROPERTIES,IP4-SETTINGS,IP4-DNS,IP6-SETTINGS,IP6-DNS"
-#define NMC_FIELDS_DEV_LIST_SECTIONS_COMMON  "GENERAL,CAPABILITIES,WIFI-PROPERTIES,AP,WIRED-PROPERTIES,IP4-SETTINGS,IP4-DNS,IP6-SETTINGS,IP6-DNS"
+#define NMC_FIELDS_DEV_LIST_SECTIONS_ALL     "GENERAL,CAPABILITIES,WIFI-PROPERTIES,AP,WIRED-PROPERTIES,IP4,DHCP4,IP6,DHCP6"
+#define NMC_FIELDS_DEV_LIST_SECTIONS_COMMON  "GENERAL,CAPABILITIES,WIFI-PROPERTIES,AP,WIRED-PROPERTIES,IP4,DHCP4,IP6,DHCP6"
 #endif
 
 /* Available fields for 'dev list' - GENERAL part */
 static NmcOutputField nmc_fields_dev_list_general[] = {
-	{"NAME",       N_("NAME"),        10, NULL, 0},  /* 0 */
-	{"DEVICE",     N_("DEVICE"),      10, NULL, 0},  /* 1 */
-	{"TYPE",       N_("TYPE"),        17, NULL, 0},  /* 2 */
-	{"DRIVER",     N_("DRIVER"),      10, NULL, 0},  /* 3 */
-	{"HWADDR",     N_("HWADDR"),      19, NULL, 0},  /* 4 */
-	{"STATE",      N_("STATE"),       14, NULL, 0},  /* 5 */
-	{NULL,         NULL,               0, NULL, 0}
+	{"NAME",              N_("NAME"),              10, NULL, 0},  /* 0 */
+	{"DEVICE",            N_("DEVICE"),            10, NULL, 0},  /* 1 */
+	{"TYPE",              N_("TYPE"),              17, NULL, 0},  /* 2 */
+	{"VENDOR",            N_("VENDOR"),            20, NULL, 0},  /* 3 */
+	{"PRODUCT",           N_("PRODUCT"),           50, NULL, 0},  /* 4 */
+	{"DRIVER",            N_("DRIVER"),             9, NULL, 0},  /* 5 */
+	{"HWADDR",            N_("HWADDR"),            19, NULL, 0},  /* 6 */
+	{"STATE",             N_("STATE"),             14, NULL, 0},  /* 7 */
+	{"REASON",            N_("REASON"),            25, NULL, 0},  /* 8 */
+	{"UDI",               N_("UDI"),               64, NULL, 0},  /* 9 */
+	{"IP-IFACE",          N_("IP-IFACE"),          10, NULL, 0},  /* 10 */
+	{"NM-MANAGED",        N_("NM-MANAGED"),        15, NULL, 0},  /* 11 */
+	{"FIRMWARE-MISSING",  N_("FIRMWARE-MISSING"),  18, NULL, 0},  /* 12 */
+	{"CONNECTION",        N_("CONNECTION"),        51, NULL, 0},  /* 13 */
+	{NULL, NULL, 0, NULL, 0}
 };
-#define NMC_FIELDS_DEV_LIST_GENERAL_ALL     "NAME,DEVICE,TYPE,DRIVER,HWADDR,STATE"
-#define NMC_FIELDS_DEV_LIST_GENERAL_COMMON  "NAME,DEVICE,TYPE,DRIVER,HWADDR,STATE"
+#define NMC_FIELDS_DEV_LIST_GENERAL_ALL     "NAME,DEVICE,TYPE,VENDOR,PRODUCT,DRIVER,HWADDR,STATE,REASON,UDI,IP-IFACE,NM-MANAGED,FIRMWARE-MISSING,CONNECTION"
+#define NMC_FIELDS_DEV_LIST_GENERAL_COMMON  "NAME,DEVICE,TYPE,VENDOR,PRODUCT,DRIVER,HWADDR,STATE"
 
 /* Available fields for 'dev list' - CAPABILITIES part */
 static NmcOutputField nmc_fields_dev_list_cap[] = {
@@ -157,46 +166,6 @@ static NmcOutputField nmc_fields_dev_list_wimax_prop[] = {
 #define NMC_FIELDS_DEV_LIST_WIMAX_PROP_COMMON  "NAME,CTR-FREQ,RSSI,CINR,TX-POW,BSID"
 #endif
 
-/* Available fields for 'dev list' - IPv4 settings part */
-static NmcOutputField nmc_fields_dev_list_ip4_settings[] = {
-	{"NAME",       N_("NAME"),        15, NULL, 0},  /* 0 */
-	{"ADDRESS",    N_("ADDRESS"),     15, NULL, 0},  /* 1 */
-	{"PREFIX",     N_("PREFIX"),      20, NULL, 0},  /* 2 */
-	{"GATEWAY",    N_("GATEWAY"),     20, NULL, 0},  /* 3 */
-	{NULL,         NULL,               0, NULL, 0}
-};
-#define NMC_FIELDS_DEV_LIST_IP4_SETTINGS_ALL     "NAME,ADDRESS,PREFIX,GATEWAY"
-#define NMC_FIELDS_DEV_LIST_IP4_SETTINGS_COMMON  "NAME,ADDRESS,PREFIX,GATEWAY"
-
-/* Available fields for 'dev list' - IPv6 settings part */
-static NmcOutputField nmc_fields_dev_list_ip6_settings[] = {
-	{"NAME",       N_("NAME"),        15, NULL, 0},  /* 0 */
-	{"ADDRESS",    N_("ADDRESS"),     15, NULL, 0},  /* 1 */
-	{"PREFIX",     N_("PREFIX"),      20, NULL, 0},  /* 2 */
-	{"GATEWAY",    N_("GATEWAY"),     20, NULL, 0},  /* 3 */
-	{NULL,         NULL,               0, NULL, 0}
-};
-#define NMC_FIELDS_DEV_LIST_IP6_SETTINGS_ALL     "NAME,ADDRESS,PREFIX,GATEWAY"
-#define NMC_FIELDS_DEV_LIST_IP6_SETTINGS_COMMON  "NAME,ADDRESS,PREFIX,GATEWAY"
-
-/* Available fields for 'dev list' - IPv4 settings DNS part */
-static NmcOutputField nmc_fields_dev_list_ip4_dns[] = {
-	{"NAME",       N_("NAME"),        15, NULL, 0},  /* 0 */
-	{"DNS",        N_("DNS"),         17, NULL, 0},  /* 1 */
-	{NULL,         NULL,               0, NULL, 0}
-};
-#define NMC_FIELDS_DEV_LIST_IP4_DNS_ALL     "NAME,DNS"
-#define NMC_FIELDS_DEV_LIST_IP4_DNS_COMMON  "NAME,DNS"
-
-/* Available fields for 'dev list' - IPv6 settings DNS part */
-static NmcOutputField nmc_fields_dev_list_ip6_dns[] = {
-	{"NAME",       N_("NAME"),        15, NULL, 0},  /* 0 */
-	{"DNS",        N_("DNS"),         17, NULL, 0},  /* 1 */
-	{NULL,         NULL,               0, NULL, 0}
-};
-#define NMC_FIELDS_DEV_LIST_IP6_DNS_ALL     "NAME,DNS"
-#define NMC_FIELDS_DEV_LIST_IP6_DNS_COMMON  "NAME,DNS"
-
 /* Available fields for 'dev wifi list' */
 static NmcOutputField nmc_fields_dev_wifi_list[] = {
 	{"NAME",       N_("NAME"),        15, NULL, 0},  /* 0 */
@@ -299,6 +268,167 @@ device_state_to_string (NMDeviceState state)
 	}
 }
 
+static const char *
+device_reason_to_string (NMDeviceStateReason reason)
+{
+	switch (reason) {
+	case NM_DEVICE_STATE_REASON_NONE:
+		return _("No reason given");
+
+	case NM_DEVICE_STATE_REASON_UNKNOWN:
+		return _("Unknown error");
+
+	case NM_DEVICE_STATE_REASON_NOW_MANAGED:
+		return _("Device is now managed");
+
+	case NM_DEVICE_STATE_REASON_NOW_UNMANAGED:
+		return _("Device is now unmanaged");
+
+	case NM_DEVICE_STATE_REASON_CONFIG_FAILED:
+		return _("The device could not be readied for configuration");
+
+	case NM_DEVICE_STATE_REASON_IP_CONFIG_UNAVAILABLE:
+		return _("IP configuration could not be reserved (no available address, timeout, etc)");
+
+	case NM_DEVICE_STATE_REASON_IP_CONFIG_EXPIRED:
+		return _("The IP configuration is no longer valid");
+
+	case NM_DEVICE_STATE_REASON_NO_SECRETS:
+		return _("Secrets were required, but not provided");
+
+	case NM_DEVICE_STATE_REASON_SUPPLICANT_DISCONNECT:
+		return _("802.1X supplicant disconnected");
+
+	case NM_DEVICE_STATE_REASON_SUPPLICANT_CONFIG_FAILED:
+		return _("802.1X supplicant configuration failed");
+
+	case NM_DEVICE_STATE_REASON_SUPPLICANT_FAILED:
+		return _("802.1X supplicant failed");
+
+	case NM_DEVICE_STATE_REASON_SUPPLICANT_TIMEOUT:
+		return _("802.1X supplicant took too long to authenticate");
+
+	case NM_DEVICE_STATE_REASON_PPP_START_FAILED:
+		return _("PPP service failed to start");
+
+	case NM_DEVICE_STATE_REASON_PPP_DISCONNECT:
+		return _("PPP service disconnected");
+
+	case NM_DEVICE_STATE_REASON_PPP_FAILED:
+		return _("PPP failed");
+
+	case NM_DEVICE_STATE_REASON_DHCP_START_FAILED:
+		return _("DHCP client failed to start");
+
+	case NM_DEVICE_STATE_REASON_DHCP_ERROR:
+		return _("DHCP client error");
+
+	case NM_DEVICE_STATE_REASON_DHCP_FAILED:
+		return _("DHCP client failed");
+
+	case NM_DEVICE_STATE_REASON_SHARED_START_FAILED:
+		return _("Shared connection service failed to start");
+
+	case NM_DEVICE_STATE_REASON_SHARED_FAILED:
+		return _("Shared connection service failed");
+
+	case NM_DEVICE_STATE_REASON_AUTOIP_START_FAILED:
+		return _("AutoIP service failed to start");
+
+	case NM_DEVICE_STATE_REASON_AUTOIP_ERROR:
+		return _("AutoIP service error");
+
+	case NM_DEVICE_STATE_REASON_AUTOIP_FAILED:
+		return _("AutoIP service failed");
+
+	case NM_DEVICE_STATE_REASON_MODEM_BUSY:
+		return _("The line is busy");
+
+	case NM_DEVICE_STATE_REASON_MODEM_NO_DIAL_TONE:
+		return _("No dial tone");
+
+	case NM_DEVICE_STATE_REASON_MODEM_NO_CARRIER:
+		return _("No carrier could be established");
+
+	case NM_DEVICE_STATE_REASON_MODEM_DIAL_TIMEOUT:
+		return _("The dialing request timed out");
+
+	case NM_DEVICE_STATE_REASON_MODEM_DIAL_FAILED:
+		return _("The dialing attempt failed");
+
+	case NM_DEVICE_STATE_REASON_MODEM_INIT_FAILED:
+		return _("Modem initialization failed");
+
+	case NM_DEVICE_STATE_REASON_GSM_APN_FAILED:
+		return _("Failed to select the specified APN");
+
+	case NM_DEVICE_STATE_REASON_GSM_REGISTRATION_NOT_SEARCHING:
+		return _("Not searching for networks");
+
+	case NM_DEVICE_STATE_REASON_GSM_REGISTRATION_DENIED:
+		return _("Network registration denied");
+
+	case NM_DEVICE_STATE_REASON_GSM_REGISTRATION_TIMEOUT:
+		return _("Network registration timed out");
+
+	case NM_DEVICE_STATE_REASON_GSM_REGISTRATION_FAILED:
+		return _("Failed to register with the requested network");
+
+	case NM_DEVICE_STATE_REASON_GSM_PIN_CHECK_FAILED:
+		return _("PIN check failed");
+
+	case NM_DEVICE_STATE_REASON_FIRMWARE_MISSING:
+		return _("Necessary firmware for the device may be missing");
+
+	case NM_DEVICE_STATE_REASON_REMOVED:
+		return _("The device was removed");
+
+	case NM_DEVICE_STATE_REASON_SLEEPING:
+		return _("NetworkManager went to sleep");
+
+	case NM_DEVICE_STATE_REASON_CONNECTION_REMOVED:
+		return _("The device's active connection disappeared");
+
+	case NM_DEVICE_STATE_REASON_USER_REQUESTED:
+		return _("Device disconnected by user or client");
+
+	case NM_DEVICE_STATE_REASON_CARRIER:
+		return _("Carrier/link changed");
+
+	case NM_DEVICE_STATE_REASON_CONNECTION_ASSUMED:
+		return _("The device's existing connection was assumed");
+
+	case NM_DEVICE_STATE_REASON_SUPPLICANT_AVAILABLE:
+		return _("The supplicant is now available");
+
+	case NM_DEVICE_STATE_REASON_MODEM_NOT_FOUND:
+		return _("The modem could not be found");
+
+	case NM_DEVICE_STATE_REASON_BT_FAILED:
+		return _("The Bluetooth connection failed or timed out");
+
+	case NM_DEVICE_STATE_REASON_GSM_SIM_NOT_INSERTED:
+		return _("GSM Modem's SIM card not inserted");
+
+	case NM_DEVICE_STATE_REASON_GSM_SIM_PIN_REQUIRED:
+		return _("GSM Modem's SIM PIN required");
+
+	case NM_DEVICE_STATE_REASON_GSM_SIM_PUK_REQUIRED:
+		return _("GSM Modem's SIM PUK required");
+
+	case NM_DEVICE_STATE_REASON_GSM_SIM_WRONG:
+		return _("GSM Modem's SIM wrong");
+
+	case NM_DEVICE_STATE_REASON_INFINIBAND_MODE:
+		return _("InfiniBand device does not support connected mode");
+
+        case NM_DEVICE_STATE_REASON_DEPENDENCY_FAILED:
+		return _("A dependency of the connection failed");
+	default:
+		return _("Unknown");
+	}
+}
+
 /* Convert device type to string. Use setting names strings to match with
  * connection type names.
  */
@@ -321,12 +451,18 @@ device_type_to_string (NMDevice *device)
 		return _("Unknown");
 	case NM_DEVICE_TYPE_BT:
 		return NM_SETTING_BLUETOOTH_SETTING_NAME;
-//	case NM_DEVICE_TYPE_OLPC_MESH:
-//		return NM_SETTING_OLPC_MESH_SETTING_NAME;
+	case NM_DEVICE_TYPE_OLPC_MESH:
+		return NM_SETTING_OLPC_MESH_SETTING_NAME;
 #if WITH_WIMAX
 	case NM_DEVICE_TYPE_WIMAX:
 		return NM_SETTING_WIMAX_SETTING_NAME;
 #endif
+	case NM_DEVICE_TYPE_INFINIBAND:
+		return NM_SETTING_INFINIBAND_SETTING_NAME;
+	case NM_DEVICE_TYPE_BOND:
+		return NM_SETTING_BOND_SETTING_NAME;
+	case NM_DEVICE_TYPE_VLAN:
+		return NM_SETTING_VLAN_SETTING_NAME;
 	default:
 		return _("Unknown");
 	}
@@ -374,46 +510,6 @@ ap_wpa_rsn_flags_to_string (NM80211ApSecurityFlags flags)
 	return ret_str;
 }
 
-static gchar *
-ip4_address_as_string (guint32 ip)
-{
-	struct in_addr tmp_addr;
-	char buf[INET_ADDRSTRLEN+1];
-
-	memset (&buf, '\0', sizeof (buf));
-	tmp_addr.s_addr = ip;
-
-	if (inet_ntop (AF_INET, &tmp_addr, buf, INET_ADDRSTRLEN)) {
-		return g_strdup (buf);
-	} else {
-		g_warning (_("%s: error converting IP4 address 0x%X"),
-		            __func__, ntohl (tmp_addr.s_addr));
-		return NULL;
-	}
-}
-
-static gchar *
-ip6_address_as_string (const struct in6_addr *ip)
-{
-	char buf[INET6_ADDRSTRLEN];
-
-	memset (&buf, '\0', sizeof (buf));
-
-	if (inet_ntop (AF_INET6, ip, buf, INET6_ADDRSTRLEN)) {
-		return g_strdup (buf);
-	} else {
-		int j;
-		GString *ip6_str = g_string_new (NULL);
-		g_string_append_printf (ip6_str, "%02X", ip->s6_addr[0]);
-		for (j = 1; j < 16; j++)
-			g_string_append_printf (ip6_str, " %02X", ip->s6_addr[j]);
-		g_warning ("%s: error converting IP6 address %s",
-		           __func__, ip6_str->str);
-		g_string_free (ip6_str, TRUE);
-		return NULL;
-	}
-}
-
 typedef struct {
 	NmCli *nmc;
 	int index;
@@ -572,13 +668,15 @@ show_device_info (gpointer data, gpointer user_data)
 	NmCli *nmc = (NmCli *) user_data;
 	GError *error = NULL;
 	APInfo *info;
-	char *tmp;
 	const char *hwaddr = NULL;
 	NMDeviceState state = NM_DEVICE_STATE_UNKNOWN;
+	NMDeviceStateReason reason = NM_DEVICE_STATE_REASON_NONE;
 	NMDeviceCapabilities caps;
+	NMActiveConnection *acon;
 	guint32 speed;
 	char *speed_str = NULL;
-	const GArray *array;
+	char *state_str = NULL;
+	char *reason_str = NULL;
 	GArray *sections_array;
 	int k;
 	char *fields_str;
@@ -623,7 +721,7 @@ show_device_info (gpointer data, gpointer user_data)
 
 		was_output = FALSE;
 
-		state = nm_device_get_state (device);
+		state = nm_device_get_state_reason (device, &reason);
 
 		/* section GENERAL */
 		if (!strcasecmp (nmc_fields_dev_list_sections[section_idx].name, nmc_fields_dev_list_sections[0].name)) {
@@ -640,16 +738,36 @@ show_device_info (gpointer data, gpointer user_data)
 			else if (NM_IS_DEVICE_WIMAX (device))
 				hwaddr = nm_device_wimax_get_hw_address (NM_DEVICE_WIMAX (device));
 #endif
+			else if (NM_IS_DEVICE_INFINIBAND (device))
+				hwaddr = nm_device_infiniband_get_hw_address (NM_DEVICE_INFINIBAND (device));
+			else if (NM_IS_DEVICE_BOND (device))
+				hwaddr = nm_device_bond_get_hw_address (NM_DEVICE_BOND (device));
+			else if (NM_IS_DEVICE_VLAN (device))
+				hwaddr = nm_device_vlan_get_hw_address (NM_DEVICE_VLAN (device));
+
+			state_str = g_strdup_printf ("%d (%s)", state, device_state_to_string (state));
+			reason_str = g_strdup_printf ("%d (%s)", reason, device_reason_to_string (reason));
 
 			nmc->allowed_fields[0].value = nmc_fields_dev_list_sections[0].name;  /* "GENERAL"*/
 			nmc->allowed_fields[1].value = nm_device_get_iface (device);
 			nmc->allowed_fields[2].value = device_type_to_string (device);
-			nmc->allowed_fields[3].value = nm_device_get_driver (device) ? nm_device_get_driver (device) : _("(unknown)");
-			nmc->allowed_fields[4].value = hwaddr ? hwaddr : _("unknown)");
-			nmc->allowed_fields[5].value = device_state_to_string (state);
+			nmc->allowed_fields[3].value = nm_device_get_vendor (device);
+			nmc->allowed_fields[4].value = nm_device_get_product (device);
+			nmc->allowed_fields[5].value = nm_device_get_driver (device) ? nm_device_get_driver (device) : _("(unknown)");
+			nmc->allowed_fields[6].value = hwaddr ? hwaddr : _("(unknown)");
+			nmc->allowed_fields[7].value = state_str;
+			nmc->allowed_fields[8].value = reason_str;
+			nmc->allowed_fields[9].value = nm_device_get_udi (device);
+			nmc->allowed_fields[10].value = nm_device_get_ip_iface (device);
+			nmc->allowed_fields[11].value = nm_device_get_managed (device) ? _("yes") : _("no");
+			nmc->allowed_fields[12].value = nm_device_get_firmware_missing (device) ? _("yes") : _("no");
+			nmc->allowed_fields[13].value = (acon = nm_device_get_active_connection (device)) ?
+			                                   nm_object_get_path (NM_OBJECT (acon)) : _("not connected");
 
 			nmc->print_fields.flags = multiline_flag | mode_flag | escape_flag | NMC_PF_FLAG_SECTION_PREFIX;
 			print_fields (nmc->print_fields, nmc->allowed_fields); /* Print values */
+			g_free (state_str);
+			g_free (reason_str);
 			was_output = TRUE;
 		}
 
@@ -823,124 +941,28 @@ show_device_info (gpointer data, gpointer user_data)
 		}
 #endif
 
-		/* IP Setup info */
+		/* IP configuration info */
 		if (state == NM_DEVICE_STATE_ACTIVATED) {
 			NMIP4Config *cfg4 = nm_device_get_ip4_config (device);
 			NMIP6Config *cfg6 = nm_device_get_ip6_config (device);
-			GSList *iter;
+			NMDHCP4Config *dhcp4 = nm_device_get_dhcp4_config (device);
+			NMDHCP6Config *dhcp6 = nm_device_get_dhcp6_config (device);
 
-			/* IP4-SETTINGS */
-			if (cfg4 && !strcasecmp (nmc_fields_dev_list_sections[section_idx].name, nmc_fields_dev_list_sections[7].name)) {
-				nmc->allowed_fields = nmc_fields_dev_list_ip4_settings;
-				nmc->print_fields.flags = multiline_flag | mode_flag | escape_flag | NMC_PF_FLAG_FIELD_NAMES;
-				nmc->print_fields.indices = parse_output_fields (NMC_FIELDS_DEV_LIST_IP4_SETTINGS_ALL, nmc->allowed_fields, NULL);
-				print_fields (nmc->print_fields, nmc->allowed_fields); /* Print header */
-
-				for (iter = (GSList *) nm_ip4_config_get_addresses (cfg4); iter; iter = g_slist_next (iter)) {
-					NMIP4Address *addr = (NMIP4Address *) iter->data;
-					guint32 prefix = nm_ip4_address_get_prefix (addr);
-					char *tmp2;
-					char *addr_str, *prefix_str, *gateway_str;
-
-					addr_str = ip4_address_as_string (nm_ip4_address_get_address (addr));
-
-					tmp2 = ip4_address_as_string (nm_utils_ip4_prefix_to_netmask (prefix));
-					prefix_str = g_strdup_printf ("%d (%s)", prefix, tmp2);
-					g_free (tmp2);
-
-					gateway_str = ip4_address_as_string (nm_ip4_address_get_gateway (addr));
-
-					nmc->allowed_fields[0].value = nmc_fields_dev_list_sections[7].name;  /* "IP4-SETTINGS" */
-					nmc->allowed_fields[1].value = addr_str;
-					nmc->allowed_fields[2].value = prefix_str;
-					nmc->allowed_fields[3].value = gateway_str;
-
-					nmc->print_fields.flags = multiline_flag | mode_flag | escape_flag | NMC_PF_FLAG_SECTION_PREFIX;
-					print_fields (nmc->print_fields, nmc->allowed_fields); /* Print values */
-					g_free (addr_str);
-					g_free (prefix_str);
-					g_free (gateway_str);
-				}
-				was_output = TRUE;
-			}
-			/* IP4-DNS */
-			if (cfg4 && !strcasecmp (nmc_fields_dev_list_sections[section_idx].name, nmc_fields_dev_list_sections[8].name)) {
-				array = nm_ip4_config_get_nameservers (cfg4);
-				if (array) {
-					int i;
-
-					nmc->allowed_fields = nmc_fields_dev_list_ip4_dns;
-					nmc->print_fields.flags = multiline_flag | mode_flag | escape_flag | NMC_PF_FLAG_FIELD_NAMES;
-					nmc->print_fields.indices = parse_output_fields (NMC_FIELDS_DEV_LIST_IP4_DNS_ALL, nmc->allowed_fields, NULL);
-					print_fields (nmc->print_fields, nmc->allowed_fields); /* Print header */
-
-					for (i = 0; i < array->len; i++) {
-						char *dns_name = g_strdup_printf ("%s%d", nmc_fields_dev_list_sections[8].name, i+1);
-						tmp = ip4_address_as_string (g_array_index (array, guint32, i));
-						nmc->allowed_fields[0].value = dns_name;  /* "IP4-DNS<num>" */
-						nmc->allowed_fields[1].value = tmp;
-
-						nmc->print_fields.flags = multiline_flag | mode_flag | escape_flag | NMC_PF_FLAG_SECTION_PREFIX;
-						print_fields (nmc->print_fields, nmc->allowed_fields); /* Print values */
-						g_free (tmp);
-						g_free (dns_name);
-					}
-				}
-				was_output = TRUE;
-			}
-
-			/* IP6-SETTINGS */
-			if (cfg6 && !strcasecmp (nmc_fields_dev_list_sections[section_idx].name, nmc_fields_dev_list_sections[9].name)) {
-				nmc->allowed_fields = nmc_fields_dev_list_ip6_settings;
-				nmc->print_fields.flags = multiline_flag | mode_flag | escape_flag | NMC_PF_FLAG_FIELD_NAMES;
-				nmc->print_fields.indices = parse_output_fields (NMC_FIELDS_DEV_LIST_IP6_SETTINGS_ALL, nmc->allowed_fields, NULL);
-				print_fields (nmc->print_fields, nmc->allowed_fields); /* Print header */
-
-				for (iter = (GSList *) nm_ip6_config_get_addresses (cfg6); iter; iter = g_slist_next (iter)) {
-					NMIP6Address *addr = (NMIP6Address *) iter->data;
-					guint32 prefix = nm_ip6_address_get_prefix (addr);
-					char *addr_str, *prefix_str, *gateway_str;
-
-					addr_str = ip6_address_as_string (nm_ip6_address_get_address (addr));
+			/* IP4 */
+			if (cfg4 && !strcasecmp (nmc_fields_dev_list_sections[section_idx].name, nmc_fields_dev_list_sections[7].name))
+				was_output = print_ip4_config (cfg4, nmc, nmc_fields_dev_list_sections[7].name);
 
-					prefix_str = g_strdup_printf ("%d", prefix);
-					gateway_str = ip6_address_as_string (nm_ip6_address_get_gateway (addr));
+			/* DHCP4 */
+			if (dhcp4 && !strcasecmp (nmc_fields_dev_list_sections[section_idx].name, nmc_fields_dev_list_sections[8].name))
+				was_output = print_dhcp4_config (dhcp4, nmc, nmc_fields_dev_list_sections[8].name);
 
-					nmc->allowed_fields[0].value = nmc_fields_dev_list_sections[9].name;  /* "IP6-SETTINGS" */
-					nmc->allowed_fields[1].value = addr_str;
-					nmc->allowed_fields[2].value = prefix_str;
-					nmc->allowed_fields[3].value = gateway_str;
+			/* IP6 */
+			if (cfg6 && !strcasecmp (nmc_fields_dev_list_sections[section_idx].name, nmc_fields_dev_list_sections[9].name))
+				was_output = print_ip6_config (cfg6, nmc, nmc_fields_dev_list_sections[9].name);
 
-					nmc->print_fields.flags = multiline_flag | mode_flag | escape_flag | NMC_PF_FLAG_SECTION_PREFIX;
-					print_fields (nmc->print_fields, nmc->allowed_fields); /* Print values */
-					g_free (addr_str);
-					g_free (prefix_str);
-					g_free (gateway_str);
-				}
-				was_output = TRUE;
-			}
-			/* IP6-DNS */
-			if (cfg6 && !strcasecmp (nmc_fields_dev_list_sections[section_idx].name, nmc_fields_dev_list_sections[10].name)) {
-				int i = 1;
-				nmc->allowed_fields = nmc_fields_dev_list_ip6_dns;
-				nmc->print_fields.flags = multiline_flag | mode_flag | escape_flag | NMC_PF_FLAG_FIELD_NAMES;
-				nmc->print_fields.indices = parse_output_fields (NMC_FIELDS_DEV_LIST_IP6_DNS_ALL, nmc->allowed_fields, NULL);
-				print_fields (nmc->print_fields, nmc->allowed_fields); /* Print header */
-
-				for (iter = (GSList *) nm_ip6_config_get_nameservers (cfg6); iter; iter = g_slist_next (iter)) {
-					char *dns_name = g_strdup_printf ("%s%d", nmc_fields_dev_list_sections[10].name, i++);
-
-					tmp = ip6_address_as_string (iter->data);
-					nmc->allowed_fields[0].value = dns_name;  /* "IP6-DNS<num>" */
-					nmc->allowed_fields[1].value = tmp;
-
-					nmc->print_fields.flags = multiline_flag | mode_flag | escape_flag | NMC_PF_FLAG_SECTION_PREFIX;
-					print_fields (nmc->print_fields, nmc->allowed_fields); /* Print values */
-					g_free (tmp);
-					g_free (dns_name);
-				}
-				was_output = TRUE;
-			}
+			/* DHCP6 */
+			if (dhcp6 && !strcasecmp (nmc_fields_dev_list_sections[section_idx].name, nmc_fields_dev_list_sections[10].name))
+				was_output = print_dhcp6_config (dhcp6, nmc, nmc_fields_dev_list_sections[10].name);
 		}
 	}
 
diff --git a/cli/src/nmcli.h b/cli/src/nmcli.h
index 90091b36..9ffa42ed 100644
--- a/cli/src/nmcli.h
+++ b/cli/src/nmcli.h
@@ -14,7 +14,7 @@
  * with this program; if not, write to the Free Software Foundation, Inc.,
  * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
  *
- * (C) Copyright 2010 - 2011 Red Hat, Inc.
+ * (C) Copyright 2010 - 2012 Red Hat, Inc.
  */
 
 #ifndef NMC_NMCLI_H
@@ -48,11 +48,14 @@ typedef enum {
 	/* Error in device disconnect */
 	NMC_RESULT_ERROR_DEV_DISCONNECT = 6,
 
+	/* Error in connection deletion */
+	NMC_RESULT_ERROR_CON_DEL = 7,
+
 	/* NetworkManager is not running */
-	NMC_RESULT_ERROR_NM_NOT_RUNNING = 7,
+	NMC_RESULT_ERROR_NM_NOT_RUNNING = 8,
 
 	/* nmcli and NetworkManager versions mismatch */
-	NMC_RESULT_ERROR_VERSIONS_MISMATCH = 8
+	NMC_RESULT_ERROR_VERSIONS_MISMATCH = 9
 } NMCResultCode;
 
 typedef enum {
@@ -62,23 +65,26 @@ typedef enum {
 } NMCPrintOutput;
 
 /* === Output fields === */
+/* Flags for NmcOutputField */
+#define NMC_OF_FLAG_ARRAY              0x00000001   /* 'value' is an NULL-terminated array rather then a single string */
+
 typedef struct {
 	const char *name;       /* Field's name */
 	const char *name_l10n;  /* Field's name for translation */
 	int width;              /* Width in screen columns */
-	const char *value;      /* Value of current field */
+	const void *value;      /* Value of current field - char* or char** */
 	guint32 flags;          /* Flags */
 } NmcOutputField;
 
 /* Flags for NmcPrintFields */
-#define	NMC_PF_FLAG_MULTILINE          0x00000001   /* Multiline output instead of tabular */
-#define	NMC_PF_FLAG_TERSE              0x00000002   /* Terse output mode */
-#define	NMC_PF_FLAG_PRETTY             0x00000004   /* Pretty output mode */
-#define	NMC_PF_FLAG_MAIN_HEADER_ADD    0x00000008   /* Print main header in addition to values/field names */
-#define	NMC_PF_FLAG_MAIN_HEADER_ONLY   0x00000010   /* Print main header only */
-#define	NMC_PF_FLAG_FIELD_NAMES        0x00000020   /* Print field names instead of values */
-#define	NMC_PF_FLAG_ESCAPE             0x00000040   /* Escape column separator and '\' */
-#define	NMC_PF_FLAG_SECTION_PREFIX     0x00000080   /* Use the first value as section prefix for the other field names - just in multiline */
+#define NMC_PF_FLAG_MULTILINE          0x00000001   /* Multiline output instead of tabular */
+#define NMC_PF_FLAG_TERSE              0x00000002   /* Terse output mode */
+#define NMC_PF_FLAG_PRETTY             0x00000004   /* Pretty output mode */
+#define NMC_PF_FLAG_MAIN_HEADER_ADD    0x00000008   /* Print main header in addition to values/field names */
+#define NMC_PF_FLAG_MAIN_HEADER_ONLY   0x00000010   /* Print main header only */
+#define NMC_PF_FLAG_FIELD_NAMES        0x00000020   /* Print field names instead of values */
+#define NMC_PF_FLAG_ESCAPE             0x00000040   /* Escape column separator and '\' */
+#define NMC_PF_FLAG_SECTION_PREFIX     0x00000080   /* Use the first value as section prefix for the other field names - just in multiline */
 
 typedef struct {
 	GArray *indices;      /* Array of field indices to the array of allowed fields */
diff --git a/cli/src/settings.c b/cli/src/settings.c
index ccbe9589..bf422920 100644
--- a/cli/src/settings.c
+++ b/cli/src/settings.c
@@ -14,11 +14,13 @@
  * with this program; if not, write to the Free Software Foundation, Inc.,
  * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
  *
- * (C) Copyright 2010 - 2011 Red Hat, Inc.
+ * (C) Copyright 2010 - 2012 Red Hat, Inc.
  */
 
 #include "config.h"
 
+#include "net/if_arp.h"
+
 #include <glib.h>
 #include <glib/gi18n.h>
 #include <libnm-util/nm-utils.h>
@@ -88,34 +90,36 @@ static NmcOutputField nmc_fields_setting_8021X[] = {
 	SETTING_FIELD (NM_SETTING_802_1X_EAP, 10),                          /* 1 */
 	SETTING_FIELD (NM_SETTING_802_1X_IDENTITY, 15),                     /* 2 */
 	SETTING_FIELD (NM_SETTING_802_1X_ANONYMOUS_IDENTITY, 15),           /* 3 */
-	SETTING_FIELD (NM_SETTING_802_1X_CA_CERT, 10),                      /* 4 */
-	SETTING_FIELD (NM_SETTING_802_1X_CA_PATH, 10),                      /* 5 */
-	SETTING_FIELD (NM_SETTING_802_1X_SUBJECT_MATCH, 10),                /* 6 */
-	SETTING_FIELD (NM_SETTING_802_1X_ALTSUBJECT_MATCHES, 10),           /* 7 */
-	SETTING_FIELD (NM_SETTING_802_1X_CLIENT_CERT, 10),                  /* 8 */
-	SETTING_FIELD (NM_SETTING_802_1X_PHASE1_PEAPVER, 10),               /* 9 */
-	SETTING_FIELD (NM_SETTING_802_1X_PHASE1_PEAPLABEL, 10),             /* 10 */
-	SETTING_FIELD (NM_SETTING_802_1X_PHASE1_FAST_PROVISIONING, 10),     /* 11 */
-	SETTING_FIELD (NM_SETTING_802_1X_PHASE2_AUTH, 10),                  /* 12 */
-	SETTING_FIELD (NM_SETTING_802_1X_PHASE2_AUTHEAP, 10),               /* 13 */
-	SETTING_FIELD (NM_SETTING_802_1X_PHASE2_CA_CERT, 20),               /* 14 */
-	SETTING_FIELD (NM_SETTING_802_1X_PHASE2_CA_PATH, 20),               /* 15 */
-	SETTING_FIELD (NM_SETTING_802_1X_PHASE2_SUBJECT_MATCH, 10),         /* 16 */
-	SETTING_FIELD (NM_SETTING_802_1X_PHASE2_ALTSUBJECT_MATCHES, 10),    /* 17 */
-	SETTING_FIELD (NM_SETTING_802_1X_PHASE2_CLIENT_CERT, 20),           /* 18 */
-	SETTING_FIELD (NM_SETTING_802_1X_PASSWORD, 10),                     /* 19 */
-	SETTING_FIELD (NM_SETTING_802_1X_PRIVATE_KEY, 15),                  /* 20 */
-	SETTING_FIELD (NM_SETTING_802_1X_PRIVATE_KEY_PASSWORD, 20),         /* 21 */
-	SETTING_FIELD (NM_SETTING_802_1X_PHASE2_PRIVATE_KEY, 20),           /* 22 */
-	SETTING_FIELD (NM_SETTING_802_1X_PHASE2_PRIVATE_KEY_PASSWORD, 20),  /* 23 */
-	SETTING_FIELD (NM_SETTING_802_1X_PIN, 8),                           /* 24 */
-	SETTING_FIELD (NM_SETTING_802_1X_SYSTEM_CA_CERTS, 17),              /* 25 */
+	SETTING_FIELD (NM_SETTING_802_1X_PAC_FILE, 15),                     /* 4 */
+	SETTING_FIELD (NM_SETTING_802_1X_CA_CERT, 10),                      /* 5 */
+	SETTING_FIELD (NM_SETTING_802_1X_CA_PATH, 10),                      /* 6 */
+	SETTING_FIELD (NM_SETTING_802_1X_SUBJECT_MATCH, 10),                /* 7 */
+	SETTING_FIELD (NM_SETTING_802_1X_ALTSUBJECT_MATCHES, 10),           /* 8 */
+	SETTING_FIELD (NM_SETTING_802_1X_CLIENT_CERT, 10),                  /* 9 */
+	SETTING_FIELD (NM_SETTING_802_1X_PHASE1_PEAPVER, 10),               /* 10 */
+	SETTING_FIELD (NM_SETTING_802_1X_PHASE1_PEAPLABEL, 10),             /* 11 */
+	SETTING_FIELD (NM_SETTING_802_1X_PHASE1_FAST_PROVISIONING, 10),     /* 12 */
+	SETTING_FIELD (NM_SETTING_802_1X_PHASE2_AUTH, 10),                  /* 13 */
+	SETTING_FIELD (NM_SETTING_802_1X_PHASE2_AUTHEAP, 10),               /* 14 */
+	SETTING_FIELD (NM_SETTING_802_1X_PHASE2_CA_CERT, 20),               /* 15 */
+	SETTING_FIELD (NM_SETTING_802_1X_PHASE2_CA_PATH, 20),               /* 16 */
+	SETTING_FIELD (NM_SETTING_802_1X_PHASE2_SUBJECT_MATCH, 10),         /* 17 */
+	SETTING_FIELD (NM_SETTING_802_1X_PHASE2_ALTSUBJECT_MATCHES, 10),    /* 18 */
+	SETTING_FIELD (NM_SETTING_802_1X_PHASE2_CLIENT_CERT, 20),           /* 19 */
+	SETTING_FIELD (NM_SETTING_802_1X_PASSWORD, 10),                     /* 20 */
+	SETTING_FIELD (NM_SETTING_802_1X_PRIVATE_KEY, 15),                  /* 21 */
+	SETTING_FIELD (NM_SETTING_802_1X_PRIVATE_KEY_PASSWORD, 20),         /* 22 */
+	SETTING_FIELD (NM_SETTING_802_1X_PHASE2_PRIVATE_KEY, 20),           /* 23 */
+	SETTING_FIELD (NM_SETTING_802_1X_PHASE2_PRIVATE_KEY_PASSWORD, 20),  /* 24 */
+	SETTING_FIELD (NM_SETTING_802_1X_PIN, 8),                           /* 25 */
+	SETTING_FIELD (NM_SETTING_802_1X_SYSTEM_CA_CERTS, 17),              /* 26 */
 	{NULL, NULL, 0, NULL, 0}
 };
 #define NMC_FIELDS_SETTING_802_1X_ALL     "name"","\
                                           NM_SETTING_802_1X_EAP","\
                                           NM_SETTING_802_1X_IDENTITY","\
                                           NM_SETTING_802_1X_ANONYMOUS_IDENTITY","\
+                                          NM_SETTING_802_1X_PAC_FILE","\
                                           NM_SETTING_802_1X_CA_CERT","\
                                           NM_SETTING_802_1X_CA_PATH","\
                                           NM_SETTING_802_1X_SUBJECT_MATCH","\
@@ -438,6 +442,52 @@ static NmcOutputField nmc_fields_setting_wimax[] = {
                                          NM_SETTING_WIMAX_NETWORK_NAME
 #define NMC_FIELDS_SETTING_WIMAX_COMMON  NMC_FIELDS_SETTING_WIMAX_ALL
 
+/* Available fields for NM_SETTING_INFINIBAND_SETTING_NAME */
+static NmcOutputField nmc_fields_setting_infiniband[] = {
+	SETTING_FIELD ("name",  12),                                       /* 0 */
+	SETTING_FIELD (NM_SETTING_INFINIBAND_MAC_ADDRESS, 61),             /* 1 */
+	SETTING_FIELD (NM_SETTING_INFINIBAND_MTU, 6),                      /* 2 */
+	SETTING_FIELD (NM_SETTING_INFINIBAND_TRANSPORT_MODE, 12),          /* 3 */
+	{NULL, NULL, 0, NULL, 0}
+};
+#define NMC_FIELDS_SETTING_INFINIBAND_ALL     "name"","\
+                                              NM_SETTING_INFINIBAND_MAC_ADDRESS","\
+                                              NM_SETTING_INFINIBAND_MTU","\
+                                              NM_SETTING_INFINIBAND_TRANSPORT_MODE
+#define NMC_FIELDS_SETTING_INFINIBAND_COMMON  NMC_FIELDS_SETTING_INFINIBAND_ALL
+
+/* Available fields for NM_SETTING_BOND_SETTING_NAME */
+static NmcOutputField nmc_fields_setting_bond[] = {
+	SETTING_FIELD ("name",  8),                                        /* 0 */
+	SETTING_FIELD (NM_SETTING_BOND_INTERFACE_NAME, 15),                /* 1 */
+	SETTING_FIELD (NM_SETTING_BOND_OPTIONS, 30),                       /* 2 */
+	{NULL, NULL, 0, NULL, 0}
+};
+#define NMC_FIELDS_SETTING_BOND_ALL     "name"","\
+                                        NM_SETTING_BOND_INTERFACE_NAME","\
+                                        NM_SETTING_BOND_OPTIONS
+#define NMC_FIELDS_SETTING_BOND_COMMON  NMC_FIELDS_SETTING_BOND_ALL
+
+/* Available fields for NM_SETTING_VLAN_SETTING_NAME */
+static NmcOutputField nmc_fields_setting_vlan[] = {
+	SETTING_FIELD ("name",  6),                                        /* 0 */
+	SETTING_FIELD (NM_SETTING_VLAN_INTERFACE_NAME, 15),                /* 1 */
+	SETTING_FIELD (NM_SETTING_VLAN_PARENT, 8),                         /* 2 */
+	SETTING_FIELD (NM_SETTING_VLAN_ID, 6),                             /* 3 */
+	SETTING_FIELD (NM_SETTING_VLAN_FLAGS, 45),                         /* 4 */
+	SETTING_FIELD (NM_SETTING_VLAN_INGRESS_PRIORITY_MAP, 22),          /* 5 */
+	SETTING_FIELD (NM_SETTING_VLAN_EGRESS_PRIORITY_MAP, 22),           /* 6 */
+	{NULL, NULL, 0, NULL, 0}
+};
+#define NMC_FIELDS_SETTING_VLAN_ALL     "name"","\
+                                        NM_SETTING_VLAN_INTERFACE_NAME","\
+                                        NM_SETTING_VLAN_PARENT","\
+                                        NM_SETTING_VLAN_ID","\
+                                        NM_SETTING_VLAN_FLAGS","\
+                                        NM_SETTING_VLAN_INGRESS_PRIORITY_MAP","\
+                                        NM_SETTING_VLAN_EGRESS_PRIORITY_MAP
+#define NMC_FIELDS_SETTING_VLAN_COMMON  NMC_FIELDS_SETTING_VLAN_ALL
+
 
 static char *
 wep_key_type_to_string (NMWepKeyType type)
@@ -519,10 +569,57 @@ allowed_bands_to_string (guint32 bands)
 	return g_string_free (band_str, FALSE);
 }
 
+static char *
+vlan_flags_to_string (guint32 flags)
+{
+	GString *flag_str;
+
+	if (flags == 0)
+		return g_strdup (_("0 (NONE)"));
+
+	flag_str = g_string_new (NULL);
+	g_string_printf (flag_str, "%d (", flags);
+
+	if (flags & NM_VLAN_FLAG_REORDER_HEADERS)
+		g_string_append (flag_str, _("REORDER_HEADERS, "));
+	if (flags & NM_VLAN_FLAG_GVRP)
+		g_string_append (flag_str, _("GVRP, "));
+	if (flags & NM_VLAN_FLAG_LOOSE_BINDING)
+		g_string_append (flag_str, _("LOOSE_BINDING, "));
+
+	if (flag_str->str[flag_str->len-1] == '(')
+		g_string_assign (flag_str, _("unknown"));
+	else
+		g_string_truncate (flag_str, flag_str->len-2);  /* chop off trailing ', ' */
+
+	g_string_append_c (flag_str, ')');
+
+	return g_string_free (flag_str, FALSE);
+}
+
+static char *
+vlan_priorities_to_string (NMSettingVlan *s_vlan, NMVlanPriorityMap map)
+{
+	GString *priorities;
+	int i;
+
+	priorities = g_string_new (NULL);
+	for (i = 0; i < nm_setting_vlan_get_num_priorities (s_vlan, map); i++) {
+		guint32 from, to;
+
+		nm_setting_vlan_get_priority (s_vlan, map, i, &from, &to);
+		g_string_append_printf (priorities, "%d:%d,", from, to);
+	}
+	g_string_truncate (priorities, priorities->len-1);  /* chop off trailing ',' */
+
+	return g_string_free (priorities, FALSE);
+}
+
+/*----------------------------------------------------------------------------*/
+
 gboolean
-setting_connection_details (NMSetting *setting, NmCli *nmc)
+setting_connection_details (NMSettingConnection *s_con, NmCli *nmc)
 {
-	NMSettingConnection *s_con;
 	guint64 timestamp;
 	char *timestamp_str;
 	const char *perm_item;
@@ -533,8 +630,7 @@ setting_connection_details (NMSetting *setting, NmCli *nmc)
 	guint32 multiline_flag = nmc->multiline_output ? NMC_PF_FLAG_MULTILINE : 0;
 	guint32 escape_flag = nmc->escape_values ? NMC_PF_FLAG_ESCAPE : 0;
 
-	g_return_val_if_fail (NM_IS_SETTING_CONNECTION (setting), FALSE);
-	s_con = (NMSettingConnection *) setting;
+	g_return_val_if_fail (NM_IS_SETTING_CONNECTION (s_con), FALSE);
 
 	nmc->allowed_fields = nmc_fields_setting_connection;
 	nmc->print_fields.indices = parse_output_fields (NMC_FIELDS_SETTING_CONNECTION_ALL, nmc->allowed_fields, NULL);
@@ -572,9 +668,8 @@ setting_connection_details (NMSetting *setting, NmCli *nmc)
 }
 
 gboolean
-setting_wired_details (NMSetting *setting, NmCli *nmc)
+setting_wired_details (NMSettingWired *s_wired, NmCli *nmc)
 {
-	NMSettingWired *s_wired;
 	const GByteArray *mac;
 	const GSList *iter;
 	const GPtrArray *s390_channels;
@@ -585,8 +680,7 @@ setting_wired_details (NMSetting *setting, NmCli *nmc)
 	guint32 multiline_flag = nmc->multiline_output ? NMC_PF_FLAG_MULTILINE : 0;
 	guint32 escape_flag = nmc->escape_values ? NMC_PF_FLAG_ESCAPE : 0;
 
-	g_return_val_if_fail (NM_IS_SETTING_WIRED (setting), FALSE);
-	s_wired = (NMSettingWired *) setting;
+	g_return_val_if_fail (NM_IS_SETTING_WIRED (s_wired), FALSE);
 
 	nmc->allowed_fields = nmc_fields_setting_wired;
 	nmc->print_fields.indices = parse_output_fields (NMC_FIELDS_SETTING_WIRED_ALL, nmc->allowed_fields, NULL);
@@ -597,10 +691,10 @@ setting_wired_details (NMSetting *setting, NmCli *nmc)
 	mtu_str = g_strdup_printf ("%d", nm_setting_wired_get_mtu (s_wired));
 	mac = nm_setting_wired_get_mac_address (s_wired);
 	if (mac)
-		device_mac_str = g_strdup_printf ("%02X:%02X:%02X:%02X:%02X:%02X", mac->data[0], mac->data[1], mac->data[2], mac->data[3], mac->data[4], mac->data[5]);
+		device_mac_str = nm_utils_hwaddr_ntoa (mac->data, ARPHRD_ETHER);
 	mac = nm_setting_wired_get_cloned_mac_address (s_wired);
 	if (mac)
-		cloned_mac_str = g_strdup_printf ("%02X:%02X:%02X:%02X:%02X:%02X", mac->data[0], mac->data[1], mac->data[2], mac->data[3], mac->data[4], mac->data[5]);
+		cloned_mac_str = nm_utils_hwaddr_ntoa (mac->data, ARPHRD_ETHER);
 
 	mac_blacklist_s = g_string_new (NULL);
 	iter = nm_setting_wired_get_mac_address_blacklist (s_wired);
@@ -653,9 +747,8 @@ setting_wired_details (NMSetting *setting, NmCli *nmc)
 }
 
 gboolean
-setting_802_1X_details (NMSetting *setting, NmCli *nmc)
+setting_802_1X_details (NMSetting8021x *s_8021X, NmCli *nmc)
 {
-	NMSetting8021x *s_8021X;
 	NMSetting8021xCKScheme scheme;
 	GString *eap_str, *alt_sub_match, *phase2_alt_sub_match;
 	char *ca_cert_str = NULL, *client_cert_str = NULL, *phase2_ca_cert_str = NULL;
@@ -665,8 +758,7 @@ setting_802_1X_details (NMSetting *setting, NmCli *nmc)
 	guint32 multiline_flag = nmc->multiline_output ? NMC_PF_FLAG_MULTILINE : 0;
 	guint32 escape_flag = nmc->escape_values ? NMC_PF_FLAG_ESCAPE : 0;
 
-	g_return_val_if_fail (NM_IS_SETTING_802_1X (setting), FALSE);
-	s_8021X = (NMSetting8021x *) setting;
+	g_return_val_if_fail (NM_IS_SETTING_802_1X (s_8021X), FALSE);
 
 	nmc->allowed_fields = nmc_fields_setting_8021X;
 	nmc->print_fields.indices = parse_output_fields (NMC_FIELDS_SETTING_802_1X_ALL, nmc->allowed_fields, NULL);
@@ -729,28 +821,29 @@ setting_802_1X_details (NMSetting *setting, NmCli *nmc)
 	nmc->allowed_fields[1].value = eap_str->str;
 	nmc->allowed_fields[2].value = nm_setting_802_1x_get_identity (s_8021X);
 	nmc->allowed_fields[3].value = nm_setting_802_1x_get_anonymous_identity (s_8021X);
-	nmc->allowed_fields[4].value = ca_cert_str;
-	nmc->allowed_fields[5].value = nm_setting_802_1x_get_ca_path (s_8021X);
-	nmc->allowed_fields[6].value = nm_setting_802_1x_get_subject_match (s_8021X);
-	nmc->allowed_fields[7].value = alt_sub_match->str;
-	nmc->allowed_fields[8].value = client_cert_str;
-	nmc->allowed_fields[9].value = nm_setting_802_1x_get_phase1_peapver (s_8021X);
-	nmc->allowed_fields[10].value = nm_setting_802_1x_get_phase1_peaplabel (s_8021X);
-	nmc->allowed_fields[11].value = nm_setting_802_1x_get_phase1_fast_provisioning (s_8021X);
-	nmc->allowed_fields[12].value = nm_setting_802_1x_get_phase2_auth (s_8021X);
-	nmc->allowed_fields[13].value = nm_setting_802_1x_get_phase2_autheap (s_8021X);
-	nmc->allowed_fields[14].value = phase2_ca_cert_str;
-	nmc->allowed_fields[15].value = nm_setting_802_1x_get_phase2_ca_path (s_8021X);
-	nmc->allowed_fields[16].value = nm_setting_802_1x_get_phase2_subject_match (s_8021X);
-	nmc->allowed_fields[17].value = phase2_alt_sub_match->str;
-	nmc->allowed_fields[18].value = phase2_client_cert_str;
-	nmc->allowed_fields[19].value = nm_setting_802_1x_get_password (s_8021X);
-	nmc->allowed_fields[20].value = private_key_str;
-	nmc->allowed_fields[21].value = nm_setting_802_1x_get_private_key_password (s_8021X);
-	nmc->allowed_fields[22].value = phase2_private_key_str;
-	nmc->allowed_fields[23].value = nm_setting_802_1x_get_phase2_private_key_password (s_8021X);
-	nmc->allowed_fields[24].value = nm_setting_802_1x_get_pin (s_8021X);
-	nmc->allowed_fields[25].value = nm_setting_802_1x_get_system_ca_certs (s_8021X) ? _("yes") : _("no");
+	nmc->allowed_fields[4].value = nm_setting_802_1x_get_pac_file (s_8021X);
+	nmc->allowed_fields[5].value = ca_cert_str;
+	nmc->allowed_fields[6].value = nm_setting_802_1x_get_ca_path (s_8021X);
+	nmc->allowed_fields[7].value = nm_setting_802_1x_get_subject_match (s_8021X);
+	nmc->allowed_fields[8].value = alt_sub_match->str;
+	nmc->allowed_fields[9].value = client_cert_str;
+	nmc->allowed_fields[10].value = nm_setting_802_1x_get_phase1_peapver (s_8021X);
+	nmc->allowed_fields[11].value = nm_setting_802_1x_get_phase1_peaplabel (s_8021X);
+	nmc->allowed_fields[12].value = nm_setting_802_1x_get_phase1_fast_provisioning (s_8021X);
+	nmc->allowed_fields[13].value = nm_setting_802_1x_get_phase2_auth (s_8021X);
+	nmc->allowed_fields[14].value = nm_setting_802_1x_get_phase2_autheap (s_8021X);
+	nmc->allowed_fields[15].value = phase2_ca_cert_str;
+	nmc->allowed_fields[16].value = nm_setting_802_1x_get_phase2_ca_path (s_8021X);
+	nmc->allowed_fields[17].value = nm_setting_802_1x_get_phase2_subject_match (s_8021X);
+	nmc->allowed_fields[18].value = phase2_alt_sub_match->str;
+	nmc->allowed_fields[19].value = phase2_client_cert_str;
+	nmc->allowed_fields[20].value = nm_setting_802_1x_get_password (s_8021X);
+	nmc->allowed_fields[21].value = private_key_str;
+	nmc->allowed_fields[22].value = nm_setting_802_1x_get_private_key_password (s_8021X);
+	nmc->allowed_fields[23].value = phase2_private_key_str;
+	nmc->allowed_fields[24].value = nm_setting_802_1x_get_phase2_private_key_password (s_8021X);
+	nmc->allowed_fields[25].value = nm_setting_802_1x_get_pin (s_8021X);
+	nmc->allowed_fields[26].value = nm_setting_802_1x_get_system_ca_certs (s_8021X) ? _("yes") : _("no");
 
 	nmc->print_fields.flags = multiline_flag | mode_flag | escape_flag | NMC_PF_FLAG_SECTION_PREFIX;
 	print_fields (nmc->print_fields, nmc->allowed_fields); /* Print values */
@@ -769,9 +862,8 @@ setting_802_1X_details (NMSetting *setting, NmCli *nmc)
 }
 
 gboolean
-setting_wireless_details (NMSetting *setting, NmCli *nmc)
+setting_wireless_details (NMSettingWireless *s_wireless, NmCli *nmc)
 {
-	NMSettingWireless *s_wireless;
 	int i;
 	const GByteArray *ssid, *bssid, *mac;
 	char *ssid_str, *channel_str, *rate_str, *tx_power_str, *mtu_str;
@@ -782,8 +874,7 @@ setting_wireless_details (NMSetting *setting, NmCli *nmc)
 	guint32 multiline_flag = nmc->multiline_output ? NMC_PF_FLAG_MULTILINE : 0;
 	guint32 escape_flag = nmc->escape_values ? NMC_PF_FLAG_ESCAPE : 0;
 
-	g_return_val_if_fail (NM_IS_SETTING_WIRELESS (setting), FALSE);
-	s_wireless = (NMSettingWireless *) setting;
+	g_return_val_if_fail (NM_IS_SETTING_WIRELESS (s_wireless), FALSE);
 
 	nmc->allowed_fields = nmc_fields_setting_wireless;
 	nmc->print_fields.indices = parse_output_fields (NMC_FIELDS_SETTING_WIRELESS_ALL, nmc->allowed_fields, NULL);
@@ -796,15 +887,15 @@ setting_wireless_details (NMSetting *setting, NmCli *nmc)
 	rate_str = g_strdup_printf ("%d", nm_setting_wireless_get_rate (s_wireless));
 	bssid = nm_setting_wireless_get_bssid (s_wireless);
 	if (bssid)
-		bssid_str = g_strdup_printf ("%02X:%02X:%02X:%02X:%02X:%02X", bssid->data[0], bssid->data[1], bssid->data[2], bssid->data[3], bssid->data[4], bssid->data[5]);
+		bssid_str = nm_utils_hwaddr_ntoa (bssid->data, ARPHRD_ETHER);
 	tx_power_str = g_strdup_printf ("%d", nm_setting_wireless_get_tx_power (s_wireless));
 	mtu_str = g_strdup_printf ("%d", nm_setting_wireless_get_mtu (s_wireless));
 	mac = nm_setting_wireless_get_mac_address (s_wireless);
 	if (mac)
-		device_mac_str = g_strdup_printf ("%02X:%02X:%02X:%02X:%02X:%02X", mac->data[0], mac->data[1], mac->data[2], mac->data[3], mac->data[4], mac->data[5]);
+		device_mac_str = nm_utils_hwaddr_ntoa (mac->data, ARPHRD_ETHER);
 	mac = nm_setting_wireless_get_cloned_mac_address (s_wireless);
 	if (mac)
-		cloned_mac_str = g_strdup_printf ("%02X:%02X:%02X:%02X:%02X:%02X", mac->data[0], mac->data[1], mac->data[2], mac->data[3], mac->data[4], mac->data[5]);
+		cloned_mac_str = nm_utils_hwaddr_ntoa (mac->data, ARPHRD_ETHER);
 
 	mac_blacklist = g_string_new (NULL);
 	iter = nm_setting_wireless_get_mac_address_blacklist (s_wireless);
@@ -854,9 +945,8 @@ setting_wireless_details (NMSetting *setting, NmCli *nmc)
 }
 
 gboolean
-setting_wireless_security_details (NMSetting *setting, NmCli *nmc)
+setting_wireless_security_details (NMSettingWirelessSecurity *s_wireless_sec, NmCli *nmc)
 {
-	NMSettingWirelessSecurity *s_wireless_sec;
 	int i;
 	char *wep_tx_keyidx_str, *wep_key_type_str;
 	GString *protos, *pairwises, *groups;
@@ -864,8 +954,7 @@ setting_wireless_security_details (NMSetting *setting, NmCli *nmc)
 	guint32 multiline_flag = nmc->multiline_output ? NMC_PF_FLAG_MULTILINE : 0;
 	guint32 escape_flag = nmc->escape_values ? NMC_PF_FLAG_ESCAPE : 0;
 
-	g_return_val_if_fail (NM_IS_SETTING_WIRELESS_SECURITY (setting), FALSE);
-	s_wireless_sec = (NMSettingWirelessSecurity *) setting;
+	g_return_val_if_fail (NM_IS_SETTING_WIRELESS_SECURITY (s_wireless_sec), FALSE);
 
 	nmc->allowed_fields = nmc_fields_setting_wireless_security;
 	nmc->print_fields.indices = parse_output_fields (NMC_FIELDS_SETTING_WIRELESS_SECURITY_ALL, nmc->allowed_fields, NULL);
@@ -922,17 +1011,15 @@ setting_wireless_security_details (NMSetting *setting, NmCli *nmc)
 }
 
 gboolean
-setting_ip4_config_details (NMSetting *setting, NmCli *nmc)
+setting_ip4_config_details (NMSettingIP4Config *s_ip4, NmCli *nmc)
 {
-	NMSettingIP4Config *s_ip4;
 	GString *dns_str, *dns_search_str, *addr_str, *route_str;
 	int i, num;
 	guint32 mode_flag = (nmc->print_output == NMC_PRINT_PRETTY) ? NMC_PF_FLAG_PRETTY : (nmc->print_output == NMC_PRINT_TERSE) ? NMC_PF_FLAG_TERSE : 0;
 	guint32 multiline_flag = nmc->multiline_output ? NMC_PF_FLAG_MULTILINE : 0;
 	guint32 escape_flag = nmc->escape_values ? NMC_PF_FLAG_ESCAPE : 0;
 
-	g_return_val_if_fail (NM_IS_SETTING_IP4_CONFIG (setting), FALSE);
-	s_ip4 = (NMSettingIP4Config *) setting;
+	g_return_val_if_fail (NM_IS_SETTING_IP4_CONFIG (s_ip4), FALSE);
 
 	nmc->allowed_fields = nmc_fields_setting_ip4_config;
 	nmc->print_fields.indices = parse_output_fields (NMC_FIELDS_SETTING_IP4_CONFIG_ALL, nmc->allowed_fields, NULL);
@@ -1058,17 +1145,15 @@ setting_ip4_config_details (NMSetting *setting, NmCli *nmc)
 }
 
 gboolean
-setting_ip6_config_details (NMSetting *setting, NmCli *nmc)
+setting_ip6_config_details (NMSettingIP6Config *s_ip6, NmCli *nmc)
 {
-	NMSettingIP6Config *s_ip6;
 	GString *dns_str, *dns_search_str, *addr_str, *route_str;
 	int i, num;
 	guint32 mode_flag = (nmc->print_output == NMC_PRINT_PRETTY) ? NMC_PF_FLAG_PRETTY : (nmc->print_output == NMC_PRINT_TERSE) ? NMC_PF_FLAG_TERSE : 0;
 	guint32 multiline_flag = nmc->multiline_output ? NMC_PF_FLAG_MULTILINE : 0;
 	guint32 escape_flag = nmc->escape_values ? NMC_PF_FLAG_ESCAPE : 0;
 
-	g_return_val_if_fail (NM_IS_SETTING_IP6_CONFIG (setting), FALSE);
-	s_ip6 = (NMSettingIP6Config *) setting;
+	g_return_val_if_fail (NM_IS_SETTING_IP6_CONFIG (s_ip6), FALSE);
 
 	nmc->allowed_fields = nmc_fields_setting_ip6_config;
 	nmc->print_fields.indices = parse_output_fields (NMC_FIELDS_SETTING_IP6_CONFIG_ALL, nmc->allowed_fields, NULL);
@@ -1191,16 +1276,14 @@ setting_ip6_config_details (NMSetting *setting, NmCli *nmc)
 }
 
 gboolean
-setting_serial_details (NMSetting *setting, NmCli *nmc)
+setting_serial_details (NMSettingSerial *s_serial, NmCli *nmc)
 {
-	NMSettingSerial *s_serial;
 	char *baud_str, *bits_str, *parity_str, *stopbits_str, *send_delay_str;
 	guint32 mode_flag = (nmc->print_output == NMC_PRINT_PRETTY) ? NMC_PF_FLAG_PRETTY : (nmc->print_output == NMC_PRINT_TERSE) ? NMC_PF_FLAG_TERSE : 0;
 	guint32 multiline_flag = nmc->multiline_output ? NMC_PF_FLAG_MULTILINE : 0;
 	guint32 escape_flag = nmc->escape_values ? NMC_PF_FLAG_ESCAPE : 0;
 
-	g_return_val_if_fail (NM_IS_SETTING_SERIAL (setting), FALSE);
-	s_serial = (NMSettingSerial *) setting;
+	g_return_val_if_fail (NM_IS_SETTING_SERIAL (s_serial), FALSE);
 
 	nmc->allowed_fields = nmc_fields_setting_serial;
 	nmc->print_fields.indices = parse_output_fields (NMC_FIELDS_SETTING_SERIAL_ALL, nmc->allowed_fields, NULL);
@@ -1233,16 +1316,14 @@ setting_serial_details (NMSetting *setting, NmCli *nmc)
 }
 
 gboolean
-setting_ppp_details (NMSetting *setting, NmCli *nmc)
+setting_ppp_details (NMSettingPPP *s_ppp, NmCli *nmc)
 {
-	NMSettingPPP *s_ppp;
 	char *baud_str, *mru_str, *mtu_str, *lcp_echo_failure_str, *lcp_echo_interval_str;
 	guint32 mode_flag = (nmc->print_output == NMC_PRINT_PRETTY) ? NMC_PF_FLAG_PRETTY : (nmc->print_output == NMC_PRINT_TERSE) ? NMC_PF_FLAG_TERSE : 0;
 	guint32 multiline_flag = nmc->multiline_output ? NMC_PF_FLAG_MULTILINE : 0;
 	guint32 escape_flag = nmc->escape_values ? NMC_PF_FLAG_ESCAPE : 0;
 
-	g_return_val_if_fail (NM_IS_SETTING_PPP (setting), FALSE);
-	s_ppp = (NMSettingPPP *) setting;
+	g_return_val_if_fail (NM_IS_SETTING_PPP (s_ppp), FALSE);
 
 	nmc->allowed_fields = nmc_fields_setting_ppp;
 	nmc->print_fields.indices = parse_output_fields (NMC_FIELDS_SETTING_PPP_ALL, nmc->allowed_fields, NULL);
@@ -1288,15 +1369,13 @@ setting_ppp_details (NMSetting *setting, NmCli *nmc)
 }
 
 gboolean
-setting_pppoe_details (NMSetting *setting, NmCli *nmc)
+setting_pppoe_details (NMSettingPPPOE *s_pppoe, NmCli *nmc)
 {
-	NMSettingPPPOE *s_pppoe;
 	guint32 mode_flag = (nmc->print_output == NMC_PRINT_PRETTY) ? NMC_PF_FLAG_PRETTY : (nmc->print_output == NMC_PRINT_TERSE) ? NMC_PF_FLAG_TERSE : 0;
 	guint32 multiline_flag = nmc->multiline_output ? NMC_PF_FLAG_MULTILINE : 0;
 	guint32 escape_flag = nmc->escape_values ? NMC_PF_FLAG_ESCAPE : 0;
 
-	g_return_val_if_fail (NM_IS_SETTING_PPPOE (setting), FALSE);
-	s_pppoe = (NMSettingPPPOE *) setting;
+	g_return_val_if_fail (NM_IS_SETTING_PPPOE (s_pppoe), FALSE);
 
 	nmc->allowed_fields = nmc_fields_setting_pppoe;
 	nmc->print_fields.indices = parse_output_fields (NMC_FIELDS_SETTING_PPPOE_ALL, nmc->allowed_fields, NULL);
@@ -1315,16 +1394,14 @@ setting_pppoe_details (NMSetting *setting, NmCli *nmc)
 }
 
 gboolean
-setting_gsm_details (NMSetting *setting, NmCli *nmc)
+setting_gsm_details (NMSettingGsm *s_gsm, NmCli *nmc)
 {
-	NMSettingGsm *s_gsm;
 	char *network_type_str, *allowed_bands_str;
 	guint32 mode_flag = (nmc->print_output == NMC_PRINT_PRETTY) ? NMC_PF_FLAG_PRETTY : (nmc->print_output == NMC_PRINT_TERSE) ? NMC_PF_FLAG_TERSE : 0;
 	guint32 multiline_flag = nmc->multiline_output ? NMC_PF_FLAG_MULTILINE : 0;
 	guint32 escape_flag = nmc->escape_values ? NMC_PF_FLAG_ESCAPE : 0;
 
-	g_return_val_if_fail (NM_IS_SETTING_GSM (setting), FALSE);
-	s_gsm = (NMSettingGsm *) setting;
+	g_return_val_if_fail (NM_IS_SETTING_GSM (s_gsm), FALSE);
 
 	nmc->allowed_fields = nmc_fields_setting_gsm;
 	nmc->print_fields.indices = parse_output_fields (NMC_FIELDS_SETTING_GSM_ALL, nmc->allowed_fields, NULL);
@@ -1355,15 +1432,13 @@ setting_gsm_details (NMSetting *setting, NmCli *nmc)
 }
 
 gboolean
-setting_cdma_details (NMSetting *setting, NmCli *nmc)
+setting_cdma_details (NMSettingCdma *s_cdma, NmCli *nmc)
 {
-	NMSettingCdma *s_cdma;
 	guint32 mode_flag = (nmc->print_output == NMC_PRINT_PRETTY) ? NMC_PF_FLAG_PRETTY : (nmc->print_output == NMC_PRINT_TERSE) ? NMC_PF_FLAG_TERSE : 0;
 	guint32 multiline_flag = nmc->multiline_output ? NMC_PF_FLAG_MULTILINE : 0;
 	guint32 escape_flag = nmc->escape_values ? NMC_PF_FLAG_ESCAPE : 0;
 
-	g_return_val_if_fail (NM_IS_SETTING_CDMA (setting), FALSE);
-	s_cdma = (NMSettingCdma *) setting;
+	g_return_val_if_fail (NM_IS_SETTING_CDMA (s_cdma), FALSE);
 
 	nmc->allowed_fields = nmc_fields_setting_cdma;
 	nmc->print_fields.indices = parse_output_fields (NMC_FIELDS_SETTING_CDMA_ALL, nmc->allowed_fields, NULL);
@@ -1382,17 +1457,15 @@ setting_cdma_details (NMSetting *setting, NmCli *nmc)
 }
 
 gboolean
-setting_bluetooth_details (NMSetting *setting, NmCli *nmc)
+setting_bluetooth_details (NMSettingBluetooth *s_bluetooth, NmCli *nmc)
 {
-	NMSettingBluetooth *s_bluetooth;
 	const GByteArray *bdaddr;
 	char *bdaddr_str = NULL;
 	guint32 mode_flag = (nmc->print_output == NMC_PRINT_PRETTY) ? NMC_PF_FLAG_PRETTY : (nmc->print_output == NMC_PRINT_TERSE) ? NMC_PF_FLAG_TERSE : 0;
 	guint32 multiline_flag = nmc->multiline_output ? NMC_PF_FLAG_MULTILINE : 0;
 	guint32 escape_flag = nmc->escape_values ? NMC_PF_FLAG_ESCAPE : 0;
 
-	g_return_val_if_fail (NM_IS_SETTING_BLUETOOTH (setting), FALSE);
-	s_bluetooth = (NMSettingBluetooth *) setting;
+	g_return_val_if_fail (NM_IS_SETTING_BLUETOOTH (s_bluetooth), FALSE);
 
 	nmc->allowed_fields = nmc_fields_setting_bluetooth;
 	nmc->print_fields.indices = parse_output_fields (NMC_FIELDS_SETTING_BLUETOOTH_ALL, nmc->allowed_fields, NULL);
@@ -1401,8 +1474,8 @@ setting_bluetooth_details (NMSetting *setting, NmCli *nmc)
 
 	bdaddr = nm_setting_bluetooth_get_bdaddr (s_bluetooth);
 	if (bdaddr)
-		bdaddr_str = g_strdup_printf ("%02X:%02X:%02X:%02X:%02X:%02X", bdaddr->data[0], bdaddr->data[1], bdaddr->data[2],
-		                                                               bdaddr->data[3], bdaddr->data[4], bdaddr->data[5]);
+		bdaddr_str = nm_utils_hwaddr_ntoa (bdaddr->data, ARPHRD_ETHER);
+
 	nmc->allowed_fields[0].value = NM_SETTING_BLUETOOTH_SETTING_NAME;
 	nmc->allowed_fields[1].value = bdaddr_str;
 	nmc->allowed_fields[2].value = nm_setting_bluetooth_get_connection_type (s_bluetooth);
@@ -1416,17 +1489,15 @@ setting_bluetooth_details (NMSetting *setting, NmCli *nmc)
 }
 
 gboolean
-setting_olpc_mesh_details (NMSetting *setting, NmCli *nmc)
+setting_olpc_mesh_details (NMSettingOlpcMesh *s_olpc_mesh, NmCli *nmc)
 {
-	NMSettingOlpcMesh *s_olpc_mesh;
 	const GByteArray *ssid, *dhcp_anycast;
 	char *ssid_str, *channel_str, *dhcp_anycast_str = NULL;
 	guint32 mode_flag = (nmc->print_output == NMC_PRINT_PRETTY) ? NMC_PF_FLAG_PRETTY : (nmc->print_output == NMC_PRINT_TERSE) ? NMC_PF_FLAG_TERSE : 0;
 	guint32 multiline_flag = nmc->multiline_output ? NMC_PF_FLAG_MULTILINE : 0;
 	guint32 escape_flag = nmc->escape_values ? NMC_PF_FLAG_ESCAPE : 0;
 
-	g_return_val_if_fail (NM_IS_SETTING_OLPC_MESH (setting), FALSE);
-	s_olpc_mesh = (NMSettingOlpcMesh *) setting;
+	g_return_val_if_fail (NM_IS_SETTING_OLPC_MESH (s_olpc_mesh), FALSE);
 
 	nmc->allowed_fields = nmc_fields_setting_olpc_mesh;
 	nmc->print_fields.indices = parse_output_fields (NMC_FIELDS_SETTING_OLPC_MESH_ALL, nmc->allowed_fields, NULL);
@@ -1438,8 +1509,8 @@ setting_olpc_mesh_details (NMSetting *setting, NmCli *nmc)
 	channel_str = g_strdup_printf ("%d", nm_setting_olpc_mesh_get_channel (s_olpc_mesh));
 	dhcp_anycast = nm_setting_olpc_mesh_get_dhcp_anycast_address (s_olpc_mesh);
 	if (dhcp_anycast)
-		dhcp_anycast_str = g_strdup_printf ("%02X:%02X:%02X:%02X:%02X:%02X", dhcp_anycast->data[0], dhcp_anycast->data[1], dhcp_anycast->data[2],
-		                                                                     dhcp_anycast->data[3], dhcp_anycast->data[4], dhcp_anycast->data[5]);
+		dhcp_anycast_str = nm_utils_hwaddr_ntoa (dhcp_anycast->data, ARPHRD_ETHER);
+
 	nmc->allowed_fields[0].value = NM_SETTING_OLPC_MESH_SETTING_NAME;
 	nmc->allowed_fields[1].value = ssid_str;
 	nmc->allowed_fields[2].value = channel_str;
@@ -1467,16 +1538,14 @@ vpn_data_item (const char *key, const char *value, gpointer user_data)
 }
 
 gboolean
-setting_vpn_details (NMSetting *setting, NmCli *nmc)
+setting_vpn_details (NMSettingVPN *s_vpn, NmCli *nmc)
 {
-	NMSettingVPN *s_vpn;
 	GString *data_item_str, *secret_str;
 	guint32 mode_flag = (nmc->print_output == NMC_PRINT_PRETTY) ? NMC_PF_FLAG_PRETTY : (nmc->print_output == NMC_PRINT_TERSE) ? NMC_PF_FLAG_TERSE : 0;
 	guint32 multiline_flag = nmc->multiline_output ? NMC_PF_FLAG_MULTILINE : 0;
 	guint32 escape_flag = nmc->escape_values ? NMC_PF_FLAG_ESCAPE : 0;
 
-	g_return_val_if_fail (NM_IS_SETTING_VPN (setting), FALSE);
-	s_vpn = (NMSettingVPN *) setting;
+	g_return_val_if_fail (NM_IS_SETTING_VPN (s_vpn), FALSE);
 
 	nmc->allowed_fields = nmc_fields_setting_vpn;
 	nmc->print_fields.indices = parse_output_fields (NMC_FIELDS_SETTING_VPN_ALL, nmc->allowed_fields, NULL);
@@ -1504,17 +1573,15 @@ setting_vpn_details (NMSetting *setting, NmCli *nmc)
 }
 
 gboolean
-setting_wimax_details (NMSetting *setting, NmCli *nmc)
+setting_wimax_details (NMSettingWimax *s_wimax, NmCli *nmc)
 {
-	NMSettingWimax *s_wimax;
 	const GByteArray *mac;
 	char *device_mac_str = NULL;
 	guint32 mode_flag = (nmc->print_output == NMC_PRINT_PRETTY) ? NMC_PF_FLAG_PRETTY : (nmc->print_output == NMC_PRINT_TERSE) ? NMC_PF_FLAG_TERSE : 0;
 	guint32 multiline_flag = nmc->multiline_output ? NMC_PF_FLAG_MULTILINE : 0;
 	guint32 escape_flag = nmc->escape_values ? NMC_PF_FLAG_ESCAPE : 0;
 
-	g_return_val_if_fail (NM_IS_SETTING_WIMAX (setting), FALSE);
-	s_wimax = (NMSettingWimax *) setting;
+	g_return_val_if_fail (NM_IS_SETTING_WIMAX (s_wimax), FALSE);
 
 	nmc->allowed_fields = nmc_fields_setting_wimax;
 	nmc->print_fields.indices = parse_output_fields (NMC_FIELDS_SETTING_WIMAX_ALL, nmc->allowed_fields, NULL);
@@ -1523,7 +1590,7 @@ setting_wimax_details (NMSetting *setting, NmCli *nmc)
 
 	mac = nm_setting_wimax_get_mac_address (s_wimax);
 	if (mac)
-		device_mac_str = g_strdup_printf ("%02X:%02X:%02X:%02X:%02X:%02X", mac->data[0], mac->data[1], mac->data[2], mac->data[3], mac->data[4], mac->data[5]);
+		device_mac_str = nm_utils_hwaddr_ntoa (mac->data, ARPHRD_ETHER);
 
 	nmc->allowed_fields[0].value = NM_SETTING_WIMAX_SETTING_NAME;
 	nmc->allowed_fields[1].value = device_mac_str;
@@ -1537,3 +1604,114 @@ setting_wimax_details (NMSetting *setting, NmCli *nmc)
 	return TRUE;
 }
 
+gboolean
+setting_infiniband_details (NMSettingInfiniband *s_infiniband, NmCli *nmc)
+{
+	const GByteArray *mac;
+	char *mtu_str, *mac_str = NULL;
+	guint32 mode_flag = (nmc->print_output == NMC_PRINT_PRETTY) ? NMC_PF_FLAG_PRETTY : (nmc->print_output == NMC_PRINT_TERSE) ? NMC_PF_FLAG_TERSE : 0;
+	guint32 multiline_flag = nmc->multiline_output ? NMC_PF_FLAG_MULTILINE : 0;
+	guint32 escape_flag = nmc->escape_values ? NMC_PF_FLAG_ESCAPE : 0;
+
+	g_return_val_if_fail (NM_IS_SETTING_INFINIBAND (s_infiniband), FALSE);
+
+	nmc->allowed_fields = nmc_fields_setting_infiniband;
+	nmc->print_fields.indices = parse_output_fields (NMC_FIELDS_SETTING_INFINIBAND_ALL, nmc->allowed_fields, NULL);
+	nmc->print_fields.flags = multiline_flag | mode_flag | escape_flag | NMC_PF_FLAG_FIELD_NAMES;
+	print_fields (nmc->print_fields, nmc->allowed_fields);  /* Print field names */
+
+	mac = nm_setting_infiniband_get_mac_address (s_infiniband);
+	if (mac)
+		mac_str = nm_utils_hwaddr_ntoa (mac->data, ARPHRD_INFINIBAND);
+	mtu_str = g_strdup_printf ("%d", nm_setting_infiniband_get_mtu (s_infiniband));
+
+	nmc->allowed_fields[0].value = NM_SETTING_INFINIBAND_SETTING_NAME;
+	nmc->allowed_fields[1].value = mac_str;
+	nmc->allowed_fields[2].value = strcmp (mtu_str, "0") ? mtu_str : _("auto");
+	nmc->allowed_fields[3].value = nm_setting_infiniband_get_transport_mode (s_infiniband);
+
+	nmc->print_fields.flags = multiline_flag | mode_flag | escape_flag | NMC_PF_FLAG_SECTION_PREFIX;
+	print_fields (nmc->print_fields, nmc->allowed_fields); /* Print values */
+
+	g_free (mac_str);
+	g_free (mtu_str);
+
+	return TRUE;
+}
+
+gboolean
+setting_bond_details (NMSettingBond *s_bond, NmCli *nmc)
+{
+	GString *bond_options_s;
+	int i;
+	guint32 mode_flag = (nmc->print_output == NMC_PRINT_PRETTY) ? NMC_PF_FLAG_PRETTY : (nmc->print_output == NMC_PRINT_TERSE) ? NMC_PF_FLAG_TERSE : 0;
+	guint32 multiline_flag = nmc->multiline_output ? NMC_PF_FLAG_MULTILINE : 0;
+	guint32 escape_flag = nmc->escape_values ? NMC_PF_FLAG_ESCAPE : 0;
+
+	g_return_val_if_fail (NM_IS_SETTING_BOND (s_bond), FALSE);
+
+	nmc->allowed_fields = nmc_fields_setting_bond;
+	nmc->print_fields.indices = parse_output_fields (NMC_FIELDS_SETTING_BOND_ALL, nmc->allowed_fields, NULL);
+	nmc->print_fields.flags = multiline_flag | mode_flag | escape_flag | NMC_PF_FLAG_FIELD_NAMES;
+	print_fields (nmc->print_fields, nmc->allowed_fields);  /* Print field names */
+
+	bond_options_s = g_string_new (NULL);
+	for (i = 0; i < nm_setting_bond_get_num_options (s_bond); i++) {
+		const char *key, *value;
+
+		nm_setting_bond_get_option (s_bond, i, &key, &value);
+		g_string_append_printf (bond_options_s, "%s=%s,", key, value);
+	}
+	g_string_truncate (bond_options_s, bond_options_s->len-1);  /* chop off trailing ',' */
+
+	nmc->allowed_fields[0].value = NM_SETTING_BOND_SETTING_NAME;
+	nmc->allowed_fields[1].value = nm_setting_bond_get_interface_name (s_bond);
+	nmc->allowed_fields[2].value = bond_options_s->str;
+
+	nmc->print_fields.flags = multiline_flag | mode_flag | escape_flag | NMC_PF_FLAG_SECTION_PREFIX;
+	print_fields (nmc->print_fields, nmc->allowed_fields); /* Print values */
+
+	g_string_free (bond_options_s, TRUE);
+
+	return TRUE;
+}
+
+gboolean
+setting_vlan_details (NMSettingVlan *s_vlan, NmCli *nmc)
+{
+	char *vlan_id_str, *vlan_flags_str, *vlan_ingress_prio_str, *vlan_egress_prio_str;
+	guint32 mode_flag = (nmc->print_output == NMC_PRINT_PRETTY) ? NMC_PF_FLAG_PRETTY : (nmc->print_output == NMC_PRINT_TERSE) ? NMC_PF_FLAG_TERSE : 0;
+	guint32 multiline_flag = nmc->multiline_output ? NMC_PF_FLAG_MULTILINE : 0;
+	guint32 escape_flag = nmc->escape_values ? NMC_PF_FLAG_ESCAPE : 0;
+
+	g_return_val_if_fail (NM_IS_SETTING_VLAN (s_vlan), FALSE);
+
+	nmc->allowed_fields = nmc_fields_setting_vlan;
+	nmc->print_fields.indices = parse_output_fields (NMC_FIELDS_SETTING_VLAN_ALL, nmc->allowed_fields, NULL);
+	nmc->print_fields.flags = multiline_flag | mode_flag | escape_flag | NMC_PF_FLAG_FIELD_NAMES;
+	print_fields (nmc->print_fields, nmc->allowed_fields);  /* Print field names */
+
+	vlan_id_str = g_strdup_printf ("%d", nm_setting_vlan_get_id (s_vlan));
+	vlan_flags_str = vlan_flags_to_string (nm_setting_vlan_get_flags (s_vlan));
+	vlan_ingress_prio_str = vlan_priorities_to_string (s_vlan, NM_VLAN_INGRESS_MAP);
+	vlan_egress_prio_str = vlan_priorities_to_string (s_vlan, NM_VLAN_EGRESS_MAP);
+
+	nmc->allowed_fields[0].value = NM_SETTING_VLAN_SETTING_NAME;
+	nmc->allowed_fields[1].value = nm_setting_vlan_get_interface_name (s_vlan);
+	nmc->allowed_fields[2].value = nm_setting_vlan_get_parent (s_vlan);
+	nmc->allowed_fields[3].value = vlan_id_str;
+	nmc->allowed_fields[4].value = vlan_flags_str;
+	nmc->allowed_fields[5].value = vlan_ingress_prio_str;
+	nmc->allowed_fields[6].value = vlan_egress_prio_str;
+
+	nmc->print_fields.flags = multiline_flag | mode_flag | escape_flag | NMC_PF_FLAG_SECTION_PREFIX;
+	print_fields (nmc->print_fields, nmc->allowed_fields); /* Print values */
+
+	g_free (vlan_id_str);
+	g_free (vlan_flags_str);
+	g_free (vlan_ingress_prio_str);
+	g_free (vlan_egress_prio_str);
+
+	return TRUE;
+}
+
diff --git a/cli/src/settings.h b/cli/src/settings.h
index 4901bf27..964d6648 100644
--- a/cli/src/settings.h
+++ b/cli/src/settings.h
@@ -14,7 +14,7 @@
  * with this program; if not, write to the Free Software Foundation, Inc.,
  * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
  *
- * (C) Copyright 2010 Red Hat, Inc.
+ * (C) Copyright 2010 - 2012 Red Hat, Inc.
  */
 
 #ifndef NMC_SETTINGS_H
@@ -36,26 +36,32 @@
 #include <nm-setting-olpc-mesh.h>
 #include <nm-setting-vpn.h>
 #include <nm-setting-wimax.h>
+#include <nm-setting-infiniband.h>
+#include <nm-setting-bond.h>
+#include <nm-setting-vlan.h>
 
 #include "nmcli.h"
 #include "utils.h"
 
 
-gboolean setting_connection_details (NMSetting *setting, NmCli *nmc);
-gboolean setting_wired_details (NMSetting *setting, NmCli *nmc);
-gboolean setting_802_1X_details (NMSetting *setting, NmCli *nmc);
-gboolean setting_wireless_details (NMSetting *setting, NmCli *nmc);
-gboolean setting_wireless_security_details (NMSetting *setting, NmCli *nmc);
-gboolean setting_ip4_config_details (NMSetting *setting, NmCli *nmc);
-gboolean setting_ip6_config_details (NMSetting *setting, NmCli *nmc);
-gboolean setting_serial_details (NMSetting *setting, NmCli *nmc);
-gboolean setting_ppp_details (NMSetting *setting, NmCli *nmc);
-gboolean setting_pppoe_details (NMSetting *setting, NmCli *nmc);
-gboolean setting_gsm_details (NMSetting *setting, NmCli *nmc);
-gboolean setting_cdma_details (NMSetting *setting, NmCli *nmc);
-gboolean setting_bluetooth_details (NMSetting *setting, NmCli *nmc);
-gboolean setting_olpc_mesh_details (NMSetting *setting, NmCli *nmc);
-gboolean setting_vpn_details (NMSetting *setting, NmCli *nmc);
-gboolean setting_wimax_details (NMSetting *setting, NmCli *nmc);
+gboolean setting_connection_details (NMSettingConnection *s_con, NmCli *nmc);
+gboolean setting_wired_details (NMSettingWired *s_wired, NmCli *nmc);
+gboolean setting_802_1X_details (NMSetting8021x *s_8021X, NmCli *nmc);
+gboolean setting_wireless_details (NMSettingWireless *s_wireless, NmCli *nmc);
+gboolean setting_wireless_security_details (NMSettingWirelessSecurity *s_wsec, NmCli *nmc);
+gboolean setting_ip4_config_details (NMSettingIP4Config *s_ip4, NmCli *nmc);
+gboolean setting_ip6_config_details (NMSettingIP6Config *s_ip6, NmCli *nmc);
+gboolean setting_serial_details (NMSettingSerial *s_serial, NmCli *nmc);
+gboolean setting_ppp_details (NMSettingPPP *s_ppp, NmCli *nmc);
+gboolean setting_pppoe_details (NMSettingPPPOE *s_pppoe, NmCli *nmc);
+gboolean setting_gsm_details (NMSettingGsm *s_gsm, NmCli *nmc);
+gboolean setting_cdma_details (NMSettingCdma *s_cdma, NmCli *nmc);
+gboolean setting_bluetooth_details (NMSettingBluetooth *s_bluetooth, NmCli *nmc);
+gboolean setting_olpc_mesh_details (NMSettingOlpcMesh *s_olpc_mesh, NmCli *nmc);
+gboolean setting_vpn_details (NMSettingVPN *s_vpn, NmCli *nmc);
+gboolean setting_wimax_details (NMSettingWimax *s_wimax, NmCli *nmc);
+gboolean setting_infiniband_details (NMSettingInfiniband *s_infiniband, NmCli *nmc);
+gboolean setting_bond_details (NMSettingBond *s_bond, NmCli *nmc);
+gboolean setting_vlan_details (NMSettingVlan *s_vlan, NmCli *nmc);
 
 #endif /* NMC_SETTINGS_H */
diff --git a/cli/src/utils.c b/cli/src/utils.c
index c5637e4f..24bc998c 100644
--- a/cli/src/utils.c
+++ b/cli/src/utils.c
@@ -14,7 +14,7 @@
  * with this program; if not, write to the Free Software Foundation, Inc.,
  * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
  *
- * (C) Copyright 2010 - 2011 Red Hat, Inc.
+ * (C) Copyright 2010 - 2012 Red Hat, Inc.
  */
 
 /* Generated configuration file */
@@ -23,6 +23,10 @@
 #include <stdio.h>
 #include <string.h>
 
+#include <sys/socket.h>
+#include <netinet/in.h>
+#include <arpa/inet.h>
+
 #include <glib.h>
 #include <glib/gi18n.h>
 #include <dbus/dbus-glib-bindings.h>
@@ -79,6 +83,60 @@ ssid_to_printable (const char *str, gsize len)
 }
 
 /*
+ * Converts IPv4 address from guint32 in network-byte order to text representation.
+ * Returns: text form of the IP or NULL (then error is set)
+ */
+char *
+nmc_ip4_address_as_string (guint32 ip, GError **error)
+{
+	struct in_addr tmp_addr;
+	char buf[INET_ADDRSTRLEN];
+
+	g_return_val_if_fail (error == NULL || *error == NULL, NULL);
+
+	memset (&buf, '\0', sizeof (buf));
+	tmp_addr.s_addr = ip;
+
+	if (inet_ntop (AF_INET, &tmp_addr, buf, INET_ADDRSTRLEN)) {
+		return g_strdup (buf);
+	} else {
+		g_set_error (error, 0, 0, _("Error converting IP4 address '0x%X' to text form"),
+		             ntohl (tmp_addr.s_addr));
+		return NULL;
+	}
+}
+
+/*
+ * Converts IPv6 address in in6_addr structure to text representation.
+ * Returns: text form of the IP or NULL (then error is set)
+ */
+char *
+nmc_ip6_address_as_string (const struct in6_addr *ip, GError **error)
+{
+	char buf[INET6_ADDRSTRLEN];
+
+	g_return_val_if_fail (error == NULL || *error == NULL, NULL);
+
+	memset (&buf, '\0', sizeof (buf));
+
+	if (inet_ntop (AF_INET6, ip, buf, INET6_ADDRSTRLEN)) {
+		return g_strdup (buf);
+	} else {
+		if (error) {
+			int j;
+			GString *ip6_str = g_string_new (NULL);
+			g_string_append_printf (ip6_str, "%02X", ip->s6_addr[0]);
+			for (j = 1; j < 16; j++)
+				g_string_append_printf (ip6_str, " %02X", ip->s6_addr[j]);
+			g_set_error (error, 0, 0, _("Error converting IP6 address '%s' to text form"),
+			             ip6_str->str);
+			g_string_free (ip6_str, TRUE);
+		}
+		return NULL;
+	}
+}
+
+/*
  * Find out how many columns an UTF-8 string occupies on the screen
  */
 int
@@ -96,6 +154,20 @@ nmc_string_screen_width (const char *start, const char *end)
 	return width;
 }
 
+void
+set_val_str (NmcOutputField fields_array[], guint32 idx, const char *value)
+{
+	fields_array[idx].flags = 0;
+	fields_array[idx].value = value;
+}
+
+void
+set_val_arr (NmcOutputField fields_array[], guint32 idx, const char **value)
+{
+	fields_array[idx].flags = NMC_OF_FLAG_ARRAY;
+	fields_array[idx].value = value;
+}
+
 /*
  * Parse comma separated fields in 'fields_str' according to 'fields_array'.
  * IN:  'field_str':    comma-separated fields names
@@ -172,9 +244,8 @@ print_fields (const NmcPrintFields fields, const NmcOutputField field_values[])
 	int table_width = 0;
 	char *line = NULL;
 	char *indent_str;
-	const char *value;
 	const char *not_set_str = _("not set");
-	int i, idx;
+	int i;
 	gboolean multiline = fields.flags & NMC_PF_FLAG_MULTILINE;
 	gboolean terse = fields.flags & NMC_PF_FLAG_TERSE;
 	gboolean pretty = fields.flags & NMC_PF_FLAG_PRETTY;
@@ -213,14 +284,39 @@ print_fields (const NmcPrintFields fields, const NmcOutputField field_values[])
 		if (!main_header_only && !field_names) {
 			for (i = 0; i < fields.indices->len; i++) {
 				char *tmp;
-				idx = g_array_index (fields.indices, int, i);
+				int idx = g_array_index (fields.indices, int, i);
+				guint32 value_is_array = field_values[idx].flags & NMC_OF_FLAG_ARRAY;
+
+				/* section prefix can't be an array */
+				g_assert (!value_is_array || !section_prefix || idx != 0);
+
 				if (section_prefix && idx == 0)  /* The first field is section prefix */
 					continue;
-				tmp = g_strdup_printf ("%s%s%s:", section_prefix ? field_values[0].value : "",
-				                                  section_prefix ? "." : "",
-				                                  _(field_values[idx].name_l10n));
-				printf ("%-*s%s\n", terse ? 0 : ML_VALUE_INDENT, tmp, field_values[idx].value ? field_values[idx].value : not_set_str);
-				g_free (tmp);
+
+				if (value_is_array) {
+					/* value is a null-terminated string array */
+					const char **p;
+					int j;
+
+					for (p = (const char **) field_values[idx].value, j = 1; p && *p; p++, j++) {
+						tmp = g_strdup_printf ("%s%s%s[%d]:", section_prefix ? (const char*) field_values[0].value : "",
+						                                      section_prefix ? "." : "",
+						                                      _(field_values[idx].name_l10n),
+						                                      j);
+						printf ("%-*s%s\n", terse ? 0 : ML_VALUE_INDENT, tmp, *p ? *p : not_set_str);
+						g_free (tmp);
+					}
+				} else {
+					/* value is a string */
+					const char *hdr_name = (const char*) field_values[0].value;
+					const char *val = (const char*) field_values[idx].value;
+
+					tmp = g_strdup_printf ("%s%s%s:", section_prefix ? hdr_name : "",
+					                                  section_prefix ? "." : "",
+					                                  _(field_values[idx].name_l10n));
+					printf ("%-*s%s\n", terse ? 0 : ML_VALUE_INDENT, tmp, val ? val : not_set_str);
+					g_free (tmp);
+				}
 			}
 			if (pretty) {
 				line = g_strnfill (ML_HEADER_WIDTH, '-');
@@ -235,11 +331,16 @@ print_fields (const NmcPrintFields fields, const NmcOutputField field_values[])
 	str = g_string_new (NULL);
 
 	for (i = 0; i < fields.indices->len; i++) {
-		idx = g_array_index (fields.indices, int, i);
+		int idx = g_array_index (fields.indices, int, i);
+		guint32 value_is_array = field_values[idx].flags & NMC_OF_FLAG_ARRAY;
+		char *value;
 		if (field_names)
 			value = _(field_values[idx].name_l10n);
 		else
-			value = field_values[idx].value ? field_values[idx].value : not_set_str;
+			value = field_values[idx].value ?
+			        (value_is_array ? g_strjoinv (" | ", (char **) field_values[idx].value) : (char *) field_values[idx].value) :
+			        (char *) not_set_str;
+
 		if (terse) {
 			if (escape) {
 				const char *p = value;
@@ -250,18 +351,19 @@ print_fields (const NmcPrintFields fields, const NmcOutputField field_values[])
 					p++;
 				}
 			}
-			else 
+			else
 				g_string_append_printf (str, "%s", value);
 			g_string_append_c (str, ':');  /* Column separator */
 		} else {
 			width1 = strlen (value);
 			width2 = nmc_string_screen_width (value, NULL);  /* Width of the string (in screen colums) */
-			if (strlen (value) == 0)
-				value = "--";
-			g_string_append_printf (str, "%-*s", field_values[idx].width + width1 - width2, value);
+			g_string_append_printf (str, "%-*s", field_values[idx].width + width1 - width2, strlen (value) > 0 ? value : "--");
 			g_string_append_c (str, ' ');  /* Column separator */
 			table_width += field_values[idx].width + width1 - width2 + 1;
 		}
+
+		if (value_is_array && field_values[idx].value && !field_values)
+			g_free (value);
 	}
 
 	/* Print the main table header */
diff --git a/cli/src/utils.h b/cli/src/utils.h
index 467054a2..a22ae144 100644
--- a/cli/src/utils.h
+++ b/cli/src/utils.h
@@ -14,7 +14,7 @@
  * with this program; if not, write to the Free Software Foundation, Inc.,
  * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
  *
- * (C) Copyright 2010 - 2011 Red Hat, Inc.
+ * (C) Copyright 2010 - 2012 Red Hat, Inc.
  */
 
 #ifndef NMC_UTILS_H
@@ -28,7 +28,11 @@
 int matches (const char *cmd, const char *pattern);
 int next_arg (int *argc, char ***argv);
 char *ssid_to_printable (const char *str, gsize len);
+char *nmc_ip4_address_as_string (guint32 ip, GError **error);
+char *nmc_ip6_address_as_string (const struct in6_addr *ip, GError **error);
 int nmc_string_screen_width (const char *start, const char *end);
+void set_val_str (NmcOutputField fields_array[], guint32 index, const char *value);
+void set_val_arr (NmcOutputField fields_array[], guint32 index, const char **value);
 GArray *parse_output_fields (const char *fields_str, const NmcOutputField fields_array[], GError **error);
 gboolean nmc_terse_option_check (NMCPrintOutput print_output, const char *fields, GError **error);
 void print_fields (const NmcPrintFields fields, const NmcOutputField field_values[]);