libnm-core, libnm, core: add AddressData and RouteData properties
authorDan Winship <danw@gnome.org>
Tue, 21 Oct 2014 12:33:18 +0000 (08:33 -0400)
committerDan Winship <danw@gnome.org>
Fri, 7 Nov 2014 12:49:40 +0000 (07:49 -0500)
Add AddressData and RouteData properties to NMSettingIPConfig and
NMIP[46]Config. These are like the existing "addresses" and "routes"
properties, but using strings and containing additional attributes,
like NMIPAddress and NMIPRoute.

This only affects the D-Bus representations; there are no API changes
to NMSettingIP{,4,6}Config or NMIP{4,6}Config as a result of this; the
additional information is just added to the existing 'addresses' and
'routes' properties.

NMSettingIP4Config and NMSettingIP6Config now always generate both
old-style data ('addresses', 'address-labels', 'routes') and new-style
data ('address-data', 'gateway', 'route-data') when serializing to
D-Bus, for backward compatibility. When deserializing, they will fill
in the 'addresses' and 'routes' properties from the new-style data if
it is present (ignoring the old-style data), or from the old-style
data if the new-style isn't present.

The daemon-side NMIP4Config and NMIP6Config always emit changes for
both 'Addresses'/'Routes' and 'AddressData'/'RouteData'. The
libnm-side classes initially listen for changes on both properties,
but start ignoring the 'Addresses' and 'Routes' properties once they
know the daemon is also providing 'AddressData' and 'RouteData'.

15 files changed:
include/nm-dbus-glib-types.h
introspection/nm-ip4-config.xml
introspection/nm-ip6-config.xml
libnm-core/nm-setting-ip-config.c
libnm-core/nm-setting-ip4-config.c
libnm-core/nm-setting-ip6-config.c
libnm-core/nm-utils.c
libnm-core/nm-utils.h
libnm-core/tests/test-general.c
libnm/nm-ip4-config.c
libnm/nm-ip6-config.c
src/nm-ip4-config.c
src/nm-ip4-config.h
src/nm-ip6-config.c
src/nm-ip6-config.h

index 66f4568..1b41c9f 100644 (file)
@@ -37,4 +37,9 @@
 #define DBUS_TYPE_G_IP6_ROUTE               (dbus_g_type_get_struct ("GValueArray", DBUS_TYPE_G_UCHAR_ARRAY, G_TYPE_UINT, DBUS_TYPE_G_UCHAR_ARRAY, G_TYPE_UINT, G_TYPE_INVALID))
 #define DBUS_TYPE_G_ARRAY_OF_IP6_ROUTE      (dbus_g_type_get_collection ("GPtrArray", DBUS_TYPE_G_IP6_ROUTE))
 
+#define DBUS_TYPE_NM_IP_ADDRESS             (dbus_g_type_get_struct ("GValueArray", G_TYPE_STRING, G_TYPE_UINT, DBUS_TYPE_G_MAP_OF_STRING, G_TYPE_INVALID))
+#define DBUS_TYPE_NM_IP_ADDRESSES           (dbus_g_type_get_collection ("GPtrArray", DBUS_TYPE_NM_IP_ADDRESS))
+#define DBUS_TYPE_NM_IP_ROUTE               (dbus_g_type_get_struct ("GValueArray", G_TYPE_STRING, G_TYPE_UINT, G_TYPE_STRING, G_TYPE_UINT, DBUS_TYPE_G_MAP_OF_STRING, G_TYPE_INVALID))
+#define DBUS_TYPE_NM_IP_ROUTES              (dbus_g_type_get_collection ("GPtrArray", DBUS_TYPE_NM_IP_ROUTE))
+
 #endif /* __NM_DBUS_GLIB_TYPES_H__ */
index 6a8750b..9807653 100644 (file)
@@ -2,20 +2,42 @@
 
 <node name="/" xmlns:tp="http://telepathy.freedesktop.org/wiki/DbusSpec#extensions-v0">
   <interface name="org.freedesktop.NetworkManager.IP4Config">
+    <property name="Addresses" type="aau" access="read">
+      <tp:docstring>
+       Array of arrays of IPv4 address/prefix/gateway.  All 3
+       elements of each array are in network byte order.  Essentially:
+       [(addr, prefix, gateway), (addr, prefix, gateway), ...]
+
+       Deprecated: use AddressData and Gateway
+      </tp:docstring>
+    </property>
+    <property name="AddressData" type="aa{sv}" access="read">
+      <tp:docstring>
+       Array of IP address data objects. All addresses will include
+       "address" (an IP address string), and "prefix" (a uint). Some
+       addresses may include additional attributes.
+      </tp:docstring>
+    </property>
     <property name="Gateway" type="s" access="read">
       <tp:docstring>The gateway in use.</tp:docstring>
     </property>
-    <property name="Addresses" type="aau" access="read">
-      <tp:docstring>Array of tuples of IPv4 address/prefix/gateway.  All 3
-      elements of each tuple are in network byte order.  Essentially:
-      [(addr, prefix, gateway), (addr, prefix, gateway), ...]
+    <property name="Routes" type="aau" access="read">
+      <tp:docstring>
+       Arrays of IPv4 route/prefix/next-hop/metric. All 4 elements of
+       each tuple are in network byte order. 'route' and 'next hop'
+       are IPv4 addresses, while prefix and metric are simple
+       unsigned integers. Essentially: [(route, prefix, next-hop,
+       metric), (route, prefix, next-hop, metric), ...]
+
+       Deprecated: use RouteData
       </tp:docstring>
     </property>
-    <property name="Routes" type="aau" access="read">
-      <tp:docstring>Tuples of IPv4 route/prefix/next-hop/metric.  All 4 elements
-      of each tuple are in network byte order.  'route' and 'next hop' are IPv4
-      addresses, while prefix and metric are simple unsigned integers.  Essentially:
-      [(route, prefix, next-hop, metric), (route, prefix, next-hop, metric), ...]
+    <property name="RouteData" type="aa{sv}" access="read">
+      <tp:docstring>
+       Array of IP route data objects. All routes will include "dest"
+       (an IP address string) and "prefix" (a uint). Some routes may
+       include "next-hop" (an IP address string), "metric" (a uint),
+       and additional attributes.
       </tp:docstring>
     </property>
     <property name="Nameservers" type="au" access="read">
index 55c519e..985dd2e 100644 (file)
@@ -2,14 +2,37 @@
 
 <node name="/" xmlns:tp="http://telepathy.freedesktop.org/wiki/DbusSpec#extensions-v0">
   <interface name="org.freedesktop.NetworkManager.IP6Config">
+    <property name="Addresses" type="a(ayuay)" access="read">
+      <tp:docstring>
+       Array of tuples of IPv6 address/prefix/gateway.
+
+       Deprecated: use AddressData and Gateway.
+      </tp:docstring>
+    </property>
+    <property name="AddressData" type="aa{sv}" access="read">
+      <tp:docstring>
+       Array of IP address data objects. All addresses will include
+       "address" (an IP address string), and "prefix" (a uint). Some
+       addresses may include additional attributes.
+      </tp:docstring>
+    </property>
     <property name="Gateway" type="s" access="read">
       <tp:docstring>The gateway in use.</tp:docstring>
     </property>
-    <property name="Addresses" type="a(ayuay)" access="read">
-      <tp:docstring>Tuples of IPv6 address/prefix/gateway.</tp:docstring>
-    </property>
     <property name="Routes" type="a(ayuayu)" access="read">
-      <tp:docstring>Tuples of IPv6 route/prefix/next-hop/metric.</tp:docstring>
+      <tp:docstring>
+       Tuples of IPv6 route/prefix/next-hop/metric.
+
+       Deprecated: use RouteData
+      </tp:docstring>
+    </property>
+    <property name="RouteData" type="aa{sv}" access="read">
+      <tp:docstring>
+       Array of IP route data objects. All routes will include "dest"
+       (an IP address string) and "prefix" (a uint). Some routes may
+       include "next-hop" (an IP address string), "metric" (a uint),
+       and additional attributes.
+      </tp:docstring>
     </property>
     <property name="Nameservers" type="aay" access="read">
       <tp:docstring>The nameservers in use.</tp:docstring>
