summary refs log tree commit diff
path: root/libnm/nm-ip-config.c
diff options
context:
space:
mode:
authorMichael Biebl <biebl@debian.org>2019-12-18 18:29:24 +0100
committerMichael Biebl <biebl@debian.org>2019-12-18 18:29:24 +0100
commit28028b26b3371756811e95d894f709f4b1207c00 (patch)
tree6fe7316fd743b51042db47601a8ef8814b3134ac /libnm/nm-ip-config.c
parente22609983008e1a669196ad64ba3a59ae8c76e0d (diff)
New upstream version 1.22.0 upstream/1.22.0
Diffstat (limited to 'libnm/nm-ip-config.c')
-rw-r--r--libnm/nm-ip-config.c542
1 files changed, 317 insertions, 225 deletions
diff --git a/libnm/nm-ip-config.c b/libnm/nm-ip-config.c
index 9df071d8..f214cdc4 100644
--- a/libnm/nm-ip-config.c
+++ b/libnm/nm-ip-config.c
@@ -1,21 +1,7 @@
+// SPDX-License-Identifier: LGPL-2.1+
 /*
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 2 of the License, or (at your option) any later version.
- *
- * This library 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
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public
- * License along with this library; if not, write to the
- * Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
- * Boston, MA 02110-1301 USA.
- *
- * Copyright 2007 - 2011 Novell, Inc.
- * Copyright 2008 - 2014 Red Hat, Inc.
+ * Copyright (C) 2007 - 2011 Novell, Inc.
+ * Copyright (C) 2008 - 2014 Red Hat, Inc.
  */
 
 #include "nm-default.h"
@@ -30,24 +16,9 @@
 #include "nm-utils.h"
 #include "nm-core-internal.h"
 
-G_DEFINE_ABSTRACT_TYPE (NMIPConfig, nm_ip_config, NM_TYPE_OBJECT)
-
-#define NM_IP_CONFIG_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), NM_TYPE_IP_CONFIG, NMIPConfigPrivate))
-
-typedef struct {
-	char *gateway;
-	GPtrArray *addresses;
-	GPtrArray *routes;
-	char **nameservers;
-	char **domains;
-	char **searches;
-	char **wins;
-
-	gboolean new_style_data;
-} NMIPConfigPrivate;
+/*****************************************************************************/
 
