static GSList *
construct_ip6_items (GSList *items, GHashTable *ip6_config, const char *prefix)
{
	GSList *addresses = NULL, *routes = NULL, *dns = NULL, *iter;
	guint32 num;
	GString *tmp;
	GValue *val;

	if (ip6_config == NULL)
		return items;

	if (prefix == NULL)
		prefix = "";

	/* IP addresses */
	val = g_hash_table_lookup (ip6_config, "addresses");
	if (val)
		addresses = nm_utils_ip6_addresses_from_gvalue (val);

	for (iter = addresses, num = 0; iter; iter = g_slist_next (iter)) {
		NMIP6Address *addr = (NMIP6Address *) iter->data;
		char str_addr[INET6_ADDRSTRLEN + 1];
		char str_gw[INET6_ADDRSTRLEN + 1];
		const struct in6_addr *tmp_addr;
		guint32 ip_prefix = nm_ip6_address_get_prefix (addr);
		char *addrtmp;

		memset (str_addr, 0, sizeof (str_addr));
		tmp_addr = nm_ip6_address_get_address (addr);
		if (!inet_ntop (AF_INET6, &tmp_addr, str_addr, sizeof (str_addr)))
			continue;

		memset (str_gw, 0, sizeof (str_gw));
		tmp_addr = nm_ip6_address_get_gateway (addr);
		inet_ntop (AF_INET6, &tmp_addr, str_gw, sizeof (str_gw));

		addrtmp = g_strdup_printf ("%sIP6_ADDRESS_%d=%s/%d %s", prefix, num++, str_addr, ip_prefix, str_gw);
		items = g_slist_prepend (items, addrtmp);
	}
	if (num)
		items = g_slist_prepend (items, g_strdup_printf ("%sIP6_NUM_ADDRESSES=%d", prefix, num));
	if (addresses) {
		g_slist_foreach (addresses, (GFunc) nm_ip6_address_unref, NULL);
		g_slist_free (addresses);
	}

	/* DNS servers */
	val = g_hash_table_lookup (ip6_config, "nameservers");
	if (val)
		dns = nm_utils_ip6_dns_from_gvalue (val);

	if (g_slist_length (dns)) {
		tmp = g_string_new (NULL);
		g_string_append_printf (tmp, "%sIP6_NAMESERVERS=", prefix);

		for (iter = dns; iter; iter = g_slist_next (iter)) {
			const struct in6_addr *addr = iter->data;
			gboolean first = TRUE;
			char buf[INET6_ADDRSTRLEN + 1];

			memset (buf, 0, sizeof (buf));
			if (inet_ntop (AF_INET6, addr, buf, sizeof (buf))) {
				if (!first)
					g_string_append_c (tmp, ' ');
				g_string_append (tmp, buf);
				first = FALSE;
			}
		}
	
		items = g_slist_prepend (items, tmp->str);
		g_string_free (tmp, FALSE);
	}

	/* Search domains */
	items = add_domains (items, ip6_config, prefix, '6');

	/* Static routes */
	val = g_hash_table_lookup (ip6_config, "routes");
	if (val)
		routes = nm_utils_ip6_routes_from_gvalue (val);

	for (iter = routes, num = 0; iter; iter = g_slist_next (iter)) {
		NMIP6Route *route = (NMIP6Route *) iter->data;
		char str_addr[INET6_ADDRSTRLEN + 1];
		char str_nh[INET6_ADDRSTRLEN + 1];
		const struct in6_addr *tmp_addr;
		guint32 ip_prefix = nm_ip6_route_get_prefix (route);
		guint32 metric = nm_ip6_route_get_metric (route);
		char *routetmp;

		memset (str_addr, 0, sizeof (str_addr));
		tmp_addr = nm_ip6_route_get_dest (route);
		if (!inet_ntop (AF_INET6, &tmp_addr, str_addr, sizeof (str_addr)))
			continue;

		memset (str_nh, 0, sizeof (str_nh));
		tmp_addr = nm_ip6_route_get_next_hop (route);
		inet_ntop (AF_INET6, &tmp_addr, str_nh, sizeof (str_nh));

		routetmp = g_strdup_printf ("%sIP6_ROUTE_%d=%s/%d %s %d", prefix, num++, str_addr, ip_prefix, str_nh, metric);
		items = g_slist_prepend (items, routetmp);
	}
	if (num)
		items = g_slist_prepend (items, g_strdup_printf ("%sIP6_NUM_ROUTES=%d", prefix, num));
	if (routes) {
		g_slist_foreach (routes, (GFunc) nm_ip6_route_unref, NULL);
		g_slist_free (routes);
	}

	return items;
}
static GSList *
construct_ip4_items (GSList *items, GHashTable *ip4_config, const char *prefix)
{
	GSList *addresses = NULL, *routes = NULL, *iter;
	GArray *dns = NULL, *wins = NULL;
	guint32 num, i;
	GString *tmp;
	GValue *val;

	if (ip4_config == NULL)
		return items;

	if (prefix == NULL)
		prefix = "";

	/* IP addresses */
	val = g_hash_table_lookup (ip4_config, "addresses");
	if (val)
		addresses = nm_utils_ip4_addresses_from_gvalue (val);

	for (iter = addresses, num = 0; iter; iter = g_slist_next (iter)) {
		NMIP4Address *addr = (NMIP4Address *) iter->data;
		char str_addr[INET_ADDRSTRLEN + 1];
		char str_gw[INET_ADDRSTRLEN + 1];
		struct in_addr tmp_addr;
		guint32 ip_prefix = nm_ip4_address_get_prefix (addr);
		char *addrtmp;

		memset (str_addr, 0, sizeof (str_addr));
		tmp_addr.s_addr = nm_ip4_address_get_address (addr);
		if (!inet_ntop (AF_INET, &tmp_addr, str_addr, sizeof (str_addr)))
			continue;

		memset (str_gw, 0, sizeof (str_gw));
		tmp_addr.s_addr = nm_ip4_address_get_gateway (addr);
		inet_ntop (AF_INET, &tmp_addr, str_gw, sizeof (str_gw));

		addrtmp = g_strdup_printf ("%sIP4_ADDRESS_%d=%s/%d %s", prefix, num++, str_addr, ip_prefix, str_gw);
		items = g_slist_prepend (items, addrtmp);
	}
	if (num)
		items = g_slist_prepend (items, g_strdup_printf ("%sIP4_NUM_ADDRESSES=%d", prefix, num));
	if (addresses) {
		g_slist_foreach (addresses, (GFunc) nm_ip4_address_unref, NULL);
		g_slist_free (addresses);
	}

	/* DNS servers */
	val = g_hash_table_lookup (ip4_config, "nameservers");
	if (val && G_VALUE_HOLDS (val, DBUS_TYPE_G_UINT_ARRAY))
		dns = (GArray *) g_value_get_boxed (val);

	if (dns && (dns->len > 0)) {
		gboolean first = TRUE;

		tmp = g_string_new (NULL);
		g_string_append_printf (tmp, "%sIP4_NAMESERVERS=", prefix);
		for (i = 0; i < dns->len; i++) {
			struct in_addr addr;
			char buf[INET_ADDRSTRLEN + 1];

			addr.s_addr = g_array_index (dns, guint32, i);
			memset (buf, 0, sizeof (buf));
			if (inet_ntop (AF_INET, &addr, buf, sizeof (buf))) {
				if (!first)
					g_string_append_c (tmp, ' ');
				g_string_append (tmp, buf);
				first = FALSE;
			}
		}
		items = g_slist_prepend (items, tmp->str);
		g_string_free (tmp, FALSE);
	}

	/* Search domains */
	items = add_domains (items, ip4_config, prefix, '4');

	/* WINS servers */
	val = g_hash_table_lookup (ip4_config, "wins-servers");
	if (val && G_VALUE_HOLDS (val, DBUS_TYPE_G_UINT_ARRAY))
		wins = (GArray *) g_value_get_boxed (val);

	if (wins && wins->len) {
		gboolean first = TRUE;

		tmp = g_string_new (NULL);
		g_string_append_printf (tmp, "%sIP4_WINS_SERVERS=", prefix);
		for (i = 0; i < wins->len; i++) {
			struct in_addr addr;
			char buf[INET_ADDRSTRLEN + 1];

			addr.s_addr = g_array_index (wins, guint32, i);
			memset (buf, 0, sizeof (buf));
			if (inet_ntop (AF_INET, &addr, buf, sizeof (buf))) {
				if (!first)
					g_string_append_c (tmp, ' ');
				g_string_append (tmp, buf);
				first = FALSE;
			}
		}
		items = g_slist_prepend (items, tmp->str);
		g_string_free (tmp, FALSE);
	}

	/* Static routes */
	val = g_hash_table_lookup (ip4_config, "routes");
	if (val)
		routes = nm_utils_ip4_routes_from_gvalue (val);

	for (iter = routes, num = 0; iter; iter = g_slist_next (iter)) {
		NMIP4Route *route = (NMIP4Route *) iter->data;
		char str_addr[INET_ADDRSTRLEN + 1];
		char str_nh[INET_ADDRSTRLEN + 1];
		struct in_addr tmp_addr;
		guint32 ip_prefix = nm_ip4_route_get_prefix (route);
		guint32 metric = nm_ip4_route_get_metric (route);
		char *routetmp;

		memset (str_addr, 0, sizeof (str_addr));
		tmp_addr.s_addr = nm_ip4_route_get_dest (route);
		if (!inet_ntop (AF_INET, &tmp_addr, str_addr, sizeof (str_addr)))
			continue;

		memset (str_nh, 0, sizeof (str_nh));
		tmp_addr.s_addr = nm_ip4_route_get_next_hop (route);
		inet_ntop (AF_INET, &tmp_addr, str_nh, sizeof (str_nh));

		routetmp = g_strdup_printf ("%sIP4_ROUTE_%d=%s/%d %s %d", prefix, num++, str_addr, ip_prefix, str_nh, metric);
		items = g_slist_prepend (items, routetmp);
	}
	items = g_slist_prepend (items, g_strdup_printf ("%sIP4_NUM_ROUTES=%d", prefix, num));
	if (routes) {
		g_slist_foreach (routes, (GFunc) nm_ip4_route_unref, NULL);
		g_slist_free (routes);
	}

	return items;
}
static GSList *
construct_ip6_items (GSList *items, GVariant *ip6_config, const char *prefix)
{
	GPtrArray *addresses, *routes;
	char *gateway = NULL;
	GVariant *val;
	int i;

	if (ip6_config == NULL)
		return items;

	if (prefix == NULL)
		prefix = "";

	/* IP addresses */
	val = g_variant_lookup_value (ip6_config, "addresses", G_VARIANT_TYPE ("a(ayuay)"));
	if (val) {
		addresses = nm_utils_ip6_addresses_from_variant (val, &gateway);
		if (!gateway)
			gateway = g_strdup ("::");

		for (i = 0; i < addresses->len; i++) {
			NMIPAddress *addr = addresses->pdata[i];
			char *addrtmp;

			addrtmp = g_strdup_printf ("%sIP6_ADDRESS_%d=%s/%d %s", prefix, i,
			                           nm_ip_address_get_address (addr),
			                           nm_ip_address_get_prefix (addr),
			                           gateway);
			items = g_slist_prepend (items, addrtmp);
		}
		if (addresses->len)
			items = g_slist_prepend (items, g_strdup_printf ("%sIP6_NUM_ADDRESSES=%d", prefix, addresses->len));

		/* Write gateway to a separate variable, too. */
		items = g_slist_prepend (items, g_strdup_printf ("%sIP6_GATEWAY=%s", prefix, gateway));

		g_ptr_array_unref (addresses);
		g_free (gateway);
		g_variant_unref (val);
	}

	/* DNS servers */
	val = g_variant_lookup_value (ip6_config, "nameservers", G_VARIANT_TYPE ("aay"));
	if (val) {
		items = _list_append_val_strv (items, nm_utils_ip6_dns_from_variant (val),
		                               "%sIP6_NAMESERVERS=", prefix);
		g_variant_unref (val);
	}

	/* Search domains */
	items = add_domains (items, ip6_config, prefix, '6');

	/* Static routes */
	val = g_variant_lookup_value (ip6_config, "routes", G_VARIANT_TYPE ("a(ayuayu)"));
	if (val) {
		routes = nm_utils_ip6_routes_from_variant (val);

		for (i = 0; i < routes->len; i++) {
			NMIPRoute *route = routes->pdata[i];
			const char *next_hop;
			char *routetmp;

			next_hop = nm_ip_route_get_next_hop (route);
			if (!next_hop)
				next_hop = "::";

			routetmp = g_strdup_printf ("%sIP6_ROUTE_%d=%s/%d %s %u", prefix, i,
			                            nm_ip_route_get_dest (route),
			                            nm_ip_route_get_prefix (route),
			                            next_hop,
			                            (guint32) MAX (0, nm_ip_route_get_metric (route)));
			items = g_slist_prepend (items, routetmp);
		}
		if (routes->len)
			items = g_slist_prepend (items, g_strdup_printf ("%sIP6_NUM_ROUTES=%d", prefix, routes->len));
		g_ptr_array_unref (routes);
		g_variant_unref (val);
	}

	return items;
}