index 0ed612c..30e7b26 100644 (file)
@@ -472,6 +472,7 @@ nm_ip_address_set_attribute (NMIPAddress *address, const char *name, GVariant *v
 {
        g_return_if_fail (address != NULL);
        g_return_if_fail (name != NULL && *name != '\0');
+       g_return_if_fail (strcmp (name, "address") != 0 && strcmp (name, "prefix") != 0);
 
        if (!address->attributes) {
                address->attributes = g_hash_table_new_full (g_str_hash, g_str_equal,
@@ -1009,6 +1010,8 @@ nm_ip_route_set_attribute (NMIPRoute *route, const char *name, GVariant *value)
 {
        g_return_if_fail (route != NULL);
        g_return_if_fail (name != NULL && *name != '\0');
+       g_return_if_fail (   strcmp (name, "dest") != 0 && strcmp (name, "prefix") != 0
+                         && strcmp (name, "next-hop") != 0 && strcmp (name, "metric") != 0);
 
        if (!route->attributes) {
                route->attributes = g_hash_table_new_full (g_str_hash, g_str_equal,
index 66f2ea9..9eab49d 100644 (file)
@@ -269,9 +269,14 @@ ip4_addresses_set (NMSetting  *setting,
        char **labels, *gateway = NULL;
        int i;
 
-       addrs = nm_utils_ip4_addresses_from_variant (value, &gateway);
-
        s_ip4 = g_variant_lookup_value (connection_dict, NM_SETTING_IP4_CONFIG_SETTING_NAME, NM_VARIANT_TYPE_SETTING);
+       /* If 'address-data' is set then ignore 'addresses' */
+       if (g_variant_lookup (s_ip4, "address-data", "aa{sv}", NULL)) {
+               g_variant_unref (s_ip4);
+               return;
+       }
+
+       addrs = nm_utils_ip4_addresses_from_variant (value, &gateway);
 
        if (g_variant_lookup (s_ip4, "address-labels", "^as", &labels)) {
                for (i = 0; i < addrs->len && labels[i]; i++)
@@ -319,16 +324,95 @@ ip4_address_labels_get (NMSetting    *setting,
 }
 
 static GVariant *
-ip4_routes_to_dbus (const GValue *prop_value)
+ip4_address_data_get (NMSetting    *setting,
+                      NMConnection *connection,
+                      const char   *property)
+{
+       GPtrArray *addrs;
+       GVariant *ret;
+
+       g_object_get (setting, NM_SETTING_IP_CONFIG_ADDRESSES, &addrs, NULL);
+       ret = nm_utils_ip_addresses_to_variant (addrs);
+       g_ptr_array_unref (addrs);
+
+       return ret;
+}
+
+static void
+ip4_address_data_set (NMSetting  *setting,
+                      GVariant   *connection_dict,
+                      const char *property,
+                      GVariant   *value)
+{
+       GPtrArray *addrs;
+
+       addrs = nm_utils_ip_addresses_from_variant (value, AF_INET);
+       g_object_set (setting, NM_SETTING_IP_CONFIG_ADDRESSES, addrs, NULL);
+       g_ptr_array_unref (addrs);
+}
+
+static GVariant *
+ip4_routes_get (NMSetting  *setting,
+                const char *property)
+{
+       GPtrArray *routes;
+       GVariant *ret;
+
+       g_object_get (setting, property, &routes, NULL);
+       ret = nm_utils_ip4_routes_to_variant (routes);
+       g_ptr_array_unref (routes);
+
+       return ret;
+}
+
+static void
+ip4_routes_set (NMSetting  *setting,
+                GVariant   *connection_dict,
+                const char *property,
+                GVariant   *value)
+{
+       GPtrArray *routes;
+       GVariant *s_ip4;
+
+       s_ip4 = g_variant_lookup_value (connection_dict, NM_SETTING_IP4_CONFIG_SETTING_NAME, NM_VARIANT_TYPE_SETTING);
+       /* If 'route-data' is set then ignore 'routes' */
+       if (g_variant_lookup (s_ip4, "route-data", "aa{sv}", NULL)) {
+               g_variant_unref (s_ip4);
+               return;
+       }
+       g_variant_unref (s_ip4);
+
+       routes = nm_utils_ip4_routes_from_variant (value);
+       g_object_set (setting, property, routes, NULL);
+       g_ptr_array_unref (routes);
+}
+
+static GVariant *
+ip4_route_data_get (NMSetting    *setting,
+                    NMConnection *connection,
+                    const char   *property)
 {
-       return nm_utils_ip4_routes_to_variant (g_value_get_boxed (prop_value));
+       GPtrArray *routes;
+       GVariant *ret;
+
+       g_object_get (setting, NM_SETTING_IP_CONFIG_ROUTES, &routes, NULL);
+       ret = nm_utils_ip_routes_to_variant (routes);
+       g_ptr_array_unref (routes);
+
+       return ret;
 }
 
 static void
-ip4_routes_from_dbus (GVariant *dbus_value,
-                      GValue *prop_value)
+ip4_route_data_set (NMSetting  *setting,
+                    GVariant   *connection_dict,
+                    const char *property,
+                    GVariant   *value)
 {
-       g_value_take_boxed (prop_value, nm_utils_ip4_routes_from_variant (dbus_value));
+       GPtrArray *routes;
+
+       routes = nm_utils_ip_routes_from_variant (value, AF_INET);
+       g_object_set (setting, NM_SETTING_IP_CONFIG_ROUTES, routes, NULL);
+       g_ptr_array_unref (routes);
 }
 
 
@@ -381,9 +465,23 @@ nm_setting_ip4_config_class_init (NMSettingIP4ConfigClass *ip4_class)
                                                  ip4_address_labels_get,
                                                  NULL);
 
-       _nm_setting_class_transform_property (setting_class,
-                                             NM_SETTING_IP_CONFIG_ROUTES,
-                                             G_VARIANT_TYPE ("aau"),
-                                             ip4_routes_to_dbus,
-                                             ip4_routes_from_dbus);
+       _nm_setting_class_add_dbus_only_property (setting_class,
+                                                 "address-data",
+                                                 G_VARIANT_TYPE ("aa{sv}"),
+                                                 ip4_address_data_get,
+                                                 ip4_address_data_set);
+
+       _nm_setting_class_override_property (setting_class,
+                                            NM_SETTING_IP_CONFIG_ROUTES,
+                                            G_VARIANT_TYPE ("aau"),
+                                            ip4_routes_get,
+                                            ip4_routes_set,
+                                            NULL);
+
+       _nm_setting_class_add_dbus_only_property (setting_class,
+                                                 "route-data",
+                                                 G_VARIANT_TYPE ("aa{sv}"),
+                                                 ip4_route_data_get,
+                                                 ip4_route_data_set);
+
 }
index 9e30011..6e3ff61 100644 (file)
@@ -214,9 +214,14 @@ ip6_addresses_set (NMSetting  *setting,
        GVariant *s_ip6;
        char *gateway = NULL;
 
-       addrs = nm_utils_ip6_addresses_from_variant (value, &gateway);
-
        s_ip6 = g_variant_lookup_value (connection_dict, NM_SETTING_IP6_CONFIG_SETTING_NAME, NM_VARIANT_TYPE_SETTING);
+       /* If 'address-data' is set then ignore 'addresses' */
+       if (g_variant_lookup (s_ip6, "address-data", "aa{sv}", NULL)) {
+               g_variant_unref (s_ip6);
+               return;
+       }
+
+       addrs = nm_utils_ip6_addresses_from_variant (value, &gateway);
 
        if (gateway && !g_variant_lookup (s_ip6, "gateway", "s", NULL)) {
                g_object_set (setting,
@@ -232,16 +237,95 @@ ip6_addresses_set (NMSetting  *setting,
 }
 
 static GVariant *
-ip6_routes_to_dbus (const GValue *prop_value)
+ip6_address_data_get (NMSetting    *setting,
+                      NMConnection *connection,
+                      const char   *property)
+{
+       GPtrArray *addrs;
+       GVariant *ret;
+
+       g_object_get (setting, NM_SETTING_IP_CONFIG_ADDRESSES, &addrs, NULL);
+       ret = nm_utils_ip_addresses_to_variant (addrs);
+       g_ptr_array_unref (addrs);
+
+       return ret;
+}
+
+static void
+ip6_address_data_set (NMSetting  *setting,
+                      GVariant   *connection_dict,
+                      const char *property,
+                      GVariant   *value)
+{
+       GPtrArray *addrs;
+
+       addrs = nm_utils_ip_addresses_from_variant (value, AF_INET6);
+       g_object_set (setting, NM_SETTING_IP_CONFIG_ADDRESSES, addrs, NULL);
+       g_ptr_array_unref (addrs);
+}
+
+static GVariant *
+ip6_routes_get (NMSetting  *setting,
+                const char *property)
+{
+       GPtrArray *routes;
+       GVariant *ret;
+
+       g_object_get (setting, property, &routes, NULL);
+       ret = nm_utils_ip6_routes_to_variant (routes);
+       g_ptr_array_unref (routes);
+
+       return ret;
+}
+
+static void
+ip6_routes_set (NMSetting  *setting,
+                GVariant   *connection_dict,
+                const char *property,
+                GVariant   *value)
+{
+       GPtrArray *routes;
+       GVariant *s_ip6;
+
+       s_ip6 = g_variant_lookup_value (connection_dict, NM_SETTING_IP6_CONFIG_SETTING_NAME, NM_VARIANT_TYPE_SETTING);
+       /* If 'route-data' is set then ignore 'routes' */
+       if (g_variant_lookup (s_ip6, "route-data", "aa{sv}", NULL)) {
+               g_variant_unref (s_ip6);
+               return;
+       }
+       g_variant_unref (s_ip6);
+
+       routes = nm_utils_ip6_routes_from_variant (value);
+       g_object_set (setting, property, routes, NULL);
+       g_ptr_array_unref (routes);
+}
+
+static GVariant *
+ip6_route_data_get (NMSetting    *setting,
+                    NMConnection *connection,
+                    const char   *property)
 {
-       return nm_utils_ip6_routes_to_variant (g_value_get_boxed (prop_value));
+       GPtrArray *routes;
+       GVariant *ret;
+
+       g_object_get (setting, NM_SETTING_IP_CONFIG_ROUTES, &routes, NULL);
+       ret = nm_utils_ip_routes_to_variant (routes);
+       g_ptr_array_unref (routes);
+
+       return ret;
 }
 
 static void
-ip6_routes_from_dbus (GVariant *dbus_value,
-                      GValue *prop_value)
+ip6_route_data_set (NMSetting  *setting,
+                    GVariant   *connection_dict,
+                    const char *property,
+                    GVariant   *value)
 {
-       g_value_take_boxed (prop_value, nm_utils_ip6_routes_from_variant (dbus_value));
+       GPtrArray *routes;
+
+       routes = nm_utils_ip_routes_from_variant (value, AF_INET6);
+       g_object_set (setting, NM_SETTING_IP_CONFIG_ROUTES, routes, NULL);
+       g_ptr_array_unref (routes);
 }
 
 static void
@@ -324,9 +408,22 @@ nm_setting_ip6_config_class_init (NMSettingIP6ConfigClass *ip6_class)
                                             ip6_addresses_set,
                                             NULL);
 
-       _nm_setting_class_transform_property (setting_class,
-                                             NM_SETTING_IP_CONFIG_ROUTES,
-                                             G_VARIANT_TYPE ("a(ayuayu)"),
-                                             ip6_routes_to_dbus,
-                                             ip6_routes_from_dbus);
+       _nm_setting_class_add_dbus_only_property (setting_class,
+                                                 "address-data",
+                                                 G_VARIANT_TYPE ("aa{sv}"),
+                                                 ip6_address_data_get,
+                                                 ip6_address_data_set);
+
+       _nm_setting_class_override_property (setting_class,
+                                            NM_SETTING_IP_CONFIG_ROUTES,
+                                            G_VARIANT_TYPE ("a(ayuayu)"),
+                                            ip6_routes_get,
+                                            ip6_routes_set,
+                                            NULL);
+
+       _nm_setting_class_add_dbus_only_property (setting_class,
+                                                 "route-data",
+                                                 G_VARIANT_TYPE ("aa{sv}"),
+                                                 ip6_route_data_get,
+                                                 ip6_route_data_set);
 }
index 62698ee..f8105da 100644 (file)
@@ -1711,6 +1711,245 @@ nm_utils_ip6_routes_from_variant (GVariant *value)
        return routes;
 }
 
+/**
+ * nm_utils_ip_addresses_to_variant:
+ * @addresses: (element-type NMIPAddress): an array of #NMIPAddress objects
+ *
+ * Utility function to convert a #GPtrArray of #NMIPAddress objects representing
+ * IPv4 or IPv6 addresses into a #GVariant of type 'aa{sv}' representing an
+ * array of new-style NetworkManager IP addresses. All addresses will include
+ * "address" (an IP address string), and "prefix" (a uint). Some addresses may
+ * include additional attributes.
+ *
+ * Returns: (transfer none): a new floating #GVariant representing @addresses.
+ **/
+GVariant *
+nm_utils_ip_addresses_to_variant (GPtrArray *addresses)
+{
+       GVariantBuilder builder;
+       int i;
+
+       g_variant_builder_init (&builder, G_VARIANT_TYPE ("aa{sv}"));
+
+       if (addresses) {
+               for (i = 0; i < addresses->len; i++) {
+                       NMIPAddress *addr = addresses->pdata[i];
+                       GVariantBuilder addr_builder;
+                       char **names;
+                       int n;
+
+                       g_variant_builder_init (&addr_builder, G_VARIANT_TYPE ("a{sv}"));
+                       g_variant_builder_add (&addr_builder, "{sv}",
+                                              "address",
+                                              g_variant_new_string (nm_ip_address_get_address (addr)));
+                       g_variant_builder_add (&addr_builder, "{sv}",
+                                              "prefix",
+                                              g_variant_new_uint32 (nm_ip_address_get_prefix (addr)));
+
+                       names = nm_ip_address_get_attribute_names (addr);
+                       for (n = 0; names[n]; n++) {
+                               g_variant_builder_add (&addr_builder, "{sv}",
+                                                      names[n],
+                                                      nm_ip_address_get_attribute (addr, names[n]));
+                       }
+                       g_strfreev (names);
+
+                       g_variant_builder_add (&builder, "a{sv}", &addr_builder);
+               }
+       }
+
+       return g_variant_builder_end (&builder);
+}
+
+/**
+ * nm_utils_ip_addresses_from_variant:
+ * @value: a #GVariant of type 'aa{sv}'
+ * @family: an IP address family
+ *
+ * Utility function to convert a #GVariant representing a list of new-style
+ * NetworkManager IPv4 or IPv6 addresses (as described in the documentation for
+ * nm_utils_ip_addresses_to_variant()) into a #GPtrArray of #NMIPAddress
+ * objects.
+ *
+ * Returns: (transfer full) (element-type NMIPAddress): a newly allocated
+ *   #GPtrArray of #NMIPAddress objects
+ **/
+GPtrArray *
+nm_utils_ip_addresses_from_variant (GVariant *value,
+                                    int family)
+{
+       GPtrArray *addresses;
+       GVariantIter iter, attrs_iter;
+       GVariant *addr_var;
+       const char *ip;
+       guint32 prefix;
+       const char *attr_name;
+       GVariant *attr_val;
+       NMIPAddress *addr;
+       GError *error = NULL;
+
+       g_return_val_if_fail (g_variant_is_of_type (value, G_VARIANT_TYPE ("aa{sv}")), NULL);
+
+       g_variant_iter_init (&iter, value);
+       addresses = g_ptr_array_new_with_free_func ((GDestroyNotify) nm_ip_address_unref);
+
+       while (g_variant_iter_next (&iter, "@a{sv}", &addr_var)) {
+               if (   !g_variant_lookup (addr_var, "address", "&s", &ip)
+                   || !g_variant_lookup (addr_var, "prefix", "u", &prefix)) {
+                       g_warning ("Ignoring invalid address");
+                       g_variant_unref (addr_var);
+                       continue;
+               }
+
+               addr = nm_ip_address_new (family, ip, prefix, &error);
+               if (!addr) {
+                       g_warning ("Ignoring invalid address: %s", error->message);
+                       g_clear_error (&error);
+                       g_variant_unref (addr_var);
+                       continue;
+               }
+
+               g_variant_iter_init (&attrs_iter, addr_var);
+               while (g_variant_iter_next (&attrs_iter, "{&sv}", &attr_name, &attr_val)) {
+                       if (   strcmp (attr_name, "address") != 0
+                           && strcmp (attr_name, "prefix") != 0)
+                               nm_ip_address_set_attribute (addr, attr_name, attr_val);
+                       g_variant_unref (attr_val);
+               }
+
+               g_ptr_array_add (addresses, addr);
+       }
+
+       return addresses;
+}
+
+/**
+ * nm_utils_ip_routes_to_variant:
+ * @routes: (element-type NMIPRoute): an array of #NMIPRoute objects
+ *
+ * Utility function to convert a #GPtrArray of #NMIPRoute objects representing
+ * IPv4 or IPv6 routes into a #GVariant of type 'aa{sv}' representing an array
+ * of new-style NetworkManager IP routes (which are tuples of destination,
+ * prefix, next hop, metric, and additional attributes).
+ *
+ * Returns: (transfer none): a new floating #GVariant representing @routes.
+ **/
+GVariant *
+nm_utils_ip_routes_to_variant (GPtrArray *routes)
+{
+       GVariantBuilder builder;
+       int i;
+
+       g_variant_builder_init (&builder, G_VARIANT_TYPE ("aa{sv}"));
+
+       if (routes) {
+               for (i = 0; i < routes->len; i++) {
+                       NMIPRoute *route = routes->pdata[i];
+                       GVariantBuilder route_builder;
+                       char **names;
+                       int n;
+
+                       g_variant_builder_init (&route_builder, G_VARIANT_TYPE ("a{sv}"));
+                       g_variant_builder_add (&route_builder, "{sv}",
+                                              "dest",
+                                              g_variant_new_string (nm_ip_route_get_dest (route)));
+                       g_variant_builder_add (&route_builder, "{sv}",
+                                              "prefix",
+                                              g_variant_new_uint32 (nm_ip_route_get_prefix (route)));
+                       if (nm_ip_route_get_next_hop (route)) {
+                               g_variant_builder_add (&route_builder, "{sv}",
+                                                      "next-hop",
+                                                      g_variant_new_string (nm_ip_route_get_next_hop (route)));
+                       }
+                       if (nm_ip_route_get_metric (route)) {
+                               g_variant_builder_add (&route_builder, "{sv}",
+                                                      "metric",
+                                                      g_variant_new_uint32 (nm_ip_route_get_metric (route)));
+                       }
+
+                       names = nm_ip_route_get_attribute_names (route);
+                       for (n = 0; names[n]; n++) {
+                               g_variant_builder_add (&route_builder, "{sv}",
+                                                      names[n],
+                                                      nm_ip_route_get_attribute (route, names[n]));
+                       }
+                       g_strfreev (names);
+
+                       g_variant_builder_add (&builder, "a{sv}", &route_builder);
+               }
+       }
+
+       return g_variant_builder_end (&builder);
+}
+
+/**
+ * nm_utils_ip_routes_from_variant:
+ * @value: a #GVariant of type 'aa{sv}'
+ * @family: an IP address family
+ *
+ * Utility function to convert a #GVariant representing a list of new-style
+ * NetworkManager IPv4 or IPv6 addresses (which are tuples of destination,
+ * prefix, next hop, metric, and additional attributes) into a #GPtrArray of
+ * #NMIPRoute objects.
+ *
+ * Returns: (transfer full) (element-type NMIPRoute): a newly allocated
+ *   #GPtrArray of #NMIPRoute objects
+ **/
+GPtrArray *
+nm_utils_ip_routes_from_variant (GVariant *value,
+                                 int family)
+{
+       GPtrArray *routes;
+       GVariantIter iter, attrs_iter;
+       GVariant *route_var;
+       const char *dest, *next_hop;
+       guint32 prefix, metric;
+       const char *attr_name;
+       GVariant *attr_val;
+       NMIPRoute *route;
+       GError *error = NULL;
+
+       g_return_val_if_fail (g_variant_is_of_type (value, G_VARIANT_TYPE ("aa{sv}")), NULL);
+
+       g_variant_iter_init (&iter, value);
+       routes = g_ptr_array_new_with_free_func ((GDestroyNotify) nm_ip_route_unref);
+
+       while (g_variant_iter_next (&iter, "@a{sv}", &route_var)) {
+               if (   !g_variant_lookup (route_var, "dest", "&s", &dest)
+                   || !g_variant_lookup (route_var, "prefix", "u", &prefix)) {
+                       g_warning ("Ignoring invalid address");
+                       g_variant_unref (route_var);
+                       continue;
+               }
+               if (!g_variant_lookup (route_var, "next-hop", "&s", &next_hop))
+                       next_hop = NULL;
+               if (!g_variant_lookup (route_var, "metric", "u", &metric))
+                       metric = 0;
+
+               route = nm_ip_route_new (family, dest, prefix, next_hop, metric, &error);
+               if (!route) {
+                       g_warning ("Ignoring invalid route: %s", error->message);
+                       g_clear_error (&error);
+                       g_variant_unref (route_var);
+                       continue;
+               }
+
+               g_variant_iter_init (&attrs_iter, route_var);
+               while (g_variant_iter_next (&attrs_iter, "{&sv}", &attr_name, &attr_val)) {
+                       if (   strcmp (attr_name, "dest") != 0
+                           && strcmp (attr_name, "prefix") != 0
+                           && strcmp (attr_name, "next-hop") != 0
+                           && strcmp (attr_name, "metric") != 0)
+                               nm_ip_route_set_attribute (route, attr_name, attr_val);
+                       g_variant_unref (attr_val);
+               }
+
+               g_ptr_array_add (routes, route);
+       }
+
+       return routes;
+}
+
 /**
  * nm_utils_uuid_generate:
  *
index 628fa0f..25f09c4 100644 (file)
@@ -117,6 +117,13 @@ GPtrArray *nm_utils_ip6_addresses_from_variant (GVariant *value,
 GVariant  *nm_utils_ip6_routes_to_variant (GPtrArray *routes);
 GPtrArray *nm_utils_ip6_routes_from_variant (GVariant *value);
 
+GVariant  *nm_utils_ip_addresses_to_variant (GPtrArray *addresses);
+GPtrArray *nm_utils_ip_addresses_from_variant (GVariant *value,
+                                               int family);
+GVariant  *nm_utils_ip_routes_to_variant (GPtrArray *routes);
+GPtrArray *nm_utils_ip_routes_from_variant (GVariant *value,
+                                            int family);
+
 char *nm_utils_uuid_generate (void);
 char *nm_utils_uuid_generate_from_string (const char *s);
 
index d66a9c9..1bab4e0 100644 (file)
@@ -329,7 +329,7 @@ test_setting_ip4_config_labels (void)
        GPtrArray *addrs;
        char **labels;
        NMConnection *conn;
-       GVariant *dict, *setting_dict, *value;
+       GVariant *dict, *dict2, *setting_dict, *value;
        GError *error = NULL;
 
        s_ip4 = (NMSettingIPConfig *) nm_setting_ip4_config_new ();
@@ -395,7 +395,9 @@ test_setting_ip4_config_labels (void)
        label = nm_ip_address_get_attribute (addr, "label");
        g_assert (label == NULL);
 
-       /* The labels should appear in the D-Bus serialization */
+       /* The labels should appear in the D-Bus serialization under both
+        * 'address-labels' and 'address-data'.
+        */
        conn = nmtst_create_minimal_connection ("label test", NULL, NM_SETTING_WIRED_SETTING_NAME, NULL);
        nm_connection_add_setting (conn, NM_SETTING (s_ip4));
        dict = nm_connection_to_dbus (conn, NM_CONNECTION_SERIALIZE_ALL);
@@ -403,19 +405,41 @@ test_setting_ip4_config_labels (void)
 
        setting_dict = g_variant_lookup_value (dict, NM_SETTING_IP4_CONFIG_SETTING_NAME, NM_VARIANT_TYPE_SETTING);
        g_assert (setting_dict != NULL);
+
        value = g_variant_lookup_value (setting_dict, "address-labels", G_VARIANT_TYPE_STRING_ARRAY);
        g_assert (value != NULL);
-
        g_variant_get (value, "^as", &labels);
        g_assert_cmpint (g_strv_length (labels), ==, 2);
        g_assert_cmpstr (labels[0], ==, "eth0:1");
        g_assert_cmpstr (labels[1], ==, "");
-
-       g_variant_unref (setting_dict);
        g_variant_unref (value);
        g_strfreev (labels);
 
-       /* And should be deserialized */
+       value = g_variant_lookup_value (setting_dict, "address-data", G_VARIANT_TYPE ("aa{sv}"));
+       addrs = nm_utils_ip_addresses_from_variant (value, AF_INET);
+       g_variant_unref (value);
+       g_assert (addrs != NULL);
+       g_assert_cmpint (addrs->len, ==, 2);
+       addr = addrs->pdata[0];
+       label = nm_ip_address_get_attribute (addr, "label");
+       g_assert (label != NULL);
+       g_assert_cmpstr (g_variant_get_string (label, NULL), ==, "eth0:1");
+       addr = addrs->pdata[1];
+       label = nm_ip_address_get_attribute (addr, "label");
+       g_assert (label == NULL);
+       g_ptr_array_unref (addrs);
+
+       g_variant_unref (setting_dict);
+
+       /* We should be able to deserialize the labels from either 'address-labels'
+        * or 'address-data'.
+        */
+       dict2 = g_variant_ref (dict);
+
+       NMTST_VARIANT_EDITOR (dict,
+                             NMTST_VARIANT_DROP_PROPERTY (NM_SETTING_IP4_CONFIG_SETTING_NAME,
+                                                          "address-data");
+                             );
        conn = nm_simple_connection_new_from_dbus (dict, &error);
        g_assert_no_error (error);
        g_variant_unref (dict);
@@ -433,6 +457,28 @@ test_setting_ip4_config_labels (void)
        label = nm_ip_address_get_attribute (addr, "label");
        g_assert (label == NULL);
 
+       g_object_unref (conn);
+
+       NMTST_VARIANT_EDITOR (dict2,
+                             NMTST_VARIANT_DROP_PROPERTY (NM_SETTING_IP4_CONFIG_SETTING_NAME,
+                                                          "address-labels");
+                             );
+       conn = nm_simple_connection_new_from_dbus (dict2, &error);
+       g_assert_no_error (error);
+       g_variant_unref (dict2);
+
+       s_ip4 = nm_connection_get_setting_ip4_config (conn);
+
+       addr = nm_setting_ip_config_get_address (s_ip4, 0);
+       g_assert_cmpstr (nm_ip_address_get_address (addr), ==, "2.2.2.2");
+       label = nm_ip_address_get_attribute (addr, "label");
+       g_assert_cmpstr (g_variant_get_string (label, NULL), ==, "eth0:1");
+
+       addr = nm_setting_ip_config_get_address (s_ip4, 1);
+       g_assert_cmpstr (nm_ip_address_get_address (addr), ==, "3.3.3.3");
+       label = nm_ip_address_get_attribute (addr, "label");
+       g_assert (label == NULL);
+
        /* Test explicit property assignment */
        g_object_get (G_OBJECT (s_ip4),
                      NM_SETTING_IP_CONFIG_ADDRESSES, &addrs,
@@ -3391,10 +3437,14 @@ test_setting_ip4_gateway (void)
 
        g_variant_unref (ip4_dict);
 
-       /* When deserializing, the first gateway in ipv4.addresses is copied to ipv4.gateway */
+       /* When deserializing an old-style connection, the gateway from the first address
+        * is copied to :gateway.
+        */
        NMTST_VARIANT_EDITOR (conn_dict,
                              NMTST_VARIANT_DROP_PROPERTY (NM_SETTING_IP4_CONFIG_SETTING_NAME,
                                                           NM_SETTING_IP_CONFIG_GATEWAY);
+                             NMTST_VARIANT_DROP_PROPERTY (NM_SETTING_IP4_CONFIG_SETTING_NAME,
+                                                          "address-data");
                              );
 
        conn = nm_simple_connection_new_from_dbus (conn_dict, &error);
@@ -3460,10 +3510,14 @@ test_setting_ip6_gateway (void)
 
        g_variant_unref (ip6_dict);
 
-       /* When deserializing, the first gateway in ipv4.addresses is copied to ipv4.gateway */
+       /* When deserializing an old-style connection, the gateway from the first address
+        * is copied to :gateway.
+        */
        NMTST_VARIANT_EDITOR (conn_dict,
                              NMTST_VARIANT_DROP_PROPERTY (NM_SETTING_IP6_CONFIG_SETTING_NAME,
                                                           NM_SETTING_IP_CONFIG_GATEWAY);
+                             NMTST_VARIANT_DROP_PROPERTY (NM_SETTING_IP6_CONFIG_SETTING_NAME,
+                                                          "address-data");
                              );
 
        conn = nm_simple_connection_new_from_dbus (conn_dict, &error);
index a37f835..d242fe5 100644 (file)
@@ -40,6 +40,8 @@ typedef struct {
        char **domains;
        char **searches;
        char **wins;
+
+       gboolean new_style_data;
 } NMIP4ConfigPrivate;
 
 enum {
@@ -69,10 +71,13 @@ nm_ip4_config_init (NMIP4Config *config)
 }
 
 static gboolean
-demarshal_ip4_address_array (NMObject *object, GParamSpec *pspec, GVariant *value, gpointer field)
+demarshal_ip4_addresses (NMObject *object, GParamSpec *pspec, GVariant *value, gpointer field)
 {
        NMIP4ConfigPrivate *priv = NM_IP4_CONFIG_GET_PRIVATE (object);
 
+       if (priv->new_style_data)
+               return TRUE;
+
        g_ptr_array_unref (priv->addresses);
        priv->addresses = nm_utils_ip4_addresses_from_variant (value, NULL);
        _nm_object_queue_notify (object, NM_IP4_CONFIG_ADDRESSES);
@@ -80,6 +85,20 @@ demarshal_ip4_address_array (NMObject *object, GParamSpec *pspec, GVariant *valu
        return TRUE;
 }
 
+static gboolean
+demarshal_ip4_address_data (NMObject *object, GParamSpec *pspec, GVariant *value, gpointer field)
+{
+       NMIP4ConfigPrivate *priv = NM_IP4_CONFIG_GET_PRIVATE (object);
+
+       priv->new_style_data = TRUE;
+
+       g_ptr_array_unref (priv->addresses);
+       priv->addresses = nm_utils_ip_addresses_from_variant (value, AF_INET);
+       _nm_object_queue_notify (object, NM_IP4_CONFIG_ADDRESSES);
+
+       return TRUE;
+}
+
 static gboolean
 demarshal_ip4_array (NMObject *object, GParamSpec *pspec, GVariant *value, gpointer field)
 {
@@ -96,10 +115,13 @@ demarshal_ip4_array (NMObject *object, GParamSpec *pspec, GVariant *value, gpoin
 }
 
 static gboolean
-demarshal_ip4_routes_array (NMObject *object, GParamSpec *pspec, GVariant *value, gpointer field)
+demarshal_ip4_routes (NMObject *object, GParamSpec *pspec, GVariant *value, gpointer field)
 {
        NMIP4ConfigPrivate *priv = NM_IP4_CONFIG_GET_PRIVATE (object);
 
+       if (priv->new_style_data)
+               return TRUE;
+
        g_ptr_array_unref (priv->routes);
        priv->routes = nm_utils_ip4_routes_from_variant (value);
        _nm_object_queue_notify (object, NM_IP4_CONFIG_ROUTES);
@@ -107,14 +129,30 @@ demarshal_ip4_routes_array (NMObject *object, GParamSpec *pspec, GVariant *value
        return TRUE;
 }
 
+static gboolean
+demarshal_ip4_route_data (NMObject *object, GParamSpec *pspec, GVariant *value, gpointer field)
+{
+       NMIP4ConfigPrivate *priv = NM_IP4_CONFIG_GET_PRIVATE (object);
+
+       priv->new_style_data = TRUE;
+
+       g_ptr_array_unref (priv->routes);
+       priv->routes = nm_utils_ip_routes_from_variant (value, AF_INET);
+       _nm_object_queue_notify (object, NM_IP4_CONFIG_ROUTES);
+
+       return TRUE;
+}
+
 static void
 init_dbus (NMObject *object)
 {
        NMIP4ConfigPrivate *priv = NM_IP4_CONFIG_GET_PRIVATE (object);
        const NMPropertiesInfo property_info[] = {
                { NM_IP4_CONFIG_GATEWAY,      &priv->gateway, },
-               { NM_IP4_CONFIG_ADDRESSES,    &priv->addresses, demarshal_ip4_address_array },
-               { NM_IP4_CONFIG_ROUTES,       &priv->routes, demarshal_ip4_routes_array },
+               { NM_IP4_CONFIG_ADDRESSES,    &priv->addresses, demarshal_ip4_addresses },
+               { "address-data",             &priv->addresses, demarshal_ip4_address_data },
+               { NM_IP4_CONFIG_ROUTES,       &priv->routes, demarshal_ip4_routes },
+               { "route-data",               &priv->routes, demarshal_ip4_route_data },
                { NM_IP4_CONFIG_NAMESERVERS,  &priv->nameservers, demarshal_ip4_array },
                { NM_IP4_CONFIG_DOMAINS,      &priv->domains, },
                { NM_IP4_CONFIG_SEARCHES,     &priv->searches, },
index 82d377e..7318f5f 100644 (file)
@@ -39,6 +39,8 @@ typedef struct {
        char **nameservers;
        char **domains;
        char **searches;
+
+       gboolean new_style_data;
 } NMIP6ConfigPrivate;
 
 enum {
@@ -54,10 +56,13 @@ enum {
 };
 
 static gboolean
-demarshal_ip6_address_array (NMObject *object, GParamSpec *pspec, GVariant *value, gpointer field)
+demarshal_ip6_addresses (NMObject *object, GParamSpec *pspec, GVariant *value, gpointer field)
 {
        NMIP6ConfigPrivate *priv = NM_IP6_CONFIG_GET_PRIVATE (object);
 
+       if (priv->new_style_data)
+               return TRUE;
+
        g_ptr_array_unref (priv->addresses);
        priv->addresses = nm_utils_ip6_addresses_from_variant (value, NULL);
        _nm_object_queue_notify (object, NM_IP6_CONFIG_ADDRESSES);
@@ -65,6 +70,20 @@ demarshal_ip6_address_array (NMObject *object, GParamSpec *pspec, GVariant *valu
        return TRUE;
 }
 
+static gboolean
+demarshal_ip6_address_data (NMObject *object, GParamSpec *pspec, GVariant *value, gpointer field)
+{
+       NMIP6ConfigPrivate *priv = NM_IP6_CONFIG_GET_PRIVATE (object);
+
+       priv->new_style_data = TRUE;
+
+       g_ptr_array_unref (priv->addresses);
+       priv->addresses = nm_utils_ip_addresses_from_variant (value, AF_INET6);
+       _nm_object_queue_notify (object, NM_IP6_CONFIG_ADDRESSES);
+
+       return TRUE;
+}
+
 static gboolean
 demarshal_ip6_nameserver_array (NMObject *object, GParamSpec *pspec, GVariant *value, gpointer field)
 {
@@ -81,10 +100,13 @@ demarshal_ip6_nameserver_array (NMObject *object, GParamSpec *pspec, GVariant *v
 }
 
 static gboolean
-demarshal_ip6_routes_array (NMObject *object, GParamSpec *pspec, GVariant *value, gpointer field)
+demarshal_ip6_routes (NMObject *object, GParamSpec *pspec, GVariant *value, gpointer field)
 {
        NMIP6ConfigPrivate *priv = NM_IP6_CONFIG_GET_PRIVATE (object);
 
+       if (priv->new_style_data)
+               return TRUE;
+
        g_ptr_array_unref (priv->routes);
        priv->routes = nm_utils_ip6_routes_from_variant (value);
        _nm_object_queue_notify (object, NM_IP6_CONFIG_ROUTES);
@@ -92,14 +114,30 @@ demarshal_ip6_routes_array (NMObject *object, GParamSpec *pspec, GVariant *value
        return TRUE;
 }
 
+static gboolean
+demarshal_ip6_route_data (NMObject *object, GParamSpec *pspec, GVariant *value, gpointer field)
+{
+       NMIP6ConfigPrivate *priv = NM_IP6_CONFIG_GET_PRIVATE (object);
+
+       priv->new_style_data = TRUE;
+
+       g_ptr_array_unref (priv->routes);
+       priv->routes = nm_utils_ip_routes_from_variant (value, AF_INET6);
+       _nm_object_queue_notify (object, NM_IP6_CONFIG_ROUTES);
+
+       return TRUE;
+}
+
 static void
 init_dbus (NMObject *object)
 {
        NMIP6ConfigPrivate *priv = NM_IP6_CONFIG_GET_PRIVATE (object);
        const NMPropertiesInfo property_info[] = {
                { NM_IP6_CONFIG_GATEWAY,      &priv->gateway, },
-               { NM_IP6_CONFIG_ADDRESSES,    &priv->addresses, demarshal_ip6_address_array },
-               { NM_IP6_CONFIG_ROUTES,       &priv->routes, demarshal_ip6_routes_array },
+               { NM_IP6_CONFIG_ADDRESSES,    &priv->addresses, demarshal_ip6_addresses },
+               { "address-data",             &priv->addresses, demarshal_ip6_address_data },
+               { NM_IP6_CONFIG_ROUTES,       &priv->routes, demarshal_ip6_routes },
+               { "route-data",               &priv->routes, demarshal_ip6_route_data },
                { NM_IP6_CONFIG_NAMESERVERS,  &priv->nameservers, demarshal_ip6_nameserver_array },
                { NM_IP6_CONFIG_DOMAINS,      &priv->domains, },
                { NM_IP6_CONFIG_SEARCHES,     &priv->searches, },
index 12d3919..74a7556 100644 (file)
@@ -59,9 +59,11 @@ G_STATIC_ASSERT (G_MAXUINT >= 0xFFFFFFFF);
 
 enum {
        PROP_0,
-       PROP_GATEWAY,
+       PROP_ADDRESS_DATA,
        PROP_ADDRESSES,
+       PROP_ROUTE_DATA,
        PROP_ROUTES,
+       PROP_GATEWAY,
        PROP_NAMESERVERS,
        PROP_DOMAINS,
        PROP_SEARCHES,
@@ -235,6 +237,8 @@ nm_ip4_config_capture (int ifindex, gboolean capture_resolv_conf)
        }
 
        /* actually, nobody should be connected to the signal, just to be sure, notify */
+       _NOTIFY (config, PROP_ADDRESS_DATA);
+       _NOTIFY (config, PROP_ROUTE_DATA);
        _NOTIFY (config, PROP_ADDRESSES);
        _NOTIFY (config, PROP_ROUTES);
        if (priv->gateway != old_gateway)
@@ -1013,6 +1017,7 @@ nm_ip4_config_reset_addresses (NMIP4Config *config)
 
        if (priv->addresses->len != 0) {
                g_array_set_size (priv->addresses, 0);
+               _NOTIFY (config, PROP_ADDRESS_DATA);
                _NOTIFY (config, PROP_ADDRESSES);
        }
 }
@@ -1070,6 +1075,7 @@ nm_ip4_config_add_address (NMIP4Config *config, const NMPlatformIP4Address *new)
 
        g_array_append_val (priv->addresses, *new);
 NOTIFY:
+       _NOTIFY (config, PROP_ADDRESS_DATA);
        _NOTIFY (config, PROP_ADDRESSES);
 }
 
@@ -1081,6 +1087,7 @@ nm_ip4_config_del_address (NMIP4Config *config, guint i)
        g_return_if_fail (i < priv->addresses->len);
 
        g_array_remove_index (priv->addresses, i);
+       _NOTIFY (config, PROP_ADDRESS_DATA);
        _NOTIFY (config, PROP_ADDRESSES);
 }
 
@@ -1125,6 +1132,7 @@ nm_ip4_config_reset_routes (NMIP4Config *config)
 
        if (priv->routes->len != 0) {
                g_array_set_size (priv->routes, 0);
+               _NOTIFY (config, PROP_ROUTE_DATA);
                _NOTIFY (config, PROP_ROUTES);
        }
 }
@@ -1164,6 +1172,7 @@ nm_ip4_config_add_route (NMIP4Config *config, const NMPlatformIP4Route *new)
 
        g_array_append_val (priv->routes, *new);
 NOTIFY:
+       _NOTIFY (config, PROP_ROUTE_DATA);
        _NOTIFY (config, PROP_ROUTES);
 }
 
@@ -1175,6 +1184,7 @@ nm_ip4_config_del_route (NMIP4Config *config, guint i)
        g_return_if_fail (i < priv->routes->len);
 
        g_array_remove_index (priv->routes, i);
+       _NOTIFY (config, PROP_ROUTE_DATA);
        _NOTIFY (config, PROP_ROUTES);
 }
 
@@ -1705,11 +1715,41 @@ get_property (GObject *object, guint prop_id,
        NMIP4ConfigPrivate *priv = NM_IP4_CONFIG_GET_PRIVATE (object);
 
        switch (prop_id) {
-       case PROP_GATEWAY:
-               if (priv->gateway)
-                       g_value_set_string (value, nm_utils_inet4_ntop (priv->gateway, NULL));
-               else
-                       g_value_set_string (value, NULL);
+       case PROP_ADDRESS_DATA:
+               {
+                       GPtrArray *addresses = g_ptr_array_new ();
+                       int naddr = nm_ip4_config_get_num_addresses (config);
+                       int i;
+
+                       for (i = 0; i < naddr; i++) {
+                               const NMPlatformIP4Address *address = nm_ip4_config_get_address (config, i);
+                               GValueArray *array = g_value_array_new (3);
+                               GHashTable *attrs;
+                               GValue val = { 0, };
+
+                               g_value_init (&val, G_TYPE_STRING);
+                               g_value_set_string (&val, nm_utils_inet4_ntop (address->address, NULL));
+                               g_value_array_append (array, &val);
+                               g_value_unset (&val);
+
+                               g_value_init (&val, G_TYPE_UINT);
+                               g_value_set_uint (&val, address->plen);
+                               g_value_array_append (array, &val);
+                               g_value_unset (&val);
+
+                               g_value_init (&val, DBUS_TYPE_G_MAP_OF_STRING);
+                               attrs = g_hash_table_new_full (g_str_hash, g_str_equal, NULL, g_free);
+                               if (*address->label)
+                                       g_hash_table_insert (attrs, "label", g_strdup (address->label));
+                               g_value_take_boxed (&val, attrs);
+                               g_value_array_append (array, &val);
+                               g_value_unset (&val);
+
+                               g_ptr_array_add (addresses, array);
+                       }
+
+                       g_value_take_boxed (value, addresses);
+               }
                break;
        case PROP_ADDRESSES:
                {
@@ -1732,6 +1772,53 @@ get_property (GObject *object, guint prop_id,
                        g_value_take_boxed (value, addresses);
                }
                break;
+       case PROP_ROUTE_DATA:
+               {
+                       GPtrArray *routes = g_ptr_array_new ();
+                       guint nroutes = nm_ip4_config_get_num_routes (config);
+                       int i;
+
+                       for (i = 0; i < nroutes; i++) {
+                               const NMPlatformIP4Route *route = nm_ip4_config_get_route (config, i);
+                               GValueArray *array = g_value_array_new (5);
+                               GHashTable *attrs;
+                               GValue val = { 0, };
+
+                               g_value_init (&val, G_TYPE_STRING);
+                               g_value_set_string (&val, nm_utils_inet4_ntop (route->network, NULL));
+                               g_value_array_append (array, &val);
+                               g_value_unset (&val);
+
+                               g_value_init (&val, G_TYPE_UINT);
+                               g_value_set_uint (&val, route->plen);
+                               g_value_array_append (array, &val);
+                               g_value_unset (&val);
+
+                               g_value_init (&val, G_TYPE_STRING);
+                               if (route->gateway)
+                                       g_value_set_string (&val, nm_utils_inet4_ntop (route->gateway, NULL));
+                               else
+                                       g_value_set_string (&val, "");
+                               g_value_array_append (array, &val);
+                               g_value_unset (&val);
+
+                               g_value_init (&val, G_TYPE_UINT);
+                               g_value_set_uint (&val, route->metric);
+                               g_value_array_append (array, &val);
+                               g_value_unset (&val);
+
+                               g_value_init (&val, DBUS_TYPE_G_MAP_OF_STRING);
+                               attrs = g_hash_table_new (g_str_hash, g_str_equal);
+                               g_value_take_boxed (&val, attrs);
+                               g_value_array_append (array, &val);
+                               g_value_unset (&val);
+
+                               g_ptr_array_add (routes, array);
+                       }
+
+                       g_value_take_boxed (value, routes);
+               }
+               break;
        case PROP_ROUTES:
                {
                        GPtrArray *routes = g_ptr_array_new ();
@@ -1753,6 +1840,12 @@ get_property (GObject *object, guint prop_id,
                        g_value_take_boxed (value, routes);
                }
                break;
+       case PROP_GATEWAY:
+               if (priv->gateway)
+                       g_value_set_string (value, nm_utils_inet4_ntop (priv->gateway, NULL));
+               else
+                       g_value_set_string (value, NULL);
+               break;
        case PROP_NAMESERVERS:
                g_value_set_boxed (value, priv->nameservers);
                break;
@@ -1781,19 +1874,29 @@ nm_ip4_config_class_init (NMIP4ConfigClass *config_class)
        object_class->get_property = get_property;
        object_class->finalize = finalize;
 
-       obj_properties[PROP_GATEWAY] =
-                g_param_spec_string (NM_IP4_CONFIG_GATEWAY, "", "",
-                                     NULL,
-                                     G_PARAM_READABLE |
-                                     G_PARAM_STATIC_STRINGS);
+       obj_properties[PROP_ADDRESS_DATA] =
+                g_param_spec_boxed (NM_IP4_CONFIG_ADDRESS_DATA, "", "",
+                                    DBUS_TYPE_NM_IP_ADDRESSES,
+                                    G_PARAM_READABLE |
+                                    G_PARAM_STATIC_STRINGS);
        obj_properties[PROP_ADDRESSES] =
-                g_param_spec_boxed (NM_IP4_CONFIG_ADDRESSES, "", "",
-                                    DBUS_TYPE_G_ARRAY_OF_ARRAY_OF_UINT,
+               g_param_spec_boxed (NM_IP4_CONFIG_ADDRESSES, "", "",
+                                   DBUS_TYPE_G_ARRAY_OF_ARRAY_OF_UINT,
+                                   G_PARAM_READABLE |
+                                   G_PARAM_STATIC_STRINGS);
+       obj_properties[PROP_ROUTE_DATA] =
+                g_param_spec_boxed (NM_IP4_CONFIG_ROUTE_DATA, "", "",
+                                    DBUS_TYPE_NM_IP_ROUTES,
                                     G_PARAM_READABLE |
                                     G_PARAM_STATIC_STRINGS);
        obj_properties[PROP_ROUTES] =
-                g_param_spec_boxed (NM_IP4_CONFIG_ROUTES, "", "",
-                                    DBUS_TYPE_G_ARRAY_OF_ARRAY_OF_UINT,
+               g_param_spec_boxed (NM_IP4_CONFIG_ROUTES, "", "",
+                                   DBUS_TYPE_G_ARRAY_OF_ARRAY_OF_UINT,
+                                   G_PARAM_READABLE |
+                                   G_PARAM_STATIC_STRINGS);
+       obj_properties[PROP_GATEWAY] =
+               g_param_spec_string (NM_IP4_CONFIG_GATEWAY, "", "",
+                                    NULL,
                                     G_PARAM_READABLE |
                                     G_PARAM_STATIC_STRINGS);
        obj_properties[PROP_NAMESERVERS] =
index e9f2642..555f167 100644 (file)
@@ -41,14 +41,18 @@ typedef struct {
        GObjectClass parent;
 } NMIP4ConfigClass;
 
+#define NM_IP4_CONFIG_ADDRESS_DATA "address-data"
+#define NM_IP4_CONFIG_ROUTE_DATA "route-data"
 #define NM_IP4_CONFIG_GATEWAY "gateway"
-#define NM_IP4_CONFIG_ADDRESSES "addresses"
-#define NM_IP4_CONFIG_ROUTES "routes"
 #define NM_IP4_CONFIG_NAMESERVERS "nameservers"
 #define NM_IP4_CONFIG_DOMAINS "domains"
 #define NM_IP4_CONFIG_SEARCHES "searches"
 #define NM_IP4_CONFIG_WINS_SERVERS "wins-servers"
 
+/* deprecated */
+#define NM_IP4_CONFIG_ADDRESSES "addresses"
+#define NM_IP4_CONFIG_ROUTES "routes"
+
 GType nm_ip4_config_get_type (void);
 
 
index e007b20..19552e0 100644 (file)
@@ -51,9 +51,11 @@ typedef struct {
 
 enum {
        PROP_0,
-       PROP_GATEWAY,
+       PROP_ADDRESS_DATA,
        PROP_ADDRESSES,
+       PROP_ROUTE_DATA,
        PROP_ROUTES,
+       PROP_GATEWAY,
        PROP_NAMESERVERS,
        PROP_DOMAINS,
        PROP_SEARCHES,
@@ -271,6 +273,7 @@ nm_ip6_config_addresses_sort (NMIP6Config *self, NMSettingIP6ConfigPrivacy use_t
                g_free (data_pre);
 
                if (changed) {
+                       _NOTIFY (self, PROP_ADDRESS_DATA);
                        _NOTIFY (self, PROP_ADDRESSES);
                        return TRUE;
                }
@@ -346,7 +349,9 @@ nm_ip6_config_capture (int ifindex, gboolean capture_resolv_conf, NMSettingIP6Co
        /* actually, nobody should be connected to the signal, just to be sure, notify */
        if (notify_nameservers)
                _NOTIFY (config, PROP_NAMESERVERS);
+       _NOTIFY (config, PROP_ADDRESS_DATA);
        _NOTIFY (config, PROP_ADDRESSES);
+       _NOTIFY (config, PROP_ROUTE_DATA);
        _NOTIFY (config, PROP_ROUTES);
        if (!IN6_ARE_ADDR_EQUAL (&priv->gateway, &old_gateway))
                _NOTIFY (config, PROP_GATEWAY);
@@ -1016,6 +1021,7 @@ nm_ip6_config_reset_addresses (NMIP6Config *config)
 
        if (priv->addresses->len != 0) {
                g_array_set_size (priv->addresses, 0);
+               _NOTIFY (config, PROP_ADDRESS_DATA);
                _NOTIFY (config, PROP_ADDRESSES);
        }
 }
@@ -1073,6 +1079,7 @@ nm_ip6_config_add_address (NMIP6Config *config, const NMPlatformIP6Address *new)
 
        g_array_append_val (priv->addresses, *new);
 NOTIFY:
+       _NOTIFY (config, PROP_ADDRESS_DATA);
        _NOTIFY (config, PROP_ADDRESSES);
 }
 
@@ -1084,6 +1091,7 @@ nm_ip6_config_del_address (NMIP6Config *config, guint i)
        g_return_if_fail (i < priv->addresses->len);
 
        g_array_remove_index (priv->addresses, i);
+       _NOTIFY (config, PROP_ADDRESS_DATA);
        _NOTIFY (config, PROP_ADDRESSES);
 }
 
@@ -1129,6 +1137,7 @@ nm_ip6_config_reset_routes (NMIP6Config *config)
 
        if (priv->routes->len != 0) {
                g_array_set_size (priv->routes, 0);
+               _NOTIFY (config, PROP_ROUTE_DATA);
                _NOTIFY (config, PROP_ROUTES);
        }
 }
@@ -1168,6 +1177,7 @@ nm_ip6_config_add_route (NMIP6Config *config, const NMPlatformIP6Route *new)
 
        g_array_append_val (priv->routes, *new);
 NOTIFY:
+       _NOTIFY (config, PROP_ROUTE_DATA);
        _NOTIFY (config, PROP_ROUTES);
 }
 
@@ -1179,6 +1189,7 @@ nm_ip6_config_del_route (NMIP6Config *config, guint i)
        g_return_if_fail (i < priv->routes->len);
 
        g_array_remove_index (priv->routes, i);
+       _NOTIFY (config, PROP_ROUTE_DATA);
        _NOTIFY (config, PROP_ROUTES);
 }
 
@@ -1578,11 +1589,39 @@ get_property (GObject *object, guint prop_id,
        NMIP6ConfigPrivate *priv = NM_IP6_CONFIG_GET_PRIVATE (object);
 
        switch (prop_id) {
-       case PROP_GATEWAY:
-               if (!IN6_IS_ADDR_UNSPECIFIED (&priv->gateway))
-                       g_value_set_string (value, nm_utils_inet6_ntop (&priv->gateway, NULL));
-               else
-                       g_value_set_string (value, NULL);
+       case PROP_ADDRESS_DATA:
+               {
+                       GPtrArray *addresses = g_ptr_array_new ();
+                       int naddr = nm_ip6_config_get_num_addresses (config);
+                       int i;
+
+                       for (i = 0; i < naddr; i++) {
+                               const NMPlatformIP6Address *address = nm_ip6_config_get_address (config, i);
+                               GValueArray *array = g_value_array_new (3);
+                               GHashTable *attrs;
+                               GValue val = { 0, };
+
+                               g_value_init (&val, G_TYPE_STRING);
+                               g_value_set_string (&val, nm_utils_inet6_ntop (&address->address, NULL));
+                               g_value_array_append (array, &val);
+                               g_value_unset (&val);
+
+                               g_value_init (&val, G_TYPE_UINT);
+                               g_value_set_uint (&val, address->plen);
+                               g_value_array_append (array, &val);
+                               g_value_unset (&val);
+
+                               g_value_init (&val, DBUS_TYPE_G_MAP_OF_STRING);
+                               attrs = g_hash_table_new (g_str_hash, g_str_equal);
+                               g_value_take_boxed (&val, attrs);
+                               g_value_array_append (array, &val);
+                               g_value_unset (&val);
+
+                               g_ptr_array_add (addresses, array);
+                       }
+
+                       g_value_take_boxed (value, addresses);
+               }
                break;
        case PROP_ADDRESSES:
                {
@@ -1626,6 +1665,53 @@ get_property (GObject *object, guint prop_id,
                        g_value_take_boxed (value, addresses);
                }
                break;
+       case PROP_ROUTE_DATA:
+               {
+                       GPtrArray *routes = g_ptr_array_new ();
+                       guint nroutes = nm_ip6_config_get_num_routes (config);
+                       int i;
+
+                       for (i = 0; i < nroutes; i++) {
+                               const NMPlatformIP6Route *route = nm_ip6_config_get_route (config, i);
+                               GValueArray *array = g_value_array_new (5);
+                               GHashTable *attrs;
+                               GValue val = { 0, };
+
+                               g_value_init (&val, G_TYPE_STRING);
+                               g_value_set_string (&val, nm_utils_inet6_ntop (&route->network, NULL));
+                               g_value_array_append (array, &val);
+                               g_value_unset (&val);
+
+                               g_value_init (&val, G_TYPE_UINT);
+                               g_value_set_uint (&val, route->plen);
+                               g_value_array_append (array, &val);
+                               g_value_unset (&val);
+
+                               g_value_init (&val, G_TYPE_STRING);
+                               if (memcmp (&route->gateway, &in6addr_any, sizeof (struct in6_addr)) != 0)
+                                       g_value_set_string (&val, nm_utils_inet6_ntop (&route->gateway, NULL));
+                               else
+                                       g_value_set_string (&val, "");
+                               g_value_array_append (array, &val);
+                               g_value_unset (&val);
+
+                               g_value_init (&val, G_TYPE_UINT);
+                               g_value_set_uint (&val, route->metric);
+                               g_value_array_append (array, &val);
+                               g_value_unset (&val);
+
+                               g_value_init (&val, DBUS_TYPE_G_MAP_OF_STRING);
+                               attrs = g_hash_table_new (g_str_hash, g_str_equal);
+                               g_value_take_boxed (&val, attrs);
+                               g_value_array_append (array, &val);
+                               g_value_unset (&val);
+
+                               g_ptr_array_add (routes, array);
+                       }
+
+                       g_value_take_boxed (value, routes);
+               }
+               break;
        case PROP_ROUTES:
                {
                        GPtrArray *routes = g_ptr_array_new ();
@@ -1669,6 +1755,12 @@ get_property (GObject *object, guint prop_id,
                        g_value_take_boxed (value, routes);
                }
                break;
+       case PROP_GATEWAY:
+               if (!IN6_IS_ADDR_UNSPECIFIED (&priv->gateway))
+                       g_value_set_string (value, nm_utils_inet6_ntop (&priv->gateway, NULL));
+               else
+                       g_value_set_string (value, NULL);
+               break;
        case PROP_NAMESERVERS:
                nameservers_to_gvalue (priv->nameservers, value);
                break;
@@ -1696,21 +1788,31 @@ nm_ip6_config_class_init (NMIP6ConfigClass *config_class)
        object_class->finalize = finalize;
 
        /* properties */
-       obj_properties[PROP_GATEWAY] =
-           g_param_spec_string (NM_IP6_CONFIG_GATEWAY, "", "",
-                                NULL,
-                                G_PARAM_READABLE |
-                                G_PARAM_STATIC_STRINGS);
-       obj_properties[PROP_ADDRESSES] =
-           g_param_spec_boxed (NM_IP6_CONFIG_ADDRESSES, "", "",
-                               DBUS_TYPE_G_ARRAY_OF_IP6_ADDRESS,
+       obj_properties[PROP_ADDRESS_DATA] =
+           g_param_spec_boxed (NM_IP6_CONFIG_ADDRESS_DATA, "", "",
+                               DBUS_TYPE_NM_IP_ADDRESSES,
                                G_PARAM_READABLE |
                                G_PARAM_STATIC_STRINGS);
+       obj_properties[PROP_ADDRESSES] =
+               g_param_spec_boxed (NM_IP6_CONFIG_ADDRESSES, "", "",
+                                   DBUS_TYPE_G_ARRAY_OF_IP6_ADDRESS,
+                                   G_PARAM_READABLE |
+                                   G_PARAM_STATIC_STRINGS);
+       obj_properties[PROP_ROUTE_DATA] =
+               g_param_spec_boxed (NM_IP6_CONFIG_ROUTE_DATA, "", "",
+                                   DBUS_TYPE_NM_IP_ROUTES,
+                                   G_PARAM_READABLE |
+                                   G_PARAM_STATIC_STRINGS);
        obj_properties[PROP_ROUTES] =
            g_param_spec_boxed (NM_IP6_CONFIG_ROUTES, "", "",
                                DBUS_TYPE_G_ARRAY_OF_IP6_ROUTE,
                                G_PARAM_READABLE |
                                G_PARAM_STATIC_STRINGS);
+       obj_properties[PROP_GATEWAY] =
+               g_param_spec_string (NM_IP6_CONFIG_GATEWAY, "", "",
+                                    NULL,
+                                    G_PARAM_READABLE |
+                                    G_PARAM_STATIC_STRINGS);
        obj_properties[PROP_NAMESERVERS] =
            g_param_spec_boxed (NM_IP6_CONFIG_NAMESERVERS, "", "",
                                DBUS_TYPE_G_ARRAY_OF_ARRAY_OF_UCHAR,
index 19eef01..0174158 100644 (file)
@@ -42,13 +42,17 @@ typedef struct {
        GObjectClass parent;
 } NMIP6ConfigClass;
 
+#define NM_IP6_CONFIG_ADDRESS_DATA "address-data"
+#define NM_IP6_CONFIG_ROUTE_DATA "route-data"
 #define NM_IP6_CONFIG_GATEWAY "gateway"
-#define NM_IP6_CONFIG_ADDRESSES "addresses"
-#define NM_IP6_CONFIG_ROUTES "routes"
 #define NM_IP6_CONFIG_NAMESERVERS "nameservers"
 #define NM_IP6_CONFIG_DOMAINS "domains"
 #define NM_IP6_CONFIG_SEARCHES "searches"
 
+/* deprecated */
+#define NM_IP6_CONFIG_ADDRESSES "addresses"
+#define NM_IP6_CONFIG_ROUTES "routes"
+
 GType nm_ip6_config_get_type (void);