-enum {
-	PROP_0,
+NM_GOBJECT_PROPERTIES_DEFINE (NMIPConfig,
 	PROP_FAMILY,
 	PROP_GATEWAY,
 	PROP_ADDRESSES,
@@ -56,156 +27,214 @@ enum {
 	PROP_DOMAINS,
 	PROP_SEARCHES,
 	PROP_WINS_SERVERS,
+);
 
-	LAST_PROP
-};
-
-static void
-nm_ip_config_init (NMIPConfig *config)
-{
-	NMIPConfigPrivate *priv = NM_IP_CONFIG_GET_PRIVATE (config);
-
-	priv->addresses = g_ptr_array_new ();
-	priv->routes = g_ptr_array_new ();
-	priv->nameservers = g_new0 (char *, 1);
-	priv->domains = g_new0 (char *, 1);
-	priv->searches = g_new0 (char *, 1);
-	priv->wins = g_new0 (char *, 1);
-}
+typedef struct _NMIPConfigPrivate {
+	GPtrArray *addresses;
+	GPtrArray *routes;
+	char **nameservers;
+	char **domains;
+	char **searches;
+	char **wins_servers;
+	char *gateway;
 
-static gboolean
-demarshal_ip_addresses (NMObject *object, GParamSpec *pspec, GVariant *value, gpointer field)
-{
-	NMIPConfigPrivate *priv = NM_IP_CONFIG_GET_PRIVATE (object);
+	bool addresses_new_style:1;
+	bool routes_new_style:1;
+	bool nameservers_new_style:1;
+	bool wins_servers_new_style:1;
+} NMIPConfigPrivate;
 
-	if (priv->new_style_data)
-		return TRUE;
+G_DEFINE_ABSTRACT_TYPE (NMIPConfig, nm_ip_config, NM_TYPE_OBJECT)
 
-	g_ptr_array_unref (priv->addresses);
-	if (NM_IS_IP4_CONFIG (object))
-		priv->addresses = nm_utils_ip4_addresses_from_variant (value, NULL);
-	else
-		priv->addresses = nm_utils_ip6_addresses_from_variant (value, NULL);
-	_nm_object_queue_notify (object, NM_IP_CONFIG_ADDRESSES);
+#define NM_IP_CONFIG_GET_PRIVATE(self) _NM_GET_PRIVATE_PTR(self, NMIPConfig, NM_IS_IP_CONFIG, NMObject)
 
-	return TRUE;
-}
+/*****************************************************************************/
 
-static gboolean
-demarshal_ip_address_data (NMObject *object, GParamSpec *pspec, GVariant *value, gpointer field)
+static NMLDBusNotifyUpdatePropFlags
+_notify_update_prop_addresses (NMClient *client,
+                               NMLDBusObject *dbobj,
+                               const NMLDBusMetaIface *meta_iface,
+                               guint dbus_property_idx,
+                               GVariant *value)
 {
-	NMIPConfigPrivate *priv = NM_IP_CONFIG_GET_PRIVATE (object);
-
-	priv->new_style_data = TRUE;
-
-	g_ptr_array_unref (priv->addresses);
-	if (NM_IS_IP4_CONFIG (object))
-		priv->addresses = nm_utils_ip_addresses_from_variant (value, AF_INET);
-	else
-		priv->addresses = nm_utils_ip_addresses_from_variant (value, AF_INET6);
-	_nm_object_queue_notify (object, NM_IP_CONFIG_ADDRESSES);
+	NMIPConfig *self = NM_IP_CONFIG (dbobj->nmobj);
+	NMIPConfigPrivate *priv = NM_IP_CONFIG_GET_PRIVATE (self);
+	gs_unref_ptrarray GPtrArray *addresses_old = NULL;
+	gs_unref_ptrarray GPtrArray *addresses_new = NULL;
+	int addr_family =   meta_iface == &_nml_dbus_meta_iface_nm_ip4config
+	                  ? AF_INET : AF_INET6;
+	gboolean new_style;
+
+	new_style = (((const char *) meta_iface->dbus_properties[dbus_property_idx].dbus_type)[2] == '{');
+
+	if (priv->addresses_new_style) {
+		if (!new_style)
+			return NML_DBUS_NOTIFY_UPDATE_PROP_FLAGS_NONE;
+	} else
+		priv->addresses_new_style = new_style;
+
+	if (value) {
+		if (new_style)
+			addresses_new = nm_utils_ip_addresses_from_variant (value, addr_family);
+		else if (addr_family == AF_INET)
+			addresses_new = nm_utils_ip4_addresses_from_variant (value, NULL);
+		else
+			addresses_new = nm_utils_ip6_addresses_from_variant (value, NULL);
+		nm_assert (addresses_new);
+	}
+	if (!addresses_new)
+		addresses_new = g_ptr_array_new_with_free_func ((GDestroyNotify) nm_ip_address_unref);
 
-	return TRUE;
+	addresses_old = priv->addresses;
+	priv->addresses = g_steal_pointer (&addresses_new);
+	return NML_DBUS_NOTIFY_UPDATE_PROP_FLAGS_NOTIFY;
 }
 
-static gboolean
-demarshal_ip_array (NMObject *object, GParamSpec *pspec, GVariant *value, gpointer field)
+static NMLDBusNotifyUpdatePropFlags
+_notify_update_prop_routes (NMClient *client,
+                            NMLDBusObject *dbobj,
+                            const NMLDBusMetaIface *meta_iface,
+                            guint dbus_property_idx,
+                            GVariant *value)
 {
-	char ***obj_field;
-
-	obj_field = field;
-	if (*obj_field)
-		g_strfreev (*obj_field);
-
-	if (NM_IS_IP4_CONFIG (object))
-		*obj_field = nm_utils_ip4_dns_from_variant (value);
-	else
-		*obj_field = nm_utils_ip6_dns_from_variant (value);
+	NMIPConfig *self = NM_IP_CONFIG (dbobj->nmobj);
+	NMIPConfigPrivate *priv = NM_IP_CONFIG_GET_PRIVATE (self);
+	gs_unref_ptrarray GPtrArray *routes_old = NULL;
+	gs_unref_ptrarray GPtrArray *routes_new = NULL;
+	int addr_family =   meta_iface == &_nml_dbus_meta_iface_nm_ip4config
+	                  ? AF_INET : AF_INET6;
+	gboolean new_style;
+
+	new_style = (((const char *) meta_iface->dbus_properties[dbus_property_idx].dbus_type)[2] == '{');
+
+	if (priv->routes_new_style) {
+		if (!new_style)
+			return NML_DBUS_NOTIFY_UPDATE_PROP_FLAGS_NONE;
+	} else
+		priv->routes_new_style = new_style;
+
+	if (value) {
+		if (new_style)
+			routes_new = nm_utils_ip_routes_from_variant (value, addr_family);
+		else if (addr_family == AF_INET)
+			routes_new = nm_utils_ip4_routes_from_variant (value);
+		else
+			routes_new = nm_utils_ip6_routes_from_variant (value);
+		nm_assert (routes_new);
+	}
+	if (!routes_new)
+		routes_new = g_ptr_array_new_with_free_func ((GDestroyNotify) nm_ip_route_unref);
 
-	_nm_object_queue_notify (object, pspec->name);
-	return TRUE;
+	routes_old = priv->routes;
+	priv->routes = g_steal_pointer (&routes_new);
+	return NML_DBUS_NOTIFY_UPDATE_PROP_FLAGS_NOTIFY;
 }
 
-static gboolean
-demarshal_ip_routes (NMObject *object, GParamSpec *pspec, GVariant *value, gpointer field)
+static NMLDBusNotifyUpdatePropFlags
+_notify_update_prop_nameservers (NMClient *client,
+                                 NMLDBusObject *dbobj,
+                                 const NMLDBusMetaIface *meta_iface,
+                                 guint dbus_property_idx,
+                                 GVariant *value)
 {
-	NMIPConfigPrivate *priv = NM_IP_CONFIG_GET_PRIVATE (object);
-
-	if (priv->new_style_data)
-		return TRUE;
+	NMIPConfig *self = NM_IP_CONFIG (dbobj->nmobj);
+	NMIPConfigPrivate *priv = NM_IP_CONFIG_GET_PRIVATE (self);
+	gs_strfreev char **nameservers_new = NULL;
+	gboolean new_style = TRUE;
+	int addr_family =   meta_iface == &_nml_dbus_meta_iface_nm_ip4config
+	                  ? AF_INET : AF_INET6;
+
+	if (addr_family == AF_INET) {
+		new_style = (((const char *) meta_iface->dbus_properties[dbus_property_idx].dbus_type)[1] == 'a');
+
+		if (priv->nameservers_new_style) {
+			if (!new_style)
+				return NML_DBUS_NOTIFY_UPDATE_PROP_FLAGS_NONE;
+		} else
+			priv->nameservers_new_style = new_style;
+	}
 
-	g_ptr_array_unref (priv->routes);
-	if (NM_IS_IP4_CONFIG (object))
-		priv->routes = nm_utils_ip4_routes_from_variant (value);
-	else
-		priv->routes = nm_utils_ip6_routes_from_variant (value);
-	_nm_object_queue_notify (object, NM_IP_CONFIG_ROUTES);
+	if (value) {
+		if (addr_family == AF_INET6)
+			nameservers_new = nm_utils_ip6_dns_from_variant (value);
+		else if (!new_style)
+			nameservers_new = nm_utils_ip4_dns_from_variant (value);
+		else {
+			GVariantIter iter;
+			GVariantIter *iter_v;
+			gs_unref_ptrarray GPtrArray *arr = NULL;
+
+			g_variant_iter_init (&iter, value);
+			while (g_variant_iter_next (&iter, "a{sv}", &iter_v)) {
+				const char *key;
+				GVariant *val;
+
+				while (g_variant_iter_next (iter_v, "{&sv}", &key, &val)) {
+					if (nm_streq (key, "address")) {
+						gs_free char *val_str = NULL;
+
+						if (!g_variant_is_of_type (val, G_VARIANT_TYPE_STRING))
+							goto next;
+						if (!nm_utils_parse_inaddr (AF_INET, g_variant_get_string (val, NULL), &val_str))
+							goto next;
+						if (!arr)
+							arr = g_ptr_array_new ();
+						g_ptr_array_add (arr, g_steal_pointer (&val_str));
+						goto next;
+					}
+next:
+					g_variant_unref (val);
+				}
+				g_variant_iter_free (iter_v);
+			}
+			if (   arr
+			    && arr->len > 0)
+				nameservers_new = nm_utils_strv_dup (arr->pdata, arr->len, FALSE);
+			else
+				nameservers_new = g_new0 (char *, 1);
+		}
+		nm_assert (nameservers_new);
+	}
 
-	return TRUE;
+	g_strfreev (priv->nameservers);
+	priv->nameservers = g_steal_pointer (&nameservers_new);
+	return NML_DBUS_NOTIFY_UPDATE_PROP_FLAGS_NOTIFY;
 }
 
-static gboolean
-demarshal_ip_route_data (NMObject *object, GParamSpec *pspec, GVariant *value, gpointer field)
+static NMLDBusNotifyUpdatePropFlags
+_notify_update_prop_wins_servers (NMClient *client,
+                                  NMLDBusObject *dbobj,
+                                  const NMLDBusMetaIface *meta_iface,
+                                  guint dbus_property_idx,
+                                  GVariant *value)
 {
-	NMIPConfigPrivate *priv = NM_IP_CONFIG_GET_PRIVATE (object);
-
-	priv->new_style_data = TRUE;
-
-	g_ptr_array_unref (priv->routes);
-	if (NM_IS_IP4_CONFIG (object))
-		priv->routes = nm_utils_ip_routes_from_variant (value, AF_INET);
-	else
-		priv->routes = nm_utils_ip_routes_from_variant (value, AF_INET6);
-	_nm_object_queue_notify (object, NM_IP_CONFIG_ROUTES);
+	NMIPConfig *self = NM_IP_CONFIG (dbobj->nmobj);
+	NMIPConfigPrivate *priv = NM_IP_CONFIG_GET_PRIVATE (self);
+	gs_strfreev char **wins_servers_new = NULL;
+	gboolean new_style;
+
+	new_style = (((const char *) meta_iface->dbus_properties[dbus_property_idx].dbus_type)[1] == 's');
+
+	if (priv->wins_servers_new_style) {
+		if (!new_style)
+			return NML_DBUS_NOTIFY_UPDATE_PROP_FLAGS_NONE;
+	} else
+		priv->wins_servers_new_style = new_style;
+
+	if (value) {
+		if (new_style)
+			wins_servers_new = g_variant_dup_strv (value, NULL);
+		else
+			wins_servers_new = nm_utils_ip4_dns_from_variant (value);
+		nm_assert (wins_servers_new);
+	}
 
-	return TRUE;
+	g_strfreev (priv->wins_servers);
+	priv->wins_servers = g_steal_pointer (&wins_servers_new);
+	return NML_DBUS_NOTIFY_UPDATE_PROP_FLAGS_NOTIFY;
 }
 
-static void
-init_dbus (NMObject *object)
-{
-	NMIPConfigPrivate *priv = NM_IP_CONFIG_GET_PRIVATE (object);
-	const NMPropertiesInfo property_info[] = {
-		{ NM_IP_CONFIG_GATEWAY,      &priv->gateway, },
-		{ NM_IP_CONFIG_ADDRESSES,    &priv->addresses, demarshal_ip_addresses },
-		{ "address-data",            &priv->addresses, demarshal_ip_address_data },
-		{ NM_IP_CONFIG_ROUTES,       &priv->routes, demarshal_ip_routes },
-		{ "route-data",              &priv->routes, demarshal_ip_route_data },
-		/* Still use deprecated "Nameservers" property instead of "NameserverData" */
-		{ NM_IP_CONFIG_NAMESERVERS,  &priv->nameservers, demarshal_ip_array },
-		{ NM_IP_CONFIG_DOMAINS,      &priv->domains, },
-		{ NM_IP_CONFIG_SEARCHES,     &priv->searches, },
-		/* Still use deprecated "WinsServers" property instead of "WinsServerData" */
-		{ NM_IP_CONFIG_WINS_SERVERS, &priv->wins, demarshal_ip_array },
-		{ NULL },
-	};
-
-	NM_OBJECT_CLASS (nm_ip_config_parent_class)->init_dbus (object);
-
-	_nm_object_register_properties (object,
-	                                (NM_IS_IP4_CONFIG (object) ?
-	                                 NM_DBUS_INTERFACE_IP4_CONFIG :
-	                                 NM_DBUS_INTERFACE_IP6_CONFIG),
-	                                property_info);
-}
-
-static void
-finalize (GObject *object)
-{
-	NMIPConfigPrivate *priv = NM_IP_CONFIG_GET_PRIVATE (object);
-
-	g_free (priv->gateway);
-
-	g_ptr_array_unref (priv->addresses);
-	g_ptr_array_unref (priv->routes);
-
-	g_strfreev (priv->nameservers);
-	g_strfreev (priv->domains);
-	g_strfreev (priv->searches);
-	g_strfreev (priv->wins);
-
-	G_OBJECT_CLASS (nm_ip_config_parent_class)->finalize (object);
-}
+/*****************************************************************************/
 
 static void
 get_property (GObject *object,
@@ -250,21 +279,89 @@ get_property (GObject *object,
 	}
 }
 
+/*****************************************************************************/
+
+static void
+nm_ip_config_init (NMIPConfig *self)
+{
+	NMIPConfigPrivate *priv;
+
+	priv = G_TYPE_INSTANCE_GET_PRIVATE (self, NM_TYPE_IP_CONFIG, NMIPConfigPrivate);
+
+	self->_priv = priv;
+
+	priv->addresses = g_ptr_array_new_with_free_func ((GDestroyNotify) nm_ip_address_unref);
+	priv->routes = g_ptr_array_new_with_free_func ((GDestroyNotify) nm_ip_route_unref);
+}
+
+static void
+finalize (GObject *object)
+{
+	NMIPConfigPrivate *priv = NM_IP_CONFIG_GET_PRIVATE (object);
+
+	g_free (priv->gateway);
+
+	g_ptr_array_unref (priv->routes);
+	g_ptr_array_unref (priv->addresses);
+
+	g_strfreev (priv->nameservers);
+	g_strfreev (priv->domains);
+	g_strfreev (priv->searches);
+	g_strfreev (priv->wins_servers);
+
+	G_OBJECT_CLASS (nm_ip_config_parent_class)->finalize (object);
+}
+
+const NMLDBusMetaIface _nml_dbus_meta_iface_nm_ip4config = NML_DBUS_META_IFACE_INIT_PROP (
+	NM_DBUS_INTERFACE_IP4_CONFIG,
+	nm_ip4_config_get_type,
+	NML_DBUS_META_INTERFACE_PRIO_INSTANTIATE_HIGH,
+	NML_DBUS_META_IFACE_DBUS_PROPERTIES (
+		NML_DBUS_META_PROPERTY_INIT_FCN    ("AddressData",    PROP_ADDRESSES,    "aa{sv}",          _notify_update_prop_addresses                                         ),
+		NML_DBUS_META_PROPERTY_INIT_FCN    ("Addresses",      PROP_ADDRESSES,    "aau",             _notify_update_prop_addresses,    .obj_property_no_reverse_idx = TRUE ),
+		NML_DBUS_META_PROPERTY_INIT_TODO   ("DnsOptions",    "as"                                                                                                         ),
+		NML_DBUS_META_PROPERTY_INIT_TODO   ("DnsPriority",   "i"                                                                                                          ),
+		NML_DBUS_META_PROPERTY_INIT_AS     ("Domains",        PROP_DOMAINS,      NMIPConfigPrivate, domains                                                               ),
+		NML_DBUS_META_PROPERTY_INIT_S      ("Gateway",        PROP_GATEWAY,      NMIPConfigPrivate, gateway                                                               ),
+		NML_DBUS_META_PROPERTY_INIT_FCN    ("NameserverData", PROP_NAMESERVERS,  "aa{sv}",          _notify_update_prop_nameservers                                       ),
+		NML_DBUS_META_PROPERTY_INIT_FCN    ("Nameservers",    PROP_NAMESERVERS,  "au",              _notify_update_prop_nameservers,  .obj_property_no_reverse_idx = TRUE ),
+		NML_DBUS_META_PROPERTY_INIT_FCN    ("RouteData",      PROP_ROUTES,       "aa{sv}",          _notify_update_prop_routes                                            ),
+		NML_DBUS_META_PROPERTY_INIT_FCN    ("Routes",         PROP_ROUTES,       "aau",             _notify_update_prop_routes,       .obj_property_no_reverse_idx = TRUE ),
+		NML_DBUS_META_PROPERTY_INIT_AS     ("Searches",       PROP_SEARCHES,     NMIPConfigPrivate, searches                                                              ),
+		NML_DBUS_META_PROPERTY_INIT_FCN    ("WinsServerData", PROP_WINS_SERVERS, "as",              _notify_update_prop_wins_servers                                      ),
+		NML_DBUS_META_PROPERTY_INIT_FCN    ("WinsServers",    PROP_WINS_SERVERS, "au",              _notify_update_prop_wins_servers, .obj_property_no_reverse_idx = TRUE ),
+	),
+	.base_struct_offset = G_STRUCT_OFFSET (NMIPConfig, _priv),
+);
+
+const NMLDBusMetaIface _nml_dbus_meta_iface_nm_ip6config = NML_DBUS_META_IFACE_INIT_PROP (
+	NM_DBUS_INTERFACE_IP6_CONFIG,
+	nm_ip6_config_get_type,
+	NML_DBUS_META_INTERFACE_PRIO_INSTANTIATE_HIGH,
+	NML_DBUS_META_IFACE_DBUS_PROPERTIES (
+		NML_DBUS_META_PROPERTY_INIT_FCN         ("AddressData", PROP_ADDRESSES,   "aa{sv}",          _notify_update_prop_addresses                                       ),
+		NML_DBUS_META_PROPERTY_INIT_FCN         ("Addresses",   PROP_ADDRESSES,   "a(ayuay)",        _notify_update_prop_addresses,  .obj_property_no_reverse_idx = TRUE ),
+		NML_DBUS_META_PROPERTY_INIT_TODO        ("DnsOptions",  "as"                                                                                                     ),
+		NML_DBUS_META_PROPERTY_INIT_TODO        ("DnsPriority", "i"                                                                                                      ),
+		NML_DBUS_META_PROPERTY_INIT_AS          ("Domains",     PROP_DOMAINS,     NMIPConfigPrivate, domains                                                             ),
+		NML_DBUS_META_PROPERTY_INIT_S           ("Gateway",     PROP_GATEWAY,     NMIPConfigPrivate, gateway                                                             ),
+		NML_DBUS_META_PROPERTY_INIT_FCN         ("Nameservers", PROP_NAMESERVERS, "aay",             _notify_update_prop_nameservers                                     ),
+		NML_DBUS_META_PROPERTY_INIT_FCN         ("RouteData",   PROP_ROUTES,      "aa{sv}",          _notify_update_prop_routes                                          ),
+		NML_DBUS_META_PROPERTY_INIT_FCN         ("Routes",      PROP_ROUTES,      "a(ayuayu)",       _notify_update_prop_routes,     .obj_property_no_reverse_idx = TRUE ),
+		NML_DBUS_META_PROPERTY_INIT_AS          ("Searches",    PROP_SEARCHES,    NMIPConfigPrivate, searches                                                            ),
+	),
+	.base_struct_offset = G_STRUCT_OFFSET (NMIPConfig, _priv),
+);
+
 static void
 nm_ip_config_class_init (NMIPConfigClass *config_class)
 {
 	GObjectClass *object_class = G_OBJECT_CLASS (config_class);
-	NMObjectClass *nm_object_class = NM_OBJECT_CLASS (config_class);
 
 	g_type_class_add_private (config_class, sizeof (NMIPConfigPrivate));
 
-	/* virtual methods */
 	object_class->get_property = get_property;
-	object_class->finalize = finalize;
-
-	nm_object_class->init_dbus = init_dbus;
-
-	/* properties */
+	object_class->finalize     = finalize;
 
 	/**
 	 * NMIPConfig:family:
@@ -272,84 +369,77 @@ nm_ip_config_class_init (NMIPConfigClass *config_class)
 	 * The IP address family of the configuration; either
 	 * <literal>AF_INET</literal> or <literal>AF_INET6</literal>.
 	 **/
-	g_object_class_install_property
-	    (object_class, PROP_FAMILY,
-	     g_param_spec_int (NM_IP_CONFIG_FAMILY, "", "",
-	                       0, 255, AF_UNSPEC,
-	                       G_PARAM_READABLE |
-	                       G_PARAM_STATIC_STRINGS));
+	obj_properties[PROP_FAMILY] =
+	    g_param_spec_int (NM_IP_CONFIG_FAMILY, "", "",
+	                      0, 255, AF_UNSPEC,
+	                      G_PARAM_READABLE |
+	                      G_PARAM_STATIC_STRINGS);
 
 	/**
 	 * NMIPConfig:gateway:
 	 *
 	 * The IP gateway address of the configuration as string.
 	 **/
-	g_object_class_install_property
-		(object_class, PROP_GATEWAY,
-		 g_param_spec_string (NM_IP_CONFIG_GATEWAY, "", "",
-		                      NULL,
-		                      G_PARAM_READABLE |
-		                      G_PARAM_STATIC_STRINGS));
+	obj_properties[PROP_GATEWAY] =
+	    g_param_spec_string (NM_IP_CONFIG_GATEWAY, "", "",
+	                         NULL,
+	                         G_PARAM_READABLE |
+	                         G_PARAM_STATIC_STRINGS);
 
 	/**
 	 * NMIPConfig:addresses:
 	 *
 	 * A #GPtrArray containing the addresses (#NMIPAddress) of the configuration.
 	 **/
-	g_object_class_install_property
-	    (object_class, PROP_ADDRESSES,
-	     g_param_spec_boxed (NM_IP_CONFIG_ADDRESSES, "", "",
-	                         G_TYPE_PTR_ARRAY,
-	                         G_PARAM_READABLE |
-	                         G_PARAM_STATIC_STRINGS));
+	obj_properties[PROP_ADDRESSES] =
+	    g_param_spec_boxed (NM_IP_CONFIG_ADDRESSES, "", "",
+	                        G_TYPE_PTR_ARRAY,
+	                        G_PARAM_READABLE |
+	                        G_PARAM_STATIC_STRINGS);
 
 	/**
 	 * NMIPConfig:routes: (type GPtrArray(NMIPRoute))
 	 *
 	 * A #GPtrArray containing the routes (#NMIPRoute) of the configuration.
 	 **/
-	g_object_class_install_property
-	    (object_class, PROP_ROUTES,
-	     g_param_spec_boxed (NM_IP_CONFIG_ROUTES, "", "",
-	                         G_TYPE_PTR_ARRAY,
-	                         G_PARAM_READABLE |
-	                         G_PARAM_STATIC_STRINGS));
+	obj_properties[PROP_ROUTES] =
+	    g_param_spec_boxed (NM_IP_CONFIG_ROUTES, "", "",
+	                        G_TYPE_PTR_ARRAY,
+	                        G_PARAM_READABLE |
+	                        G_PARAM_STATIC_STRINGS);
 
 	/**
 	 * NMIPConfig:nameservers:
 	 *
 	 * The array containing name server IP addresses of the configuration.
 	 **/
-	g_object_class_install_property
-	    (object_class, PROP_NAMESERVERS,
-	     g_param_spec_boxed (NM_IP_CONFIG_NAMESERVERS, "", "",
-	                         G_TYPE_STRV,
-	                         G_PARAM_READABLE |
-	                         G_PARAM_STATIC_STRINGS));
+	obj_properties[PROP_NAMESERVERS] =
+	    g_param_spec_boxed (NM_IP_CONFIG_NAMESERVERS, "", "",
+	                        G_TYPE_STRV,
+	                        G_PARAM_READABLE |
+	                        G_PARAM_STATIC_STRINGS);
 
 	/**
 	 * NMIPConfig:domains:
 	 *
 	 * The array containing domain strings of the configuration.
 	 **/
-	g_object_class_install_property
-	    (object_class, PROP_DOMAINS,
-	     g_param_spec_boxed (NM_IP_CONFIG_DOMAINS, "", "",
-	                         G_TYPE_STRV,
-	                         G_PARAM_READABLE |
-	                         G_PARAM_STATIC_STRINGS));
+	obj_properties[PROP_DOMAINS] =
+	    g_param_spec_boxed (NM_IP_CONFIG_DOMAINS, "", "",
+	                        G_TYPE_STRV,
+	                        G_PARAM_READABLE |
+	                        G_PARAM_STATIC_STRINGS);
 
 	/**
 	 * NMIPConfig:searches:
 	 *
 	 * The array containing DNS search strings of the configuration.
 	 **/
-	g_object_class_install_property
-	    (object_class, PROP_SEARCHES,
-	     g_param_spec_boxed (NM_IP_CONFIG_SEARCHES, "", "",
-	                         G_TYPE_STRV,
-	                         G_PARAM_READABLE |
-	                         G_PARAM_STATIC_STRINGS));
+	obj_properties[PROP_SEARCHES] =
+	    g_param_spec_boxed (NM_IP_CONFIG_SEARCHES, "", "",
+	                        G_TYPE_STRV,
+	                        G_PARAM_READABLE |
+	                        G_PARAM_STATIC_STRINGS);
 
 	/**
 	 * NMIPConfig:wins-servers:
@@ -357,12 +447,14 @@ nm_ip_config_class_init (NMIPConfigClass *config_class)
 	 * The array containing WINS server IP addresses of the configuration.
 	 * (This will always be empty for IPv6 configurations.)
 	 **/
-	g_object_class_install_property
-	    (object_class, PROP_WINS_SERVERS,
-	     g_param_spec_boxed (NM_IP_CONFIG_WINS_SERVERS, "", "",
-	                         G_TYPE_STRV,
-	                         G_PARAM_READABLE |
-	                         G_PARAM_STATIC_STRINGS));
+	obj_properties[PROP_WINS_SERVERS] =
+	    g_param_spec_boxed (NM_IP_CONFIG_WINS_SERVERS, "", "",
+	                        G_TYPE_STRV,
+	                        G_PARAM_READABLE |
+	                        G_PARAM_STATIC_STRINGS);
+
+	_nml_dbus_meta_class_init_with_properties (object_class, &_nml_dbus_meta_iface_nm_ip4config,
+	                                                         &_nml_dbus_meta_iface_nm_ip6config);
 }
 
 /**
@@ -395,7 +487,7 @@ nm_ip_config_get_gateway (NMIPConfig *config)
 {
 	g_return_val_if_fail (NM_IS_IP_CONFIG (config), NULL);
 
-	return nm_str_not_empty (NM_IP_CONFIG_GET_PRIVATE (config)->gateway);
+	return _nml_coerce_property_str_not_empty (NM_IP_CONFIG_GET_PRIVATE (config)->gateway);
 }
 
 /**
@@ -425,12 +517,12 @@ nm_ip_config_get_addresses (NMIPConfig *config)
  *
  * Returns: (transfer none): the array of nameserver IP addresses
  **/
-const char * const *
+const char *const*
 nm_ip_config_get_nameservers (NMIPConfig *config)
 {
 	g_return_val_if_fail (NM_IS_IP_CONFIG (config), NULL);
 
-	return (const char * const *) NM_IP_CONFIG_GET_PRIVATE (config)->nameservers;
+	return _nml_coerce_property_strv_not_null (NM_IP_CONFIG_GET_PRIVATE (config)->nameservers);
 }
 
 /**
@@ -442,12 +534,12 @@ nm_ip_config_get_nameservers (NMIPConfig *config)
  * Returns: (transfer none): the array of domains.
  * (This is never %NULL, though it may be 0-length).
  **/
-const char * const *
+const char *const*
 nm_ip_config_get_domains (NMIPConfig *config)
 {
 	g_return_val_if_fail (NM_IS_IP_CONFIG (config), NULL);
 
-	return (const char * const *) NM_IP_CONFIG_GET_PRIVATE (config)->domains;
+	return _nml_coerce_property_strv_not_null (NM_IP_CONFIG_GET_PRIVATE (config)->domains);
 }
 
 /**
@@ -459,12 +551,12 @@ nm_ip_config_get_domains (NMIPConfig *config)
  * Returns: (transfer none): the array of DNS search strings.
  * (This is never %NULL, though it may be 0-length).
  **/
-const char * const *
+const char *const*
 nm_ip_config_get_searches (NMIPConfig *config)
 {
 	g_return_val_if_fail (NM_IS_IP_CONFIG (config), NULL);
 
-	return (const char * const *) NM_IP_CONFIG_GET_PRIVATE (config)->searches;
+	return _nml_coerce_property_strv_not_null (NM_IP_CONFIG_GET_PRIVATE (config)->searches);
 }
 
 /**
@@ -476,12 +568,12 @@ nm_ip_config_get_searches (NMIPConfig *config)
  * Returns: (transfer none): the arry of WINS server IP address strings.
  * (This is never %NULL, though it may be 0-length.)
  **/
-const char * const *
+const char *const*
 nm_ip_config_get_wins_servers (NMIPConfig *config)
 {
 	g_return_val_if_fail (NM_IS_IP_CONFIG (config), NULL);
 
-	return (const char * const *) NM_IP_CONFIG_GET_PRIVATE (config)->wins;
+	return _nml_coerce_property_strv_not_null (NM_IP_CONFIG_GET_PRIVATE (config)->wins_servers);
 }
 
 /**