From 3b0255f73c6d539b5dcd882f38c5d23ad3f7dab2 Mon Sep 17 00:00:00 2001 From: Jirka Klimes Date: Tue, 5 Jan 2010 18:51:53 -0600 Subject: [PATCH] libnm-util: add IPv6 comparison functions --- libnm-util/nm-param-spec-specialized.c | 207 ++++++++++++++++++++++++- 1 file changed, 205 insertions(+), 2 deletions(-) diff --git a/libnm-util/nm-param-spec-specialized.c b/libnm-util/nm-param-spec-specialized.c index 10621fac47..ad0febfcf6 100644 --- a/libnm-util/nm-param-spec-specialized.c +++ b/libnm-util/nm-param-spec-specialized.c @@ -31,8 +31,11 @@ struct _NMParamSpecSpecialized { #include #include +#include #include +#include "nm-dbus-glib-types.h" + /***********************************************************/ /* nm_gvalues_compare */ @@ -367,11 +370,129 @@ nm_gvalues_compare_map (const GValue *value1, const GValue *value2) return ret; } +static gint +nm_gvalue_ip6_address_compare (const GValue *value1, const GValue *value2) +{ + GValueArray *values1, *values2; + GValue *tmp_val; + GByteArray *addr1, *addr2; + guint32 prefix1, prefix2; + gint ret = 0; + int i; + + /* IP6 addresses are GValueArrays (see nm-dbus-glib-types.h) */ + values1 = g_value_get_boxed (value1); + values2 = g_value_get_boxed (value2); + + /* Since they are NM IPv6 address structures, we expect both + * to contain two elements as specified in nm-dbus-glib-types.h. + */ + g_return_val_if_fail (values1->n_values == 2, 0); + g_return_val_if_fail (values2->n_values == 2, 0); + + /* First struct IPv6 address */ + tmp_val = g_value_array_get_nth (values1, 0); + addr1 = g_value_get_boxed (tmp_val); + /* First struct IPv6 prefix */ + tmp_val = g_value_array_get_nth (values1, 1); + prefix1 = g_value_get_uint (tmp_val); + + /* Second struct IPv6 address */ + tmp_val = g_value_array_get_nth (values2, 0); + addr2 = g_value_get_boxed (tmp_val); + /* Second struct IPv6 prefix */ + tmp_val = g_value_array_get_nth (values2, 1); + prefix2 = g_value_get_uint (tmp_val); + + /* Compare IPv6 addresses */ + if (prefix1 != prefix2) + return prefix1 < prefix2 ? -1 : prefix1 > prefix2; + + if (!IN6_ARE_ADDR_EQUAL ((struct in6_addr *)addr1->data, (struct in6_addr *)addr2->data)) { + for (i = 0; ret == 0 && i < addr1->len; i++) + ret = addr1->data[i] < addr2->data[i] ? -1 : addr1->data[i] > addr2->data[i]; + } + + return ret; +} + +static gint +nm_gvalue_ip6_route_compare (const GValue *value1, const GValue *value2) +{ + GValueArray *values1, *values2; + GValue *tmp_val; + GByteArray *dest1, *dest2; + GByteArray *next_hop1, *next_hop2; + guint32 prefix1, prefix2; + guint32 metric1, metric2; + gint ret = 0; + int i; + + /* IP6 routes are GValueArrays (see nm-dbus-glib-types.h) */ + values1 = g_value_get_boxed (value1); + values2 = g_value_get_boxed (value2); + + /* Since they are NM IPv6 route structures, we expect both + * to contain 4 elements as specified in nm-dbus-glib-types.h. + */ + g_return_val_if_fail (values1->n_values == 4, 0); + g_return_val_if_fail (values2->n_values == 4, 0); + + /* First struct IPv6 route */ + tmp_val = g_value_array_get_nth (values1, 0); + dest1 = g_value_get_boxed (tmp_val); + tmp_val = g_value_array_get_nth (values1, 1); + prefix1 = g_value_get_uint (tmp_val); + tmp_val = g_value_array_get_nth (values1, 2); + next_hop1 = g_value_get_boxed (tmp_val); + tmp_val = g_value_array_get_nth (values1, 3); + metric1 = g_value_get_uint (tmp_val); + + /* Second struct IPv6 route */ + tmp_val = g_value_array_get_nth (values2, 0); + dest2 = g_value_get_boxed (tmp_val); + tmp_val = g_value_array_get_nth (values2, 1); + prefix2 = g_value_get_uint (tmp_val); + tmp_val = g_value_array_get_nth (values2, 2); + next_hop2 = g_value_get_boxed (tmp_val); + tmp_val = g_value_array_get_nth (values2, 3); + metric2 = g_value_get_uint (tmp_val); + + /* Compare the routes */ + if (prefix1 != prefix2) + return prefix1 < prefix2 ? -1 : prefix1 > prefix2; + + if (!IN6_ARE_ADDR_EQUAL ((struct in6_addr *)dest1->data, (struct in6_addr *)dest2->data)) { + for (i = 0; ret == 0 && i < dest1->len; i++) + ret = dest1->data[i] < dest2->data[i] ? -1 : dest1->data[i] > dest2->data[i]; + } + + if (!IN6_ARE_ADDR_EQUAL ((struct in6_addr *)next_hop1->data, (struct in6_addr *)next_hop2->data)) { + for (i = 0; ret == 0 && i < next_hop1->len; i++) + ret = next_hop1->data[i] < next_hop2->data[i] ? -1 : next_hop1->data[i] > next_hop2->data[i]; + } + + if (metric1 != metric2) + ret = metric1 < metric2 ? -1 : metric1 > metric2; + + return ret; +} + static gint nm_gvalues_compare_struct (const GValue *value1, const GValue *value2) { - g_warning ("Not implemented"); - return 0; + /* value1 and value2 must contain the same type since + * nm_gvalues_compare() enforced that already. + */ + + if (G_VALUE_HOLDS (value1, DBUS_TYPE_G_IP6_ADDRESS)) { + return nm_gvalue_ip6_address_compare (value1, value2); + } else if (G_VALUE_HOLDS (value1, DBUS_TYPE_G_IP6_ROUTE)) { + return nm_gvalue_ip6_route_compare (value1, value2); + } else { + g_warning ("Don't know how to compare structures"); + return (value1 == value2); + } } gint @@ -736,6 +857,87 @@ compare_gvalue_hash (void) g_print ("Comparing different str hashes: %d\n", nm_gvalues_compare (&value1, &value2)); } +static void +compare_ip6_addresses (void) +{ + GValueArray *array1; + GValueArray *array2; + GValueArray *array3; + GByteArray *ba1; + GByteArray *ba2; + GByteArray *ba3; + GValue element = { 0 }; + GValue value1 = { 0 }; + GValue value2 = { 0 }; + struct in6_addr addr1; + struct in6_addr addr2; + struct in6_addr addr3; + guint32 prefix1 = 64; + guint32 prefix2 = 64; + guint32 prefix3 = 0; + + inet_pton (AF_INET6, "1:2:3:4:5:6:7:8", &addr1, sizeof (struct in6_addr)); + inet_pton (AF_INET6, "ffff:2:3:4:5:6:7:8", &addr2, sizeof (struct in6_addr)); + inet_pton (AF_INET6, "::", &addr3, sizeof (struct in6_addr)); + + /* address 1 */ + ba1 = g_byte_array_new (); + array1 = g_value_array_new (2); + g_value_init (&element, DBUS_TYPE_G_UCHAR_ARRAY); + g_byte_array_append (ba1, (guint8 *) addr1.s6_addr, 16); + g_value_take_boxed (&element, ba1); + g_value_array_append (array1, &element); + g_value_unset (&element); + + g_value_init (&element, G_TYPE_UINT); + g_value_set_uint (&element, prefix1); + g_value_array_append (array1, &element); + g_value_unset (&element); + + /* address 2 */ + ba2 = g_byte_array_new (); + array2 = g_value_array_new (2); + g_value_init (&element, DBUS_TYPE_G_UCHAR_ARRAY); + g_byte_array_append (ba2, (guint8 *) addr2.s6_addr, 16); + g_value_take_boxed (&element, ba2); + g_value_array_append (array2, &element); + g_value_unset (&element); + + g_value_init (&element, G_TYPE_UINT); + g_value_set_uint (&element, prefix2); + g_value_array_append (array2, &element); + g_value_unset (&element); + + /* address 3 */ + ba3 = g_byte_array_new (); + array3 = g_value_array_new (2); + g_value_init (&element, DBUS_TYPE_G_UCHAR_ARRAY); + g_byte_array_append (ba3, (guint8 *) addr3.s6_addr, 16); + g_value_take_boxed (&element, ba3); + g_value_array_append (array3, &element); + g_value_unset (&element); + + g_value_init (&element, G_TYPE_UINT); + g_value_set_uint (&element, prefix3); + g_value_array_append (array3, &element); + g_value_unset (&element); + + g_value_init (&value1, DBUS_TYPE_G_IP6_ADDRESS); + g_value_init (&value2, DBUS_TYPE_G_IP6_ADDRESS); + + g_value_set_boxed (&value1, array1); + g_value_set_boxed (&value2, array1); + g_print ("Comparing identical IPv6 address structures: %d\n", nm_gvalues_compare (&value1, &value2)); + + g_value_set_boxed (&value1, array1); + g_value_set_boxed (&value2, array2); + g_print ("Comparing different IPv6 address structures: %d\n", nm_gvalues_compare (&value1, &value2)); + + g_value_set_boxed (&value1, array1); + g_value_set_boxed (&value2, array3); + g_print ("Comparing different IPv6 address structures: %d\n", nm_gvalues_compare (&value1, &value2)); +} + int main (int argc, char *argv[]) { @@ -751,6 +953,7 @@ main (int argc, char *argv[]) compare_ptrarrays (); compare_str_hash (); compare_gvalue_hash (); + compare_ip6_addresses (); return 0; }